Kembali ke katalog plugin
ai
tts
Ubah teks jadi pesan suara
Turn text into a voice note
plugins/ai/tts.js
Lokasi file di repo kana-md
3
Perintah termasuk alias
3.8 KB
Ukuran file sumber
4/11/2026
Update terakhir, commit 11aee2b
Daftar perintah
Ketuk tombol salin untuk menyalin perintah, lalu tempel di chat WhatsApp bot KANA.
.tts.suara.voiceCara pakai
.tts <teks>
Contoh
.tts halo, selamat pagi semua
Kode sumber plugin
Cara pasang: simpan file ini ke folder plugins/ai/ di bot KANA kamu, lalu restart bot. Pemilik source code lain bisa mengambil update plugin terbaru dari halaman ini kapan saja.
// .tts: ubah teks jadi voice note lewat Google Translate TTS publik.
// Endpoint translate_tts publik tanpa key; nasibnya bisa berubah
// (kadang diblokir Google), jadi kegagalan dibalas jujur, bukan
// pura-pura berhasil. Teks dipotong per permintaan maksimal 200
// karakter di batas kata, total maksimal 600 karakter.
import { downloadBuffer, withBreaker } from '../../src/scrapers/runner.js'
import { sendButtons } from '../../src/ui/buttons.js'
export const config = {
name: 'tts',
alias: ['suara', 'voice'],
category: 'ai',
description: { id: 'Ubah teks jadi pesan suara', en: 'Turn text into a voice note' },
usage: '.tts <teks>',
example: '.tts halo, selamat pagi semua',
cooldown: 10,
limit: 3,
}
export const i18n = {
id: {
tts: {
needText: 'Tulis teksnya dulu yaa, contoh: .tts halo selamat pagi~ đī¸',
tooLong: 'Teksnya kepanjangan nih, KANA potong sampai 600 karakter yaa~ Sisanya nggak dibacakan âī¸',
failed: 'Mouu, suara KANA gagal dibuat: {message}. Layanan TTS gratisnya lagi bermasalah, coba lagi nanti ya~ (âĨīšâĨ)',
done: 'Voice note-nya udah KANA kirim di atas yaa~ đī¸â¨ {mood}',
btnAgain: 'Ucapkan Lagi',
btnMenu: 'Menu AI',
},
},
en: {
tts: {
needText: 'Write the text first, example: .tts hello good morning~ đī¸',
tooLong: 'That text is too long, KANA trimmed it to 600 characters~ The rest was not read out âī¸',
failed: 'Mouu, KANA failed to make the voice: {message}. The free TTS service is having trouble, try again later~ (âĨīšâĨ)',
done: 'KANA sent the voice note above~ đī¸â¨ {mood}',
btnAgain: 'Say Again',
btnMenu: 'AI Menu',
},
},
}
export const TTS_CHUNK_CHARS = 200
export const TTS_MAX_CHARS = 600
// Potong teks jadi potongan maksimal maxChars, di batas kata bila bisa.
export function chunkTtsText(text, maxChars = TTS_CHUNK_CHARS) {
const clean = String(text ?? '').replace(/\s+/g, ' ').trim()
const chunks = []
let rest = clean
while (rest.length > maxChars) {
let cut = rest.lastIndexOf(' ', maxChars)
if (cut < Math.floor(maxChars / 2)) cut = maxChars
chunks.push(rest.slice(0, cut).trim())
rest = rest.slice(cut).trim()
}
if (rest) chunks.push(rest)
return chunks.filter(Boolean)
}
export const test = { input: '.tts Halo semuanya, aku KANA', expect: /Voice note/i }
export async function handler(ctx) {
const rawText = ctx.text.trim()
if (!rawText) return ctx.reply(ctx.t('tts.needText'))
const truncated = rawText.length > TTS_MAX_CHARS
const text = truncated ? rawText.slice(0, TTS_MAX_CHARS) : rawText
const lang = ctx.lang === 'en' ? 'en' : 'id'
const chunks = chunkTtsText(text, TTS_CHUNK_CHARS)
const buffers = []
try {
for (const chunk of chunks) {
const url = `https://translate.google.com/translate_tts?ie=UTF-8&tl=${lang}&client=tw-ob&q=${encodeURIComponent(chunk)}`
const media = await withBreaker('google-tts', () =>
downloadBuffer(url, { maxBytes: 5 * 1024 * 1024, timeout: 20000 })
)
buffers.push(media.buffer)
}
} catch (err) {
return ctx.reply(ctx.t('tts.failed', { message: err.message }))
}
if (!buffers.length) return ctx.reply(ctx.t('tts.failed', { message: 'audio kosong' }))
const audio = Buffer.concat(buffers)
await ctx.sock.sendMessage(ctx.chat, { audio, ptt: true, mimetype: 'audio/mpeg' }, { quoted: ctx.raw })
if (truncated) await ctx.reply(ctx.t('tts.tooLong'))
const body = ctx.t('tts.done', { mood: ctx.say('senang') })
const shortText = text.slice(0, 60)
return sendButtons(ctx.sock, ctx.chat, {
title: process.env.BOT_NAME || 'KANA',
body,
footer: ctx.t('menu.footer'),
replies: [
{ text: ctx.t('tts.btnAgain'), id: `.tts ${shortText}` },
{ text: ctx.t('tts.btnMenu'), id: '.menu ai' },
],
textFallback: body,
})
}
