@redaksjon/protokoll-engine 0.1.19-dev.20260320160259.f31c4f6 → 0.2.0
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/index33.js +1 -1
- package/dist/index34.js +2 -2
- package/dist/index35.js +4 -4
- package/dist/index36.js +1 -1
- package/dist/index44.js +1 -0
- package/dist/index44.js.map +1 -1
- package/dist/index46.js +2 -0
- package/dist/index46.js.map +1 -1
- package/dist/index53.js +5 -48
- package/dist/index53.js.map +1 -1
- package/dist/index54.js +46 -34
- package/dist/index54.js.map +1 -1
- package/dist/index55.js +35 -280
- package/dist/index55.js.map +1 -1
- package/dist/index56.js +258 -137
- package/dist/index56.js.map +1 -1
- package/dist/index57.js +142 -60
- package/dist/index57.js.map +1 -1
- package/dist/index58.js +73 -70
- package/dist/index58.js.map +1 -1
- package/dist/index59.js +73 -3
- package/dist/index59.js.map +1 -1
- package/dist/index60.js +148 -5
- package/dist/index60.js.map +1 -1
- package/dist/index61.js +4 -4
- package/dist/index62.js +5 -148
- package/dist/index62.js.map +1 -1
- package/package.json +3 -3
package/dist/index33.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Context from '@redaksjon/context';
|
|
2
2
|
import { create as create$1 } from './index6.js';
|
|
3
|
-
import { create as create$2 } from './
|
|
3
|
+
import { create as create$2 } from './index53.js';
|
|
4
4
|
import { create as create$3 } from './index11.js';
|
|
5
5
|
import { create as create$4 } from './index3.js';
|
|
6
6
|
import { create as create$5 } from './index2.js';
|
package/dist/index34.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { getLogger } from './index47.js';
|
|
2
2
|
import { create as create$1 } from './index13.js';
|
|
3
3
|
import { create as create$2 } from './index14.js';
|
|
4
|
-
import { transcribeAudio } from './
|
|
5
|
-
import { stringifyJSON } from './
|
|
4
|
+
import { transcribeAudio } from './index54.js';
|
|
5
|
+
import { stringifyJSON } from './index55.js';
|
|
6
6
|
import path__default from 'node:path';
|
|
7
7
|
import { create as create$4 } from './index5.js';
|
|
8
8
|
import { create as create$3 } from './index2.js';
|
package/dist/index35.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { getLogger } from './index47.js';
|
|
2
2
|
import { create as create$1 } from './index13.js';
|
|
3
|
-
import { create as create$2 } from './
|
|
4
|
-
import { create as create$3 } from './
|
|
5
|
-
import { create as create$4 } from './
|
|
6
|
-
import { stringifyJSON } from './
|
|
3
|
+
import { create as create$2 } from './index56.js';
|
|
4
|
+
import { create as create$3 } from './index57.js';
|
|
5
|
+
import { create as create$4 } from './index58.js';
|
|
6
|
+
import { stringifyJSON } from './index55.js';
|
|
7
7
|
import path from 'path';
|
|
8
8
|
|
|
9
9
|
const create = (config, contextInstance) => {
|
package/dist/index36.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getLogger } from './index47.js';
|
|
2
2
|
import { create as create$3 } from './index14.js';
|
|
3
3
|
import { create as create$1 } from './index13.js';
|
|
4
|
-
import { create as create$2 } from './
|
|
4
|
+
import { create as create$2 } from './index59.js';
|
|
5
5
|
import { DEFAULT_INTERMEDIATE_DIRECTORY } from './index18.js';
|
|
6
6
|
import path__default from 'node:path';
|
|
7
7
|
|
package/dist/index44.js
CHANGED
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} 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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"}
|
|
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
CHANGED
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 * 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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"}
|
|
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,51 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { create } from './index13.js';
|
|
3
|
-
import { getLogger } from './index47.js';
|
|
4
|
-
import { DEFAULT_TRANSCRIPTION_MODEL } from './index18.js';
|
|
1
|
+
import { create as create$1 } from './index60.js';
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
}
|
|
3
|
+
const create = (config) => {
|
|
4
|
+
return create$1(config);
|
|
5
|
+
};
|
|
49
6
|
|
|
50
|
-
export {
|
|
7
|
+
export { create };
|
|
51
8
|
//# 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/out/index.ts"],"sourcesContent":["/**\n * Output Management System\n *\n * Main entry point for the output management system. Handles intermediate\n * files and final output destinations.\n */\n\nimport { OutputConfig, OutputPaths, IntermediateFiles, RawTranscriptData } from './types';\nimport * as Manager from './manager';\nimport * as Metadata from '../util/metadata';\n\nexport interface OutputInstance {\n createOutputPaths(\n audioFile: string,\n routedDestination: string,\n hash: string,\n date: Date\n ): OutputPaths;\n ensureDirectories(paths: OutputPaths): Promise<void>;\n writeIntermediate(\n paths: OutputPaths,\n type: keyof IntermediateFiles,\n content: unknown\n ): Promise<string>;\n /**\n * Write the raw Whisper transcript to the .transcript/ directory alongside final output.\n * This enables compare and reanalyze workflows.\n */\n writeRawTranscript(paths: OutputPaths, data: RawTranscriptData): Promise<string>;\n writeTranscript(paths: OutputPaths, content: string, metadata?: Metadata.TranscriptMetadata): Promise<string>;\n /**\n * Read a previously stored raw transcript from the .transcript/ directory.\n * Returns null if no raw transcript exists.\n */\n readRawTranscript(finalOutputPath: string): Promise<RawTranscriptData | null>;\n cleanIntermediates(paths: OutputPaths): Promise<void>;\n}\n\nexport const create = (config: OutputConfig): OutputInstance => {\n return Manager.create(config);\n};\n\nexport const DEFAULT_OUTPUT_CONFIG: OutputConfig = {\n intermediateDir: './output/protokoll',\n keepIntermediates: true,\n timestampFormat: 'YYMMDD-HHmm',\n};\n\n// Re-export types\nexport * from './types';\n"],"names":["Manager.create"],"mappings":";;AAsCO,MAAM,MAAA,GAAS,CAAC,MAAA,KAAyC;AAC5D,EAAA,OAAOA,SAAe,MAAM,CAAA;AAChC;;;;"}
|
package/dist/index54.js
CHANGED
|
@@ -1,39 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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';
|
|
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");
|
|
17
19
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
arrOfKeyVals.push(keyOut + stringifyJSON(keyValOut));
|
|
31
|
-
}
|
|
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
32
|
});
|
|
33
|
-
|
|
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}`);
|
|
34
47
|
}
|
|
35
|
-
|
|
36
|
-
};
|
|
48
|
+
}
|
|
37
49
|
|
|
38
|
-
export {
|
|
50
|
+
export { OpenAIError, transcribeAudio };
|
|
39
51
|
//# 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/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;;;;"}
|