crewly 1.20.213 → 1.20.215

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.
Files changed (91) hide show
  1. package/config/skills/agent/core/project-tickets/SKILL.md +42 -10
  2. package/config/skills/agent/core/project-tickets/execute.sh +45 -12
  3. package/config/skills/agent/core/project-tickets/execute.test.sh +19 -0
  4. package/dist/backend/backend/src/constants.d.ts +124 -9
  5. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  6. package/dist/backend/backend/src/constants.js +152 -8
  7. package/dist/backend/backend/src/constants.js.map +1 -1
  8. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts +9 -1
  9. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts.map +1 -1
  10. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js +13 -1
  11. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js.map +1 -1
  12. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts +2 -1
  13. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts.map +1 -1
  14. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js +4 -2
  15. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js.map +1 -1
  16. package/dist/backend/backend/src/controllers/talk/talk-transcribe.controller.d.ts +37 -0
  17. package/dist/backend/backend/src/controllers/talk/talk-transcribe.controller.d.ts.map +1 -0
  18. package/dist/backend/backend/src/controllers/talk/talk-transcribe.controller.js +97 -0
  19. package/dist/backend/backend/src/controllers/talk/talk-transcribe.controller.js.map +1 -0
  20. package/dist/backend/backend/src/controllers/talk/talk-transcribe.routes.d.ts +18 -0
  21. package/dist/backend/backend/src/controllers/talk/talk-transcribe.routes.d.ts.map +1 -0
  22. package/dist/backend/backend/src/controllers/talk/talk-transcribe.routes.js +25 -0
  23. package/dist/backend/backend/src/controllers/talk/talk-transcribe.routes.js.map +1 -0
  24. package/dist/backend/backend/src/index.d.ts.map +1 -1
  25. package/dist/backend/backend/src/index.js +22 -4
  26. package/dist/backend/backend/src/index.js.map +1 -1
  27. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  28. package/dist/backend/backend/src/routes/api.routes.js +4 -0
  29. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  30. package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.d.ts.map +1 -1
  31. package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js +6 -0
  32. package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js.map +1 -1
  33. package/dist/backend/backend/src/services/project-tickets/autopilot-speed-command.d.ts +108 -0
  34. package/dist/backend/backend/src/services/project-tickets/autopilot-speed-command.d.ts.map +1 -0
  35. package/dist/backend/backend/src/services/project-tickets/autopilot-speed-command.js +223 -0
  36. package/dist/backend/backend/src/services/project-tickets/autopilot-speed-command.js.map +1 -0
  37. package/dist/backend/backend/src/services/project-tickets/autopilot-speed.wiring.d.ts +57 -0
  38. package/dist/backend/backend/src/services/project-tickets/autopilot-speed.wiring.d.ts.map +1 -0
  39. package/dist/backend/backend/src/services/project-tickets/autopilot-speed.wiring.js +90 -0
  40. package/dist/backend/backend/src/services/project-tickets/autopilot-speed.wiring.js.map +1 -0
  41. package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts +18 -4
  42. package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts.map +1 -1
  43. package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.js +18 -4
  44. package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.js.map +1 -1
  45. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts +135 -14
  46. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts.map +1 -1
  47. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js +111 -18
  48. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js.map +1 -1
  49. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts +67 -1
  50. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts.map +1 -1
  51. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js +75 -1
  52. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js.map +1 -1
  53. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-trace.d.ts +1 -1
  54. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-trace.d.ts.map +1 -1
  55. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-trace.js +7 -0
  56. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-trace.js.map +1 -1
  57. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts +99 -4
  58. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts.map +1 -1
  59. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js +422 -11
  60. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js.map +1 -1
  61. package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
  62. package/dist/backend/backend/src/services/slack/slack-initializer.js +2 -1
  63. package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
  64. package/dist/backend/backend/src/services/talk/talk-transcribe.service.d.ts +344 -0
  65. package/dist/backend/backend/src/services/talk/talk-transcribe.service.d.ts.map +1 -0
  66. package/dist/backend/backend/src/services/talk/talk-transcribe.service.js +642 -0
  67. package/dist/backend/backend/src/services/talk/talk-transcribe.service.js.map +1 -0
  68. package/dist/backend/backend/src/types/ticket-autopilot.types.d.ts +46 -4
  69. package/dist/backend/backend/src/types/ticket-autopilot.types.d.ts.map +1 -1
  70. package/dist/backend/backend/src/types/ticket-autopilot.types.js +43 -2
  71. package/dist/backend/backend/src/types/ticket-autopilot.types.js.map +1 -1
  72. package/dist/backend/backend/src/types/v2/work-item.types.d.ts +1 -1
  73. package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  74. package/dist/backend/backend/src/types/v2/work-item.types.js +1 -0
  75. package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
  76. package/dist/backend/build-info.json +2 -2
  77. package/dist/cli/backend/src/constants.d.ts +124 -9
  78. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  79. package/dist/cli/backend/src/constants.js +152 -8
  80. package/dist/cli/backend/src/constants.js.map +1 -1
  81. package/dist/cli/backend/src/types/ticket-autopilot.types.d.ts +46 -4
  82. package/dist/cli/backend/src/types/ticket-autopilot.types.d.ts.map +1 -1
  83. package/dist/cli/backend/src/types/ticket-autopilot.types.js +43 -2
  84. package/dist/cli/backend/src/types/ticket-autopilot.types.js.map +1 -1
  85. package/dist/cli/backend/src/types/v2/work-item.types.d.ts +1 -1
  86. package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  87. package/dist/cli/backend/src/types/v2/work-item.types.js +1 -0
  88. package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
  89. package/frontend/dist/assets/{index-917db1b8.js → index-839f4374.js} +272 -272
  90. package/frontend/dist/index.html +1 -1
  91. package/package.json +1 -1
