@redaksjon/protokoll-engine 0.1.10 → 0.1.11-dev.20260301221841.afe8256
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/index17.js.map +1 -1
- package/dist/index33.js +6 -2
- package/dist/index33.js.map +1 -1
- package/dist/index34.js +2 -2
- package/dist/index35.js +4 -4
- package/dist/index36.js +1 -1
- package/dist/index38.js.map +1 -1
- package/dist/index40.js.map +1 -1
- package/dist/index41.js.map +1 -1
- package/dist/index44.js.map +1 -1
- package/dist/index46.js.map +1 -1
- package/dist/index53.js +48 -5
- package/dist/index53.js.map +1 -1
- package/dist/index54.js +34 -46
- package/dist/index54.js.map +1 -1
- package/dist/index55.js +280 -35
- package/dist/index55.js.map +1 -1
- package/dist/index56.js +137 -258
- package/dist/index56.js.map +1 -1
- package/dist/index57.js +60 -142
- package/dist/index57.js.map +1 -1
- package/dist/index58.js +70 -73
- package/dist/index58.js.map +1 -1
- package/dist/index59.js +3 -73
- package/dist/index59.js.map +1 -1
- package/dist/index60.js +5 -148
- package/dist/index60.js.map +1 -1
- package/dist/index61.js +4 -4
- package/dist/index62.js +148 -5
- package/dist/index62.js.map +1 -1
- package/dist/pipeline/orchestrator.d.ts.map +1 -1
- package/dist/pipeline/types.d.ts +7 -0
- package/dist/pipeline/types.d.ts.map +1 -1
- package/dist/transcript/operations.d.ts +4 -2
- package/dist/transcript/operations.d.ts.map +1 -1
- package/dist/transcript/pkl-utils.d.ts +24 -1
- package/dist/transcript/pkl-utils.d.ts.map +1 -1
- package/dist/transcript/upload-utils.d.ts +17 -1
- package/dist/transcript/upload-utils.d.ts.map +1 -1
- package/dist/util/enhancement-logger.d.ts +22 -1
- package/dist/util/enhancement-logger.d.ts.map +1 -1
- package/dist/weighting/builder.d.ts.map +1 -1
- package/dist/weighting/prepositioning.d.ts +6 -1
- package/dist/weighting/prepositioning.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index40.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index40.js","sources":["../src/transcript/pkl-utils.ts"],"sourcesContent":["/**\n * PKL Transcript Utilities\n * \n * Simple utility functions for working with .pkl transcript files.\n * This replaces the dual-format format-adapter.ts with PKL-only operations.\n */\n\nimport * as path from 'node:path';\nimport * as fs from 'fs/promises';\nimport { PklTranscript, isUuidInput } from '@redaksjon/protokoll-format';\
|
|
1
|
+
{"version":3,"file":"index40.js","sources":["../src/transcript/pkl-utils.ts"],"sourcesContent":["/**\n * PKL Transcript Utilities\n * \n * Simple utility functions for working with .pkl transcript files.\n * This replaces the dual-format format-adapter.ts with PKL-only operations.\n */\n\nimport * as path from 'node:path';\nimport * as fs from 'fs/promises';\nimport { PklTranscript, isUuidInput } from '@redaksjon/protokoll-format';\n\ntype PklMetadata = {\n date?: Date;\n recordingTime?: string;\n project?: string;\n projectId?: string;\n routing?: {\n destination?: string;\n confidence?: number;\n };\n tags?: string[];\n duration?: string;\n status?: string;\n tasks?: unknown[];\n entities?: unknown;\n history?: unknown;\n title?: string;\n};\n\n/**\n * Check if a file is a .pkl transcript\n */\nexport function isPklFile(filePath: string): boolean {\n return path.extname(filePath).toLowerCase() === '.pkl';\n}\n\n/**\n * Get the glob pattern for finding transcript files (PKL only)\n */\nexport function getTranscriptGlobPattern(): string {\n return '**/*.pkl';\n}\n\n/**\n * Strip .pkl extension from a transcript path\n * Used for creating extension-agnostic identifiers\n */\nexport function stripTranscriptExtension(filePath: string): string {\n return filePath.replace(/\\.pkl$/i, '');\n}\n\n/**\n * Ensure a path has .pkl extension\n */\nexport function ensurePklExtension(filePath: string): string {\n if (isPklFile(filePath)) {\n return filePath;\n }\n // Remove any .md extension if present, add .pkl\n return filePath.replace(/\\.md$/i, '') + '.pkl';\n}\n\n/**\n * Check if a transcript file exists\n * \n * If the path has .pkl extension, checks that file.\n * If no extension, adds .pkl and checks.\n */\nexport async function transcriptExists(basePath: string): Promise<{ exists: boolean; path: string | null }> {\n const pklPath = ensurePklExtension(basePath);\n \n try {\n await fs.access(pklPath);\n return { exists: true, path: pklPath };\n } catch {\n return { exists: false, path: null };\n }\n}\n\n/**\n * Enhanced transcript existence check supporting UUID\n * \n * @param pathOrUuid - File path or UUID to check\n * @param searchDirectories - Optional directories to search if UUID is provided\n * @returns Existence info with path and UUID if found\n */\nexport async function transcriptExistsUuid(\n pathOrUuid: string,\n searchDirectories?: string[]\n): Promise<{ exists: boolean; path?: string; uuid?: string }> {\n if (isUuidInput(pathOrUuid)) {\n if (!searchDirectories || searchDirectories.length === 0) {\n return { exists: false };\n }\n // Import dynamically to avoid circular dependency\n const { findTranscriptByUuid } = await import('./operations');\n const foundPath = await findTranscriptByUuid(pathOrUuid, searchDirectories);\n if (foundPath) {\n // Extract UUID from found file\n const transcript = PklTranscript.open(foundPath, { readOnly: true });\n const uuid = transcript.metadata.id;\n transcript.close();\n return { exists: true, path: foundPath, uuid };\n }\n return { exists: false };\n }\n \n // Fallback to existing transcriptExists logic\n const result = await transcriptExists(ensurePklExtension(pathOrUuid));\n return { exists: result.exists, path: result.path ?? undefined };\n}\n\n/**\n * Resolve a transcript identifier to an actual file path\n * \n * @param identifier The transcript identifier (with or without extension)\n * @param baseDirectory Optional base directory to resolve relative paths\n * @returns The resolved file info\n */\nexport async function resolveTranscriptPath(\n identifier: string,\n baseDirectory?: string\n): Promise<{ exists: boolean; path: string | null }> {\n let basePath = identifier;\n if (baseDirectory && !path.isAbsolute(identifier)) {\n basePath = path.resolve(baseDirectory, identifier);\n }\n \n return transcriptExists(basePath);\n}\n\n/**\n * Read transcript content from a .pkl file\n * Returns the content and metadata\n */\nexport async function readTranscriptContent(filePath: string): Promise<{\n content: string;\n mimeType: string;\n metadata: Record<string, unknown>;\n title?: string;\n}> {\n const pklPath = ensurePklExtension(filePath);\n const transcript = PklTranscript.open(pklPath, { readOnly: true });\n \n try {\n const pklMetadata = transcript.metadata as PklMetadata;\n return {\n content: transcript.content,\n mimeType: 'text/plain',\n metadata: convertPklMetadataToLegacy(pklMetadata),\n title: pklMetadata.title,\n };\n } finally {\n transcript.close();\n }\n}\n\n/**\n * Convert PklTranscript metadata to a simpler format for legacy compatibility\n */\nexport function convertPklMetadataToLegacy(\n pklMetadata: PklMetadata\n): Record<string, unknown> {\n return {\n date: pklMetadata.date instanceof Date \n ? pklMetadata.date.toISOString().split('T')[0] \n : undefined,\n time: pklMetadata.recordingTime,\n project: pklMetadata.project,\n projectId: pklMetadata.projectId,\n destination: pklMetadata.routing?.destination,\n confidence: pklMetadata.routing?.confidence?.toString(),\n tags: pklMetadata.tags,\n duration: pklMetadata.duration,\n status: pklMetadata.status,\n tasks: pklMetadata.tasks,\n entities: pklMetadata.entities,\n history: pklMetadata.history,\n };\n}\n"],"names":[],"mappings":";;;;AAgCO,SAAS,UAAU,QAAA,EAA2B;AACjD,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,QAAQ,CAAA,CAAE,aAAY,KAAM,MAAA;AACpD;AAKO,SAAS,wBAAA,GAAmC;AAC/C,EAAA,OAAO,UAAA;AACX;AAMO,SAAS,yBAAyB,QAAA,EAA0B;AAC/D,EAAA,OAAO,QAAA,CAAS,OAAA,CAAQ,SAAA,EAAW,EAAE,CAAA;AACzC;AAKO,SAAS,mBAAmB,QAAA,EAA0B;AACzD,EAAA,IAAI,SAAA,CAAU,QAAQ,CAAA,EAAG;AACrB,IAAA,OAAO,QAAA;AAAA,EACX;AAEA,EAAA,OAAO,QAAA,CAAS,OAAA,CAAQ,QAAA,EAAU,EAAE,CAAA,GAAI,MAAA;AAC5C;AAQA,eAAsB,iBAAiB,QAAA,EAAqE;AACxG,EAAA,MAAM,OAAA,GAAU,mBAAmB,QAAQ,CAAA;AAE3C,EAAA,IAAI;AACA,IAAA,MAAM,EAAA,CAAG,OAAO,OAAO,CAAA;AACvB,IAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,OAAA,EAAQ;AAAA,EACzC,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,IAAA,EAAK;AAAA,EACvC;AACJ;AASA,eAAsB,oBAAA,CAClB,YACA,iBAAA,EAC0D;AAC1D,EAAA,IAAI,WAAA,CAAY,UAAU,CAAA,EAAG;AACzB,IAAA,IAAI,CAAC,iBAAA,IAAqB,iBAAA,CAAkB,MAAA,KAAW,CAAA,EAAG;AACtD,MAAA,OAAO,EAAE,QAAQ,KAAA,EAAM;AAAA,IAC3B;AAEA,IAAA,MAAM,EAAE,oBAAA,EAAqB,GAAI,MAAM,OAAO,cAAc,CAAA;AAC5D,IAAA,MAAM,SAAA,GAAY,MAAM,oBAAA,CAAqB,UAAA,EAAY,iBAAiB,CAAA;AAC1E,IAAA,IAAI,SAAA,EAAW;AAEX,MAAA,MAAM,aAAa,aAAA,CAAc,IAAA,CAAK,WAAW,EAAE,QAAA,EAAU,MAAM,CAAA;AACnE,MAAA,MAAM,IAAA,GAAO,WAAW,QAAA,CAAS,EAAA;AACjC,MAAA,UAAA,CAAW,KAAA,EAAM;AACjB,MAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,WAAW,IAAA,EAAK;AAAA,IACjD;AACA,IAAA,OAAO,EAAE,QAAQ,KAAA,EAAM;AAAA,EAC3B;AAGA,EAAA,MAAM,MAAA,GAAS,MAAM,gBAAA,CAAiB,kBAAA,CAAmB,UAAU,CAAC,CAAA;AACpE,EAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,CAAO,QAAQ,IAAA,EAAM,MAAA,CAAO,QAAQ,MAAA,EAAU;AACnE;AASA,eAAsB,qBAAA,CAClB,YACA,aAAA,EACiD;AACjD,EAAA,IAAI,QAAA,GAAW,UAAA;AACf,EAAA,IAAI,aAAA,IAAiB,CAAC,IAAA,CAAK,UAAA,CAAW,UAAU,CAAA,EAAG;AAC/C,IAAA,QAAA,GAAW,IAAA,CAAK,OAAA,CAAQ,aAAA,EAAe,UAAU,CAAA;AAAA,EACrD;AAEA,EAAA,OAAO,iBAAiB,QAAQ,CAAA;AACpC;AAMA,eAAsB,sBAAsB,QAAA,EAKzC;AACC,EAAA,MAAM,OAAA,GAAU,mBAAmB,QAAQ,CAAA;AAC3C,EAAA,MAAM,aAAa,aAAA,CAAc,IAAA,CAAK,SAAS,EAAE,QAAA,EAAU,MAAM,CAAA;AAEjE,EAAA,IAAI;AACA,IAAA,MAAM,cAAc,UAAA,CAAW,QAAA;AAC/B,IAAA,OAAO;AAAA,MACH,SAAS,UAAA,CAAW,OAAA;AAAA,MACpB,QAAA,EAAU,YAAA;AAAA,MACV,QAAA,EAAU,2BAA2B,WAAW,CAAA;AAAA,MAChD,OAAO,WAAA,CAAY;AAAA,KACvB;AAAA,EACJ,CAAA,SAAE;AACE,IAAA,UAAA,CAAW,KAAA,EAAM;AAAA,EACrB;AACJ;AAKO,SAAS,2BACZ,WAAA,EACuB;AACvB,EAAA,OAAO;AAAA,IACH,IAAA,EAAM,WAAA,CAAY,IAAA,YAAgB,IAAA,GAC5B,WAAA,CAAY,IAAA,CAAK,WAAA,EAAY,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,GAC3C,MAAA;AAAA,IACN,MAAM,WAAA,CAAY,aAAA;AAAA,IAClB,SAAS,WAAA,CAAY,OAAA;AAAA,IACrB,WAAW,WAAA,CAAY,SAAA;AAAA,IACvB,WAAA,EAAa,YAAY,OAAA,EAAS,WAAA;AAAA,IAClC,UAAA,EAAY,WAAA,CAAY,OAAA,EAAS,UAAA,EAAY,QAAA,EAAS;AAAA,IACtD,MAAM,WAAA,CAAY,IAAA;AAAA,IAClB,UAAU,WAAA,CAAY,QAAA;AAAA,IACtB,QAAQ,WAAA,CAAY,MAAA;AAAA,IACpB,OAAO,WAAA,CAAY,KAAA;AAAA,IACnB,UAAU,WAAA,CAAY,QAAA;AAAA,IACtB,SAAS,WAAA,CAAY;AAAA,GACzB;AACJ;;;;"}
|
package/dist/index41.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index41.js","sources":["../src/transcript/upload-utils.ts"],"sourcesContent":["/**\n * Upload workflow utilities for audio transcription\n * \n * Handles creation of transcript records for uploaded audio files\n * and queue scanning for files awaiting transcription.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { join } from 'node:path';\nimport { glob } from 'glob';\nimport { PklTranscript } from '@redaksjon/protokoll-format';\nimport type { TranscriptMetadata } from '@redaksjon/protokoll-format';\n\n/**\n * Parameters for creating an upload transcript\n */\nexport interface CreateUploadTranscriptParams {\n audioFile: string; // Path to uploaded audio file\n originalFilename: string; // Original uploaded filename\n audioHash: string; // File hash for deduplication\n outputDirectory: string; // Where to create PKL\n title?: string; // Optional title hint\n project?: string; // Optional project hint\n}\n\n/**\n * Generate a UUID-prefixed filename\n * Format: {8-char-uuid}-{basename}.pkl\n */\nexport function generateFilenameWithUuid(uuid: string, basename: string): string {\n // Take first 8 characters of UUID\n const prefix = uuid.substring(0, 8);\n // Remove .pkl extension from basename if present\n const base = basename.replace(/\\.pkl$/, '');\n return `${prefix}-${base}.pkl`;\n}\n\n/**\n * Format timestamp for filename\n */\nfunction formatTimestamp(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n const hour = String(date.getHours()).padStart(2, '0');\n const minute = String(date.getMinutes()).padStart(2, '0');\n const second = String(date.getSeconds()).padStart(2, '0');\n return `${year}${month}${day}-${hour}${minute}${second}`;\n}\n\n/**\n * Create a transcript record for an uploaded audio file\n * \n * Creates a PKL file with 'uploaded' status and UUID-prefixed filename.\n * This makes the transcript discoverable via findTranscriptByUuid().\n * \n * @param params - Upload transcript parameters\n * @returns UUID and file path of created transcript\n */\nexport async function createUploadTranscript(\n params: CreateUploadTranscriptParams\n): Promise<{ uuid: string; filePath: string }> {\n const uuid = randomUUID();\n const timestamp = formatTimestamp(new Date());\n \n // Use UUID-prefixed filename for uploads\n const filename = generateFilenameWithUuid(uuid, `${timestamp}-upload.pkl`);\n const filePath = join(params.outputDirectory, filename);\n \n const metadata: TranscriptMetadata = {\n id: uuid,\n status: 'uploaded',\n audioFile: params.audioFile, // Actual filename on disk (e.g. hash.ext) for worker to locate file\n audioHash: params.audioHash,\n date: new Date(),\n title: params.title,\n project: params.project,\n };\n \n const transcript = PklTranscript.create(filePath, metadata);\n await transcript.close();\n \n return { uuid, filePath };\n}\n\n/**\n * Result from scanning for uploaded transcripts\n */\nexport interface UploadedTranscript {\n uuid: string;\n filePath: string;\n metadata: TranscriptMetadata;\n}\n\n/**\n * Find all transcripts in 'uploaded' status ready for transcription\n * \n * Scans directories for PKL files with UUID prefixes and 'uploaded' status.\n * Results are sorted by date (oldest first) for FIFO processing.\n * \n * @param searchDirectories - Directories to scan for transcripts\n * @returns Array of uploaded transcripts sorted by date\n */\nexport async function findUploadedTranscripts(\n searchDirectories: string[]\n): Promise<UploadedTranscript[]> {\n const results: UploadedTranscript[] = [];\n \n for (const dir of searchDirectories) {\n // Find all PKL files with UUID prefixes (8 hex chars followed by dash)\n const files = await glob('????????-*.pkl', { cwd: dir, absolute: true });\n \n for (const file of files) {\n try {\n const transcript = PklTranscript.open(file, { readOnly: true });\n const metadata = transcript.metadata;\n \n if (metadata.status === 'uploaded') {\n results.push({ \n uuid: metadata.id, \n filePath: file, \n metadata \n });\n }\n \n await transcript.close();\n } catch (error) {\n // Skip files that can't be opened (corrupted, locked, etc.)\n // eslint-disable-next-line no-console\n console.warn(`Failed to open transcript ${file}:`, error);\n }\n }\n }\n \n // Sort by date (oldest first) for FIFO processing\n return results.sort((a, b) => {\n const aTime = a.metadata.date?.getTime() || 0;\n const bTime = b.metadata.date?.getTime() || 0;\n return aTime - bTime;\n });\n}\n\n/**\n * Find transcripts in 'transcribing' status (for recovery after crash)\n * \n * These transcripts were being processed when the server stopped.\n * They should be reset to 'uploaded' and re-queued.\n * \n * @param searchDirectories - Directories to scan for transcripts\n * @returns Array of transcribing transcripts\n */\nexport async function findTranscribingTranscripts(\n searchDirectories: string[]\n): Promise<UploadedTranscript[]> {\n const results: UploadedTranscript[] = [];\n \n for (const dir of searchDirectories) {\n const files = await glob('????????-*.pkl', { cwd: dir, absolute: true });\n \n for (const file of files) {\n try {\n const transcript = PklTranscript.open(file, { readOnly: true });\n const metadata = transcript.metadata;\n \n if (metadata.status === 'transcribing') {\n results.push({ \n uuid: metadata.id, \n filePath: file, \n metadata \n });\n }\n \n await transcript.close();\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn(`Failed to open transcript ${file}:`, error);\n }\n }\n }\n \n return results;\n}\n\n/**\n * Reset a transcript from 'transcribing' or 'error' to 'uploaded' for retry\n * \n * Used during queue recovery on server startup or manual retry.\n * \n * @param filePath - Path to transcript file\n */\nexport async function resetTranscriptToUploaded(filePath: string): Promise<void> {\n const transcript = PklTranscript.open(filePath);\n const metadata = transcript.metadata;\n \n if (metadata.status === 'transcribing' || metadata.status === 'error') {\n transcript.updateMetadata({ \n status: 'uploaded',\n errorDetails: undefined, // Clear error details on retry\n });\n await transcript.close();\n } else {\n await transcript.close();\n }\n}\n\n/**\n * Mark a transcript as transcribing (in progress)\n * \n * @param filePath - Path to transcript file\n */\nexport async function markTranscriptAsTranscribing(filePath: string): Promise<void> {\n const transcript = PklTranscript.open(filePath);\n transcript.updateMetadata({ status: 'transcribing' });\n await transcript.close();\n}\n\n/**\n * Mark a transcript as failed with error details\n * \n * @param filePath - Path to transcript file\n * @param errorDetails - Error message/details\n */\nexport async function markTranscriptAsFailed(\n filePath: string, \n errorDetails: string\n): Promise<void> {\n const transcript = PklTranscript.open(filePath);\n transcript.updateMetadata({ \n status: 'error',\n errorDetails \n });\n await transcript.close();\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index41.js","sources":["../src/transcript/upload-utils.ts"],"sourcesContent":["/**\n * Upload workflow utilities for audio transcription\n * \n * Handles creation of transcript records for uploaded audio files\n * and queue scanning for files awaiting transcription.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { join } from 'node:path';\nimport { glob } from 'glob';\nimport { PklTranscript } from '@redaksjon/protokoll-format';\n\ntype TranscriptMetadata = {\n id: string;\n status: 'uploaded' | 'transcribing' | 'error' | 'initial' | 'enhanced' | 'reviewed' | 'in_progress' | 'closed' | 'archived';\n audioFile?: string;\n audioHash?: string;\n date?: Date;\n title?: string;\n project?: string;\n errorDetails?: string;\n};\n\n/**\n * Parameters for creating an upload transcript\n */\nexport interface CreateUploadTranscriptParams {\n audioFile: string; // Path to uploaded audio file\n originalFilename: string; // Original uploaded filename\n audioHash: string; // File hash for deduplication\n outputDirectory: string; // Where to create PKL\n title?: string; // Optional title hint\n project?: string; // Optional project hint\n}\n\n/**\n * Generate a UUID-prefixed filename\n * Format: {8-char-uuid}-{basename}.pkl\n */\nexport function generateFilenameWithUuid(uuid: string, basename: string): string {\n // Take first 8 characters of UUID\n const prefix = uuid.substring(0, 8);\n // Remove .pkl extension from basename if present\n const base = basename.replace(/\\.pkl$/, '');\n return `${prefix}-${base}.pkl`;\n}\n\n/**\n * Format timestamp for filename\n */\nfunction formatTimestamp(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n const hour = String(date.getHours()).padStart(2, '0');\n const minute = String(date.getMinutes()).padStart(2, '0');\n const second = String(date.getSeconds()).padStart(2, '0');\n return `${year}${month}${day}-${hour}${minute}${second}`;\n}\n\n/**\n * Create a transcript record for an uploaded audio file\n * \n * Creates a PKL file with 'uploaded' status and UUID-prefixed filename.\n * This makes the transcript discoverable via findTranscriptByUuid().\n * \n * @param params - Upload transcript parameters\n * @returns UUID and file path of created transcript\n */\nexport async function createUploadTranscript(\n params: CreateUploadTranscriptParams\n): Promise<{ uuid: string; filePath: string }> {\n const uuid = randomUUID();\n const timestamp = formatTimestamp(new Date());\n \n // Use UUID-prefixed filename for uploads\n const filename = generateFilenameWithUuid(uuid, `${timestamp}-upload.pkl`);\n const filePath = join(params.outputDirectory, filename);\n \n const metadata: TranscriptMetadata = {\n id: uuid,\n status: 'uploaded',\n audioFile: params.audioFile, // Actual filename on disk (e.g. hash.ext) for worker to locate file\n audioHash: params.audioHash,\n date: new Date(),\n title: params.title,\n project: params.project,\n };\n \n const transcript = PklTranscript.create(filePath, metadata);\n await transcript.close();\n \n return { uuid, filePath };\n}\n\n/**\n * Result from scanning for uploaded transcripts\n */\nexport interface UploadedTranscript {\n uuid: string;\n filePath: string;\n metadata: TranscriptMetadata;\n}\n\n/**\n * Find all transcripts in 'uploaded' status ready for transcription\n * \n * Scans directories for PKL files with UUID prefixes and 'uploaded' status.\n * Results are sorted by date (oldest first) for FIFO processing.\n * \n * @param searchDirectories - Directories to scan for transcripts\n * @returns Array of uploaded transcripts sorted by date\n */\nexport async function findUploadedTranscripts(\n searchDirectories: string[]\n): Promise<UploadedTranscript[]> {\n const results: UploadedTranscript[] = [];\n \n for (const dir of searchDirectories) {\n // Find all PKL files with UUID prefixes (8 hex chars followed by dash)\n const files = await glob('????????-*.pkl', { cwd: dir, absolute: true });\n \n for (const file of files) {\n try {\n const transcript = PklTranscript.open(file, { readOnly: true });\n const metadata = transcript.metadata as TranscriptMetadata;\n \n if (metadata.status === 'uploaded') {\n results.push({ \n uuid: metadata.id, \n filePath: file, \n metadata \n });\n }\n \n await transcript.close();\n } catch (error) {\n // Skip files that can't be opened (corrupted, locked, etc.)\n // eslint-disable-next-line no-console\n console.warn(`Failed to open transcript ${file}:`, error);\n }\n }\n }\n \n // Sort by date (oldest first) for FIFO processing\n return results.sort((a, b) => {\n const aTime = a.metadata.date?.getTime() || 0;\n const bTime = b.metadata.date?.getTime() || 0;\n return aTime - bTime;\n });\n}\n\n/**\n * Find transcripts in 'transcribing' status (for recovery after crash)\n * \n * These transcripts were being processed when the server stopped.\n * They should be reset to 'uploaded' and re-queued.\n * \n * @param searchDirectories - Directories to scan for transcripts\n * @returns Array of transcribing transcripts\n */\nexport async function findTranscribingTranscripts(\n searchDirectories: string[]\n): Promise<UploadedTranscript[]> {\n const results: UploadedTranscript[] = [];\n \n for (const dir of searchDirectories) {\n const files = await glob('????????-*.pkl', { cwd: dir, absolute: true });\n \n for (const file of files) {\n try {\n const transcript = PklTranscript.open(file, { readOnly: true });\n const metadata = transcript.metadata as TranscriptMetadata;\n \n if (metadata.status === 'transcribing') {\n results.push({ \n uuid: metadata.id, \n filePath: file, \n metadata \n });\n }\n \n await transcript.close();\n } catch (error) {\n // eslint-disable-next-line no-console\n console.warn(`Failed to open transcript ${file}:`, error);\n }\n }\n }\n \n return results;\n}\n\n/**\n * Reset a transcript from 'transcribing' or 'error' to 'uploaded' for retry\n * \n * Used during queue recovery on server startup or manual retry.\n * \n * @param filePath - Path to transcript file\n */\nexport async function resetTranscriptToUploaded(filePath: string): Promise<void> {\n const transcript = PklTranscript.open(filePath);\n const metadata = transcript.metadata as TranscriptMetadata;\n \n if (metadata.status === 'transcribing' || metadata.status === 'error') {\n transcript.updateMetadata({ \n status: 'uploaded',\n errorDetails: undefined, // Clear error details on retry\n });\n await transcript.close();\n } else {\n await transcript.close();\n }\n}\n\n/**\n * Mark a transcript as transcribing (in progress)\n * \n * @param filePath - Path to transcript file\n */\nexport async function markTranscriptAsTranscribing(filePath: string): Promise<void> {\n const transcript = PklTranscript.open(filePath);\n transcript.updateMetadata({ status: 'transcribing' });\n await transcript.close();\n}\n\n/**\n * Mark a transcript as failed with error details\n * \n * @param filePath - Path to transcript file\n * @param errorDetails - Error message/details\n */\nexport async function markTranscriptAsFailed(\n filePath: string, \n errorDetails: string\n): Promise<void> {\n const transcript = PklTranscript.open(filePath);\n transcript.updateMetadata({ \n status: 'error',\n errorDetails \n });\n await transcript.close();\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index44.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index44.js","sources":["../src/weighting/builder.ts"],"sourcesContent":["/**\n * Weight Model Builder\n * \n * Constructs entity co-occurrence graphs from transcript data.\n * Supports both full builds (scan all transcripts) and incremental updates\n * (add/subtract individual transcript contributions).\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { \n WeightModel, \n WeightModelConfig, \n EntityCooccurrence, \n ProjectEntityFrequency, \n TranscriptEntitySnapshot \n} from './types';\nimport { \n listTranscripts, \n PklTranscript,\n type TranscriptEntities \n} from '@redaksjon/protokoll-format';\n\n/**\n * WeightModelBuilder\n * \n * Builds entity co-occurrence matrices from transcript data with UUID provenance tracking.\n */\nexport class WeightModelBuilder {\n constructor(private config: WeightModelConfig) {}\n\n /**\n * Build a complete weight model by scanning transcripts in a directory\n * \n * @param transcriptDirectory - Directory containing .pkl transcript files\n * @returns Complete weight model with co-occurrence data and provenance\n */\n async build(transcriptDirectory: string): Promise<WeightModel> {\n const result = await listTranscripts({\n directory: transcriptDirectory,\n limit: this.config.maxTranscripts,\n sortBy: 'date',\n sortOrder: 'desc'\n });\n\n const cooccurrence: EntityCooccurrence = {};\n const byProject: ProjectEntityFrequency = {};\n const transcriptSnapshots: TranscriptEntitySnapshot = {};\n let totalEntities = 0;\n\n for (const transcriptItem of result.transcripts) {\n // Open the transcript to get full metadata including UUID\n const transcript = PklTranscript.open(transcriptItem.filePath, { readOnly: true });\n const metadata = transcript.metadata;\n transcript.close();\n\n // Extract entity IDs from the transcript\n const entityIds = this.extractEntityIds(metadata.entities);\n if (entityIds.length === 0) continue;\n\n // Record UUID provenance snapshot\n transcriptSnapshots[metadata.id] = {\n entityIds,\n projectId: metadata.project || undefined,\n };\n\n // Build co-occurrence matrix\n this.addCooccurrences(entityIds, cooccurrence);\n \n // Track project-specific frequencies \n if (metadata.project) {\n this.addProjectFrequencies(metadata.project, entityIds, byProject);\n }\n \n totalEntities += entityIds.length;\n }\n\n const now = new Date().toISOString();\n return {\n cooccurrence: this.filterMinCounts(cooccurrence),\n byProject,\n transcriptSnapshots,\n metadata: {\n builtAt: now,\n lastUpdatedAt: now,\n transcriptCount: result.transcripts.length,\n entityCount: totalEntities,\n version: '1.0.0'\n }\n };\n }\n\n /**\n * Extract entity IDs from transcript entities\n * \n * @param entities - TranscriptEntities object with people, projects, terms, companies\n * @returns Array of entity IDs\n */\n private extractEntityIds(entities?: TranscriptEntities): string[] {\n if (!entities) return [];\n\n const ids: string[] = [];\n \n if (entities.people) {\n ids.push(...entities.people.map(e => e.id));\n }\n if (entities.projects) {\n ids.push(...entities.projects.map(e => e.id));\n }\n if (entities.terms) {\n ids.push(...entities.terms.map(e => e.id));\n }\n if (entities.companies) {\n ids.push(...entities.companies.map(e => e.id));\n }\n \n return ids;\n }\n\n /**\n * Add co-occurrence counts for a set of entity IDs.\n * Every pair of entities in the list gets +1.\n * \n * This is a public method so it can be used for incremental updates.\n * \n * @param entityIds - Array of entity IDs that co-occur\n * @param cooccurrence - Co-occurrence matrix to update (mutated in place)\n */\n addCooccurrences(entityIds: string[], cooccurrence: EntityCooccurrence): void {\n // For each pair of entities, increment their co-occurrence count\n for (let i = 0; i < entityIds.length; i++) {\n for (let j = i + 1; j < entityIds.length; j++) {\n const a = entityIds[i];\n const b = entityIds[j];\n \n // Initialize if needed\n if (!cooccurrence[a]) cooccurrence[a] = {};\n if (!cooccurrence[b]) cooccurrence[b] = {};\n \n // Increment bidirectionally\n cooccurrence[a][b] = (cooccurrence[a][b] || 0) + 1;\n cooccurrence[b][a] = (cooccurrence[b][a] || 0) + 1;\n }\n }\n }\n\n /**\n * Subtract co-occurrence counts for a set of entity IDs.\n * Used during incremental updates when removing a transcript's\n * old entity snapshot before adding the new one.\n * \n * This is a public method so it can be used for incremental updates.\n * \n * @param entityIds - Array of entity IDs to remove\n * @param cooccurrence - Co-occurrence matrix to update (mutated in place)\n */\n subtractCooccurrences(entityIds: string[], cooccurrence: EntityCooccurrence): void {\n // For each pair of entities, decrement their co-occurrence count\n for (let i = 0; i < entityIds.length; i++) {\n for (let j = i + 1; j < entityIds.length; j++) {\n const a = entityIds[i];\n const b = entityIds[j];\n \n // Decrement bidirectionally\n if (cooccurrence[a]?.[b]) {\n cooccurrence[a][b]--;\n if (cooccurrence[a][b] <= 0) {\n delete cooccurrence[a][b];\n }\n }\n if (cooccurrence[b]?.[a]) {\n cooccurrence[b][a]--;\n if (cooccurrence[b][a] <= 0) {\n delete cooccurrence[b][a];\n }\n }\n \n // Clean up empty entity entries\n if (cooccurrence[a] && Object.keys(cooccurrence[a]).length === 0) {\n delete cooccurrence[a];\n }\n if (cooccurrence[b] && Object.keys(cooccurrence[b]).length === 0) {\n delete cooccurrence[b];\n }\n }\n }\n }\n\n /**\n * Add project-specific entity frequencies\n * \n * @param projectId - Project identifier\n * @param entityIds - Entity IDs to add\n * @param byProject - Project frequency map to update (mutated in place)\n */\n addProjectFrequencies(\n projectId: string, \n entityIds: string[], \n byProject: ProjectEntityFrequency\n ): void {\n if (!byProject[projectId]) {\n byProject[projectId] = {};\n }\n \n for (const entityId of entityIds) {\n byProject[projectId][entityId] = (byProject[projectId][entityId] || 0) + 1;\n }\n }\n\n /**\n * Subtract project-specific entity frequencies\n * Used during incremental updates when removing a transcript's old snapshot\n * \n * @param projectId - Project identifier\n * @param entityIds - Entity IDs to remove\n * @param byProject - Project frequency map to update (mutated in place)\n */\n subtractProjectFrequencies(\n projectId: string, \n entityIds: string[], \n byProject: ProjectEntityFrequency\n ): void {\n if (!byProject[projectId]) return;\n \n for (const entityId of entityIds) {\n if (byProject[projectId][entityId]) {\n byProject[projectId][entityId]--;\n if (byProject[projectId][entityId] <= 0) {\n delete byProject[projectId][entityId];\n }\n }\n }\n \n // Clean up empty project entries\n if (Object.keys(byProject[projectId]).length === 0) {\n delete byProject[projectId];\n }\n }\n\n /**\n * Filter co-occurrence matrix to remove low-frequency pairs (noise reduction)\n * \n * @param cooccurrence - Raw co-occurrence matrix\n * @returns Filtered matrix with only counts >= minCooccurrenceCount\n */\n private filterMinCounts(cooccurrence: EntityCooccurrence): EntityCooccurrence {\n const filtered: EntityCooccurrence = {};\n \n for (const [entityId, cooccurring] of Object.entries(cooccurrence)) {\n const filteredCooccurring: { [key: string]: number } = {};\n \n for (const [cooccurringId, count] of Object.entries(cooccurring)) {\n if (count >= this.config.minCooccurrenceCount) {\n filteredCooccurring[cooccurringId] = count;\n }\n }\n \n if (Object.keys(filteredCooccurring).length > 0) {\n filtered[entityId] = filteredCooccurring;\n }\n }\n \n return filtered;\n }\n\n /**\n * Write weight model to JSON file\n * \n * Creates human-readable JSON output with proper formatting.\n * Ensures output directory exists before writing.\n * \n * @param model - Weight model to write\n * @param filePath - Destination file path\n */\n async writeToFile(model: WeightModel, filePath: string): Promise<void> {\n // Ensure output directory exists\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n \n // Write human-readable JSON with formatting\n const jsonContent = JSON.stringify(model, null, 2);\n await fs.writeFile(filePath, jsonContent, 'utf-8');\n }\n\n /**\n * Build weight model and write to configured output file\n * \n * Convenience method that combines build() and writeToFile().\n * \n * @param transcriptDirectory - Directory containing .pkl transcript files\n * @returns Built weight model\n */\n async buildAndWrite(transcriptDirectory: string): Promise<WeightModel> {\n const model = await this.build(transcriptDirectory);\n await this.writeToFile(model, this.config.outputFilePath);\n return model;\n }\n\n /**\n * Load weight model from JSON file\n * \n * Static method for loading previously built models.\n * Returns null if file doesn't exist or can't be parsed.\n * \n * @param filePath - Path to weight model JSON file\n * @returns Loaded weight model or null\n */\n static async loadFromFile(filePath: string): Promise<WeightModel | null> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(content) as WeightModel;\n } catch {\n // File doesn't exist or invalid JSON - return null\n return null;\n }\n }\n\n /**\n * Incrementally update the weight model when a single transcript's entities change\n * \n * Uses UUID provenance to identify what changed:\n * 1. Look up the old snapshot for this transcript\n * 2. Subtract old co-occurrences and project frequencies\n * 3. Add new co-occurrences and project frequencies\n * 4. Update the snapshot\n * \n * The model is mutated in place for efficiency.\n * \n * @param model - The current weight model (mutated in place)\n * @param transcriptUuid - The UUID of the transcript that changed\n * @param newEntityIds - The new set of entity IDs on this transcript\n * @param newProjectId - The project this transcript is routed to (may have changed)\n */\n updateTranscript(\n model: WeightModel,\n transcriptUuid: string,\n newEntityIds: string[],\n newProjectId?: string\n ): void {\n const oldSnapshot = model.transcriptSnapshots[transcriptUuid];\n\n // Subtract old co-occurrences and project frequencies\n if (oldSnapshot) {\n this.subtractCooccurrences(oldSnapshot.entityIds, model.cooccurrence);\n if (oldSnapshot.projectId) {\n this.subtractProjectFrequencies(oldSnapshot.projectId, oldSnapshot.entityIds, model.byProject);\n }\n }\n\n // Add new co-occurrences and project frequencies\n if (newEntityIds.length > 0) {\n this.addCooccurrences(newEntityIds, model.cooccurrence);\n if (newProjectId) {\n this.addProjectFrequencies(newProjectId, newEntityIds, model.byProject);\n }\n \n // Update snapshot\n model.transcriptSnapshots[transcriptUuid] = {\n entityIds: newEntityIds,\n projectId: newProjectId\n };\n } else {\n // Transcript has no entities -- remove its snapshot\n delete model.transcriptSnapshots[transcriptUuid];\n }\n\n // Update metadata\n model.metadata.lastUpdatedAt = new Date().toISOString();\n }\n\n /**\n * Remove a transcript from the model entirely\n * \n * Used when a transcript is deleted.\n * Convenience method that calls updateTranscript with empty entity list.\n * \n * @param model - The current weight model (mutated in place)\n * @param transcriptUuid - The UUID of the transcript to remove\n */\n removeTranscript(model: WeightModel, transcriptUuid: string): void {\n this.updateTranscript(model, transcriptUuid, [], undefined);\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index44.js","sources":["../src/weighting/builder.ts"],"sourcesContent":["/**\n * Weight Model Builder\n * \n * Constructs entity co-occurrence graphs from transcript data.\n * Supports both full builds (scan all transcripts) and incremental updates\n * (add/subtract individual transcript contributions).\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { \n WeightModel, \n WeightModelConfig, \n EntityCooccurrence, \n ProjectEntityFrequency, \n TranscriptEntitySnapshot \n} from './types';\nimport { \n listTranscripts, \n PklTranscript\n} from '@redaksjon/protokoll-format';\n\ntype TranscriptEntities = {\n people?: Array<{ id: string }>;\n projects?: Array<{ id: string }>;\n terms?: Array<{ id: string }>;\n companies?: Array<{ id: string }>;\n};\n\n/**\n * WeightModelBuilder\n * \n * Builds entity co-occurrence matrices from transcript data with UUID provenance tracking.\n */\nexport class WeightModelBuilder {\n constructor(private config: WeightModelConfig) {}\n\n /**\n * Build a complete weight model by scanning transcripts in a directory\n * \n * @param transcriptDirectory - Directory containing .pkl transcript files\n * @returns Complete weight model with co-occurrence data and provenance\n */\n async build(transcriptDirectory: string): Promise<WeightModel> {\n const result = await listTranscripts({\n directory: transcriptDirectory,\n limit: this.config.maxTranscripts,\n sortBy: 'date',\n sortOrder: 'desc'\n });\n\n const cooccurrence: EntityCooccurrence = {};\n const byProject: ProjectEntityFrequency = {};\n const transcriptSnapshots: TranscriptEntitySnapshot = {};\n let totalEntities = 0;\n\n for (const transcriptItem of result.transcripts) {\n // Open the transcript to get full metadata including UUID\n const transcript = PklTranscript.open(transcriptItem.filePath, { readOnly: true });\n const metadata = transcript.metadata as {\n id: string;\n project?: string;\n entities?: TranscriptEntities;\n };\n transcript.close();\n\n // Extract entity IDs from the transcript\n const entityIds = this.extractEntityIds(metadata.entities);\n if (entityIds.length === 0) continue;\n\n // Record UUID provenance snapshot\n transcriptSnapshots[metadata.id] = {\n entityIds,\n projectId: metadata.project || undefined,\n };\n\n // Build co-occurrence matrix\n this.addCooccurrences(entityIds, cooccurrence);\n \n // Track project-specific frequencies \n if (metadata.project) {\n this.addProjectFrequencies(metadata.project, entityIds, byProject);\n }\n \n totalEntities += entityIds.length;\n }\n\n const now = new Date().toISOString();\n return {\n cooccurrence: this.filterMinCounts(cooccurrence),\n byProject,\n transcriptSnapshots,\n metadata: {\n builtAt: now,\n lastUpdatedAt: now,\n transcriptCount: result.transcripts.length,\n entityCount: totalEntities,\n version: '1.0.0'\n }\n };\n }\n\n /**\n * Extract entity IDs from transcript entities\n * \n * @param entities - TranscriptEntities object with people, projects, terms, companies\n * @returns Array of entity IDs\n */\n private extractEntityIds(entities?: TranscriptEntities): string[] {\n if (!entities) return [];\n\n const ids: string[] = [];\n \n if (entities.people) {\n ids.push(...entities.people.map(e => e.id));\n }\n if (entities.projects) {\n ids.push(...entities.projects.map(e => e.id));\n }\n if (entities.terms) {\n ids.push(...entities.terms.map(e => e.id));\n }\n if (entities.companies) {\n ids.push(...entities.companies.map(e => e.id));\n }\n \n return ids;\n }\n\n /**\n * Add co-occurrence counts for a set of entity IDs.\n * Every pair of entities in the list gets +1.\n * \n * This is a public method so it can be used for incremental updates.\n * \n * @param entityIds - Array of entity IDs that co-occur\n * @param cooccurrence - Co-occurrence matrix to update (mutated in place)\n */\n addCooccurrences(entityIds: string[], cooccurrence: EntityCooccurrence): void {\n // For each pair of entities, increment their co-occurrence count\n for (let i = 0; i < entityIds.length; i++) {\n for (let j = i + 1; j < entityIds.length; j++) {\n const a = entityIds[i];\n const b = entityIds[j];\n \n // Initialize if needed\n if (!cooccurrence[a]) cooccurrence[a] = {};\n if (!cooccurrence[b]) cooccurrence[b] = {};\n \n // Increment bidirectionally\n cooccurrence[a][b] = (cooccurrence[a][b] || 0) + 1;\n cooccurrence[b][a] = (cooccurrence[b][a] || 0) + 1;\n }\n }\n }\n\n /**\n * Subtract co-occurrence counts for a set of entity IDs.\n * Used during incremental updates when removing a transcript's\n * old entity snapshot before adding the new one.\n * \n * This is a public method so it can be used for incremental updates.\n * \n * @param entityIds - Array of entity IDs to remove\n * @param cooccurrence - Co-occurrence matrix to update (mutated in place)\n */\n subtractCooccurrences(entityIds: string[], cooccurrence: EntityCooccurrence): void {\n // For each pair of entities, decrement their co-occurrence count\n for (let i = 0; i < entityIds.length; i++) {\n for (let j = i + 1; j < entityIds.length; j++) {\n const a = entityIds[i];\n const b = entityIds[j];\n \n // Decrement bidirectionally\n if (cooccurrence[a]?.[b]) {\n cooccurrence[a][b]--;\n if (cooccurrence[a][b] <= 0) {\n delete cooccurrence[a][b];\n }\n }\n if (cooccurrence[b]?.[a]) {\n cooccurrence[b][a]--;\n if (cooccurrence[b][a] <= 0) {\n delete cooccurrence[b][a];\n }\n }\n \n // Clean up empty entity entries\n if (cooccurrence[a] && Object.keys(cooccurrence[a]).length === 0) {\n delete cooccurrence[a];\n }\n if (cooccurrence[b] && Object.keys(cooccurrence[b]).length === 0) {\n delete cooccurrence[b];\n }\n }\n }\n }\n\n /**\n * Add project-specific entity frequencies\n * \n * @param projectId - Project identifier\n * @param entityIds - Entity IDs to add\n * @param byProject - Project frequency map to update (mutated in place)\n */\n addProjectFrequencies(\n projectId: string, \n entityIds: string[], \n byProject: ProjectEntityFrequency\n ): void {\n if (!byProject[projectId]) {\n byProject[projectId] = {};\n }\n \n for (const entityId of entityIds) {\n byProject[projectId][entityId] = (byProject[projectId][entityId] || 0) + 1;\n }\n }\n\n /**\n * Subtract project-specific entity frequencies\n * Used during incremental updates when removing a transcript's old snapshot\n * \n * @param projectId - Project identifier\n * @param entityIds - Entity IDs to remove\n * @param byProject - Project frequency map to update (mutated in place)\n */\n subtractProjectFrequencies(\n projectId: string, \n entityIds: string[], \n byProject: ProjectEntityFrequency\n ): void {\n if (!byProject[projectId]) return;\n \n for (const entityId of entityIds) {\n if (byProject[projectId][entityId]) {\n byProject[projectId][entityId]--;\n if (byProject[projectId][entityId] <= 0) {\n delete byProject[projectId][entityId];\n }\n }\n }\n \n // Clean up empty project entries\n if (Object.keys(byProject[projectId]).length === 0) {\n delete byProject[projectId];\n }\n }\n\n /**\n * Filter co-occurrence matrix to remove low-frequency pairs (noise reduction)\n * \n * @param cooccurrence - Raw co-occurrence matrix\n * @returns Filtered matrix with only counts >= minCooccurrenceCount\n */\n private filterMinCounts(cooccurrence: EntityCooccurrence): EntityCooccurrence {\n const filtered: EntityCooccurrence = {};\n \n for (const [entityId, cooccurring] of Object.entries(cooccurrence)) {\n const filteredCooccurring: { [key: string]: number } = {};\n \n for (const [cooccurringId, count] of Object.entries(cooccurring)) {\n if (count >= this.config.minCooccurrenceCount) {\n filteredCooccurring[cooccurringId] = count;\n }\n }\n \n if (Object.keys(filteredCooccurring).length > 0) {\n filtered[entityId] = filteredCooccurring;\n }\n }\n \n return filtered;\n }\n\n /**\n * Write weight model to JSON file\n * \n * Creates human-readable JSON output with proper formatting.\n * Ensures output directory exists before writing.\n * \n * @param model - Weight model to write\n * @param filePath - Destination file path\n */\n async writeToFile(model: WeightModel, filePath: string): Promise<void> {\n // Ensure output directory exists\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n \n // Write human-readable JSON with formatting\n const jsonContent = JSON.stringify(model, null, 2);\n await fs.writeFile(filePath, jsonContent, 'utf-8');\n }\n\n /**\n * Build weight model and write to configured output file\n * \n * Convenience method that combines build() and writeToFile().\n * \n * @param transcriptDirectory - Directory containing .pkl transcript files\n * @returns Built weight model\n */\n async buildAndWrite(transcriptDirectory: string): Promise<WeightModel> {\n const model = await this.build(transcriptDirectory);\n await this.writeToFile(model, this.config.outputFilePath);\n return model;\n }\n\n /**\n * Load weight model from JSON file\n * \n * Static method for loading previously built models.\n * Returns null if file doesn't exist or can't be parsed.\n * \n * @param filePath - Path to weight model JSON file\n * @returns Loaded weight model or null\n */\n static async loadFromFile(filePath: string): Promise<WeightModel | null> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(content) as WeightModel;\n } catch {\n // File doesn't exist or invalid JSON - return null\n return null;\n }\n }\n\n /**\n * Incrementally update the weight model when a single transcript's entities change\n * \n * Uses UUID provenance to identify what changed:\n * 1. Look up the old snapshot for this transcript\n * 2. Subtract old co-occurrences and project frequencies\n * 3. Add new co-occurrences and project frequencies\n * 4. Update the snapshot\n * \n * The model is mutated in place for efficiency.\n * \n * @param model - The current weight model (mutated in place)\n * @param transcriptUuid - The UUID of the transcript that changed\n * @param newEntityIds - The new set of entity IDs on this transcript\n * @param newProjectId - The project this transcript is routed to (may have changed)\n */\n updateTranscript(\n model: WeightModel,\n transcriptUuid: string,\n newEntityIds: string[],\n newProjectId?: string\n ): void {\n const oldSnapshot = model.transcriptSnapshots[transcriptUuid];\n\n // Subtract old co-occurrences and project frequencies\n if (oldSnapshot) {\n this.subtractCooccurrences(oldSnapshot.entityIds, model.cooccurrence);\n if (oldSnapshot.projectId) {\n this.subtractProjectFrequencies(oldSnapshot.projectId, oldSnapshot.entityIds, model.byProject);\n }\n }\n\n // Add new co-occurrences and project frequencies\n if (newEntityIds.length > 0) {\n this.addCooccurrences(newEntityIds, model.cooccurrence);\n if (newProjectId) {\n this.addProjectFrequencies(newProjectId, newEntityIds, model.byProject);\n }\n \n // Update snapshot\n model.transcriptSnapshots[transcriptUuid] = {\n entityIds: newEntityIds,\n projectId: newProjectId\n };\n } else {\n // Transcript has no entities -- remove its snapshot\n delete model.transcriptSnapshots[transcriptUuid];\n }\n\n // Update metadata\n model.metadata.lastUpdatedAt = new Date().toISOString();\n }\n\n /**\n * Remove a transcript from the model entirely\n * \n * Used when a transcript is deleted.\n * Convenience method that calls updateTranscript with empty entity list.\n * \n * @param model - The current weight model (mutated in place)\n * @param transcriptUuid - The UUID of the transcript to remove\n */\n removeTranscript(model: WeightModel, transcriptUuid: string): void {\n this.updateTranscript(model, transcriptUuid, [], undefined);\n }\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index46.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index46.js","sources":["../src/weighting/prepositioning.ts"],"sourcesContent":["/**\n * Entity Prepositioning\n * \n * Generates LLM guidance from weight model predictions to improve entity recognition.\n * Converts entity predictions into structured guidance that can be injected into\n * the LLM system prompt during agentic enhancement.\n */\n\nimport { WeightModelProvider } from './provider';\nimport { EntityPrediction, PredictionContext } from './types';\nimport type { EntityReference } from '@redaksjon/protokoll-format';\nimport * as Context from '@redaksjon/context';\n\n/**\n * Entity prepositioning guidance for LLM enhancement\n */\nexport interface EntityPrepositioningGuidance {\n /** List of likely entities with metadata */\n likelyEntities: Array<{\n id: string;\n name: string;\n type: 'person' | 'project' | 'term' | 'company';\n confidence: string;\n }>;\n \n /** Formatted guidance text for LLM system prompt */\n guidance: string;\n}\n\n/**\n * EntityPrepositioner\n * \n * Generates entity guidance for LLM enhancement based on weight model predictions.\n * Resolves entity IDs to full entity details using the context system.\n */\nexport class EntityPrepositioner {\n constructor(\n private weightModelProvider: WeightModelProvider,\n private contextInstance: Context.ContextInstance\n ) {}\n\n /**\n * Generate entity prepositioning guidance\n * \n * @param projectId - Optional project ID for project-specific predictions\n * @param knownEntities - Entities already identified in the transcript\n * @returns Entity guidance for LLM prompt\n */\n generateGuidance(\n projectId?: string,\n knownEntities: EntityReference[] = []\n ): EntityPrepositioningGuidance {\n // Graceful fallback when no model is available\n if (!this.weightModelProvider.isAvailable()) {\n return { likelyEntities: [], guidance: '' };\n }\n\n // Get predictions from weight model\n const knownEntityIds = knownEntities.map(e => e.id);\n const context: PredictionContext = {\n knownEntityIds,\n projectId,\n maxPredictions: 8, // Limit to avoid overwhelming the LLM\n minScore: 2 // Filter out very low-confidence predictions\n };\n \n const predictions = this.weightModelProvider.predictLikelyEntities(context);\n\n // Resolve predictions to full entity details\n const likelyEntities = predictions\n .map((pred: EntityPrediction) => this.resolvePredictionToEntity(pred))\n .filter((entity: ReturnType<typeof this.resolvePredictionToEntity>): entity is NonNullable<typeof entity> => entity !== null);\n\n // Return empty guidance if no predictions\n if (likelyEntities.length === 0) {\n return { likelyEntities: [], guidance: '' };\n }\n\n return {\n likelyEntities,\n guidance: this.formatGuidancePrompt(likelyEntities, projectId)\n };\n }\n\n /**\n * Format entity predictions into LLM guidance text\n * \n * @param entities - Resolved entity predictions\n * @param projectId - Optional project ID\n * @returns Formatted guidance text\n */\n private formatGuidancePrompt(\n entities: EntityPrepositioningGuidance['likelyEntities'],\n projectId?: string\n ): string {\n // Group entities by type\n const byType = entities.reduce((acc, entity) => {\n if (!acc[entity.type]) {\n acc[entity.type] = [];\n }\n acc[entity.type].push(`${entity.name} (${entity.id})`);\n return acc;\n }, {} as Record<string, string[]>);\n\n // Build guidance sections\n const sections: string[] = [];\n \n if (projectId) {\n sections.push(`This transcript is likely related to project: ${projectId}`);\n }\n \n sections.push('Based on patterns in similar transcripts, these entities are likely to appear:');\n \n if (byType.person) {\n sections.push(`- People: ${byType.person.join(', ')}`);\n }\n if (byType.project) {\n sections.push(`- Projects: ${byType.project.join(', ')}`);\n }\n if (byType.term) {\n sections.push(`- Terms: ${byType.term.join(', ')}`);\n }\n if (byType.company) {\n sections.push(`- Companies: ${byType.company.join(', ')}`);\n }\n \n return sections.join('\\n');\n }\n\n /**\n * Resolve entity prediction to full entity details\n * \n * Looks up the entity in the context system to get display name and type.\n * Returns null if entity is not found in context.\n * \n * @param pred - Entity prediction from weight model\n * @returns Resolved entity or null\n */\n private resolvePredictionToEntity(\n pred: EntityPrediction\n ): EntityPrepositioningGuidance['likelyEntities'][0] | null {\n // Try each entity type getter\n const person = this.contextInstance.getPerson(pred.entityId);\n if (person) {\n const confidence = pred.score > 10 ? 'high' : pred.score > 5 ? 'medium' : 'low';\n return {\n id: pred.entityId,\n name: person.name,\n type: 'person',\n confidence\n };\n }\n \n const project = this.contextInstance.getProject(pred.entityId);\n if (project) {\n const confidence = pred.score > 10 ? 'high' : pred.score > 5 ? 'medium' : 'low';\n return {\n id: pred.entityId,\n name: project.name,\n type: 'project',\n confidence\n };\n }\n \n const term = this.contextInstance.getTerm(pred.entityId);\n if (term) {\n const confidence = pred.score > 10 ? 'high' : pred.score > 5 ? 'medium' : 'low';\n return {\n id: pred.entityId,\n name: term.name,\n type: 'term',\n confidence\n };\n }\n \n const company = this.contextInstance.getCompany(pred.entityId);\n if (company) {\n const confidence = pred.score > 10 ? 'high' : pred.score > 5 ? 'medium' : 'low';\n return {\n id: pred.entityId,\n name: company.name,\n type: 'company',\n confidence\n };\n }\n \n // Entity not found in context\n return null;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index46.js","sources":["../src/weighting/prepositioning.ts"],"sourcesContent":["/**\n * Entity Prepositioning\n * \n * Generates LLM guidance from weight model predictions to improve entity recognition.\n * Converts entity predictions into structured guidance that can be injected into\n * the LLM system prompt during agentic enhancement.\n */\n\nimport { WeightModelProvider } from './provider';\nimport { EntityPrediction, PredictionContext } from './types';\nimport * as Context from '@redaksjon/context';\n\ntype EntityReference = { id: string; name?: string; type?: string };\n\n/**\n * Entity prepositioning guidance for LLM enhancement\n */\nexport interface EntityPrepositioningGuidance {\n /** List of likely entities with metadata */\n likelyEntities: Array<{\n id: string;\n name: string;\n type: 'person' | 'project' | 'term' | 'company';\n confidence: string;\n }>;\n \n /** Formatted guidance text for LLM system prompt */\n guidance: string;\n}\n\n/**\n * EntityPrepositioner\n * \n * Generates entity guidance for LLM enhancement based on weight model predictions.\n * Resolves entity IDs to full entity details using the context system.\n */\nexport class EntityPrepositioner {\n constructor(\n private weightModelProvider: WeightModelProvider,\n private contextInstance: Context.ContextInstance\n ) {}\n\n /**\n * Generate entity prepositioning guidance\n * \n * @param projectId - Optional project ID for project-specific predictions\n * @param knownEntities - Entities already identified in the transcript\n * @returns Entity guidance for LLM prompt\n */\n generateGuidance(\n projectId?: string,\n knownEntities: EntityReference[] = []\n ): EntityPrepositioningGuidance {\n // Graceful fallback when no model is available\n if (!this.weightModelProvider.isAvailable()) {\n return { likelyEntities: [], guidance: '' };\n }\n\n // Get predictions from weight model\n const knownEntityIds = knownEntities.map(e => e.id);\n const context: PredictionContext = {\n knownEntityIds,\n projectId,\n maxPredictions: 8, // Limit to avoid overwhelming the LLM\n minScore: 2 // Filter out very low-confidence predictions\n };\n \n const predictions = this.weightModelProvider.predictLikelyEntities(context);\n\n // Resolve predictions to full entity details\n const likelyEntities = predictions\n .map((pred: EntityPrediction) => this.resolvePredictionToEntity(pred))\n .filter((entity: ReturnType<typeof this.resolvePredictionToEntity>): entity is NonNullable<typeof entity> => entity !== null);\n\n // Return empty guidance if no predictions\n if (likelyEntities.length === 0) {\n return { likelyEntities: [], guidance: '' };\n }\n\n return {\n likelyEntities,\n guidance: this.formatGuidancePrompt(likelyEntities, projectId)\n };\n }\n\n /**\n * Format entity predictions into LLM guidance text\n * \n * @param entities - Resolved entity predictions\n * @param projectId - Optional project ID\n * @returns Formatted guidance text\n */\n private formatGuidancePrompt(\n entities: EntityPrepositioningGuidance['likelyEntities'],\n projectId?: string\n ): string {\n // Group entities by type\n const byType = entities.reduce((acc, entity) => {\n if (!acc[entity.type]) {\n acc[entity.type] = [];\n }\n acc[entity.type].push(`${entity.name} (${entity.id})`);\n return acc;\n }, {} as Record<string, string[]>);\n\n // Build guidance sections\n const sections: string[] = [];\n \n if (projectId) {\n sections.push(`This transcript is likely related to project: ${projectId}`);\n }\n \n sections.push('Based on patterns in similar transcripts, these entities are likely to appear:');\n \n if (byType.person) {\n sections.push(`- People: ${byType.person.join(', ')}`);\n }\n if (byType.project) {\n sections.push(`- Projects: ${byType.project.join(', ')}`);\n }\n if (byType.term) {\n sections.push(`- Terms: ${byType.term.join(', ')}`);\n }\n if (byType.company) {\n sections.push(`- Companies: ${byType.company.join(', ')}`);\n }\n \n return sections.join('\\n');\n }\n\n /**\n * Resolve entity prediction to full entity details\n * \n * Looks up the entity in the context system to get display name and type.\n * Returns null if entity is not found in context.\n * \n * @param pred - Entity prediction from weight model\n * @returns Resolved entity or null\n */\n private resolvePredictionToEntity(\n pred: EntityPrediction\n ): EntityPrepositioningGuidance['likelyEntities'][0] | null {\n // Try each entity type getter\n const person = this.contextInstance.getPerson(pred.entityId);\n if (person) {\n const confidence = pred.score > 10 ? 'high' : pred.score > 5 ? 'medium' : 'low';\n return {\n id: pred.entityId,\n name: person.name,\n type: 'person',\n confidence\n };\n }\n \n const project = this.contextInstance.getProject(pred.entityId);\n if (project) {\n const confidence = pred.score > 10 ? 'high' : pred.score > 5 ? 'medium' : 'low';\n return {\n id: pred.entityId,\n name: project.name,\n type: 'project',\n confidence\n };\n }\n \n const term = this.contextInstance.getTerm(pred.entityId);\n if (term) {\n const confidence = pred.score > 10 ? 'high' : pred.score > 5 ? 'medium' : 'low';\n return {\n id: pred.entityId,\n name: term.name,\n type: 'term',\n confidence\n };\n }\n \n const company = this.contextInstance.getCompany(pred.entityId);\n if (company) {\n const confidence = pred.score > 10 ? 'high' : pred.score > 5 ? 'medium' : 'low';\n return {\n id: pred.entityId,\n name: company.name,\n type: 'company',\n confidence\n };\n }\n \n // Entity not found in context\n return null;\n }\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index53.js
CHANGED
|
@@ -1,8 +1,51 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OpenAI } from 'openai';
|
|
2
|
+
import { create } from './index13.js';
|
|
3
|
+
import { getLogger } from './index47.js';
|
|
4
|
+
import { DEFAULT_TRANSCRIPTION_MODEL } from './index18.js';
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
class OpenAIError extends Error {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "OpenAIError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
async function transcribeAudio(filePath, options = {}) {
|
|
13
|
+
const logger = getLogger();
|
|
14
|
+
const storage$1 = create({ log: logger.debug });
|
|
15
|
+
try {
|
|
16
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
17
|
+
if (!apiKey) {
|
|
18
|
+
throw new OpenAIError("OPENAI_API_KEY environment variable is not set");
|
|
19
|
+
}
|
|
20
|
+
const openai = new OpenAI({
|
|
21
|
+
apiKey
|
|
22
|
+
});
|
|
23
|
+
const model = options.model || DEFAULT_TRANSCRIPTION_MODEL;
|
|
24
|
+
const fileName = filePath.split("/").pop() || filePath;
|
|
25
|
+
logger.debug("Transcribing: %s (full path: %s)", fileName, filePath);
|
|
26
|
+
const startTime = Date.now();
|
|
27
|
+
const audioStream = await storage$1.readStream(filePath);
|
|
28
|
+
const transcription = await openai.audio.transcriptions.create({
|
|
29
|
+
model,
|
|
30
|
+
file: audioStream,
|
|
31
|
+
response_format: "json"
|
|
32
|
+
});
|
|
33
|
+
if (!transcription) {
|
|
34
|
+
throw new OpenAIError("No transcription received from OpenAI");
|
|
35
|
+
}
|
|
36
|
+
const duration = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
37
|
+
logger.info("%s (%ss, %d chars)", model, duration, transcription.text?.length || 0);
|
|
38
|
+
if (options.debug && options.debugFile) {
|
|
39
|
+
await storage$1.writeFile(options.debugFile, JSON.stringify(transcription, null, 2), "utf8");
|
|
40
|
+
logger.debug("Wrote debug file to %s", options.debugFile);
|
|
41
|
+
}
|
|
42
|
+
logger.debug("Received transcription from OpenAI: %s", transcription);
|
|
43
|
+
return transcription;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
logger.error("Error transcribing audio file: %s %s", error.message, error.stack);
|
|
46
|
+
throw new OpenAIError(`Failed to transcribe audio: ${error.message}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
6
49
|
|
|
7
|
-
export {
|
|
50
|
+
export { OpenAIError, transcribeAudio };
|
|
8
51
|
//# sourceMappingURL=index53.js.map
|
package/dist/index53.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index53.js","sources":["../src/
|
|
1
|
+
{"version":3,"file":"index53.js","sources":["../src/util/openai.ts"],"sourcesContent":["import { OpenAI } from 'openai';\nimport { ChatCompletionCreateParamsNonStreaming, ChatCompletionMessageParam } from 'openai/resources/chat/completions';\nimport * as Storage from '@/util/storage';\nimport { getLogger } from '@/logging';\nimport { DEFAULT_MODEL, DEFAULT_TRANSCRIPTION_MODEL } from '@/constants';\n\nexport interface Transcription {\n text: string;\n}\n\nexport class OpenAIError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'OpenAIError';\n }\n}\n\n\nexport async function createCompletion(messages: ChatCompletionMessageParam[], options: { responseFormat?: any, model?: string, reasoningLevel?: 'none' | 'low' | 'medium' | 'high', maxTokens?: number, debug?: boolean, debugFile?: string, reason?: string } = {}): Promise<string | any> {\n const logger = getLogger();\n const storage = Storage.create({ log: logger.debug });\n try {\n const apiKey = process.env.OPENAI_API_KEY;\n if (!apiKey) {\n throw new OpenAIError('OPENAI_API_KEY environment variable is not set');\n }\n\n const openai = new OpenAI({\n apiKey: apiKey,\n });\n\n const model = options.model || DEFAULT_MODEL;\n \n // Check if model supports reasoning_effort\n const supportsReasoning = model.includes('gpt-5') || \n model.includes('o1') || model.includes('o3');\n const isReasoningCall = supportsReasoning && options.reasoningLevel && options.reasoningLevel !== 'none';\n \n logger.debug('Sending prompt to OpenAI: %j', messages);\n\n const startTime = Date.now();\n \n const requestParams: Record<string, unknown> = {\n model,\n messages,\n max_completion_tokens: options.maxTokens || 10000,\n response_format: options.responseFormat,\n };\n \n if (isReasoningCall) {\n requestParams.reasoning_effort = options.reasoningLevel;\n logger.debug('Using reasoning_effort: %s', options.reasoningLevel);\n }\n \n const completion = await openai.chat.completions.create(\n requestParams as unknown as ChatCompletionCreateParamsNonStreaming\n );\n const duration = ((Date.now() - startTime) / 1000).toFixed(1);\n\n // Log token usage with reason if provided\n const usage = completion.usage;\n const reasonSuffix = options.reason ? ` - ${options.reason}` : '';\n if (usage) {\n logger.info('%s (%ss, %d→%d tokens)%s', \n model, duration, usage.prompt_tokens, usage.completion_tokens, reasonSuffix);\n } else {\n logger.info('%s (%ss)%s', model, duration, reasonSuffix);\n }\n\n if (options.debug && options.debugFile) {\n await storage.writeFile(options.debugFile, JSON.stringify(completion, null, 2), 'utf8');\n logger.debug('Wrote debug file to %s', options.debugFile);\n }\n\n const response = completion.choices[0]?.message?.content?.trim();\n if (!response) {\n // Log the full completion object to help debug\n logger.error('Empty response from OpenAI. Full completion object: %j', completion);\n throw new OpenAIError('No response received from OpenAI');\n }\n\n logger.debug('Received response from OpenAI: %s', response);\n if (options.responseFormat) {\n return JSON.parse(response);\n } else {\n return response;\n }\n\n } catch (error: any) {\n logger.error('Error calling OpenAI API: %s %s', error.message, error.stack);\n throw new OpenAIError(`Failed to create completion: ${error.message}`);\n }\n}\n\nexport async function transcribeAudio(filePath: string, options: { model?: string, debug?: boolean, debugFile?: string } = {}): Promise<Transcription> {\n const logger = getLogger();\n const storage = Storage.create({ log: logger.debug });\n try {\n const apiKey = process.env.OPENAI_API_KEY;\n if (!apiKey) {\n throw new OpenAIError('OPENAI_API_KEY environment variable is not set');\n }\n\n const openai = new OpenAI({\n apiKey: apiKey,\n });\n\n const model = options.model || DEFAULT_TRANSCRIPTION_MODEL;\n const fileName = filePath.split('/').pop() || filePath;\n logger.debug('Transcribing: %s (full path: %s)', fileName, filePath);\n\n const startTime = Date.now();\n const audioStream = await storage.readStream(filePath);\n const transcription = await openai.audio.transcriptions.create({\n model,\n file: audioStream,\n response_format: \"json\",\n });\n \n if (!transcription) {\n throw new OpenAIError('No transcription received from OpenAI');\n }\n \n const duration = ((Date.now() - startTime) / 1000).toFixed(1);\n logger.info('%s (%ss, %d chars)', model, duration, transcription.text?.length || 0);\n\n if (options.debug && options.debugFile) {\n await storage.writeFile(options.debugFile, JSON.stringify(transcription, null, 2), 'utf8');\n logger.debug('Wrote debug file to %s', options.debugFile);\n }\n\n logger.debug('Received transcription from OpenAI: %s', transcription);\n return transcription;\n\n } catch (error: any) {\n logger.error('Error transcribing audio file: %s %s', error.message, error.stack);\n throw new OpenAIError(`Failed to transcribe audio: ${error.message}`);\n }\n}\n"],"names":["storage","Storage.create"],"mappings":";;;;;AAUO,MAAM,oBAAoB,KAAA,CAAM;AAAA,EACnC,YAAY,OAAA,EAAiB;AACzB,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,aAAA;AAAA,EAChB;AACJ;AA+EA,eAAsB,eAAA,CAAgB,QAAA,EAAkB,OAAA,GAAmE,EAAC,EAA2B;AACnJ,EAAA,MAAM,SAAS,SAAA,EAAU;AACzB,EAAA,MAAMA,YAAUC,MAAQ,CAAO,EAAE,GAAA,EAAK,MAAA,CAAO,OAAO,CAAA;AACpD,EAAA,IAAI;AACA,IAAA,MAAM,MAAA,GAAS,QAAQ,GAAA,CAAI,cAAA;AAC3B,IAAA,IAAI,CAAC,MAAA,EAAQ;AACT,MAAA,MAAM,IAAI,YAAY,gDAAgD,CAAA;AAAA,IAC1E;AAEA,IAAA,MAAM,MAAA,GAAS,IAAI,MAAA,CAAO;AAAA,MACtB;AAAA,KACH,CAAA;AAED,IAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,2BAAA;AAC/B,IAAA,MAAM,WAAW,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,CAAE,KAAI,IAAK,QAAA;AAC9C,IAAA,MAAA,CAAO,KAAA,CAAM,kCAAA,EAAoC,QAAA,EAAU,QAAQ,CAAA;AAEnE,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAC3B,IAAA,MAAM,WAAA,GAAc,MAAMD,SAAA,CAAQ,UAAA,CAAW,QAAQ,CAAA;AACrD,IAAA,MAAM,aAAA,GAAgB,MAAM,MAAA,CAAO,KAAA,CAAM,eAAe,MAAA,CAAO;AAAA,MAC3D,KAAA;AAAA,MACA,IAAA,EAAM,WAAA;AAAA,MACN,eAAA,EAAiB;AAAA,KACpB,CAAA;AAED,IAAA,IAAI,CAAC,aAAA,EAAe;AAChB,MAAA,MAAM,IAAI,YAAY,uCAAuC,CAAA;AAAA,IACjE;AAEA,IAAA,MAAM,aAAa,IAAA,CAAK,GAAA,KAAQ,SAAA,IAAa,GAAA,EAAM,QAAQ,CAAC,CAAA;AAC5D,IAAA,MAAA,CAAO,KAAK,oBAAA,EAAsB,KAAA,EAAO,UAAU,aAAA,CAAc,IAAA,EAAM,UAAU,CAAC,CAAA;AAElF,IAAA,IAAI,OAAA,CAAQ,KAAA,IAAS,OAAA,CAAQ,SAAA,EAAW;AACpC,MAAA,MAAMA,SAAA,CAAQ,SAAA,CAAU,OAAA,CAAQ,SAAA,EAAW,IAAA,CAAK,UAAU,aAAA,EAAe,IAAA,EAAM,CAAC,CAAA,EAAG,MAAM,CAAA;AACzF,MAAA,MAAA,CAAO,KAAA,CAAM,wBAAA,EAA0B,OAAA,CAAQ,SAAS,CAAA;AAAA,IAC5D;AAEA,IAAA,MAAA,CAAO,KAAA,CAAM,0CAA0C,aAAa,CAAA;AACpE,IAAA,OAAO,aAAA;AAAA,EAEX,SAAS,KAAA,EAAY;AACjB,IAAA,MAAA,CAAO,KAAA,CAAM,sCAAA,EAAwC,KAAA,CAAM,OAAA,EAAS,MAAM,KAAK,CAAA;AAC/E,IAAA,MAAM,IAAI,WAAA,CAAY,CAAA,4BAAA,EAA+B,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AAAA,EACxE;AACJ;;;;"}
|
package/dist/index54.js
CHANGED
|
@@ -1,51 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (!apiKey) {
|
|
18
|
-
throw new OpenAIError("OPENAI_API_KEY environment variable is not set");
|
|
1
|
+
const stringifyJSON = function(obj) {
|
|
2
|
+
const arrOfKeyVals = [];
|
|
3
|
+
const arrVals = [];
|
|
4
|
+
let objKeys = [];
|
|
5
|
+
if (typeof obj === "number" || typeof obj === "boolean" || obj === null)
|
|
6
|
+
return "" + obj;
|
|
7
|
+
else if (typeof obj === "string")
|
|
8
|
+
return '"' + obj + '"';
|
|
9
|
+
else if (Array.isArray(obj)) {
|
|
10
|
+
if (obj[0] === void 0)
|
|
11
|
+
return "[]";
|
|
12
|
+
else {
|
|
13
|
+
obj.forEach(function(el) {
|
|
14
|
+
arrVals.push(stringifyJSON(el));
|
|
15
|
+
});
|
|
16
|
+
return "[" + arrVals + "]";
|
|
19
17
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
18
|
+
} else if (obj instanceof Object) {
|
|
19
|
+
objKeys = Object.keys(obj);
|
|
20
|
+
objKeys.forEach(function(key) {
|
|
21
|
+
const keyOut = '"' + key + '":';
|
|
22
|
+
const keyValOut = obj[key];
|
|
23
|
+
if (keyValOut instanceof Function || keyValOut === void 0)
|
|
24
|
+
arrOfKeyVals.push("");
|
|
25
|
+
else if (typeof keyValOut === "string")
|
|
26
|
+
arrOfKeyVals.push(keyOut + '"' + keyValOut + '"');
|
|
27
|
+
else if (typeof keyValOut === "boolean" || typeof keyValOut === "number" || keyValOut === null)
|
|
28
|
+
arrOfKeyVals.push(keyOut + keyValOut);
|
|
29
|
+
else if (keyValOut instanceof Object) {
|
|
30
|
+
arrOfKeyVals.push(keyOut + stringifyJSON(keyValOut));
|
|
31
|
+
}
|
|
32
32
|
});
|
|
33
|
-
|
|
34
|
-
throw new OpenAIError("No transcription received from OpenAI");
|
|
35
|
-
}
|
|
36
|
-
const duration = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
37
|
-
logger.info("%s (%ss, %d chars)", model, duration, transcription.text?.length || 0);
|
|
38
|
-
if (options.debug && options.debugFile) {
|
|
39
|
-
await storage$1.writeFile(options.debugFile, JSON.stringify(transcription, null, 2), "utf8");
|
|
40
|
-
logger.debug("Wrote debug file to %s", options.debugFile);
|
|
41
|
-
}
|
|
42
|
-
logger.debug("Received transcription from OpenAI: %s", transcription);
|
|
43
|
-
return transcription;
|
|
44
|
-
} catch (error) {
|
|
45
|
-
logger.error("Error transcribing audio file: %s %s", error.message, error.stack);
|
|
46
|
-
throw new OpenAIError(`Failed to transcribe audio: ${error.message}`);
|
|
33
|
+
return "{" + arrOfKeyVals + "}";
|
|
47
34
|
}
|
|
48
|
-
|
|
35
|
+
return "";
|
|
36
|
+
};
|
|
49
37
|
|
|
50
|
-
export {
|
|
38
|
+
export { stringifyJSON };
|
|
51
39
|
//# sourceMappingURL=index54.js.map
|
package/dist/index54.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index54.js","sources":["../src/util/
|
|
1
|
+
{"version":3,"file":"index54.js","sources":["../src/util/general.ts"],"sourcesContent":["// Utility function for deep merging two objects.\nexport function deepMerge(target: any, source: any): any {\n for (const key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n // Block prototype-polluting keys\n if (key === '__proto__' || key === 'constructor') {\n continue;\n }\n if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {\n if (!target[key]) {\n target[key] = {};\n }\n deepMerge(target[key], source[key]);\n } else {\n target[key] = source[key];\n }\n }\n }\n return target;\n}\n\n//Recursive implementation of jSON.stringify;\nexport const stringifyJSON = function (obj: any): string {\n\n const arrOfKeyVals: string[] = [];\n const arrVals: string[] = [];\n let objKeys: string[] = [];\n\n /*********CHECK FOR PRIMITIVE TYPES**********/\n if (typeof obj === 'number' || typeof obj === 'boolean' || obj === null)\n return '' + obj;\n else if (typeof obj === 'string')\n return '\"' + obj + '\"';\n\n /*********CHECK FOR ARRAY**********/\n else if (Array.isArray(obj)) {\n //check for empty array\n if (obj[0] === undefined)\n return '[]';\n else {\n obj.forEach(function (el) {\n arrVals.push(stringifyJSON(el));\n });\n return '[' + arrVals + ']';\n }\n }\n /*********CHECK FOR OBJECT**********/\n else if (obj instanceof Object) {\n //get object keys\n objKeys = Object.keys(obj);\n //set key output;\n objKeys.forEach(function (key) {\n const keyOut = '\"' + key + '\":';\n const keyValOut = obj[key];\n //skip functions and undefined properties\n if (keyValOut instanceof Function || keyValOut === undefined)\n arrOfKeyVals.push('');\n else if (typeof keyValOut === 'string')\n arrOfKeyVals.push(keyOut + '\"' + keyValOut + '\"');\n else if (typeof keyValOut === 'boolean' || typeof keyValOut === 'number' || keyValOut === null)\n arrOfKeyVals.push(keyOut + keyValOut);\n //check for nested objects, call recursively until no more objects\n else if (keyValOut instanceof Object) {\n arrOfKeyVals.push(keyOut + stringifyJSON(keyValOut));\n }\n });\n return '{' + arrOfKeyVals + '}';\n }\n return '';\n};"],"names":[],"mappings":"AAsBO,MAAM,aAAA,GAAgB,SAAU,GAAA,EAAkB;AAErD,EAAA,MAAM,eAAyB,EAAC;AAChC,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,IAAI,UAAoB,EAAC;AAGzB,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,OAAO,GAAA,KAAQ,aAAa,GAAA,KAAQ,IAAA;AAC/D,IAAA,OAAO,EAAA,GAAK,GAAA;AAAA,OAAA,IACP,OAAO,GAAA,KAAQ,QAAA;AACpB,IAAA,OAAO,MAAM,GAAA,GAAM,GAAA;AAAA,OAAA,IAGd,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AAEzB,IAAA,IAAI,GAAA,CAAI,CAAC,CAAA,KAAM,MAAA;AACX,MAAA,OAAO,IAAA;AAAA,SACN;AACD,MAAA,GAAA,CAAI,OAAA,CAAQ,SAAU,EAAA,EAAI;AACtB,QAAA,OAAA,CAAQ,IAAA,CAAK,aAAA,CAAc,EAAE,CAAC,CAAA;AAAA,MAClC,CAAC,CAAA;AACD,MAAA,OAAO,MAAM,OAAA,GAAU,GAAA;AAAA,IAC3B;AAAA,EACJ,CAAA,MAAA,IAES,eAAe,MAAA,EAAQ;AAE5B,IAAA,OAAA,GAAU,MAAA,CAAO,KAAK,GAAG,CAAA;AAEzB,IAAA,OAAA,CAAQ,OAAA,CAAQ,SAAU,GAAA,EAAK;AAC3B,MAAA,MAAM,MAAA,GAAS,MAAM,GAAA,GAAM,IAAA;AAC3B,MAAA,MAAM,SAAA,GAAY,IAAI,GAAG,CAAA;AAEzB,MAAA,IAAI,SAAA,YAAqB,YAAY,SAAA,KAAc,MAAA;AAC/C,QAAA,YAAA,CAAa,KAAK,EAAE,CAAA;AAAA,WAAA,IACf,OAAO,SAAA,KAAc,QAAA;AAC1B,QAAA,YAAA,CAAa,IAAA,CAAK,MAAA,GAAS,GAAA,GAAM,SAAA,GAAY,GAAG,CAAA;AAAA,WAAA,IAC3C,OAAO,SAAA,KAAc,SAAA,IAAa,OAAO,SAAA,KAAc,YAAY,SAAA,KAAc,IAAA;AACtF,QAAA,YAAA,CAAa,IAAA,CAAK,SAAS,SAAS,CAAA;AAAA,WAAA,IAE/B,qBAAqB,MAAA,EAAQ;AAClC,QAAA,YAAA,CAAa,IAAA,CAAK,MAAA,GAAS,aAAA,CAAc,SAAS,CAAC,CAAA;AAAA,MACvD;AAAA,IACJ,CAAC,CAAA;AACD,IAAA,OAAO,MAAM,YAAA,GAAe,GAAA;AAAA,EAChC;AACA,EAAA,OAAO,EAAA;AACX;;;;"}
|