@redaksjon/protokoll-engine 0.1.19-dev.20260320160259.f31c4f6 → 0.1.19
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/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/package.json +3 -3
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":";;;;AAkCO,MAAM,kBAAA,CAAmB;AAAA,EAC5B,YAAoB,MAAA,EAA2B;AAA3B,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAA4B;AAAA,EAA5B,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQpB,MAAM,MAAM,mBAAA,EAAmD;AAC3D,IAAA,MAAM,MAAA,GAAS,MAAM,eAAA,CAAgB;AAAA,MACjC,SAAA,EAAW,mBAAA;AAAA,MACX,KAAA,EAAO,KAAK,MAAA,CAAO,cAAA;AAAA,MACnB,MAAA,EAAQ,MAAA;AAAA,MACR,SAAA,EAAW;AAAA,KACd,CAAA;AAED,IAAA,MAAM,eAAmC,EAAC;AAC1C,IAAA,MAAM,YAAoC,EAAC;AAC3C,IAAA,MAAM,sBAAgD,EAAC;AACvD,IAAA,IAAI,aAAA,GAAgB,CAAA;AAEpB,IAAA,KAAA,MAAW,cAAA,IAAkB,OAAO,WAAA,EAAa;AAE7C,MAAA,MAAM,UAAA,GAAa,cAAc,IAAA,CAAK,cAAA,CAAe,UAAU,EAAE,QAAA,EAAU,MAAM,CAAA;AACjF,MAAA,MAAM,WAAW,UAAA,CAAW,QAAA;AAK5B,MAAA,UAAA,CAAW,KAAA,EAAM;AAGjB,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,gBAAA,CAAiB,QAAA,CAAS,QAAQ,CAAA;AACzD,MAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAG5B,MAAA,mBAAA,CAAoB,QAAA,CAAS,EAAE,CAAA,GAAI;AAAA,QAC/B,SAAA;AAAA,QACA,SAAA,EAAW,SAAS,OAAA,IAAW;AAAA,OACnC;AAGA,MAAA,IAAA,CAAK,gBAAA,CAAiB,WAAW,YAAY,CAAA;AAG7C,MAAA,IAAI,SAAS,OAAA,EAAS;AAClB,QAAA,IAAA,CAAK,qBAAA,CAAsB,QAAA,CAAS,OAAA,EAAS,SAAA,EAAW,SAAS,CAAA;AAAA,MACrE;AAEA,MAAA,aAAA,IAAiB,SAAA,CAAU,MAAA;AAAA,IAC/B;AAEA,IAAA,MAAM,GAAA,GAAA,iBAAM,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AACnC,IAAA,OAAO;AAAA,MACH,YAAA,EAAc,IAAA,CAAK,eAAA,CAAgB,YAAY,CAAA;AAAA,MAC/C,SAAA;AAAA,MACA,mBAAA;AAAA,MACA,QAAA,EAAU;AAAA,QACN,OAAA,EAAS,GAAA;AAAA,QACT,aAAA,EAAe,GAAA;AAAA,QACf,eAAA,EAAiB,OAAO,WAAA,CAAY,MAAA;AAAA,QACpC,WAAA,EAAa,aAAA;AAAA,QACb,OAAA,EAAS;AAAA;AACb,KACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,iBAAiB,QAAA,EAAyC;AAC9D,IAAA,IAAI,CAAC,QAAA,EAAU,OAAO,EAAC;AAEvB,IAAA,MAAM,MAAgB,EAAC;AAEvB,IAAA,IAAI,SAAS,MAAA,EAAQ;AACjB,MAAA,GAAA,CAAI,IAAA,CAAK,GAAG,QAAA,CAAS,MAAA,CAAO,IAAI,CAAA,CAAA,KAAK,CAAA,CAAE,EAAE,CAAC,CAAA;AAAA,IAC9C;AACA,IAAA,IAAI,SAAS,QAAA,EAAU;AACnB,MAAA,GAAA,CAAI,IAAA,CAAK,GAAG,QAAA,CAAS,QAAA,CAAS,IAAI,CAAA,CAAA,KAAK,CAAA,CAAE,EAAE,CAAC,CAAA;AAAA,IAChD;AACA,IAAA,IAAI,SAAS,KAAA,EAAO;AAChB,MAAA,GAAA,CAAI,IAAA,CAAK,GAAG,QAAA,CAAS,KAAA,CAAM,IAAI,CAAA,CAAA,KAAK,CAAA,CAAE,EAAE,CAAC,CAAA;AAAA,IAC7C;AACA,IAAA,IAAI,SAAS,SAAA,EAAW;AACpB,MAAA,GAAA,CAAI,IAAA,CAAK,GAAG,QAAA,CAAS,SAAA,CAAU,IAAI,CAAA,CAAA,KAAK,CAAA,CAAE,EAAE,CAAC,CAAA;AAAA,IACjD;AAEA,IAAA,OAAO,GAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,gBAAA,CAAiB,WAAqB,YAAA,EAAwC;AAE1E,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,SAAA,CAAU,QAAQ,CAAA,EAAA,EAAK;AACvC,MAAA,KAAA,IAAS,IAAI,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,SAAA,CAAU,QAAQ,CAAA,EAAA,EAAK;AAC3C,QAAA,MAAM,CAAA,GAAI,UAAU,CAAC,CAAA;AACrB,QAAA,MAAM,CAAA,GAAI,UAAU,CAAC,CAAA;AAGrB,QAAA,IAAI,CAAC,YAAA,CAAa,CAAC,GAAG,YAAA,CAAa,CAAC,IAAI,EAAC;AACzC,QAAA,IAAI,CAAC,YAAA,CAAa,CAAC,GAAG,YAAA,CAAa,CAAC,IAAI,EAAC;AAGzC,QAAA,YAAA,CAAa,CAAC,EAAE,CAAC,CAAA,GAAA,CAAK,aAAa,CAAC,CAAA,CAAE,CAAC,CAAA,IAAK,CAAA,IAAK,CAAA;AACjD,QAAA,YAAA,CAAa,CAAC,EAAE,CAAC,CAAA,GAAA,CAAK,aAAa,CAAC,CAAA,CAAE,CAAC,CAAA,IAAK,CAAA,IAAK,CAAA;AAAA,MACrD;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,qBAAA,CAAsB,WAAqB,YAAA,EAAwC;AAE/E,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,SAAA,CAAU,QAAQ,CAAA,EAAA,EAAK;AACvC,MAAA,KAAA,IAAS,IAAI,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,SAAA,CAAU,QAAQ,CAAA,EAAA,EAAK;AAC3C,QAAA,MAAM,CAAA,GAAI,UAAU,CAAC,CAAA;AACrB,QAAA,MAAM,CAAA,GAAI,UAAU,CAAC,CAAA;AAGrB,QAAA,IAAI,YAAA,CAAa,CAAC,CAAA,GAAI,CAAC,CAAA,EAAG;AACtB,UAAA,YAAA,CAAa,CAAC,EAAE,CAAC,CAAA,EAAA;AACjB,UAAA,IAAI,YAAA,CAAa,CAAC,CAAA,CAAE,CAAC,KAAK,CAAA,EAAG;AACzB,YAAA,OAAO,YAAA,CAAa,CAAC,CAAA,CAAE,CAAC,CAAA;AAAA,UAC5B;AAAA,QACJ;AACA,QAAA,IAAI,YAAA,CAAa,CAAC,CAAA,GAAI,CAAC,CAAA,EAAG;AACtB,UAAA,YAAA,CAAa,CAAC,EAAE,CAAC,CAAA,EAAA;AACjB,UAAA,IAAI,YAAA,CAAa,CAAC,CAAA,CAAE,CAAC,KAAK,CAAA,EAAG;AACzB,YAAA,OAAO,YAAA,CAAa,CAAC,CAAA,CAAE,CAAC,CAAA;AAAA,UAC5B;AAAA,QACJ;AAGA,QAAA,IAAI,YAAA,CAAa,CAAC,CAAA,IAAK,MAAA,CAAO,IAAA,CAAK,aAAa,CAAC,CAAC,CAAA,CAAE,MAAA,KAAW,CAAA,EAAG;AAC9D,UAAA,OAAO,aAAa,CAAC,CAAA;AAAA,QACzB;AACA,QAAA,IAAI,YAAA,CAAa,CAAC,CAAA,IAAK,MAAA,CAAO,IAAA,CAAK,aAAa,CAAC,CAAC,CAAA,CAAE,MAAA,KAAW,CAAA,EAAG;AAC9D,UAAA,OAAO,aAAa,CAAC,CAAA;AAAA,QACzB;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,qBAAA,CACI,SAAA,EACA,SAAA,EACA,SAAA,EACI;AACJ,IAAA,IAAI,CAAC,SAAA,CAAU,SAAS,CAAA,EAAG;AACvB,MAAA,SAAA,CAAU,SAAS,IAAI,EAAC;AAAA,IAC5B;AAEA,IAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAC9B,MAAA,SAAA,CAAU,SAAS,EAAE,QAAQ,CAAA,GAAA,CAAK,UAAU,SAAS,CAAA,CAAE,QAAQ,CAAA,IAAK,CAAA,IAAK,CAAA;AAAA,IAC7E;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,0BAAA,CACI,SAAA,EACA,SAAA,EACA,SAAA,EACI;AACJ,IAAA,IAAI,CAAC,SAAA,CAAU,SAAS,CAAA,EAAG;AAE3B,IAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAC9B,MAAA,IAAI,SAAA,CAAU,SAAS,CAAA,CAAE,QAAQ,CAAA,EAAG;AAChC,QAAA,SAAA,CAAU,SAAS,EAAE,QAAQ,CAAA,EAAA;AAC7B,QAAA,IAAI,SAAA,CAAU,SAAS,CAAA,CAAE,QAAQ,KAAK,CAAA,EAAG;AACrC,UAAA,OAAO,SAAA,CAAU,SAAS,CAAA,CAAE,QAAQ,CAAA;AAAA,QACxC;AAAA,MACJ;AAAA,IACJ;AAGA,IAAA,IAAI,OAAO,IAAA,CAAK,SAAA,CAAU,SAAS,CAAC,CAAA,CAAE,WAAW,CAAA,EAAG;AAChD,MAAA,OAAO,UAAU,SAAS,CAAA;AAAA,IAC9B;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,gBAAgB,YAAA,EAAsD;AAC1E,IAAA,MAAM,WAA+B,EAAC;AAEtC,IAAA,KAAA,MAAW,CAAC,QAAA,EAAU,WAAW,KAAK,MAAA,CAAO,OAAA,CAAQ,YAAY,CAAA,EAAG;AAChE,MAAA,MAAM,sBAAiD,EAAC;AAExD,MAAA,KAAA,MAAW,CAAC,aAAA,EAAe,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAA,EAAG;AAC9D,QAAA,IAAI,KAAA,IAAS,IAAA,CAAK,MAAA,CAAO,oBAAA,EAAsB;AAC3C,UAAA,mBAAA,CAAoB,aAAa,CAAA,GAAI,KAAA;AAAA,QACzC;AAAA,MACJ;AAEA,MAAA,IAAI,MAAA,CAAO,IAAA,CAAK,mBAAmB,CAAA,CAAE,SAAS,CAAA,EAAG;AAC7C,QAAA,QAAA,CAAS,QAAQ,CAAA,GAAI,mBAAA;AAAA,MACzB;AAAA,IACJ;AAEA,IAAA,OAAO,QAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,WAAA,CAAY,KAAA,EAAoB,QAAA,EAAiC;AAEnE,IAAA,MAAM,EAAA,CAAG,MAAM,IAAA,CAAK,OAAA,CAAQ,QAAQ,CAAA,EAAG,EAAE,SAAA,EAAW,IAAA,EAAM,CAAA;AAG1D,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,SAAA,CAAU,KAAA,EAAO,MAAM,CAAC,CAAA;AACjD,IAAA,MAAM,EAAA,CAAG,SAAA,CAAU,QAAA,EAAU,WAAA,EAAa,OAAO,CAAA;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,cAAc,mBAAA,EAAmD;AACnE,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,KAAA,CAAM,mBAAmB,CAAA;AAClD,IAAA,MAAM,IAAA,CAAK,WAAA,CAAY,KAAA,EAAO,IAAA,CAAK,OAAO,cAAc,CAAA;AACxD,IAAA,OAAO,KAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,aAAa,aAAa,QAAA,EAA+C;AACrE,IAAA,IAAI;AACA,MAAA,MAAM,OAAA,GAAU,MAAM,EAAA,CAAG,QAAA,CAAS,UAAU,OAAO,CAAA;AACnD,MAAA,OAAO,IAAA,CAAK,MAAM,OAAO,CAAA;AAAA,IAC7B,CAAA,CAAA,MAAQ;AAEJ,MAAA,OAAO,IAAA;AAAA,IACX;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,gBAAA,CACI,KAAA,EACA,cAAA,EACA,YAAA,EACA,YAAA,EACI;AACJ,IAAA,MAAM,WAAA,GAAc,KAAA,CAAM,mBAAA,CAAoB,cAAc,CAAA;AAG5D,IAAA,IAAI,WAAA,EAAa;AACb,MAAA,IAAA,CAAK,qBAAA,CAAsB,WAAA,CAAY,SAAA,EAAW,KAAA,CAAM,YAAY,CAAA;AACpE,MAAA,IAAI,YAAY,SAAA,EAAW;AACvB,QAAA,IAAA,CAAK,2BAA2B,WAAA,CAAY,SAAA,EAAW,WAAA,CAAY,SAAA,EAAW,MAAM,SAAS,CAAA;AAAA,MACjG;AAAA,IACJ;AAGA,IAAA,IAAI,YAAA,CAAa,SAAS,CAAA,EAAG;AACzB,MAAA,IAAA,CAAK,gBAAA,CAAiB,YAAA,EAAc,KAAA,CAAM,YAAY,CAAA;AACtD,MAAA,IAAI,YAAA,EAAc;AACd,QAAA,IAAA,CAAK,qBAAA,CAAsB,YAAA,EAAc,YAAA,EAAc,KAAA,CAAM,SAAS,CAAA;AAAA,MAC1E;AAGA,MAAA,KAAA,CAAM,mBAAA,CAAoB,cAAc,CAAA,GAAI;AAAA,QACxC,SAAA,EAAW,YAAA;AAAA,QACX,SAAA,EAAW;AAAA,OACf;AAAA,IACJ,CAAA,MAAO;AAEH,MAAA,OAAO,KAAA,CAAM,oBAAoB,cAAc,CAAA;AAAA,IACnD;AAGA,IAAA,KAAA,CAAM,QAAA,CAAS,aAAA,GAAA,iBAAgB,IAAI,IAAA,IAAO,WAAA,EAAY;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,gBAAA,CAAiB,OAAoB,cAAA,EAA8B;AAC/D,IAAA,IAAA,CAAK,gBAAA,CAAiB,KAAA,EAAO,cAAA,EAAgB,IAAI,MAAS,CAAA;AAAA,EAC9D;AACJ;;;;"}
|
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redaksjon/protokoll-engine",
|
|
3
|
-
"version": "0.1.19
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"description": "Processing engine for Protokoll - transcription pipeline, agentic execution, routing, and LLM integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"@anthropic-ai/sdk": "^0.71.2",
|
|
47
47
|
"@google/generative-ai": "^0.24.1",
|
|
48
48
|
"@kjerneverk/riotprompt": "^1.0.6",
|
|
49
|
-
"@redaksjon/context": "^0.0.
|
|
50
|
-
"@redaksjon/protokoll-format": "^0.1.
|
|
49
|
+
"@redaksjon/context": "^0.0.16",
|
|
50
|
+
"@redaksjon/protokoll-format": "^0.1.11",
|
|
51
51
|
"@utilarium/cardigantime": "^0.0.27",
|
|
52
52
|
"@utilarium/dreadcabinet": "^0.0.18",
|
|
53
53
|
"dayjs": "^1.11.13",
|