UNPKG

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
#!/usr/bin/env node 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(); }