diff --git a/src/handlers/onAudio.ts b/src/handlers/onAudio.ts index 8ed69d5..dbce803 100644 --- a/src/handlers/onAudio.ts +++ b/src/handlers/onAudio.ts @@ -40,6 +40,7 @@ export async function processAudio( const link = await ctx.telegram.getFileLink(voice.file_id); const oggPath = tmp.tmpNameSync({ postfix: ".ogg" }); let mp3Path: string | null = null; + let progressTimer: NodeJS.Timeout | null = null; try { const response = await fetch(link.href); @@ -50,6 +51,16 @@ export async function processAudio( await fs.promises.writeFile(oggPath, Buffer.from(arrayBuffer)); mp3Path = await convertToMp3(oggPath); + + progressTimer = setInterval(() => { + void sendTelegramMessage( + chatId, + "Распознавание продолжается...", + undefined, + ctx, + ); + }, 60_000); + const res = (await sendAudioWhisper({ mp3Path })) as WhisperResponse; if (res.error) { @@ -110,6 +121,7 @@ export async function processAudio( ); } finally { try { + if (progressTimer) clearInterval(progressTimer); if (fs.existsSync(oggPath)) fs.unlinkSync(oggPath); if (mp3Path && fs.existsSync(mp3Path)) fs.unlinkSync(mp3Path); } catch (cleanupError) { diff --git a/src/utils/text.ts b/src/utils/text.ts index 6f5fdab..33e2eca 100644 --- a/src/utils/text.ts +++ b/src/utils/text.ts @@ -22,37 +22,40 @@ export function splitBigMessage(text: string) { msg += line + "\n"; } } - + // Handle any remaining text in the buffer if (msg) { // Remove trailing newline if present const trimmedMsg = msg.endsWith("\n") ? msg.slice(0, -1) : msg; if (trimmedMsg) msgs.push(trimmedMsg); } - + return msgs; } export function prettyText(text: string) { - const paragraphs = []; - const sentences = text.split(/[.?!][ \n]/g); - // console.log("sentences:", sentences.length); - let paragraph = ''; - while (sentences.length > 0) { - paragraph += sentences.shift() + '. '; - paragraph = paragraph.replace(/\.\. $/, '. '); // remove .. + if (!text) return ""; + + const paragraphs: string[] = []; + const sentences = text.match(/[^.?!]+[.?!]?/g) || []; + + let paragraph = ""; + for (let sentence of sentences) { + sentence = sentence.trim(); + if (!/[.?!]$/.test(sentence)) sentence += "."; + + paragraph += sentence + " "; + paragraph = paragraph.replace(/\.\. $/, ". "); if (paragraph.length > 200) { - paragraphs.push(paragraph.trim() + ''); - // console.log("zero paragraph:", paragraph); - paragraph = ''; + paragraphs.push(paragraph.trim()); + paragraph = ""; } } - if (paragraph.length > 0) { - paragraphs.push(paragraph.trim() + ''); + + if (paragraph.trim()) { + paragraphs.push(paragraph.trim()); } - // console.log("paragraphs", paragraphs); - const prettyText = paragraphs.join('\n\n'); - return prettyText; + return paragraphs.join("\n\n"); } diff --git a/tests/handlers/onAudioProcess.test.ts b/tests/handlers/onAudioProcess.test.ts index 5adf1ef..bb23de2 100644 --- a/tests/handlers/onAudioProcess.test.ts +++ b/tests/handlers/onAudioProcess.test.ts @@ -64,7 +64,7 @@ describe("processAudio", () => { await processAudio(ctx as Context, { file_id: "f" }, 1); expect(mockSendTelegramMessage).toHaveBeenCalledWith( 1, - "hello", + "hello.", undefined, ctx, ); diff --git a/tests/utils/text.test.ts b/tests/utils/text.test.ts index b51f627..406879e 100644 --- a/tests/utils/text.test.ts +++ b/tests/utils/text.test.ts @@ -13,14 +13,15 @@ describe("splitBigMessage", () => { it("truncates single oversized line", () => { const line = "x".repeat(4100); - const [msg] = splitBigMessage(line); - expect(msg.length).toBe(4096); - expect(msg.endsWith("...")).toBe(true); + const msgs = splitBigMessage(line); + expect(msgs.length).toBe(2); + expect(msgs[0].length).toBe(4096); + expect(msgs[1].length).toBe(4); }); it("keeps blank lines", () => { const res = splitBigMessage("a\n\nb"); - expect(res).toEqual(["a\n\nb\n"]); + expect(res).toEqual(["a\n\nb"]); }); }); @@ -28,26 +29,26 @@ describe("prettyText", () => { it("formats a simple sentence correctly", () => { const input = "Hello world."; const result = prettyText(input); - expect(result).toBe("Hello world. "); + expect(result).toBe("Hello world."); }); it("combines short sentences into one paragraph", () => { const input = "First sentence. Second sentence. Third sentence."; const result = prettyText(input); - expect(result).toBe("First sentence. Second sentence. Third sentence. "); + expect(result).toBe("First sentence. Second sentence. Third sentence."); }); it("splits long text into multiple paragraphs", () => { - const longText = + const longText = "This is a long sentence that should be in the first paragraph. " + "This is another long sentence that should be in the first paragraph. " + "This is a very long sentence that should trigger a new paragraph because " + "it makes the total length exceed the 200 character limit. " + "This should be in the second paragraph."; - + const result = prettyText(longText); const paragraphs = result.split("\n\n"); - + expect(paragraphs.length).toBe(2); expect(paragraphs[0].length).toBeGreaterThan(200); expect(paragraphs[0]).toContain("first paragraph."); @@ -67,6 +68,6 @@ describe("prettyText", () => { }); it("handles single word", () => { - expect(prettyText("Hello")).toBe("Hello. "); + expect(prettyText("Hello")).toBe("Hello."); }); });