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.