id-auto-formalizer
Version:
Konversi teks Bahasa Indonesia dari kasual ke formal untuk surat, email, dan laporan resmi
291 lines (238 loc) • 10.1 kB
JavaScript
import chalk from 'chalk';
import { Command } from 'commander';
import fs from 'fs/promises';
import ora from 'ora';
import path from 'path';
import readline from 'readline';
import IndonesianFormalizer from './formalizer.js'; // tambahkan .js agar import ESM bisa resolve
const program = new Command();
const formalizer = new IndonesianFormalizer();
// ASCII Art Banner
const banner = `
╔═══════════════════════════════════════════════════╗
║ 🇮🇩 Bahasa Indonesia Auto Formalizer 🇮🇩 ║
║ Konversi teks kasual → formal dengan mudah! ║
╚═══════════════════════════════════════════════════╝
`;
program
.name('formalize')
.description('CLI untuk mengkonversi teks Bahasa Indonesia dari kasual ke formal')
.version('0.1.0');
// Command: Formalize text langsung
program
.command('text <text>')
.description('Formalisasi teks langsung')
.option('-c, --no-capitalize', 'Nonaktifkan auto kapitalisasi')
.option('-p, --no-punctuation', 'Nonaktifkan auto punctuation')
.option('-a, --analyze', 'Tampilkan analisis formalitas')
.option('-s, --suggest', 'Tampilkan saran perbaikan')
.action((text, options) => {
console.log(chalk.cyan(banner));
const spinner = ora('Memproses teks...').start();
setTimeout(() => {
const result = formalizer.formalize(text, {
autoCapitalize: options.capitalize,
autoPunctuation: options.punctuation
});
spinner.succeed('Proses selesai!');
console.log('\n' + chalk.yellow('📝 Teks Original:'));
console.log(chalk.gray(text));
console.log('\n' + chalk.green('✨ Teks Formal:'));
console.log(chalk.white(result));
if (options.analyze) {
const analysis = formalizer.analyzeFormalityLevel(text);
console.log('\n' + chalk.blue('📊 Analisis Formalitas:'));
console.log(chalk.white(` Level: ${analysis.level}`));
console.log(chalk.white(` Skor Formalitas: ${analysis.score}%`));
// eslint-disable-next-line max-len
console.log(chalk.white(` Kata Informal: ${analysis.informalWords}/${analysis.totalWords}`));
}
if (options.suggest) {
const suggestions = formalizer.suggestImprovements(text);
if (suggestions.length > 0) {
console.log('\n' + chalk.magenta('💡 Saran Perbaikan:'));
suggestions.forEach((s, i) => {
// eslint-disable-next-line max-len
console.log(chalk.white(` ${i + 1}. ${s.reason}: "${s.original}" → "${s.suggestion}"`));
});
}
}
}, 500);
});
// Command: Formalize file
program
.command('file <filepath>')
.description('Formalisasi teks dari file')
.option('-o, --output <filepath>', 'Simpan hasil ke file')
.option('-c, --no-capitalize', 'Nonaktifkan auto kapitalisasi')
.option('-p, --no-punctuation', 'Nonaktifkan auto punctuation')
.action(async (filepath, options) => {
console.log(chalk.cyan(banner));
const spinner = ora('Membaca file...').start();
try {
const content = await fs.readFile(filepath, 'utf8');
const lines = content.split('\n').filter(line => line.trim());
spinner.text = 'Memproses teks...';
const results = lines.map(line => formalizer.formalize(line, {
autoCapitalize: options.capitalize,
autoPunctuation: options.punctuation
}));
spinner.succeed(`Berhasil memproses ${lines.length} baris!`);
if (options.output) {
await fs.writeFile(options.output, results.join('\n'), 'utf8');
console.log(chalk.green(`✅ Hasil disimpan ke: ${options.output}`));
} else {
console.log('\n' + chalk.green('✨ Hasil Formalisasi:'));
results.forEach((result, i) => {
if (lines[i] !== result) {
console.log(chalk.gray(`\n[${i + 1}] Original: ${lines[i]}`));
console.log(chalk.white(` Formal: ${result}`));
}
});
}
} catch (error) {
spinner.fail('Gagal memproses file');
console.error(chalk.red(error.message));
}
});
// Command: Interactive mode
program
.command('interactive')
.alias('i')
.description('Mode interaktif untuk formalisasi real-time')
.action(() => {
console.log(chalk.cyan(banner));
// eslint-disable-next-line max-len
console.log(chalk.yellow('Mode Interaktif - Ketik teks informal, tekan Enter untuk formalisasi'));
console.log(chalk.gray('Ketik "exit" untuk keluar, "help" untuk bantuan\n'));
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: chalk.blue('informal> ')
});
rl.prompt();
rl.on('line', line => {
const input = line.trim();
if (input === 'exit' || input === 'quit') {
console.log(chalk.yellow('\nTerima kasih telah menggunakan Formalizer! 👋'));
rl.close();
return;
}
if (input === 'help') {
console.log(chalk.cyan('\nBantuan:'));
console.log(' - Ketik teks informal dan tekan Enter');
console.log(' - Ketik "stats" untuk melihat statistik');
console.log(' - Ketik "export" untuk export mapping');
console.log(' - Ketik "exit" untuk keluar\n');
rl.prompt();
return;
}
if (input === 'stats') {
const stats = formalizer.getStatistics();
console.log(chalk.cyan('\n📊 Statistik:'));
console.log(` Total Mapping: ${stats.totalMappings}`);
console.log(` Kata Ganti: ${stats.categories.pronouns}`);
console.log(` Kata Kerja: ${stats.categories.verbs}`);
console.log(` Kata Sifat: ${stats.categories.adjectives}`);
console.log(` Slang: ${stats.categories.slang}\n`);
rl.prompt();
return;
}
if (input === 'export') {
const mappings = formalizer.exportMappings();
const filename = `mappings_${Date.now()}.json`;
fs.writeFile(filename, JSON.stringify(mappings, null, 2))
.then(() => console.log(chalk.green(`✅ Mapping diekspor ke ${filename}\n`)))
.catch(err => console.log(chalk.red(`❌ Error: ${err.message}\n`)));
rl.prompt();
return;
}
if (input) {
const result = formalizer.formalize(input);
const analysis = formalizer.analyzeFormalityLevel(input);
console.log(chalk.green('formal> ') + result);
console.log(chalk.gray(` (Skor formalitas: ${analysis.score}%)`));
}
rl.prompt();
});
rl.on('close', () => {
process.exit(0);
});
});
// Command: Add mapping
program
.command('add-mapping <informal> <formal>')
.description('Tambah mapping kata informal → formal')
.action((informal, formal) => {
console.log(chalk.cyan(banner));
formalizer.addMapping(informal, formal);
console.log(chalk.green(`✅ Mapping ditambahkan: "${informal}" → "${formal}"`));
// Test the new mapping
const test = `Test: ${informal} jadi ${informal}`;
const result = formalizer.formalize(test);
console.log(chalk.gray('\nContoh hasil:'));
console.log(chalk.white(result));
});
// Command: Batch process
program
.command('batch')
.description('Proses multiple file sekaligus')
.option('-d, --directory <dir>', 'Directory input')
.option('-o, --output-dir <dir>', 'Directory output')
.option('-e, --extension <ext>', 'File extension (default: .txt)', '.txt')
.action(async options => {
console.log(chalk.cyan(banner));
const dir = options.directory || '.';
const outputDir = options.outputDir || './formalized';
const ext = options.extension;
const spinner = ora('Scanning directory...').start();
try {
// Create output directory if not exists
await fs.mkdir(outputDir, { recursive: true });
// Read all files
const files = await fs.readdir(dir);
const textFiles = files.filter(f => f.endsWith(ext));
spinner.text = `Found ${textFiles.length} files to process...`;
let processed = 0;
for (const file of textFiles) {
const inputPath = path.join(dir, file);
const outputPath = path.join(outputDir, `formal_${file}`);
const content = await fs.readFile(inputPath, 'utf8');
const lines = content.split('\n');
const formalizedLines = lines.map(line =>
line.trim() ? formalizer.formalize(line) : line
);
await fs.writeFile(outputPath, formalizedLines.join('\n'), 'utf8');
processed++;
spinner.text = `Processing... (${processed}/${textFiles.length})`;
}
spinner.succeed(`Successfully processed ${processed} files!`);
console.log(chalk.green(`✅ Output saved to: ${outputDir}`));
} catch (error) {
spinner.fail('Batch processing failed');
console.error(chalk.red(error.message));
}
});
// Command: Stats
program
.command('stats')
.description('Tampilkan statistik mapping kata')
.action(() => {
console.log(chalk.cyan(banner));
const stats = formalizer.getStatistics();
console.log(chalk.blue('📊 Statistik Mapping:\n'));
console.log(chalk.white(`Total Mapping: ${chalk.yellow(stats.totalMappings)} kata`));
console.log(chalk.white('\nKategori:'));
console.log(chalk.white(` • Kata Ganti: ${chalk.green(stats.categories.pronouns)}`));
console.log(chalk.white(` • Kata Kerja: ${chalk.green(stats.categories.verbs)}`));
console.log(chalk.white(` • Kata Sifat: ${chalk.green(stats.categories.adjectives)}`));
console.log(chalk.white(` • Slang/Gaul: ${chalk.green(stats.categories.slang)}`));
console.log(chalk.gray('\nGunakan "formalize add-mapping" untuk menambah mapping baru'));
});
// Parse arguments
program.parse(process.argv);
// Show help if no arguments
if (!process.argv.slice(2).length) {
program.outputHelp();
}