Split content in playVoice instead of readChannel handler

This commit is contained in:
kimpure 2026-05-21 14:36:20 +00:00
parent d77f3694a6
commit d4f8013d94
No known key found for this signature in database
4 changed files with 67 additions and 24 deletions

View file

@ -64,10 +64,7 @@ export default defineEvent("messageCreate", async (message) => {
}
}
for (const text of content.split("\n")) {
await playVoice(guild, profile, voice, text, options);
}
await playVoice(guild, profile, voice, content, options);
} catch(err) {
message.reply("말이 꼬이네요 ㅜ.ㅜ");
console.log("playVoice failed. ", err);

View file

@ -68,40 +68,48 @@ export async function playVoice(
throw new Error(`the user ${profile.userId} is can't use typecast voice`);
}
let voiceBuffer: Buffer
let voiceBufferList: Buffer[]
if (voice == "TypeCast") {
const content = TTSTypecastModel.instance.ttsify(text);
if (!content.length)
throw new Error("Empty content");
voiceBuffer = await TTSTypecastModel.instance.getMemcachedVoice(
voiceBufferList = await Promise.all(content.split("\n").map(
(content) => TTSTypecastModel.instance.getMemcachedVoice(
TTSTypecastModel.instance.createRequestId(content)
);
)
));
} else if (voice == "Supertonic") {
const content = TTSSupertonicModel.instance.ttsify(text);
if (!content.length)
throw new Error("Empty content");
voiceBuffer = await TTSSupertonicModel.instance.getMemcachedVoice(
voiceBufferList = await Promise.all(content.split("\n").map(
(content) => TTSSupertonicModel.instance.getMemcachedVoice(
TTSSupertonicModel.instance.createRequestId(content, options?.supertonicStyleId)
);
)
));
} else if (voice == "Papago") {
const content = TTSPapagoModel.instance.ttsify(text);
if (!content.length)
throw new Error("Empty content");
voiceBuffer = await TTSPapagoModel.instance.getMemcachedVoice(
voiceBufferList = await Promise.all(content.split("\n").map(
(content) => TTSPapagoModel.instance.getMemcachedVoice(
TTSPapagoModel.instance.createRequestId(content)
);
)
));
} else {
throw new Error(`Unknown voice type: ${voice}`);
}
for (const voiceBuffer of voiceBufferList) {
VoiceQueue.fromConnection(connection).enqueue(
TTSModelBase.bufferToAudioResource(voiceBuffer)
);
}
} catch(err) {
OutputHandler.errorLog("[PlayVoice Error]", err);
throw new Error(err as any);

View file

@ -44,6 +44,7 @@ export default class IntegerKorean {
}
static convertFromString(num: string): string {
num = num.replace(/,/g, "");
let isNegative = false;
if (num.startsWith("-")) {
num = num.slice(1, -1);

View file

@ -25,6 +25,11 @@ export const SymbolMap = {
"~": "물결표",
"\\": "역슬래쉬",
"♡": "하트 ",
"|": "",
">": "",
"<": "",
":": "콜론",
";": "세미콜론"
};
export const VersionPostfix = {
"a": "알파",
@ -120,7 +125,19 @@ export const SIPrefix = {
"zi": "제비",
"y": "요타",
"yi": "요비",
}
};
export const LiterPrefix = {
"m": "밀리",
"": "",
};
export const MeterPrefix = {
"m": "밀리",
"c": "센치",
"": "",
"k": "킬로",
};
export function processDots(input: string): string {
return input.replace(/[\.,]+$/, "")
@ -136,6 +153,8 @@ export function saferKorean(input: string): string {
element as keyof typeof IsolatedSymbolMap
]).join("")
))
.replace(/\s\|\|\s/g, " 오얼 ")
.replace(/\s\&\&\s/g, " 엔드 ")
// Process codeblock
.replace(/\`\`\`([\s\S]*?)\`\`\`/g, (_, content: string)=>{
@ -153,7 +172,6 @@ export function saferKorean(input: string): string {
// Process koreans
.replace(/ㅋ{2,}/g, (content) => "크".repeat(content.length))
.replace(/[아ㅏ]{3,}/g, "아아아")
.replace(/https\S+/g, "링크")
.replace(/ㅌ{2,}/g, "틔틔")
.replace(/ㄷ{2,}/g, "덜덜")
.replace(/(ㅊㅋ)+/g, (content: string) => {
@ -173,12 +191,24 @@ export function saferKorean(input: string): string {
.replace(/[ㄱ-ㅎㄲㄸㅃㅆㅉ]/g, (char: string) => ChoseongMap[char as keyof typeof ChoseongMap])
// Process number, unit
.replace(/(\d+)([kKMmgGtTpP][iI]?)[bB]/g, (_, num: string, mod: string) => {
// 10kib => 10키비바이트
.replace(/([\d,]+)([kKMmgGtTpP][iI]?)[bB]/g, (_, num: string, mod: string) => {
// 10kib => 키비바이트
num = IntegerKorean.convertFromString(num);
mod = SIPrefix[mod.toLowerCase() as keyof typeof SIPrefix];
return `${num} ${mod}바이트 `;
})
.replace(/([\d,]+)([mck]?)m/g, (_, num: string, mod: string) => {
// 10m => 십미터
num = IntegerKorean.convertFromString(num);
mod = MeterPrefix[mod as keyof typeof MeterPrefix];
return `${num} ${mod}미터`;
})
.replace(/([\d,]+)([m]?)l/g, (_, num: string, mod: string) => {
// 10l => 십리터
num = IntegerKorean.convertFromString(num);
mod = LiterPrefix[mod as keyof typeof LiterPrefix];
return `${num} ${mod}리터`;
})
.replace(/([\d\.]+)\s*([개살시평명])/g, (_, num: string, postfix: string)=>{
// 10명 => 열명
if (num.includes(".")) {
@ -194,7 +224,6 @@ export function saferKorean(input: string): string {
.replace(/[\d,]+/g, (num: string) => {
// 1,000 원 => 천원
if (!num.includes(",")) return num;
num = num.replace(/,/g, "");
return IntegerKorean.convertFromString(num);
})
.replace(/(v?)([\d\.]+)([ab]?)/g, (_, suffix: string, num: string, postfix: string) => {
@ -231,10 +260,18 @@ export function saferKorean(input: string): string {
.replace(/㎡/g, "제곱미터")
.replace(/㎢/g, "제곱킬로미터")
// Process link
.replace(/[hH][tT]{2}[pP][sS]?:\/\/(\S+)/g, (_, url: string) => {
if (url.startsWith("tenor.com/view")) {
return "움짤";
}
return "링크";
})
// Process symbol
.replace(/[\%\^\&\*\#\@\.\-\+\_\=\/\\♡\$]/g, (t) => (
.replace(/[\%\^\&\*\#\@\.\-\+\_\=\/\\♡\$\|\:\;\>\<]/g, (t) => (
SymbolMap[t as keyof typeof SymbolMap]
))
.replace(/([\?\!]+)/g, (_, content: string) => content[0])
.replace(/\s+/g, " ")
.replace(/[ \t\f\r]+/g, " ")
}