@@ -0,0 +1,642 @@
1
+ /**
2
+ * Talk transcription — speech-to-text for the portal Talk page on the
3
+ * owner's own machine (specs/2026-10-04-talk-whisper-transcribe.md, #1074).
4
+ *
5
+ * The phone records a short clip and sends it over the relay to the machine
6
+ * of the agent being talked to; this service turns it into text with
7
+ * whisper.cpp and hands the text back. It never sends anything to an agent:
8
+ * the owner reads, edits and confirms the text on the phone first.
9
+ *
10
+ * Engine: the `transcribe-audio` skill's — same `whisper-cli` lookup order,
11
+ * same large-v3-turbo model file, same ffmpeg normalisation to 16 kHz mono
12
+ * WAV. Its setup block is what installs the pieces ({@link startSetup}).
13
+ *
14
+ * Properties:
15
+ * - **One at a time.** whisper uses most of the CPU; requests queue behind
16
+ * the running one (at most {@link TALK_TRANSCRIBE_CONSTANTS.MAX_QUEUE}
17
+ * waiting) and share one deadline that includes the wait.
18
+ * - **Nothing kept.** Audio is written to a private temp dir that is removed
19
+ * in `finally`; neither audio nor transcript is ever logged.
20
+ * - **Clear failures.** Every refusal carries a code the phone acts on by
21
+ * falling back to on-device recognition: `whisper_unavailable`,
22
+ * `too_long`, `timeout`, `failed` (and `busy`, `invalid_audio`).
23
+ *
24
+ * @module services/talk/talk-transcribe.service
25
+ */
26
+ import * as fs from 'fs';
27
+ import * as os from 'os';
28
+ import * as path from 'path';
29
+ import { SKILL_SETUP_CONSTANTS, TALK_TRANSCRIBE_CONSTANTS } from '../../constants.js';
30
+ import { getCrewlyHomePath } from '../core/crewly-home.utils.js';
31
+ import { LoggerService } from '../core/logger.service.js';
32
+ import { resolveExecutable, runCommand } from '../harness/harness-exec.utils.js';
33
+ const C = TALK_TRANSCRIBE_CONSTANTS;
34
+ /** HTTP status for each refusal. */
35
+ export const TALK_TRANSCRIBE_HTTP_STATUS = {
36
+ [C.CODES.WHISPER_UNAVAILABLE]: 503,
37
+ [C.CODES.TOO_LONG]: 413,
38
+ [C.CODES.TIMEOUT]: 504,
39
+ [C.CODES.FAILED]: 500,
40
+ [C.CODES.BUSY]: 429,
41
+ [C.CODES.INVALID_AUDIO]: 400,
42
+ [C.CODES.OWNER_ONLY]: 403,
43
+ };
44
+ /** A refusal with a machine-readable code. Its message never contains audio or transcript. */
45
+ export class TalkTranscribeError extends Error {
46
+ code;
47
+ /**
48
+ * @param code - What went wrong (the phone falls back on any of them)
49
+ * @param message - Short English explanation
50
+ */
51
+ constructor(code, message) {
52
+ super(message);
53
+ this.code = code;
54
+ this.name = 'TalkTranscribeError';
55
+ }
56
+ /** HTTP status for this refusal. */
57
+ get httpStatus() {
58
+ return TALK_TRANSCRIBE_HTTP_STATUS[this.code];
59
+ }
60
+ }
61
+ /**
62
+ * Whether a file exists and is executable.
63
+ *
64
+ * @param file - Absolute path
65
+ * @returns True when executable
66
+ */
67
+ function defaultIsExecutable(file) {
68
+ try {
69
+ fs.accessSync(file, fs.constants.X_OK);
70
+ return fs.statSync(file).isFile();
71
+ }
72
+ catch {
73
+ return false;
74
+ }
75
+ }
76
+ /**
77
+ * Whether a regular file exists.
78
+ *
79
+ * @param file - Absolute path
80
+ * @returns True when it is a file
81
+ */
82
+ function defaultIsFile(file) {
83
+ try {
84
+ return fs.statSync(file).isFile();
85
+ }
86
+ catch {
87
+ return false;
88
+ }
89
+ }
90
+ /**
91
+ * Temp-file extension for a MediaRecorder type (`audio/webm;codecs=opus` → `webm`).
92
+ *
93
+ * @param mimeType - Container type
94
+ * @returns Extension, or null when the type is not audio we take
95
+ */
96
+ export function extensionForMime(mimeType) {
97
+ const base = mimeType.split(';')[0].trim().toLowerCase();
98
+ return C.MIME_EXTENSIONS[base] ?? null;
99
+ }
100
+ /**
101
+ * Decode the base64 body, refusing anything malformed or over the size cap
102
+ * before decoding it.
103
+ *
104
+ * @param audio - Base64 string, optionally a `data:` URL
105
+ * @param maxBytes - Size cap of the decoded audio
106
+ * @returns The audio bytes
107
+ * @throws TalkTranscribeError `invalid_audio` or `too_long`
108
+ */
109
+ export function decodeAudio(audio, maxBytes) {
110
+ if (typeof audio !== 'string' || audio.length === 0) {
111
+ throw new TalkTranscribeError(C.CODES.INVALID_AUDIO, 'audio (base64) is required');
112
+ }
113
+ const comma = audio.startsWith('data:') ? audio.indexOf(',') : -1;
114
+ const b64 = (comma >= 0 ? audio.slice(comma + 1) : audio).replace(/\s+/g, '');
115
+ if (b64.length > Math.ceil(maxBytes / 3) * 4) {
116
+ throw new TalkTranscribeError(C.CODES.TOO_LONG, `The clip is larger than ${Math.round(maxBytes / 1024)} KB`);
117
+ }
118
+ if (!/^[A-Za-z0-9+/]+={0,2}$/.test(b64)) {
119
+ throw new TalkTranscribeError(C.CODES.INVALID_AUDIO, 'audio is not valid base64');
120
+ }
121
+ const bytes = Buffer.from(b64, 'base64');
122
+ if (bytes.length === 0)
123
+ throw new TalkTranscribeError(C.CODES.INVALID_AUDIO, 'audio is empty');
124
+ if (bytes.length > maxBytes) {
125
+ throw new TalkTranscribeError(C.CODES.TOO_LONG, `The clip is larger than ${Math.round(maxBytes / 1024)} KB`);
126
+ }
127
+ return bytes;
128
+ }
129
+ /**
130
+ * The initial prompt: the Simplified-Chinese bias sentence, then the owner
131
+ * glossary and this machine's team / agent / project names, so names like
132
+ * "CE" are not heard as "侧". Bounded so whisper keeps all of it.
133
+ *
134
+ * @param names - Vocabulary from this machine
135
+ * @param maxChars - Bound on the vocabulary part
136
+ * @returns Prompt text
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * buildVocabularyPrompt(['Marketing', 'Ella']);
141
+ * // '以下是普通话的句子。Crewly、CE、Crewly Cloud、Slack、Marketing、Ella。'
142
+ * ```
143
+ */
144
+ export function buildVocabularyPrompt(names, maxChars = C.MAX_VOCAB_CHARS) {
145
+ const seen = new Set();
146
+ const words = [];
147
+ let used = 0;
148
+ for (const raw of [...C.GLOSSARY, ...names]) {
149
+ const word = typeof raw === 'string' ? raw.replace(/\s+/g, ' ').trim() : '';
150
+ if (!word || word.length > 40)
151
+ continue;
152
+ const key = word.toLowerCase();
153
+ if (seen.has(key))
154
+ continue;
155
+ if (used + word.length + 1 > maxChars)
156
+ break;
157
+ seen.add(key);
158
+ words.push(word);
159
+ used += word.length + 1;
160
+ }
161
+ return words.length > 0 ? `${C.PROMPT_PREFIX}${words.join('、')}。` : C.PROMPT_PREFIX;
162
+ }
163
+ /**
164
+ * Join whisper segments: a space only between two Latin-script edges, so
165
+ * Chinese stays unspaced and English words stay apart.
166
+ *
167
+ * @param segments - Segment texts
168
+ * @returns The transcript
169
+ */
170
+ export function joinSegments(segments) {
171
+ let out = '';
172
+ for (const raw of segments) {
173
+ const seg = raw.trim();
174
+ if (!seg || /^\[.*\]$/.test(seg) || /^\(.*\)$/.test(seg))
175
+ continue; // [BLANK_AUDIO], (music)
176
+ if (out && /[A-Za-z0-9.,!?;:]$/.test(out) && /^[A-Za-z0-9]/.test(seg))
177
+ out += ' ';
178
+ out += seg;
179
+ }
180
+ return out.trim();
181
+ }
182
+ /** Talk speech-to-text with whisper.cpp. */
183
+ export class TalkTranscribeService {
184
+ run;
185
+ env;
186
+ homeDir;
187
+ crewlyHome;
188
+ isExecutable;
189
+ isFile;
190
+ vocabulary;
191
+ deviceNameFn;
192
+ startSetupFn;
193
+ setupJobFn;
194
+ tmpDir;
195
+ cpuCount;
196
+ now;
197
+ logger;
198
+ maxAudioBytes;
199
+ maxDurationSec;
200
+ requestTimeoutMs;
201
+ maxQueue;
202
+ running = false;
203
+ waiters = [];
204
+ lastSetup = null;
205
+ /**
206
+ * @param deps - Injectable dependencies
207
+ */
208
+ constructor(deps = {}) {
209
+ this.run = deps.run ?? runCommand;
210
+ this.env = deps.env ?? process.env;
211
+ this.homeDir = deps.homeDir ?? os.homedir;
212
+ this.crewlyHome = deps.crewlyHome ?? getCrewlyHomePath;
213
+ this.isExecutable = deps.isExecutable ?? defaultIsExecutable;
214
+ this.isFile = deps.isFile ?? defaultIsFile;
215
+ this.vocabulary = deps.vocabulary ?? (async () => []);
216
+ this.deviceNameFn = deps.deviceName ?? (async () => os.hostname());
217
+ this.startSetupFn = deps.startSetup ?? null;
218
+ this.setupJobFn = deps.setupJob ?? null;
219
+ this.tmpDir = deps.tmpDir ?? os.tmpdir;
220
+ this.cpuCount = deps.cpuCount ?? (() => os.cpus().length);
221
+ this.now = deps.now ?? Date.now;
222
+ this.logger = deps.logger ?? LoggerService.getInstance().createComponentLogger('TalkTranscribe');
223
+ this.maxAudioBytes = deps.limits?.maxAudioBytes ?? C.MAX_AUDIO_BYTES;
224
+ this.maxDurationSec = deps.limits?.maxDurationSec ?? C.MAX_DURATION_SEC;
225
+ this.requestTimeoutMs = deps.limits?.requestTimeoutMs ?? C.REQUEST_TIMEOUT_MS;
226
+ this.maxQueue = deps.limits?.maxQueue ?? C.MAX_QUEUE;
227
+ }
228
+ // -------------------------------------------------------------------------
229
+ // Engine discovery (the transcribe-audio skill's order)
230
+ // -------------------------------------------------------------------------
231
+ /**
232
+ * PATH searched for commands: `$CREWLY_HOME/bin`, the process PATH, then
233
+ * the usual system and Homebrew dirs (a backend started by launchd often
234
+ * lacks /opt/homebrew/bin) — the skill setup runner's search path.
235
+ *
236
+ * @returns PATH string
237
+ */
238
+ searchPath() {
239
+ const entries = [
240
+ path.join(this.crewlyHome(), SKILL_SETUP_CONSTANTS.BIN_DIR),
241
+ ...(this.env.PATH ?? '').split(path.delimiter),
242
+ ...SKILL_SETUP_CONSTANTS.EXTRA_COMMAND_DIRS,
243
+ ].filter((e) => e.length > 0);
244
+ return [...new Set(entries)].join(path.delimiter);
245
+ }
246
+ /**
247
+ * Find whisper-cli, the model and ffmpeg. Checked on every call (cheap
248
+ * file checks), so a finished setup is seen at once.
249
+ *
250
+ * Order, as in `transcribe-audio/execute.sh`: `FLOPOST_WHISPER_BIN`,
251
+ * `~/.flopost/whisper/whisper-cli`, `$CREWLY_HOME/bin`, PATH, Homebrew;
252
+ * model: `FLOPOST_WHISPER_MODEL`, `~/.flopost/whisper/`, `~/.cache/whisper-models/`.
253
+ *
254
+ * @returns Paths (null = missing)
255
+ */
256
+ resolveEngine() {
257
+ const home = this.homeDir();
258
+ let whisperBin = null;
259
+ const envBin = this.env.FLOPOST_WHISPER_BIN;
260
+ if (envBin && this.isExecutable(envBin))
261
+ whisperBin = envBin;
262
+ for (const rel of C.HOME_BIN_CANDIDATES) {
263
+ if (whisperBin)
264
+ break;
265
+ const p = path.join(home, rel);
266
+ if (this.isExecutable(p))
267
+ whisperBin = p;
268
+ }
269
+ const searchPath = this.searchPath();
270
+ whisperBin ??= resolveExecutable(C.WHISPER_BINARY, searchPath, this.isExecutable);
271
+ let model = null;
272
+ const envModel = this.env.FLOPOST_WHISPER_MODEL;
273
+ if (envModel && this.isFile(envModel))
274
+ model = envModel;
275
+ for (const dir of C.MODEL_DIRS) {
276
+ if (model)
277
+ break;
278
+ const p = path.join(home, dir, C.MODEL_FILENAME);
279
+ if (this.isFile(p))
280
+ model = p;
281
+ }
282
+ const ffmpeg = resolveExecutable(C.FFMPEG_BINARY, searchPath, this.isExecutable);
283
+ return { whisperBin, model, ffmpeg };
284
+ }
285
+ /**
286
+ * Missing pieces, named by the skill's setup step ids.
287
+ *
288
+ * @param engine - Resolved engine
289
+ * @returns e.g. `['whisper-model']`
290
+ */
291
+ missingParts(engine) {
292
+ const missing = [];
293
+ if (!engine.ffmpeg)
294
+ missing.push('ffmpeg');
295
+ if (!engine.whisperBin)
296
+ missing.push('whisper-cli');
297
+ if (!engine.model)
298
+ missing.push('whisper-model');
299
+ return missing;
300
+ }
301
+ /**
302
+ * Whether a transcription can run here now.
303
+ *
304
+ * @returns True when whisper-cli, the model and ffmpeg are present
305
+ */
306
+ isReady() {
307
+ return this.missingParts(this.resolveEngine()).length === 0;
308
+ }
309
+ /**
310
+ * Capabilities for the Cloud heartbeat: `talk_whisper` while ready.
311
+ *
312
+ * @returns Capability list
313
+ */
314
+ capabilities() {
315
+ return this.isReady() ? [C.CAPABILITY] : [];
316
+ }
317
+ /**
318
+ * This machine's name, never failing.
319
+ *
320
+ * @returns Device name
321
+ */
322
+ async deviceName() {
323
+ try {
324
+ return (await this.deviceNameFn()) || os.hostname();
325
+ }
326
+ catch {
327
+ return os.hostname();
328
+ }
329
+ }
330
+ /**
331
+ * Status for the phone: ready or not, what is missing, queue, setup.
332
+ *
333
+ * @returns Status
334
+ */
335
+ async getStatus() {
336
+ const missing = this.missingParts(this.resolveEngine());
337
+ const setup = await this.currentSetup();
338
+ return {
339
+ whisperReady: missing.length === 0,
340
+ missing,
341
+ deviceName: await this.deviceName(),
342
+ busy: this.running,
343
+ queued: this.waiters.length,
344
+ maxDurationSec: this.maxDurationSec,
345
+ maxAudioBytes: this.maxAudioBytes,
346
+ ...(setup ? { setup } : {}),
347
+ };
348
+ }
349
+ /**
350
+ * The last setup job, refreshed from the job service.
351
+ *
352
+ * @returns State, or null when none was started here
353
+ */
354
+ async currentSetup() {
355
+ if (!this.lastSetup)
356
+ return null;
357
+ if (this.lastSetup.jobId && this.setupJobFn) {
358
+ const fresh = await this.setupJobFn(this.lastSetup.jobId).catch(() => null);
359
+ if (fresh)
360
+ this.lastSetup = fresh;
361
+ }
362
+ return this.lastSetup;
363
+ }
364
+ /**
365
+ * Install ffmpeg, whisper-cli and the model with the transcribe-audio
366
+ * skill's setup block, in the background (unattended; the skill is
367
+ * official). Returns at once.
368
+ *
369
+ * @returns The setup state (`succeeded` when everything was already there)
370
+ * @throws TalkTranscribeError `failed` when setup cannot be started
371
+ */
372
+ async startSetup() {
373
+ if (this.isReady()) {
374
+ this.lastSetup = { state: 'succeeded', message: 'Whisper is ready' };
375
+ return this.lastSetup;
376
+ }
377
+ if (!this.startSetupFn)
378
+ throw new TalkTranscribeError(C.CODES.FAILED, 'Setup is not available on this machine');
379
+ try {
380
+ this.lastSetup = await this.startSetupFn();
381
+ }
382
+ catch (error) {
383
+ const message = error instanceof Error ? error.message : String(error);
384
+ this.lastSetup = { state: 'failed', message };
385
+ throw new TalkTranscribeError(C.CODES.FAILED, message);
386
+ }
387
+ this.logger.info('Whisper setup for Talk started', { state: this.lastSetup.state, jobId: this.lastSetup.jobId });
388
+ return this.lastSetup;
389
+ }
390
+ // -------------------------------------------------------------------------
391
+ // Transcription
392
+ // -------------------------------------------------------------------------
393
+ /**
394
+ * Take the one-at-a-time slot, waiting until `deadline` at most.
395
+ *
396
+ * @param deadline - Absolute ms
397
+ * @throws TalkTranscribeError `busy` (queue full) or `timeout`
398
+ */
399
+ acquire(deadline) {
400
+ if (!this.running) {
401
+ this.running = true;
402
+ return Promise.resolve();
403
+ }
404
+ if (this.waiters.length >= this.maxQueue) {
405
+ return Promise.reject(new TalkTranscribeError(C.CODES.BUSY, 'Another transcription is running; try again in a moment'));
406
+ }
407
+ return new Promise((resolve, reject) => {
408
+ const grant = () => {
409
+ clearTimeout(timer);
410
+ resolve();
411
+ };
412
+ const timer = setTimeout(() => {
413
+ const i = this.waiters.indexOf(grant);
414
+ if (i >= 0)
415
+ this.waiters.splice(i, 1);
416
+ reject(new TalkTranscribeError(C.CODES.TIMEOUT, 'Timed out waiting for the previous transcription'));
417
+ }, Math.max(0, deadline - this.now()));
418
+ this.waiters.push(grant);
419
+ });
420
+ }
421
+ /** Hand the slot to the next waiter, or free it. */
422
+ release() {
423
+ const next = this.waiters.shift();
424
+ if (next)
425
+ next();
426
+ else
427
+ this.running = false;
428
+ }
429
+ /**
430
+ * Transcribe one clip.
431
+ *
432
+ * Validation (type, size, engine present) happens before queueing; the
433
+ * deadline covers the wait, ffmpeg and whisper. Temp files are removed in
434
+ * `finally`. Logs carry only sizes, durations and codes.
435
+ *
436
+ * @param input - Base64 audio, container type, language hint
437
+ * @returns The transcript
438
+ * @throws TalkTranscribeError with a code the phone falls back on
439
+ *
440
+ * @example
441
+ * ```ts
442
+ * const r = await svc.transcribe({ audio: b64, mimeType: 'audio/mp4' });
443
+ * // { text: '帮我看一下 CE 的网站', language: 'zh', durationSec: 3.2, ... }
444
+ * ```
445
+ */
446
+ async transcribe(input) {
447
+ const started = this.now();
448
+ const deadline = started + this.requestTimeoutMs;
449
+ const mimeType = typeof input.mimeType === 'string' ? input.mimeType : '';
450
+ const ext = extensionForMime(mimeType);
451
+ if (!ext)
452
+ throw new TalkTranscribeError(C.CODES.INVALID_AUDIO, `Unsupported audio type: ${mimeType.slice(0, 60) || '(none)'}`);
453
+ const language = input.language === undefined || input.language === null || input.language === '' ? 'auto' : input.language;
454
+ if (typeof language !== 'string' || !C.LANGUAGES.includes(language)) {
455
+ throw new TalkTranscribeError(C.CODES.INVALID_AUDIO, `language must be one of ${C.LANGUAGES.join(', ')}`);
456
+ }
457
+ const bytes = decodeAudio(input.audio, this.maxAudioBytes);
458
+ const engine = this.resolveEngine();
459
+ const missing = this.missingParts(engine);
460
+ if (missing.length > 0) {
461
+ throw new TalkTranscribeError(C.CODES.WHISPER_UNAVAILABLE, `Whisper is not set up on this machine (missing: ${missing.join(', ')})`);
462
+ }
463
+ await this.acquire(deadline);
464
+ let workDir = null;
465
+ try {
466
+ workDir = fs.mkdtempSync(path.join(this.tmpDir(), C.TEMP_PREFIX));
467
+ const paths = { whisperBin: engine.whisperBin, model: engine.model, ffmpeg: engine.ffmpeg };
468
+ const result = await this.runEngine(paths, workDir, bytes, ext, language, deadline);
469
+ const elapsedMs = this.now() - started;
470
+ this.logger.info('Talk clip transcribed', {
471
+ bytes: bytes.length,
472
+ durationSec: result.durationSec,
473
+ language: result.language,
474
+ chars: result.text.length,
475
+ elapsedMs,
476
+ });
477
+ return { ...result, engine: 'whisper.cpp', deviceName: await this.deviceName(), elapsedMs };
478
+ }
479
+ catch (error) {
480
+ const code = error instanceof TalkTranscribeError ? error.code : C.CODES.FAILED;
481
+ this.logger.warn('Talk clip not transcribed', { code, bytes: bytes.length, elapsedMs: this.now() - started });
482
+ if (error instanceof TalkTranscribeError)
483
+ throw error;
484
+ throw new TalkTranscribeError(C.CODES.FAILED, 'Transcription failed');
485
+ }
486
+ finally {
487
+ if (workDir) {
488
+ try {
489
+ fs.rmSync(workDir, { recursive: true, force: true });
490
+ }
491
+ catch {
492
+ /* best effort; the OS temp dir is cleaned anyway */
493
+ }
494
+ }
495
+ this.release();
496
+ }
497
+ }
498
+ /**
499
+ * ffmpeg → WAV, duration check, whisper-cli → JSON → text.
500
+ *
501
+ * @param engine - Resolved paths (all present)
502
+ * @param workDir - Private temp dir
503
+ * @param bytes - Encoded audio
504
+ * @param ext - Input extension
505
+ * @param language - `auto` / `zh` / `en`
506
+ * @param deadline - Absolute ms
507
+ * @returns Text, language, duration
508
+ */
509
+ async runEngine(engine, workDir, bytes, ext, language, deadline) {
510
+ const inFile = path.join(workDir, `clip.${ext}`);
511
+ const wav = path.join(workDir, 'clip.wav');
512
+ fs.writeFileSync(inFile, bytes, { mode: 0o600 });
513
+ const env = { ...this.env, PATH: this.searchPath() };
514
+ const remaining = () => {
515
+ const ms = deadline - this.now();
516
+ if (ms <= 0)
517
+ throw new TalkTranscribeError(C.CODES.TIMEOUT, 'Transcription timed out');
518
+ return ms;
519
+ };
520
+ // One second past the cap is decoded so an over-long clip is detected, not silently cut.
521
+ const conv = await this.run(engine.ffmpeg, ['-hide_banner', '-loglevel', 'error', '-nostdin', '-y', '-i', inFile, '-t', String(this.maxDurationSec + 1), '-vn', '-ac', '1', '-ar', String(C.SAMPLE_RATE), '-c:a', 'pcm_s16le', wav], { env, timeoutMs: remaining() });
522
+ if (conv.code !== 0) {
523
+ if (conv.code === null && /timed out/.test(conv.error ?? ''))
524
+ throw new TalkTranscribeError(C.CODES.TIMEOUT, 'Transcription timed out');
525
+ throw new TalkTranscribeError(C.CODES.INVALID_AUDIO, 'Could not decode the audio');
526
+ }
527
+ let wavBytes = 0;
528
+ try {
529
+ wavBytes = fs.statSync(wav).size;
530
+ }
531
+ catch {
532
+ throw new TalkTranscribeError(C.CODES.INVALID_AUDIO, 'Could not decode the audio');
533
+ }
534
+ const durationSec = Math.max(0, (wavBytes - C.WAV_HEADER_BYTES) / C.WAV_BYTES_PER_SEC);
535
+ if (durationSec > this.maxDurationSec) {
536
+ throw new TalkTranscribeError(C.CODES.TOO_LONG, `The clip is longer than ${this.maxDurationSec} s`);
537
+ }
538
+ const rounded = Math.round(durationSec * 100) / 100;
539
+ const prompt = buildVocabularyPrompt(await this.vocabulary().catch(() => []));
540
+ const prefix = path.join(workDir, 'out');
541
+ const threads = Math.max(C.MIN_THREADS, this.cpuCount() - C.THREADS_RESERVED);
542
+ const res = await this.run(engine.whisperBin, ['-m', engine.model, '-f', wav, '-l', language, '--prompt', prompt, '-oj', '-of', prefix, '-t', String(threads), '-np'], { env, timeoutMs: remaining() });
543
+ if (res.code !== 0) {
544
+ if (res.code === null && /timed out/.test(res.error ?? ''))
545
+ throw new TalkTranscribeError(C.CODES.TIMEOUT, 'Transcription timed out');
546
+ throw new TalkTranscribeError(C.CODES.FAILED, `whisper-cli exited with ${res.code ?? 'an error'}`);
547
+ }
548
+ let parsed;
549
+ try {
550
+ parsed = JSON.parse(fs.readFileSync(`${prefix}.json`, 'utf8'));
551
+ }
552
+ catch {
553
+ throw new TalkTranscribeError(C.CODES.FAILED, 'whisper-cli produced no readable output');
554
+ }
555
+ let text = joinSegments((parsed.transcription ?? []).map((s) => (typeof s.text === 'string' ? s.text : '')));
556
+ // On silence whisper can echo its prompt back; that is not what was said.
557
+ if (text === C.PROMPT_PREFIX || text === prompt)
558
+ text = '';
559
+ const detected = parsed.result?.language || (language === 'auto' ? 'auto' : language);
560
+ return { text, language: detected, durationSec: rounded };
561
+ }
562
+ }
563
+ // ---------------------------------------------------------------------------
564
+ // Singleton
565
+ // ---------------------------------------------------------------------------
566
+ let instance = null;
567
+ /**
568
+ * The process-wide service, created with the default dependencies on first use.
569
+ *
570
+ * @returns The service
571
+ */
572
+ export function getTalkTranscribeService() {
573
+ instance ??= new TalkTranscribeService(defaultDeps());
574
+ return instance;
575
+ }
576
+ /**
577
+ * Replace the process-wide service (tests; null resets).
578
+ *
579
+ * @param service - Service or null
580
+ */
581
+ export function setTalkTranscribeService(service) {
582
+ instance = service;
583
+ }
584
+ /**
585
+ * Capabilities for the Cloud heartbeat (`talk_whisper` while Whisper is ready).
586
+ *
587
+ * @returns Capability list
588
+ */
589
+ export function talkTranscribeCapabilities() {
590
+ try {
591
+ return getTalkTranscribeService().capabilities();
592
+ }
593
+ catch {
594
+ return [];
595
+ }
596
+ }
597
+ /**
598
+ * Production wiring: vocabulary from storage, the device name, and the skill
599
+ * install job service for setup. Imports are lazy so the module stays light.
600
+ *
601
+ * @returns Dependencies
602
+ */
603
+ function defaultDeps() {
604
+ return {
605
+ vocabulary: async () => {
606
+ const { StorageService } = await import('../core/storage.service.js');
607
+ const storage = StorageService.getInstance();
608
+ const [teams, projects] = await Promise.all([storage.getTeams().catch(() => []), storage.getProjects().catch(() => [])]);
609
+ const names = [];
610
+ for (const team of teams) {
611
+ names.push(team.name);
612
+ for (const member of team.members ?? [])
613
+ names.push(member.name);
614
+ }
615
+ for (const project of projects)
616
+ names.push(project.name);
617
+ return names.filter((n) => typeof n === 'string');
618
+ },
619
+ deviceName: async () => {
620
+ const { DeviceIdentityService } = await import('../cloud/device-identity.service.js');
621
+ return (await DeviceIdentityService.getInstance().getOrCreateIdentity()).deviceName;
622
+ },
623
+ startSetup: async () => {
624
+ const { getSkillInstallJobService } = await import('../skill-setup/skill-install-job.service.js');
625
+ const started = await getSkillInstallJobService().startInstall({ skillId: C.SKILL_ID, ownerDashboard: true });
626
+ if (started.kind === 'already-ready')
627
+ return { state: 'succeeded', message: 'Whisper is ready' };
628
+ return { state: started.job.state, jobId: started.job.jobId, ...(started.job.message ? { message: started.job.message } : {}) };
629
+ },
630
+ setupJob: async (jobId) => {
631
+ const { getSkillInstallJobService } = await import('../skill-setup/skill-install-job.service.js');
632
+ try {
633
+ const job = getSkillInstallJobService().getJob(jobId);
634
+ return { state: job.state, jobId: job.jobId, ...(job.message ? { message: job.message } : {}) };
635
+ }
636
+ catch {
637
+ return null;
638
+ }
639
+ },
640
+ };
641
+ }
642
+ //# sourceMappingURL=talk-transcribe.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"talk-transcribe.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/talk/talk-transcribe.service.ts"],"names":[],"mappings":"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"}