From 61985afc4bd0bbcaa88cc25fd0e8b04c10034569 Mon Sep 17 00:00:00 2001 From: Nick Szaunig Date: Fri, 16 Oct 2026 09:44:58 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20Fachwortliste=20f=C3=BCr=20Whisper=20au?= =?UTF-8?q?s=20einer=20Quelle=20(T7=20L2=20Task=2012)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit npm run export:voice-vocabulary schreibt ApiCore-Whisper/vocabulary.txt aus whisperInitialPrompt(); ein Wächter vergleicht Datei und Quelle im Monorepo (im Backend-Image-Build ohne Nachbarordner übersprungen). Datei mit LF über .gitattributes; scripts/ aus dem Nest-Build ausgeschlossen. Refs #27 Co-Authored-By: Claude Opus 5.5 (1M context) --- .gitattributes | 4 +++ ApiCore-Backend/package.json | 3 ++- .../scripts/export-voice-vocabulary.ts | 15 +++++++++++ .../core/voice-vocabulary-export.spec.ts | 26 +++++++++++++++++++ ApiCore-Backend/tsconfig.build.json | 2 +- ApiCore-Whisper/vocabulary.txt | 1 + 6 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 ApiCore-Backend/scripts/export-voice-vocabulary.ts create mode 100644 ApiCore-Backend/src/voice/core/voice-vocabulary-export.spec.ts create mode 100644 ApiCore-Whisper/vocabulary.txt diff --git a/.gitattributes b/.gitattributes index 6d14a19..917ca6f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,7 @@ # Shell scripts must keep LF line endings, also on Windows checkouts with # core.autocrlf, or bash fails on the carriage returns. *.sh text eol=lf + +# The Whisper word list is generated (npm run export:voice-vocabulary) and +# copied into the image; keep LF so the file stays byte-identical everywhere. +ApiCore-Whisper/vocabulary.txt text eol=lf diff --git a/ApiCore-Backend/package.json b/ApiCore-Backend/package.json index 3bbf95e..bccab2d 100644 --- a/ApiCore-Backend/package.json +++ b/ApiCore-Backend/package.json @@ -22,7 +22,8 @@ "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:e2e": "jest --config ./test/jest-e2e.json", "migrate:deploy": "prisma migrate deploy", - "seed": "node dist/seed.js" + "seed": "node dist/seed.js", + "export:voice-vocabulary": "ts-node scripts/export-voice-vocabulary.ts" }, "dependencies": { "@nestjs/common": "^11.0.1", diff --git a/ApiCore-Backend/scripts/export-voice-vocabulary.ts b/ApiCore-Backend/scripts/export-voice-vocabulary.ts new file mode 100644 index 0000000..abb3074 --- /dev/null +++ b/ApiCore-Backend/scripts/export-voice-vocabulary.ts @@ -0,0 +1,15 @@ +/** + * Writes the Whisper initial prompt to ApiCore-Whisper/vocabulary.txt, so the + * Python image uses the same word list as the backend (one source: + * src/voice/core/voice-vocabulary.ts). Run `npm run export:voice-vocabulary` + * after changing the list; voice-vocabulary-export.spec.ts fails until you do. + */ +import { mkdirSync, writeFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { whisperInitialPrompt } from '../src/voice/core/voice-vocabulary'; + +const target = join(__dirname, '..', '..', 'ApiCore-Whisper', 'vocabulary.txt'); + +mkdirSync(dirname(target), { recursive: true }); +writeFileSync(target, `${whisperInitialPrompt()}\n`, 'utf8'); +console.log(`Wrote ${target}`); diff --git a/ApiCore-Backend/src/voice/core/voice-vocabulary-export.spec.ts b/ApiCore-Backend/src/voice/core/voice-vocabulary-export.spec.ts new file mode 100644 index 0000000..fe0020d --- /dev/null +++ b/ApiCore-Backend/src/voice/core/voice-vocabulary-export.spec.ts @@ -0,0 +1,26 @@ +import { existsSync, readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { whisperInitialPrompt } from './voice-vocabulary'; + +const MONOREPO_ROOT = join(__dirname, '..', '..', '..', '..'); +const VOCABULARY_FILE = join( + MONOREPO_ROOT, + 'ApiCore-Whisper', + 'vocabulary.txt', +); + +// The backend image build only sees ApiCore-Backend, so the comparison runs in +// the monorepo checkout and is skipped inside that build. +const inMonorepo = existsSync(join(MONOREPO_ROOT, 'ApiCore-Frontend')); +const describeInMonorepo = inMonorepo ? describe : describe.skip; + +describeInMonorepo('whisper vocabulary export', () => { + it('the whisper vocabulary file equals whisperInitialPrompt()', () => { + // Windows checkouts may turn LF into CRLF; the content is what counts. + const onDisk = readFileSync(VOCABULARY_FILE, 'utf8') + .replace(/\r\n/g, '\n') + .replace(/\n$/, ''); + + expect(onDisk).toBe(whisperInitialPrompt()); + }); +}); diff --git a/ApiCore-Backend/tsconfig.build.json b/ApiCore-Backend/tsconfig.build.json index 6b878ed..47bc3c3 100644 --- a/ApiCore-Backend/tsconfig.build.json +++ b/ApiCore-Backend/tsconfig.build.json @@ -6,5 +6,5 @@ // outside it would make the next build skip "unchanged" files. "incremental": false }, - "exclude": ["node_modules", "test", "dist", "**/*spec.ts", "**/*.spec-helper.ts", "prisma.config.ts", "prisma/seed.ts"] + "exclude": ["node_modules", "test", "scripts", "dist", "**/*spec.ts", "**/*.spec-helper.ts", "prisma.config.ts", "prisma/seed.ts"] } diff --git a/ApiCore-Whisper/vocabulary.txt b/ApiCore-Whisper/vocabulary.txt new file mode 100644 index 0000000..38df70e --- /dev/null +++ b/ApiCore-Whisper/vocabulary.txt @@ -0,0 +1 @@ +Durchsicht am Bienenvolk: Königin, Stifte, Weiselzellen, Brutwaben, Futterkranz, Honigraum, Varroa, Schwarmstimmung, sanftmütig, Wabensitz, Drohnenbrut, Brutnest, Brutfläche, Spielnäpfchen, Schwarmzellen, Absperrgitter, Futterteig, Ableger, Jungvolk, Rähmchen, Mittelwand, Flugloch, Beute, Zarge, Ameisensäure, Oxalsäure, Windel, Faulbrut, Kalkbrut, Nosema, Wachsmotten, Pollen.