mirror of
https://github.com/wahyd4/cloudflare-workers.git
synced 2026-08-09 05:06:34 +10:00
167 lines
4.4 KiB
TypeScript
167 lines
4.4 KiB
TypeScript
|
|
import { Router } from 'itty-router'
|
|
|
|
/**
|
|
* demo
|
|
* https://home-tts.junv.workers.dev/tts?text=%E4%BD%A0%E7%9C%9F%E7%9A%84%E6%98%AF%E5%BE%88%E8%AE%A8%E5%8E%8C%E5%91%A2&haha=hahaJunv&voice=zh-CN-XiaoxiaoNeural&voiceStyle=angry
|
|
*
|
|
* to publish
|
|
* wrangler publish tts-bot.ts --compatibility-date 2024-04-05
|
|
*
|
|
*
|
|
*/
|
|
|
|
|
|
const router = Router()
|
|
const botToken = BOT_TOKEN;
|
|
const chatId = CHAT_ID;
|
|
const ttsKey = TTS_KEY
|
|
const format = "audio-16khz-128kbitrate-mono-mp3";
|
|
// const defaultVoice = 'zh-CN-XiaoxiaoNeural'; //female
|
|
const defaultVoice = 'zh-CN-XiaoxiaoNeural'
|
|
// male
|
|
// zh-CN-YunfengNeural
|
|
// zh-CN-YunyangNeural
|
|
|
|
// 'zh-CN-XiaoxiaoNeural'; //female
|
|
|
|
const defaultVoiceStyle = "cheerful"
|
|
|
|
// "assistant",
|
|
// "chat",
|
|
// "customerservice",
|
|
// "newscast",
|
|
// "affectionate",
|
|
// "angry",
|
|
// "calm",
|
|
// "cheerful",
|
|
// "disgruntled",
|
|
// "fearful",
|
|
// "gentle",
|
|
// "lyrical",
|
|
// "sad",
|
|
// "serious",
|
|
// "poetry-reading",
|
|
// "friendly",
|
|
// "chat-casual",
|
|
// "whisper",
|
|
// "sorry"
|
|
async function sendToAzure(text: string, voice: string, voiceStyle:string, format: string) {
|
|
const endpoint = `https://australiaeast.tts.speech.microsoft.com/cognitiveservices/v1`
|
|
const body = `<speak version="1.0" xml:lang="${voice}"><voice xml:lang="${voice}" xml:gender="Female" name="${voice}" style="${voiceStyle}" >${text}</voice></speak>`
|
|
|
|
const response = await fetch(`${endpoint}`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Ocp-Apim-Subscription-Key': ttsKey,
|
|
'Content-Type': 'application/ssml+xml',
|
|
'X-Microsoft-OutputFormat': format,
|
|
'User-Agent': 'curl'
|
|
},
|
|
body,
|
|
})
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to generate speech: ${response.statusText}`)
|
|
}
|
|
return response.arrayBuffer()
|
|
}
|
|
|
|
async function sendVoice(chatId: number | string, voice: ArrayBuffer, caption?: string): Promise<boolean> {
|
|
const apiUrl = `https://api.telegram.org/bot${botToken}/sendVoice`;
|
|
|
|
const formData = new FormData();
|
|
formData.append('chat_id', chatId.toString());
|
|
formData.append('voice', new Blob([voice], { type: 'audio/mpeg' }), 'voice.mp3');
|
|
if (caption) {
|
|
formData.append('caption', caption);
|
|
}
|
|
|
|
const response = await fetch(apiUrl, {
|
|
method: 'POST',
|
|
body: formData,
|
|
});
|
|
|
|
const responseBody = await response.json();
|
|
if (responseBody.ok) {
|
|
return true;
|
|
} else {
|
|
console.error(`Telegram API returned error ${responseBody.error_code}: ${responseBody.description}`);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Define the request handler
|
|
async function handleBotRequest(request) {
|
|
// Parse the request body as JSON
|
|
const requestBody = await request.json();
|
|
if (!requestBody.message) {
|
|
return new Response('Error: No valid message founded', { status: 400 });
|
|
}
|
|
const text = requestBody.message.text;
|
|
var audioData;
|
|
try {
|
|
// Generate the audio file from the input text
|
|
audioData = await sendToAzure(text, defaultVoice, defaultVoiceStyle, format);
|
|
} catch (err) {
|
|
await new Response('Error: something went wrong', { status: 500 });
|
|
}
|
|
|
|
if (await sendVoice(chatId, audioData)) {
|
|
return new Response(audioData, {
|
|
headers: {
|
|
'Content-Type': 'audio/mpeg',
|
|
'Content-Disposition': 'attachment; filename="audio.mp3"',
|
|
},
|
|
});
|
|
}
|
|
return new Response('Error: something went wrong', { status: 500 });
|
|
}
|
|
|
|
async function handleRequest(request: Request): Promise<Response> {
|
|
try {
|
|
const params = request.query;
|
|
if (!params) {
|
|
return new Response('Error: No valid params provided', { status: 400 });
|
|
}
|
|
var voice = params.voice
|
|
var voiceStyle = params.voiceStyle
|
|
const haha = params.haha
|
|
const text = params.text
|
|
|
|
if (haha != "hahaJunv") {
|
|
return new Response('Error: something went wrong, haha', { status: 500 });
|
|
}
|
|
if (voice == null) {
|
|
voice = defaultVoice
|
|
}
|
|
if (voiceStyle == null) {
|
|
voiceStyle = defaultVoiceStyle
|
|
}
|
|
|
|
const audioData = await sendToAzure(text, voice, voiceStyle, format)
|
|
|
|
return new Response(audioData, {
|
|
headers: {
|
|
'Content-Type': 'audio/mpeg',
|
|
},
|
|
})
|
|
} catch (error) {
|
|
console.log(error)
|
|
return new Response(error.message || 'Internal Server Error', {
|
|
status: 500,
|
|
})
|
|
}
|
|
}
|
|
|
|
// Define the Cloudflare Worker entry point
|
|
// addEventListener('fetch', event => {
|
|
// event.respondWith(handleRequest(event.request));
|
|
// });
|
|
|
|
router.post('/bot', handleBotRequest)
|
|
router.get('/tts', handleRequest)
|
|
|
|
addEventListener('fetch', event => {
|
|
event.respondWith(router.handle(event.request))
|
|
})
|