@markusylisiurunen/tau 0.3.53 → 0.3.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/commands/registry.js +10 -5
- package/dist/core/commands/registry.js.map +1 -1
- package/dist/core/config/index.js +1 -1
- package/dist/core/config/index.js.map +1 -1
- package/dist/core/config/schema.js +10 -2
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/diff_review/bridge.js +2 -1
- package/dist/core/diff_review/bridge.js.map +1 -1
- package/dist/core/diff_review/tool.js +1 -1
- package/dist/core/diff_review/tool.js.map +1 -1
- package/dist/core/static/tau_docs/config-reference.md +6 -6
- package/dist/core/static/tau_docs/credentials.md +3 -2
- package/dist/core/static/tau_docs/telegram.md +4 -3
- package/dist/core/static/tau_docs/troubleshooting.md +1 -1
- package/dist/core/static/tau_docs/tui.md +5 -3
- package/dist/core/telegram/adapter.js +40 -20
- package/dist/core/telegram/adapter.js.map +1 -1
- package/dist/core/telegram/cli.js +4 -2
- package/dist/core/telegram/cli.js.map +1 -1
- package/dist/core/telegram/runtime.js +1 -0
- package/dist/core/telegram/runtime.js.map +1 -1
- package/dist/core/utils/gemini_transcription.js +14 -15
- package/dist/core/utils/gemini_transcription.js.map +1 -1
- package/dist/core/utils/mistral_transcription.js +6 -2
- package/dist/core/utils/mistral_transcription.js.map +1 -1
- package/dist/core/utils/openai_transcription.js +431 -0
- package/dist/core/utils/openai_transcription.js.map +1 -0
- package/dist/core/utils/speech_to_text.js +66 -14
- package/dist/core/utils/speech_to_text.js.map +1 -1
- package/dist/core/version.js +1 -1
- package/dist/diff_tool/app/dist/assets/{angular-html-vSIwre92.js → angular-html-DoxI_och.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{angular-ts-B9yWa-IT.js → angular-ts-C7CUd-D2.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{apl-CBg9ewu1.js → apl-7dieYM-l.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{astro-BVjxSYjj.js → astro-Czj3O4jM.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{blade-jvqV5kiv.js → blade-ClS0E2cC.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{c-DDAfW08c.js → c-BKvTh-Jt.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{chapel-Qflwfgbt.js → chapel-qvFrfwEr.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{cobol-4iJI1LUg.js → cobol-B0vsaB-J.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{coffee-C9LbGGO3.js → coffee-BUlcrU75.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{cpp-B-x6veTx.js → cpp-CKqEgX1l.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{crystal-S06EUmKn.js → crystal-FCqSmIJ_.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{css-DA4RYriG.js → css-zZvYFJFc.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{edge-7dx6BjGp.js → edge-BKlbCo1f.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{elixir-DPywG97a.js → elixir-B2gSxtgZ.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{elm-Dgo_WnqC.js → elm-DFEdzPJz.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{erb-CVW4PjFl.js → erb-DSgn8fHS.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{git-rebase-CtU0gmBJ.js → git-rebase-CcgDECQr.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{glimmer-js-twAYiPP2.js → glimmer-js-Dwxi4cX2.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{glimmer-ts-BfNoXayN.js → glimmer-ts-BnJVER8W.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{glsl-D_XrtFF7.js → glsl-z7_gU-HN.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{graphql-B_GeapzM.js → graphql-Dt7V-d3L.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{hack-BCaCVoSX.js → hack-jVkr6EC8.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{haml-z9Mz7I1O.js → haml-BF7cRiOF.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{handlebars-D0FVYagc.js → handlebars-DAhNxR3E.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{html-BOM4tb7u.js → html-B7QW5YvU.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{html-derivative-CsSlhJgr.js → html-derivative-B-vyaE-N.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{http-Cjy9oaQn.js → http-Drkl04RP.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{hurl-CjLQ7ql5.js → hurl-7gTFrvcN.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{index-QO81yN6b.js → index-C9CiIimI.js} +41 -41
- package/dist/diff_tool/app/dist/assets/{java-cn8DiFD8.js → java-ZmvXuvs3.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{javascript-CEnHZaZM.js → javascript-C-OECu_Z.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{jinja-DIp6kVk7.js → jinja-hvkV87CG.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{jison-Dx116ito.js → jison-eJBDxKI8.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{json-C6B9h0n5.js → json-BPQU2w0u.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{jsx-CDEGT2B2.js → jsx-C19s5MOj.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{julia-CsIJA3Km.js → julia-CYISvCwi.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{just-DZRYvkQw.js → just-5omBg5pB.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{latex-CeR-RQOI.js → latex-B_L85F2z.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{liquid-Dhf8N4mn.js → liquid-BxbaQPPS.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{lua-zVTVaJzn.js → lua-DQA0z-44.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{marko-BGPq5r3o.js → marko-Dj5RV8IH.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{mdc-D8K78bym.js → mdc-CoHI6VJN.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{mojo-CFuIV2fl.js → mojo-fg40_ntQ.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{nginx-Bo-bEa75.js → nginx-COnrY-gb.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{nim-Bfy5M54r.js → nim-Ccfp0p1j.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{org-BKetN7sT.js → org-RForNsWm.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{perl-WiwTOQTV.js → perl-DhHRsiUu.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{php-CM2FzhGV.js → php-BlxKhJek.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{pug-D2WvUHZ-.js → pug-o9YxnGzH.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{qml-DGPbc6TL.js → qml-Dzf494vL.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{r-CCFYJ_KM.js → r-Dp0OUrF6.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{razor-D1JuQWQz.js → razor-gylahu-m.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{regexp-zTiHwMow.js → regexp-C0rsDjCm.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{rst-CuUAArfH.js → rst-D-DRAFtq.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{ruby-DznrLCoG.js → ruby-BnY40vXq.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{sas-D2hJmLva.js → sas-BaSo_s7i.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{scss-Cjb3p_6n.js → scss-BX5R-Yyw.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{shellscript-BtwI-tfX.js → shellscript-CpRFVBRj.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{shellsession-BYirS1xP.js → shellsession-BGRUDtms.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{soy-D4Ndk7-j.js → soy-C2WL9FSb.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{sql-DbLQ5SJl.js → sql-CGmNnOfz.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{stata-BXoNBosJ.js → stata-CDamV3Uz.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{surrealql-toyTYnAL.js → surrealql-BqI4o6tP.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{svelte-BEpa7pAW.js → svelte-DPaOUioa.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{templ-CZfW_RJI.js → templ-aqrZIEoc.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{tex-COemmIIu.js → tex-Bjjtfacp.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{ts-tags-CMVUY_BA.js → ts-tags-BGFnsvdQ.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{tsx-BTvP6uzd.js → tsx-C_rOxPqZ.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{twig-DzP5RjJc.js → twig-DYqVwCOf.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{typescript-CQaGlMoX.js → typescript-CppQYc7K.js} +1 -1
- package/dist/diff_tool/app/dist/assets/typst-KIbA0FZG.js +1 -0
- package/dist/diff_tool/app/dist/assets/{vue-html-BA_OH0Xt.js → vue-html-DcZpMui9.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{vue-DaVWTtvb.js → vue-iOYoJEJi.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{vue-vine-C_H4XbNR.js → vue-vine-C6v6c0Lr.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{xml-1JLzpunp.js → xml-zR0RltJO.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{xsl-GtZi0Erj.js → xsl-B9pBLsIV.js} +1 -1
- package/dist/diff_tool/app/dist/assets/{yaml-LueTtDDo.js → yaml-sicIihvu.js} +1 -1
- package/dist/diff_tool/app/dist/index.html +1 -1
- package/dist/tui/listen_capture.js +84 -20
- package/dist/tui/listen_capture.js.map +1 -1
- package/dist/tui/session_chat_controller.js +213 -29
- package/dist/tui/session_chat_controller.js.map +1 -1
- package/dist/tui/speech_playback.js +3 -1
- package/dist/tui/speech_playback.js.map +1 -1
- package/dist/tui/ui/footer.js +6 -6
- package/dist/tui/ui/footer.js.map +1 -1
- package/package.json +9 -9
- package/dist/diff_tool/app/dist/assets/typst-DI99ib-x.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/core/telegram/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/core/telegram/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -118,6 +118,7 @@ export async function startTelegramRuntime(options) {
|
|
|
118
118
|
speechToTextProvider: options.speechToTextProvider,
|
|
119
119
|
geminiApiKey: options.geminiApiKey,
|
|
120
120
|
mistralApiKey: options.mistralApiKey,
|
|
121
|
+
openaiApiKey: options.openaiApiKey,
|
|
121
122
|
sessionManager,
|
|
122
123
|
projectPreferences,
|
|
123
124
|
onLog: (entry) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/core/telegram/runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAA8B,MAAM,cAAc,CAAC;AAEhF,OAAO,EACL,oCAAoC,EACpC,qCAAqC,GACtC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,4BAA4B,EAC5B,+BAA+B,GAIhC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,6BAA6B,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/core/telegram/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { formatSpeechToTextContext } from "./speech_to_text_context.js";
|
|
3
3
|
const GEMINI_GENERATE_CONTENT_BASE_URL = "https://generativelanguage.googleapis.com/v1beta/models";
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const GEMINI_TRANSCRIPTION_MODEL = "gemini-3.7-flash";
|
|
5
|
+
const GEMINI_TRANSCRIPTION_THINKING_LEVEL = "low";
|
|
6
6
|
const DEFAULT_GEMINI_AUDIO_MIME_TYPE = "audio/wav";
|
|
7
7
|
const errorPayloadSchema = z.object({
|
|
8
8
|
error: z
|
|
9
9
|
.object({
|
|
10
10
|
message: z.string().trim().min(1).optional(),
|
|
11
|
-
status: z.string().trim().min(1).optional(),
|
|
12
|
-
code: z.number().int().optional(),
|
|
13
11
|
})
|
|
14
12
|
.optional(),
|
|
15
13
|
});
|
|
@@ -31,7 +29,7 @@ const apiResponseSchema = z.object({
|
|
|
31
29
|
.optional(),
|
|
32
30
|
});
|
|
33
31
|
const transcriptionResultSchema = z.object({
|
|
34
|
-
transcription: z.string(),
|
|
32
|
+
transcription: z.string().trim().min(1),
|
|
35
33
|
});
|
|
36
34
|
export async function transcribeGeminiAudio(options) {
|
|
37
35
|
const apiKey = options.apiKey.trim();
|
|
@@ -39,13 +37,13 @@ export async function transcribeGeminiAudio(options) {
|
|
|
39
37
|
throw new Error("missing Gemini API key");
|
|
40
38
|
}
|
|
41
39
|
const fetchFn = options.fetchImpl ?? fetch;
|
|
42
|
-
const
|
|
43
|
-
const response = await fetchFn(`${GEMINI_GENERATE_CONTENT_BASE_URL}/${encodeURIComponent(model)}:generateContent`, {
|
|
40
|
+
const response = await fetchFn(`${GEMINI_GENERATE_CONTENT_BASE_URL}/${GEMINI_TRANSCRIPTION_MODEL}:generateContent`, {
|
|
44
41
|
method: "POST",
|
|
45
42
|
headers: {
|
|
46
43
|
"Content-Type": "application/json",
|
|
47
44
|
"x-goog-api-key": apiKey,
|
|
48
45
|
},
|
|
46
|
+
signal: options.signal,
|
|
49
47
|
body: JSON.stringify({
|
|
50
48
|
systemInstruction: {
|
|
51
49
|
parts: [
|
|
@@ -73,7 +71,7 @@ export async function transcribeGeminiAudio(options) {
|
|
|
73
71
|
responseMimeType: "application/json",
|
|
74
72
|
responseSchema: GEMINI_TRANSCRIPTION_RESPONSE_SCHEMA,
|
|
75
73
|
thinkingConfig: {
|
|
76
|
-
thinkingLevel:
|
|
74
|
+
thinkingLevel: GEMINI_TRANSCRIPTION_THINKING_LEVEL,
|
|
77
75
|
},
|
|
78
76
|
},
|
|
79
77
|
}),
|
|
@@ -91,7 +89,11 @@ export async function transcribeGeminiAudio(options) {
|
|
|
91
89
|
const fallbackMessage = responseText.trim() || `HTTP ${response.status}`;
|
|
92
90
|
throw new Error(parsed.success ? (parsed.data.error?.message ?? fallbackMessage) : fallbackMessage);
|
|
93
91
|
}
|
|
94
|
-
|
|
92
|
+
const text = extractGeminiText(payload);
|
|
93
|
+
if (!text) {
|
|
94
|
+
throw new Error("transcription result was empty or malformed");
|
|
95
|
+
}
|
|
96
|
+
return text;
|
|
95
97
|
}
|
|
96
98
|
function buildTranscriptionSystemInstruction() {
|
|
97
99
|
return [
|
|
@@ -126,7 +128,7 @@ function buildTranscriptionPrompt(context) {
|
|
|
126
128
|
function extractGeminiText(payload) {
|
|
127
129
|
const parsed = apiResponseSchema.safeParse(payload);
|
|
128
130
|
if (!parsed.success) {
|
|
129
|
-
return
|
|
131
|
+
return undefined;
|
|
130
132
|
}
|
|
131
133
|
const responseText = (parsed.data.candidates?.[0]?.content.parts ?? [])
|
|
132
134
|
.map((part) => {
|
|
@@ -139,12 +141,9 @@ function extractGeminiText(payload) {
|
|
|
139
141
|
transcriptionPayload = responseText ? JSON.parse(responseText) : undefined;
|
|
140
142
|
}
|
|
141
143
|
catch {
|
|
142
|
-
return
|
|
144
|
+
return undefined;
|
|
143
145
|
}
|
|
144
146
|
const transcription = transcriptionResultSchema.safeParse(transcriptionPayload);
|
|
145
|
-
|
|
146
|
-
return "";
|
|
147
|
-
}
|
|
148
|
-
return transcription.data.transcription;
|
|
147
|
+
return transcription.success ? transcription.data.transcription : undefined;
|
|
149
148
|
}
|
|
150
149
|
//# sourceMappingURL=gemini_transcription.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gemini_transcription.js","sourceRoot":"","sources":["../../../src/core/utils/gemini_transcription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,yBAAyB,EAA4B,MAAM,6BAA6B,CAAC;AAElG,MAAM,gCAAgC,GAAG,yDAAyD,CAAC;AACnG,MAAM,
|
|
1
|
+
{"version":3,"file":"gemini_transcription.js","sourceRoot":"","sources":["../../../src/core/utils/gemini_transcription.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ const DEFAULT_MISTRAL_LANGUAGE = "en";
|
|
|
5
5
|
const DEFAULT_MISTRAL_AUDIO_MIME_TYPE = "audio/wav";
|
|
6
6
|
const DEFAULT_MISTRAL_AUDIO_FILE_NAME = "speech.wav";
|
|
7
7
|
const errorSchema = z.object({ message: z.string() });
|
|
8
|
-
const successSchema = z.object({ text: z.string() });
|
|
8
|
+
const successSchema = z.object({ text: z.string().trim().min(1) });
|
|
9
9
|
export async function transcribeMistralAudio(options) {
|
|
10
10
|
const formData = new FormData();
|
|
11
11
|
formData.append("model", options.model ?? DEFAULT_MISTRAL_TRANSCRIPTION_MODEL);
|
|
@@ -21,6 +21,7 @@ export async function transcribeMistralAudio(options) {
|
|
|
21
21
|
Authorization: `Bearer ${options.apiKey}`,
|
|
22
22
|
},
|
|
23
23
|
body: formData,
|
|
24
|
+
signal: options.signal,
|
|
24
25
|
});
|
|
25
26
|
const responseText = await response.text();
|
|
26
27
|
let payload;
|
|
@@ -35,6 +36,9 @@ export async function transcribeMistralAudio(options) {
|
|
|
35
36
|
throw new Error(parsed.success ? parsed.data.message : responseText.trim() || `HTTP ${response.status}`);
|
|
36
37
|
}
|
|
37
38
|
const parsed = successSchema.safeParse(payload);
|
|
38
|
-
|
|
39
|
+
if (!parsed.success) {
|
|
40
|
+
throw new Error("transcription result was empty or malformed");
|
|
41
|
+
}
|
|
42
|
+
return parsed.data.text;
|
|
39
43
|
}
|
|
40
44
|
//# sourceMappingURL=mistral_transcription.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mistral_transcription.js","sourceRoot":"","sources":["../../../src/core/utils/mistral_transcription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,yBAAyB,GAAG,gDAAgD,CAAC;AACnF,MAAM,mCAAmC,GAAG,qBAAqB,CAAC;AAClE,MAAM,wBAAwB,GAAG,IAAI,CAAC;AACtC,MAAM,+BAA+B,GAAG,WAAW,CAAC;AACpD,MAAM,+BAA+B,GAAG,YAAY,CAAC;AAErD,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACtD,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"mistral_transcription.js","sourceRoot":"","sources":["../../../src/core/utils/mistral_transcription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,yBAAyB,GAAG,gDAAgD,CAAC;AACnF,MAAM,mCAAmC,GAAG,qBAAqB,CAAC;AAClE,MAAM,wBAAwB,GAAG,IAAI,CAAC;AACtC,MAAM,+BAA+B,GAAG,WAAW,CAAC;AACpD,MAAM,+BAA+B,GAAG,YAAY,CAAC;AAErD,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACtD,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAanE,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,OAAoC;IAEpC,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,IAAI,mCAAmC,CAAC,CAAC;IAC/E,QAAQ,CAAC,MAAM,CACb,MAAM,EACN,IAAI,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE;QACzC,IAAI,EAAE,OAAO,CAAC,QAAQ,IAAI,+BAA+B;KAC1D,CAAC,EACF,OAAO,CAAC,QAAQ,IAAI,+BAA+B,CACpD,CAAC;IAEF,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,wBAAwB,CAAC;IACtE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAEtC,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;IAC3C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,yBAAyB,EAAE;QACxD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,OAAO,CAAC,MAAM,EAAE;SAC1C;QACD,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC3C,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,SAAS,CAAC;IACtB,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,IAAI,KAAK,CACb,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,QAAQ,QAAQ,CAAC,MAAM,EAAE,CACxF,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAChD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import WebSocket from "ws";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { spawnWithCapture } from "./spawn_capture.js";
|
|
4
|
+
import { formatSpeechToTextContext } from "./speech_to_text_context.js";
|
|
5
|
+
import { truncateForTokens } from "./truncate.js";
|
|
6
|
+
const OPENAI_REALTIME_TRANSCRIPTION_URL = "wss://api.openai.com/v1/realtime?intent=transcription";
|
|
7
|
+
const OPENAI_FILE_TRANSCRIPTION_URL = "https://api.openai.com/v1/audio/transcriptions";
|
|
8
|
+
const OPENAI_STREAMING_TRANSCRIPTION_MODEL = "gpt-live-transcribe";
|
|
9
|
+
const OPENAI_FILE_TRANSCRIPTION_MODEL = "gpt-transcribe";
|
|
10
|
+
const OPENAI_STREAMING_SAMPLE_RATE = 24_000;
|
|
11
|
+
const OPENAI_FILE_SAMPLE_RATE = 16_000;
|
|
12
|
+
const OPENAI_TRANSCRIPTION_CONNECT_TIMEOUT_MS = 15_000;
|
|
13
|
+
const OPENAI_TRANSCRIPTION_COMPLETION_TIMEOUT_MS = 30_000;
|
|
14
|
+
const OPENAI_TRANSCRIPTION_CONTEXT_TOKENS = 1_024;
|
|
15
|
+
const OPENAI_TRANSCRIPTION_FFMPEG_TIMEOUT_MS = 5 * 60 * 1_000;
|
|
16
|
+
const OPENAI_TRANSCRIPTION_FFMPEG_OUTPUT_LIMIT_BYTES = 20_000;
|
|
17
|
+
const OPENAI_TRANSCRIPTION_MAX_PCM_BYTES = OPENAI_FILE_SAMPLE_RATE * 2 * (OPENAI_TRANSCRIPTION_FFMPEG_TIMEOUT_MS / 1_000);
|
|
18
|
+
const eventSchema = z.object({ type: z.string() }).passthrough();
|
|
19
|
+
const errorEventSchema = z.object({
|
|
20
|
+
type: z.literal("error"),
|
|
21
|
+
error: z.object({ message: z.string().trim().min(1) }),
|
|
22
|
+
});
|
|
23
|
+
const transcriptionFailedEventSchema = z.object({
|
|
24
|
+
type: z.literal("conversation.item.input_audio_transcription.failed"),
|
|
25
|
+
error: z.object({ message: z.string().trim().min(1) }),
|
|
26
|
+
});
|
|
27
|
+
const transcriptionCompletedEventSchema = z.object({
|
|
28
|
+
type: z.literal("conversation.item.input_audio_transcription.completed"),
|
|
29
|
+
transcript: z.string().trim().min(1),
|
|
30
|
+
});
|
|
31
|
+
const fileErrorSchema = z.object({
|
|
32
|
+
error: z.object({ message: z.string().trim().min(1) }),
|
|
33
|
+
});
|
|
34
|
+
const fileSuccessSchema = z.object({ text: z.string().trim().min(1) });
|
|
35
|
+
class OpenAIStreamingTranscriptionImpl {
|
|
36
|
+
socket;
|
|
37
|
+
ready = false;
|
|
38
|
+
aborted = false;
|
|
39
|
+
failure;
|
|
40
|
+
completedTranscript;
|
|
41
|
+
hasAudio = false;
|
|
42
|
+
pendingAudio = [];
|
|
43
|
+
readyTimeout;
|
|
44
|
+
completionTimeout;
|
|
45
|
+
resolveReady;
|
|
46
|
+
rejectReady;
|
|
47
|
+
resolveCompletion;
|
|
48
|
+
rejectCompletion;
|
|
49
|
+
readyPromise;
|
|
50
|
+
constructor(options) {
|
|
51
|
+
const apiKey = options.apiKey.trim();
|
|
52
|
+
if (!apiKey) {
|
|
53
|
+
throw new Error("missing OpenAI API key");
|
|
54
|
+
}
|
|
55
|
+
const webSocketFactory = options.webSocketFactory ?? defaultWebSocketFactory;
|
|
56
|
+
this.socket = webSocketFactory(OPENAI_REALTIME_TRANSCRIPTION_URL, {
|
|
57
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
58
|
+
});
|
|
59
|
+
this.readyPromise = new Promise((resolve, reject) => {
|
|
60
|
+
this.resolveReady = resolve;
|
|
61
|
+
this.rejectReady = reject;
|
|
62
|
+
});
|
|
63
|
+
void this.readyPromise.catch(() => { });
|
|
64
|
+
this.readyTimeout = setTimeout(() => {
|
|
65
|
+
this.fail(new Error("timed out opening OpenAI transcription session"));
|
|
66
|
+
this.socket.terminate();
|
|
67
|
+
}, OPENAI_TRANSCRIPTION_CONNECT_TIMEOUT_MS);
|
|
68
|
+
this.readyTimeout.unref?.();
|
|
69
|
+
this.socket.on("open", () => {
|
|
70
|
+
this.send({
|
|
71
|
+
type: "session.update",
|
|
72
|
+
session: {
|
|
73
|
+
type: "transcription",
|
|
74
|
+
audio: {
|
|
75
|
+
input: {
|
|
76
|
+
format: {
|
|
77
|
+
type: "audio/pcm",
|
|
78
|
+
rate: OPENAI_STREAMING_SAMPLE_RATE,
|
|
79
|
+
},
|
|
80
|
+
transcription: {
|
|
81
|
+
model: OPENAI_STREAMING_TRANSCRIPTION_MODEL,
|
|
82
|
+
prompt: buildOpenAITranscriptionPrompt(options.context),
|
|
83
|
+
delay: "medium",
|
|
84
|
+
},
|
|
85
|
+
turn_detection: null,
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
this.socket.on("message", (data) => this.handleMessage(data));
|
|
92
|
+
this.socket.on("error", (error) => {
|
|
93
|
+
this.fail(new Error(`OpenAI transcription connection failed: ${error.message}`));
|
|
94
|
+
});
|
|
95
|
+
this.socket.on("close", (code, reason) => {
|
|
96
|
+
if (this.aborted || this.completedTranscript)
|
|
97
|
+
return;
|
|
98
|
+
const detail = reason.toString("utf8").trim();
|
|
99
|
+
this.fail(new Error(detail
|
|
100
|
+
? `OpenAI transcription connection closed (${code}): ${detail}`
|
|
101
|
+
: `OpenAI transcription connection closed (${code})`));
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
appendAudio(audio) {
|
|
105
|
+
if (audio.length === 0 || this.aborted || this.failure || this.completedTranscript)
|
|
106
|
+
return;
|
|
107
|
+
this.hasAudio = true;
|
|
108
|
+
if (!this.ready) {
|
|
109
|
+
this.pendingAudio.push(audio);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
this.sendAudio(audio);
|
|
113
|
+
}
|
|
114
|
+
async finish(options = {}) {
|
|
115
|
+
const abortListener = () => this.abort();
|
|
116
|
+
if (options.signal?.aborted) {
|
|
117
|
+
abortListener();
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
options.signal?.addEventListener("abort", abortListener, { once: true });
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
await this.readyPromise;
|
|
124
|
+
if (this.failure)
|
|
125
|
+
throw this.failure;
|
|
126
|
+
if (this.aborted)
|
|
127
|
+
throw new Error("OpenAI transcription was aborted");
|
|
128
|
+
if (this.completedTranscript)
|
|
129
|
+
return this.completedTranscript;
|
|
130
|
+
if (!this.hasAudio)
|
|
131
|
+
throw new Error("OpenAI transcription received no audio");
|
|
132
|
+
const completion = new Promise((resolve, reject) => {
|
|
133
|
+
this.resolveCompletion = resolve;
|
|
134
|
+
this.rejectCompletion = reject;
|
|
135
|
+
});
|
|
136
|
+
this.completionTimeout = setTimeout(() => {
|
|
137
|
+
this.fail(new Error("timed out waiting for OpenAI transcription"));
|
|
138
|
+
this.socket.terminate();
|
|
139
|
+
}, OPENAI_TRANSCRIPTION_COMPLETION_TIMEOUT_MS);
|
|
140
|
+
this.completionTimeout.unref?.();
|
|
141
|
+
this.send({ type: "input_audio_buffer.commit" });
|
|
142
|
+
return await completion;
|
|
143
|
+
}
|
|
144
|
+
finally {
|
|
145
|
+
options.signal?.removeEventListener("abort", abortListener);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
abort() {
|
|
149
|
+
if (this.aborted || this.completedTranscript)
|
|
150
|
+
return;
|
|
151
|
+
const error = new Error("OpenAI transcription was aborted");
|
|
152
|
+
this.aborted = true;
|
|
153
|
+
this.pendingAudio = [];
|
|
154
|
+
this.clearTimers();
|
|
155
|
+
this.rejectReady?.(error);
|
|
156
|
+
this.rejectCompletion?.(error);
|
|
157
|
+
this.clearWaiters();
|
|
158
|
+
this.socket.close();
|
|
159
|
+
}
|
|
160
|
+
handleMessage(data) {
|
|
161
|
+
let payload;
|
|
162
|
+
try {
|
|
163
|
+
payload = JSON.parse(formatWebSocketMessage(data));
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
this.fail(new Error("OpenAI transcription returned malformed JSON"));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const event = eventSchema.safeParse(payload);
|
|
170
|
+
if (!event.success) {
|
|
171
|
+
this.fail(new Error("OpenAI transcription returned a malformed event"));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (event.data.type === "session.updated") {
|
|
175
|
+
this.ready = true;
|
|
176
|
+
if (this.readyTimeout)
|
|
177
|
+
clearTimeout(this.readyTimeout);
|
|
178
|
+
this.readyTimeout = undefined;
|
|
179
|
+
const pendingAudio = this.pendingAudio;
|
|
180
|
+
this.pendingAudio = [];
|
|
181
|
+
for (const audio of pendingAudio) {
|
|
182
|
+
this.sendAudio(audio);
|
|
183
|
+
}
|
|
184
|
+
if (this.failure)
|
|
185
|
+
return;
|
|
186
|
+
this.resolveReady?.();
|
|
187
|
+
this.resolveReady = undefined;
|
|
188
|
+
this.rejectReady = undefined;
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (event.data.type === "error") {
|
|
192
|
+
const parsed = errorEventSchema.safeParse(payload);
|
|
193
|
+
this.fail(new Error(parsed.success ? parsed.data.error.message : "OpenAI transcription returned an error"));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (event.data.type === "conversation.item.input_audio_transcription.failed") {
|
|
197
|
+
const parsed = transcriptionFailedEventSchema.safeParse(payload);
|
|
198
|
+
this.fail(new Error(parsed.success
|
|
199
|
+
? parsed.data.error.message
|
|
200
|
+
: "OpenAI transcription failed with a malformed error"));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (event.data.type === "conversation.item.input_audio_transcription.completed") {
|
|
204
|
+
const parsed = transcriptionCompletedEventSchema.safeParse(payload);
|
|
205
|
+
if (!parsed.success) {
|
|
206
|
+
this.fail(new Error("transcription result was empty or malformed"));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
this.completedTranscript = parsed.data.transcript;
|
|
210
|
+
this.clearTimers();
|
|
211
|
+
this.resolveCompletion?.(this.completedTranscript);
|
|
212
|
+
this.clearWaiters();
|
|
213
|
+
this.socket.close();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
sendAudio(audio) {
|
|
217
|
+
this.send({
|
|
218
|
+
type: "input_audio_buffer.append",
|
|
219
|
+
audio: audio.toString("base64"),
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
send(event) {
|
|
223
|
+
if (this.failure || this.aborted)
|
|
224
|
+
return;
|
|
225
|
+
try {
|
|
226
|
+
this.socket.send(JSON.stringify(event), (error) => {
|
|
227
|
+
if (error) {
|
|
228
|
+
this.fail(new Error(`failed to send OpenAI transcription audio: ${error.message}`));
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
this.fail(new Error(`failed to send OpenAI transcription audio: ${error.message}`));
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
fail(error) {
|
|
237
|
+
if (this.failure || this.aborted || this.completedTranscript)
|
|
238
|
+
return;
|
|
239
|
+
this.failure = error;
|
|
240
|
+
this.pendingAudio = [];
|
|
241
|
+
this.clearTimers();
|
|
242
|
+
this.rejectReady?.(error);
|
|
243
|
+
this.rejectCompletion?.(error);
|
|
244
|
+
this.clearWaiters();
|
|
245
|
+
this.socket.terminate();
|
|
246
|
+
}
|
|
247
|
+
clearTimers() {
|
|
248
|
+
if (this.readyTimeout)
|
|
249
|
+
clearTimeout(this.readyTimeout);
|
|
250
|
+
if (this.completionTimeout)
|
|
251
|
+
clearTimeout(this.completionTimeout);
|
|
252
|
+
this.readyTimeout = undefined;
|
|
253
|
+
this.completionTimeout = undefined;
|
|
254
|
+
}
|
|
255
|
+
clearWaiters() {
|
|
256
|
+
this.resolveReady = undefined;
|
|
257
|
+
this.rejectReady = undefined;
|
|
258
|
+
this.resolveCompletion = undefined;
|
|
259
|
+
this.rejectCompletion = undefined;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
export function startOpenAITranscription(options) {
|
|
263
|
+
return new OpenAIStreamingTranscriptionImpl(options);
|
|
264
|
+
}
|
|
265
|
+
export async function transcribeOpenAIAudio(options) {
|
|
266
|
+
const apiKey = options.apiKey.trim();
|
|
267
|
+
if (!apiKey) {
|
|
268
|
+
throw new Error("missing OpenAI API key");
|
|
269
|
+
}
|
|
270
|
+
const wav = await decodeOpenAIAudio({
|
|
271
|
+
audio: options.audio,
|
|
272
|
+
signal: options.signal,
|
|
273
|
+
spawnImpl: options.spawnImpl,
|
|
274
|
+
});
|
|
275
|
+
const formData = new FormData();
|
|
276
|
+
formData.append("model", OPENAI_FILE_TRANSCRIPTION_MODEL);
|
|
277
|
+
formData.append("file", new Blob([Uint8Array.from(wav)], { type: "audio/wav" }), "speech.wav");
|
|
278
|
+
formData.append("prompt", buildOpenAITranscriptionPrompt(options.context));
|
|
279
|
+
const fetchFn = options.fetchImpl ?? fetch;
|
|
280
|
+
const response = await fetchFn(OPENAI_FILE_TRANSCRIPTION_URL, {
|
|
281
|
+
method: "POST",
|
|
282
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
283
|
+
body: formData,
|
|
284
|
+
signal: options.signal,
|
|
285
|
+
});
|
|
286
|
+
const responseText = await response.text();
|
|
287
|
+
let payload;
|
|
288
|
+
try {
|
|
289
|
+
payload = responseText ? JSON.parse(responseText) : undefined;
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
payload = undefined;
|
|
293
|
+
}
|
|
294
|
+
if (!response.ok) {
|
|
295
|
+
const parsed = fileErrorSchema.safeParse(payload);
|
|
296
|
+
throw new Error(parsed.success ? parsed.data.error.message : responseText.trim() || `HTTP ${response.status}`);
|
|
297
|
+
}
|
|
298
|
+
const parsed = fileSuccessSchema.safeParse(payload);
|
|
299
|
+
if (!parsed.success) {
|
|
300
|
+
throw new Error("transcription result was empty or malformed");
|
|
301
|
+
}
|
|
302
|
+
return parsed.data.text;
|
|
303
|
+
}
|
|
304
|
+
async function decodeOpenAIAudio(args) {
|
|
305
|
+
const spawnImpl = args.spawnImpl ?? spawnWithCapture;
|
|
306
|
+
const decoderAbortController = new AbortController();
|
|
307
|
+
const signal = args.signal
|
|
308
|
+
? AbortSignal.any([args.signal, decoderAbortController.signal])
|
|
309
|
+
: decoderAbortController.signal;
|
|
310
|
+
const chunks = [];
|
|
311
|
+
let decodedBytes = 0;
|
|
312
|
+
let decodeFailure;
|
|
313
|
+
let result;
|
|
314
|
+
try {
|
|
315
|
+
result = await spawnImpl("ffmpeg", [
|
|
316
|
+
"-nostdin",
|
|
317
|
+
"-hide_banner",
|
|
318
|
+
"-loglevel",
|
|
319
|
+
"error",
|
|
320
|
+
"-i",
|
|
321
|
+
"pipe:0",
|
|
322
|
+
"-vn",
|
|
323
|
+
"-ac",
|
|
324
|
+
"1",
|
|
325
|
+
"-ar",
|
|
326
|
+
String(OPENAI_FILE_SAMPLE_RATE),
|
|
327
|
+
"-c:a",
|
|
328
|
+
"pcm_s16le",
|
|
329
|
+
"-f",
|
|
330
|
+
"s16le",
|
|
331
|
+
"pipe:1",
|
|
332
|
+
], {
|
|
333
|
+
input: args.audio,
|
|
334
|
+
signal,
|
|
335
|
+
timeoutMs: OPENAI_TRANSCRIPTION_FFMPEG_TIMEOUT_MS,
|
|
336
|
+
maxCaptureBytes: OPENAI_TRANSCRIPTION_FFMPEG_OUTPUT_LIMIT_BYTES,
|
|
337
|
+
captureOutput: "stderr",
|
|
338
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
339
|
+
onSpawn: (child) => {
|
|
340
|
+
child.stdout?.on("data", (chunk) => {
|
|
341
|
+
if (decodeFailure || signal.aborted)
|
|
342
|
+
return;
|
|
343
|
+
decodedBytes += chunk.length;
|
|
344
|
+
if (decodedBytes > OPENAI_TRANSCRIPTION_MAX_PCM_BYTES) {
|
|
345
|
+
decodeFailure = new Error("audio exceeds the five-minute OpenAI transcription limit");
|
|
346
|
+
decoderAbortController.abort(decodeFailure);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
chunks.push(Buffer.from(chunk));
|
|
350
|
+
});
|
|
351
|
+
},
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
if (error.code === "ENOENT") {
|
|
356
|
+
throw new Error("ffmpeg is required for OpenAI speech transcription");
|
|
357
|
+
}
|
|
358
|
+
throw error;
|
|
359
|
+
}
|
|
360
|
+
if (decodeFailure) {
|
|
361
|
+
throw decodeFailure;
|
|
362
|
+
}
|
|
363
|
+
if (result.aborted) {
|
|
364
|
+
throw signal.reason instanceof Error
|
|
365
|
+
? signal.reason
|
|
366
|
+
: new Error("OpenAI transcription was aborted");
|
|
367
|
+
}
|
|
368
|
+
if (result.timedOut) {
|
|
369
|
+
throw new Error("ffmpeg timed out while decoding audio for OpenAI transcription");
|
|
370
|
+
}
|
|
371
|
+
if (result.exitCode !== 0) {
|
|
372
|
+
const detail = result.stderr.trim();
|
|
373
|
+
throw new Error(detail
|
|
374
|
+
? `ffmpeg failed to decode audio for OpenAI transcription: ${detail}`
|
|
375
|
+
: `ffmpeg exited with code ${result.exitCode ?? "unknown"}`);
|
|
376
|
+
}
|
|
377
|
+
if (decodedBytes === 0) {
|
|
378
|
+
throw new Error("audio contained no decodable speech data");
|
|
379
|
+
}
|
|
380
|
+
return createPcmWav(Buffer.concat(chunks, decodedBytes));
|
|
381
|
+
}
|
|
382
|
+
function createPcmWav(pcm) {
|
|
383
|
+
const header = Buffer.alloc(44);
|
|
384
|
+
header.write("RIFF", 0, "ascii");
|
|
385
|
+
header.writeUInt32LE(36 + pcm.length, 4);
|
|
386
|
+
header.write("WAVE", 8, "ascii");
|
|
387
|
+
header.write("fmt ", 12, "ascii");
|
|
388
|
+
header.writeUInt32LE(16, 16);
|
|
389
|
+
header.writeUInt16LE(1, 20);
|
|
390
|
+
header.writeUInt16LE(1, 22);
|
|
391
|
+
header.writeUInt32LE(OPENAI_FILE_SAMPLE_RATE, 24);
|
|
392
|
+
header.writeUInt32LE(OPENAI_FILE_SAMPLE_RATE * 2, 28);
|
|
393
|
+
header.writeUInt16LE(2, 32);
|
|
394
|
+
header.writeUInt16LE(16, 34);
|
|
395
|
+
header.write("data", 36, "ascii");
|
|
396
|
+
header.writeUInt32LE(pcm.length, 40);
|
|
397
|
+
return Buffer.concat([header, pcm]);
|
|
398
|
+
}
|
|
399
|
+
function buildOpenAITranscriptionPrompt(context) {
|
|
400
|
+
const formattedContext = formatSpeechToTextContext(context);
|
|
401
|
+
const boundedContext = formattedContext
|
|
402
|
+
? truncateForTokens(formattedContext, {
|
|
403
|
+
maxTokens: OPENAI_TRANSCRIPTION_CONTEXT_TOKENS,
|
|
404
|
+
strategy: "tail",
|
|
405
|
+
}).content.trim()
|
|
406
|
+
: "";
|
|
407
|
+
return [
|
|
408
|
+
"The speaker is dictating a message for insertion into an AI coding assistant chat input.",
|
|
409
|
+
boundedContext
|
|
410
|
+
? `Use this recent conversation only to resolve likely names, acronyms, terminology, and references:\n${boundedContext}`
|
|
411
|
+
: undefined,
|
|
412
|
+
]
|
|
413
|
+
.filter((line) => line !== undefined)
|
|
414
|
+
.join("\n\n");
|
|
415
|
+
}
|
|
416
|
+
function formatWebSocketMessage(data) {
|
|
417
|
+
if (typeof data === "string")
|
|
418
|
+
return data;
|
|
419
|
+
if (Buffer.isBuffer(data))
|
|
420
|
+
return data.toString("utf8");
|
|
421
|
+
if (data instanceof ArrayBuffer)
|
|
422
|
+
return Buffer.from(data).toString("utf8");
|
|
423
|
+
if (ArrayBuffer.isView(data)) {
|
|
424
|
+
return Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString("utf8");
|
|
425
|
+
}
|
|
426
|
+
throw new Error("unsupported WebSocket message");
|
|
427
|
+
}
|
|
428
|
+
function defaultWebSocketFactory(url, options) {
|
|
429
|
+
return new WebSocket(url, options);
|
|
430
|
+
}
|
|
431
|
+
//# sourceMappingURL=openai_transcription.js.map
|