@redaksjon/protokoll-engine 0.1.1-dev.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.
Files changed (240) hide show
  1. package/README.md +47 -0
  2. package/dist/agentic/executor.d.ts +21 -0
  3. package/dist/agentic/executor.d.ts.map +1 -0
  4. package/dist/agentic/index.d.ts +27 -0
  5. package/dist/agentic/index.d.ts.map +1 -0
  6. package/dist/agentic/registry.d.ts +11 -0
  7. package/dist/agentic/registry.d.ts.map +1 -0
  8. package/dist/agentic/tools/lookup-person.d.ts +3 -0
  9. package/dist/agentic/tools/lookup-person.d.ts.map +1 -0
  10. package/dist/agentic/tools/lookup-project.d.ts +3 -0
  11. package/dist/agentic/tools/lookup-project.d.ts.map +1 -0
  12. package/dist/agentic/tools/route-note.d.ts +3 -0
  13. package/dist/agentic/tools/route-note.d.ts.map +1 -0
  14. package/dist/agentic/tools/store-context.d.ts +3 -0
  15. package/dist/agentic/tools/store-context.d.ts.map +1 -0
  16. package/dist/agentic/tools/verify-spelling.d.ts +3 -0
  17. package/dist/agentic/tools/verify-spelling.d.ts.map +1 -0
  18. package/dist/agentic/types.d.ts +110 -0
  19. package/dist/agentic/types.d.ts.map +1 -0
  20. package/dist/constants.d.ts +98 -0
  21. package/dist/constants.d.ts.map +1 -0
  22. package/dist/feedback/analyzer.d.ts +13 -0
  23. package/dist/feedback/analyzer.d.ts.map +1 -0
  24. package/dist/feedback/decision-tracker.d.ts +14 -0
  25. package/dist/feedback/decision-tracker.d.ts.map +1 -0
  26. package/dist/feedback/handler.d.ts +14 -0
  27. package/dist/feedback/handler.d.ts.map +1 -0
  28. package/dist/feedback/index.d.ts +12 -0
  29. package/dist/feedback/index.d.ts.map +1 -0
  30. package/dist/feedback/types.d.ts +72 -0
  31. package/dist/feedback/types.d.ts.map +1 -0
  32. package/dist/index.d.ts +24 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +32 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/index10.js +4 -0
  37. package/dist/index10.js.map +1 -0
  38. package/dist/index11.js +22 -0
  39. package/dist/index11.js.map +1 -0
  40. package/dist/index12.js +125 -0
  41. package/dist/index12.js.map +1 -0
  42. package/dist/index13.js +124 -0
  43. package/dist/index13.js.map +1 -0
  44. package/dist/index14.js +296 -0
  45. package/dist/index14.js.map +1 -0
  46. package/dist/index15.js +100 -0
  47. package/dist/index15.js.map +1 -0
  48. package/dist/index16.js +107 -0
  49. package/dist/index16.js.map +1 -0
  50. package/dist/index17.js +185 -0
  51. package/dist/index17.js.map +1 -0
  52. package/dist/index18.js +53 -0
  53. package/dist/index18.js.map +1 -0
  54. package/dist/index19.js +19 -0
  55. package/dist/index19.js.map +1 -0
  56. package/dist/index2.js +33 -0
  57. package/dist/index2.js.map +1 -0
  58. package/dist/index20.js +105 -0
  59. package/dist/index20.js.map +1 -0
  60. package/dist/index21.js +26 -0
  61. package/dist/index21.js.map +1 -0
  62. package/dist/index22.js +49 -0
  63. package/dist/index22.js.map +1 -0
  64. package/dist/index23.js +119 -0
  65. package/dist/index23.js.map +1 -0
  66. package/dist/index24.js +330 -0
  67. package/dist/index24.js.map +1 -0
  68. package/dist/index25.js +57 -0
  69. package/dist/index25.js.map +1 -0
  70. package/dist/index26.js +38 -0
  71. package/dist/index26.js.map +1 -0
  72. package/dist/index27.js +127 -0
  73. package/dist/index27.js.map +1 -0
  74. package/dist/index28.js +157 -0
  75. package/dist/index28.js.map +1 -0
  76. package/dist/index29.js +163 -0
  77. package/dist/index29.js.map +1 -0
  78. package/dist/index3.js +36 -0
  79. package/dist/index3.js.map +1 -0
  80. package/dist/index30.js +173 -0
  81. package/dist/index30.js.map +1 -0
  82. package/dist/index31.js +423 -0
  83. package/dist/index31.js.map +1 -0
  84. package/dist/index32.js +161 -0
  85. package/dist/index32.js.map +1 -0
  86. package/dist/index33.js +152 -0
  87. package/dist/index33.js.map +1 -0
  88. package/dist/index34.js +56 -0
  89. package/dist/index34.js.map +1 -0
  90. package/dist/index35.js +103 -0
  91. package/dist/index35.js.map +1 -0
  92. package/dist/index36.js +451 -0
  93. package/dist/index36.js.map +1 -0
  94. package/dist/index37.js +431 -0
  95. package/dist/index37.js.map +1 -0
  96. package/dist/index38.js +87 -0
  97. package/dist/index38.js.map +1 -0
  98. package/dist/index39.js +122 -0
  99. package/dist/index39.js.map +1 -0
  100. package/dist/index4.js +3 -0
  101. package/dist/index4.js.map +1 -0
  102. package/dist/index40.js +299 -0
  103. package/dist/index40.js.map +1 -0
  104. package/dist/index41.js +49 -0
  105. package/dist/index41.js.map +1 -0
  106. package/dist/index42.js +151 -0
  107. package/dist/index42.js.map +1 -0
  108. package/dist/index43.js +226 -0
  109. package/dist/index43.js.map +1 -0
  110. package/dist/index44.js +49 -0
  111. package/dist/index44.js.map +1 -0
  112. package/dist/index45.js +45 -0
  113. package/dist/index45.js.map +1 -0
  114. package/dist/index46.js +37 -0
  115. package/dist/index46.js.map +1 -0
  116. package/dist/index47.js +51 -0
  117. package/dist/index47.js.map +1 -0
  118. package/dist/index48.js +39 -0
  119. package/dist/index48.js.map +1 -0
  120. package/dist/index49.js +239 -0
  121. package/dist/index49.js.map +1 -0
  122. package/dist/index5.js +17 -0
  123. package/dist/index5.js.map +1 -0
  124. package/dist/index50.js +163 -0
  125. package/dist/index50.js.map +1 -0
  126. package/dist/index51.js +81 -0
  127. package/dist/index51.js.map +1 -0
  128. package/dist/index52.js +78 -0
  129. package/dist/index52.js.map +1 -0
  130. package/dist/index53.js +22 -0
  131. package/dist/index53.js.map +1 -0
  132. package/dist/index54.js +8 -0
  133. package/dist/index54.js.map +1 -0
  134. package/dist/index55.js +8 -0
  135. package/dist/index55.js.map +1 -0
  136. package/dist/index56.js +17 -0
  137. package/dist/index56.js.map +1 -0
  138. package/dist/index57.js +4 -0
  139. package/dist/index57.js.map +1 -0
  140. package/dist/index58.js +17 -0
  141. package/dist/index58.js.map +1 -0
  142. package/dist/index59.js +4 -0
  143. package/dist/index59.js.map +1 -0
  144. package/dist/index6.js +22 -0
  145. package/dist/index6.js.map +1 -0
  146. package/dist/index60.js +6 -0
  147. package/dist/index60.js.map +1 -0
  148. package/dist/index7.js +27 -0
  149. package/dist/index7.js.map +1 -0
  150. package/dist/index8.js +22 -0
  151. package/dist/index8.js.map +1 -0
  152. package/dist/index9.js +5 -0
  153. package/dist/index9.js.map +1 -0
  154. package/dist/logging.d.ts +7 -0
  155. package/dist/logging.d.ts.map +1 -0
  156. package/dist/output/index.d.ts +15 -0
  157. package/dist/output/index.d.ts.map +1 -0
  158. package/dist/phases/complete.d.ts +17 -0
  159. package/dist/phases/complete.d.ts.map +1 -0
  160. package/dist/phases/index.d.ts +5 -0
  161. package/dist/phases/index.d.ts.map +1 -0
  162. package/dist/phases/locate.d.ts +15 -0
  163. package/dist/phases/locate.d.ts.map +1 -0
  164. package/dist/phases/simple-replace.d.ts +72 -0
  165. package/dist/phases/simple-replace.d.ts.map +1 -0
  166. package/dist/phases/transcribe.d.ts +19 -0
  167. package/dist/phases/transcribe.d.ts.map +1 -0
  168. package/dist/pipeline/index.d.ts +10 -0
  169. package/dist/pipeline/index.d.ts.map +1 -0
  170. package/dist/pipeline/orchestrator.d.ts +13 -0
  171. package/dist/pipeline/orchestrator.d.ts.map +1 -0
  172. package/dist/pipeline/types.d.ts +58 -0
  173. package/dist/pipeline/types.d.ts.map +1 -0
  174. package/dist/prompt/index.d.ts +3 -0
  175. package/dist/prompt/index.d.ts.map +1 -0
  176. package/dist/prompt/templates.d.ts +40 -0
  177. package/dist/prompt/templates.d.ts.map +1 -0
  178. package/dist/prompt/transcribe.d.ts +42 -0
  179. package/dist/prompt/transcribe.d.ts.map +1 -0
  180. package/dist/reasoning/client.d.ts +42 -0
  181. package/dist/reasoning/client.d.ts.map +1 -0
  182. package/dist/reasoning/index.d.ts +17 -0
  183. package/dist/reasoning/index.d.ts.map +1 -0
  184. package/dist/reasoning/strategy.d.ts +12 -0
  185. package/dist/reasoning/strategy.d.ts.map +1 -0
  186. package/dist/reasoning/types.d.ts +58 -0
  187. package/dist/reasoning/types.d.ts.map +1 -0
  188. package/dist/reflection/collector.d.ts +18 -0
  189. package/dist/reflection/collector.d.ts.map +1 -0
  190. package/dist/reflection/index.d.ts +13 -0
  191. package/dist/reflection/index.d.ts.map +1 -0
  192. package/dist/reflection/reporter.d.ts +10 -0
  193. package/dist/reflection/reporter.d.ts.map +1 -0
  194. package/dist/reflection/types.d.ts +99 -0
  195. package/dist/reflection/types.d.ts.map +1 -0
  196. package/dist/routing/classifier.d.ts +8 -0
  197. package/dist/routing/classifier.d.ts.map +1 -0
  198. package/dist/routing/index.d.ts +12 -0
  199. package/dist/routing/index.d.ts.map +1 -0
  200. package/dist/routing/router.d.ts +8 -0
  201. package/dist/routing/router.d.ts.map +1 -0
  202. package/dist/routing/types.d.ts +68 -0
  203. package/dist/routing/types.d.ts.map +1 -0
  204. package/dist/transcript/feedback.d.ts +70 -0
  205. package/dist/transcript/feedback.d.ts.map +1 -0
  206. package/dist/transcript/index.d.ts +10 -0
  207. package/dist/transcript/index.d.ts.map +1 -0
  208. package/dist/transcript/operations.d.ts +152 -0
  209. package/dist/transcript/operations.d.ts.map +1 -0
  210. package/dist/transcript/pkl-utils.d.ts +66 -0
  211. package/dist/transcript/pkl-utils.d.ts.map +1 -0
  212. package/dist/transcription/index.d.ts +17 -0
  213. package/dist/transcription/index.d.ts.map +1 -0
  214. package/dist/transcription/service.d.ts +10 -0
  215. package/dist/transcription/service.d.ts.map +1 -0
  216. package/dist/transcription/types.d.ts +41 -0
  217. package/dist/transcription/types.d.ts.map +1 -0
  218. package/dist/types.d.ts +28 -0
  219. package/dist/types.d.ts.map +1 -0
  220. package/dist/util/collision-detector.d.ts +77 -0
  221. package/dist/util/collision-detector.d.ts.map +1 -0
  222. package/dist/util/dates.d.ts +57 -0
  223. package/dist/util/dates.d.ts.map +1 -0
  224. package/dist/util/general.d.ts +3 -0
  225. package/dist/util/general.d.ts.map +1 -0
  226. package/dist/util/media.d.ts +9 -0
  227. package/dist/util/media.d.ts.map +1 -0
  228. package/dist/util/metadata.d.ts +138 -0
  229. package/dist/util/metadata.d.ts.map +1 -0
  230. package/dist/util/openai.d.ts +22 -0
  231. package/dist/util/openai.d.ts.map +1 -0
  232. package/dist/util/sounds-like-database.d.ts +98 -0
  233. package/dist/util/sounds-like-database.d.ts.map +1 -0
  234. package/dist/util/storage.d.ts +35 -0
  235. package/dist/util/storage.d.ts.map +1 -0
  236. package/dist/util/text-replacer.d.ts +56 -0
  237. package/dist/util/text-replacer.d.ts.map +1 -0
  238. package/dist/utils/entityFinder.d.ts +29 -0
  239. package/dist/utils/entityFinder.d.ts.map +1 -0
  240. package/package.json +84 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index31.js","sources":["../src/pipeline/orchestrator.ts"],"sourcesContent":["/**\n * Pipeline Orchestrator\n *\n * Orchestrates the intelligent transcription pipeline, coordinating\n * all the modules: context, routing, transcription, reasoning,\n * agentic tools, interactive mode, output management, and reflection.\n * \n * THIS IS THE MAIN PROCESSING FLOW - NOT DEAD CODE!\n */\n\nimport { PipelineConfig, PipelineInput, PipelineResult, PipelineState } from './types';\nimport * as Context from '@redaksjon/context';\nimport * as Routing from '../routing';\nimport * as Output from '../output';\nimport * as Reflection from '../reflection';\nimport * as Transcription from '../transcription';\nimport * as Reasoning from '../reasoning';\nimport * as Agentic from '../agentic';\nimport * as CompletePhase from '../phases/complete';\nimport * as Logging from '../logging';\nimport * as Metadata from '../util/metadata';\n\nexport interface OrchestratorInstance {\n process(input: PipelineInput): Promise<PipelineResult>;\n}\n\nexport interface OrchestratorConfig extends PipelineConfig {\n outputDirectory: string;\n outputStructure: string;\n outputFilenameOptions: string[];\n maxAudioSize: number;\n tempDirectory: string;\n}\n\nexport const create = async (config: OrchestratorConfig): Promise<OrchestratorInstance> => {\n const logger = Logging.getLogger();\n const currentWorkingDir = globalThis.process.cwd();\n \n logger.debug('Initializing intelligent transcription pipeline...');\n \n // Initialize context system (async)\n // Use explicit contextDirectories from config if provided (from protokoll-config.yaml)\n const context = await Context.create({\n startingDir: config.contextDirectory || currentWorkingDir,\n contextDirectories: config.contextDirectories,\n });\n logger.debug('Context system initialized - ready to query entities via tools');\n \n // Default routing configuration (used as fallback for projects without custom destination)\n const defaultPath = config.outputDirectory || '~/notes';\n const defaultStructure = (config.outputStructure || 'month') as Routing.FilesystemStructure;\n const defaultFilenameOptions = (config.outputFilenameOptions || ['date', 'time', 'subject']) as Routing.FilenameOption[];\n\n // Convert context projects to routing format\n // Projects without a destination inherit from the global default\n const contextProjects = context.getAllProjects();\n const routingProjects: Routing.ProjectRoute[] = contextProjects\n .filter(project => project.active !== false)\n .map(project => ({\n projectId: project.id,\n destination: {\n path: project.routing?.destination || defaultPath,\n structure: project.routing?.structure || defaultStructure,\n filename_options: project.routing?.filename_options || defaultFilenameOptions,\n createDirectories: true,\n },\n classification: project.classification,\n active: project.active,\n auto_tags: project.routing?.auto_tags,\n }));\n \n logger.debug('Loaded %d projects from context for routing', routingProjects.length);\n \n // Initialize routing with config-based defaults\n const routingConfig: Routing.RoutingConfig = {\n default: {\n path: defaultPath,\n structure: defaultStructure,\n filename_options: defaultFilenameOptions,\n createDirectories: true,\n },\n projects: routingProjects,\n conflict_resolution: 'primary',\n };\n \n const routing = Routing.create(routingConfig, context);\n logger.debug('Routing system initialized');\n \n // Interactive moved to protokoll-cli\n // const interactive = Interactive.create(\n // { enabled: config.interactive, defaultToSuggestion: true, silent: config.silent },\n // context\n // );\n \n const output = Output.create({\n intermediateDir: config.intermediateDir || './output/protokoll',\n keepIntermediates: config.keepIntermediates ?? true,\n timestampFormat: 'YYMMDD-HHmm',\n });\n logger.debug('Output manager initialized');\n \n const reflection = config.selfReflection \n ? Reflection.create({\n enabled: true,\n format: 'markdown',\n includeConversation: false,\n includeOutput: true,\n })\n : null;\n if (reflection) {\n logger.debug('Self-reflection system enabled');\n }\n \n // Initialize transcription service\n const transcription = Transcription.create({\n defaultModel: config.transcriptionModel as Transcription.TranscriptionModel,\n });\n logger.debug('Transcription service initialized with model: %s', config.transcriptionModel);\n \n // Initialize reasoning for agentic processing\n const reasoning = Reasoning.create({ \n model: config.model,\n reasoningLevel: config.reasoningLevel,\n });\n logger.debug('Reasoning system initialized with model: %s, reasoning level: %s', config.model, config.reasoningLevel || 'medium');\n\n // Initialize complete phase for moving files to processed directory\n // Pass outputStructure so processed files use the same directory structure as output\n const complete = config.processedDirectory \n ? CompletePhase.create({\n processedDirectory: config.processedDirectory,\n outputStructure: config.outputStructure as CompletePhase.FilesystemStructure,\n dryRun: config.dryRun,\n })\n : null;\n if (complete) {\n logger.debug('Complete phase initialized with processed directory: %s', config.processedDirectory);\n }\n \n // Helper to extract a human-readable title from the output path\n const extractTitleFromPath = (outputPath: string): string | undefined => {\n const filename = outputPath.split('/').pop()?.replace('.md', '');\n if (!filename) return undefined;\n \n // Remove date prefix (e.g., \"27-0716-\" from \"27-0716-meeting-notes\")\n const withoutDate = filename.replace(/^\\d{2}-\\d{4}-/, '');\n if (!withoutDate) return undefined;\n \n // Convert kebab-case to Title Case\n return withoutDate\n .split('-')\n .map(word => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n };\n \n // Helper to check if a title is meaningful (not just numbers/timestamps)\n const isMeaningfulTitle = (title: string | undefined): boolean => {\n if (!title) return false;\n // Check if title is mostly numbers (timestamp-like) or very short fragments\n const stripped = title.replace(/\\s+/g, '');\n const numberRatio = (stripped.match(/\\d/g) || []).length / stripped.length;\n // Reject if: mostly numbers, too short, or common bad patterns\n if (numberRatio > 0.5) return false;\n if (stripped.length < 3) return false;\n // Reject titles that are just common words without context\n const badPatterns = /^(i|i have|i am|the|a|an|um|uh|so|well|okay|oh|hey|hi)$/i;\n if (badPatterns.test(title.trim())) return false;\n return true;\n };\n \n // Generate a meaningful title from transcript content using LLM\n const generateTitleFromContent = async (transcriptText: string, fallbackTitle?: string): Promise<string> => {\n try {\n // Use first ~2000 chars for title generation (enough context, not too expensive)\n const textSample = transcriptText.slice(0, 2000);\n \n const response = await reasoning.complete({\n systemPrompt: `You are a title generator. Given a transcript, generate a concise, descriptive title (3-8 words) that captures the main topic or theme.\n\nRules:\n- Output ONLY the title, nothing else\n- No quotes around the title\n- Use Title Case\n- Be specific - avoid generic titles like \"Meeting Notes\" or \"Discussion\"\n- Focus on the main subject matter\n- If there are multiple topics, pick the most prominent one`,\n prompt: `Generate a title for this transcript:\\n\\n${textSample}`,\n });\n \n // Clean up the response - remove quotes, trim whitespace\n const title = response.content\n .trim()\n .replace(/^[\"']|[\"']$/g, '') // Remove surrounding quotes\n .replace(/^#\\s*/, '') // Remove markdown heading prefix\n .trim();\n \n // Validate the generated title\n if (title && title.length > 0 && title.length < 100) {\n logger.debug('Generated title from content: %s', title);\n return title;\n }\n \n logger.debug('Generated title was invalid, using fallback');\n return fallbackTitle || 'Untitled';\n } catch (error) {\n logger.warn('Title generation failed, using fallback', { error });\n return fallbackTitle || 'Untitled';\n }\n };\n\n const processInput = async (input: PipelineInput): Promise<PipelineResult> => {\n const startTime = Date.now();\n \n // Format progress prefix for log messages\n const progressPrefix = input.progress \n ? `[${input.progress.current}/${input.progress.total}]` \n : '';\n const log = (level: 'info' | 'debug', message: string, ...args: unknown[]) => {\n const prefixedMessage = progressPrefix ? `${progressPrefix} ${message}` : message;\n if (level === 'info') {\n logger.info(prefixedMessage, ...args);\n } else {\n logger.debug(prefixedMessage, ...args);\n }\n };\n \n log('info', 'Processing: %s (hash: %s)', input.audioFile, input.hash);\n \n // Initialize state\n const state: PipelineState = {\n input,\n startTime: new Date(),\n };\n \n // Start reflection collection if enabled\n if (reflection) {\n reflection.collector.start();\n }\n \n // Start interactive session if enabled\n // Interactive moved to protokoll-cli\n // if (config.interactive) {\n // interactive.startSession();\n // log('debug', 'Interactive session started');\n // }\n \n try {\n // Step 1: Check onboarding needs (moved to protokoll-cli)\n log('debug', 'Checking onboarding state...');\n // const onboardingState = interactive.checkNeedsOnboarding();\n const onboardingState = { needsOnboarding: false }; // Stub\n if (onboardingState.needsOnboarding) {\n log('debug', 'First-run detected - onboarding may be triggered');\n }\n \n // Step 2: Raw transcription using Transcription module\n log('info', 'Transcribing audio...');\n const whisperStart = Date.now();\n \n const transcriptionResult = await transcription.transcribe(input.audioFile, {\n model: config.transcriptionModel as Transcription.TranscriptionModel,\n });\n state.rawTranscript = transcriptionResult.text;\n \n const whisperDuration = Date.now() - whisperStart;\n log('info', 'Transcription: %d chars in %.1fs', \n state.rawTranscript.length, whisperDuration / 1000);\n \n if (reflection) {\n reflection.collector.recordWhisper(whisperDuration);\n }\n \n // Step 3: Route detection\n log('debug', 'Determining routing destination...');\n const routingContext: Routing.RoutingContext = {\n transcriptText: state.rawTranscript || '',\n audioDate: input.creation,\n sourceFile: input.audioFile,\n hash: input.hash,\n };\n \n const routeResult = routing.route(routingContext);\n \n log('debug', 'Routing decision: project=%s, confidence=%.2f', \n routeResult.projectId || 'default', routeResult.confidence);\n \n // Record routing decision in reflection\n if (reflection) {\n reflection.collector.recordRoutingDecision({\n projectId: routeResult.projectId,\n destination: routeResult.destination.path,\n confidence: routeResult.confidence,\n reasoning: routeResult.reasoning,\n signals: routeResult.signals.map(s => ({\n type: s.type,\n value: s.value,\n weight: s.weight,\n })),\n alternativesConsidered: routeResult.alternateMatches?.map(alt => ({\n projectId: alt.projectId,\n confidence: alt.confidence,\n whyNotChosen: `Lower confidence (${(alt.confidence * 100).toFixed(1)}%)`,\n })),\n });\n }\n \n // Build output path\n const outputPath = routing.buildOutputPath(routeResult, routingContext);\n log('debug', 'Output path: %s', outputPath);\n \n // Step 4: Create output paths using Output module\n log('debug', 'Setting up output directories...');\n const paths = output.createOutputPaths(\n input.audioFile,\n outputPath,\n input.hash,\n input.creation\n );\n \n await output.ensureDirectories(paths);\n \n // Write raw transcript to intermediate (for debugging)\n await output.writeIntermediate(paths, 'transcript', {\n text: state.rawTranscript,\n model: config.transcriptionModel,\n duration: whisperDuration,\n });\n \n // Step 5: Agentic enhancement using real executor\n log('info', 'Enhancing with %s...', config.model);\n \n const agenticStart = Date.now();\n const toolContext: Agentic.ToolContext = {\n transcriptText: state.rawTranscript || '',\n audioDate: input.creation,\n sourceFile: input.audioFile,\n contextInstance: context,\n routingInstance: routing,\n interactiveMode: config.interactive,\n // Interactive moved to protokoll-cli\n // interactiveInstance: interactive,\n };\n \n const executor = Agentic.create(reasoning, toolContext);\n const agenticResult = await executor.process(state.rawTranscript || '');\n \n state.enhancedText = agenticResult.enhancedText;\n const toolsUsed = agenticResult.toolsUsed;\n const agenticDuration = Date.now() - agenticStart;\n \n // Record tool calls in reflection\n if (reflection) {\n for (const tool of toolsUsed) {\n reflection.collector.recordToolCall(tool, agenticDuration / toolsUsed.length, true);\n }\n reflection.collector.recordCorrection(state.rawTranscript || '', state.enhancedText);\n // Record token usage from agentic result\n if (agenticResult.totalTokens) {\n reflection.collector.recordModelResponse(config.model, agenticResult.totalTokens);\n }\n // Record context changes (new projects, entities created)\n if (agenticResult.contextChanges) {\n for (const change of agenticResult.contextChanges) {\n reflection.collector.recordContextChange(change);\n }\n }\n }\n \n // Write agentic session to intermediate\n await output.writeIntermediate(paths, 'session', {\n iterations: agenticResult.iterations,\n toolsUsed: agenticResult.toolsUsed,\n state: agenticResult.state,\n });\n \n // Step 5b: Check if agentic processing found a different route\n // (e.g., via lookup_project tool finding a project with custom destination)\n if (agenticResult.state.routeDecision?.destination?.path) {\n const agenticRoute = agenticResult.state.routeDecision;\n log('debug', 'Agentic processing found route: %s -> %s', \n agenticRoute.projectId || 'unknown', \n agenticRoute.destination.path\n );\n \n // Update routeResult with the agentic decision\n routeResult.projectId = agenticRoute.projectId || routeResult.projectId;\n routeResult.destination = {\n ...routeResult.destination,\n path: agenticRoute.destination.path,\n structure: agenticRoute.destination.structure || routeResult.destination.structure,\n };\n routeResult.confidence = agenticRoute.confidence || routeResult.confidence;\n routeResult.reasoning = agenticRoute.reasoning || routeResult.reasoning;\n if (agenticRoute.signals) {\n routeResult.signals = agenticRoute.signals;\n }\n \n // Rebuild output path with the new destination\n const newOutputPath = routing.buildOutputPath(routeResult, routingContext);\n log('debug', 'Updated output path: %s -> %s', outputPath, newOutputPath);\n \n // Recreate output paths with new destination\n const newPaths = output.createOutputPaths(\n input.audioFile,\n newOutputPath,\n input.hash,\n input.creation\n );\n await output.ensureDirectories(newPaths);\n \n // Update paths reference (reassign properties since paths is const)\n Object.assign(paths, newPaths);\n }\n\n // Step 5c: Write raw transcript to .transcript/ directory alongside final output\n // This is done AFTER the route is finalized so it goes to the correct location\n // Enables compare and reanalyze workflows\n log('debug', 'Writing raw transcript to .transcript/ directory...');\n await output.writeRawTranscript(paths, {\n text: state.rawTranscript,\n model: config.transcriptionModel,\n duration: whisperDuration,\n audioFile: input.audioFile,\n audioHash: input.hash,\n transcribedAt: new Date().toISOString(),\n });\n\n // Step 6: Write final output using Output module with metadata\n log('debug', 'Writing final transcript...');\n if (state.enhancedText) {\n // Build entity metadata from referenced entities\n const buildEntityReferences = (): Metadata.TranscriptMetadata['entities'] => {\n const refs = agenticResult.state.referencedEntities;\n if (!refs) return undefined;\n \n const entities: NonNullable<Metadata.TranscriptMetadata['entities']> = {\n people: [],\n projects: [],\n terms: [],\n companies: [],\n };\n \n // Convert sets of IDs to EntityReference arrays\n for (const personId of refs.people) {\n const person = context.getPerson(personId);\n if (person) {\n entities.people!.push({ id: person.id, name: person.name, type: 'person' });\n }\n }\n \n for (const projectId of refs.projects) {\n const project = context.getProject(projectId);\n if (project) {\n entities.projects!.push({ id: project.id, name: project.name, type: 'project' });\n }\n }\n \n for (const termId of refs.terms) {\n const term = context.getTerm(termId);\n if (term) {\n entities.terms!.push({ id: term.id, name: term.name, type: 'term' });\n }\n }\n \n for (const companyId of refs.companies) {\n const company = context.getCompany(companyId);\n if (company) {\n entities.companies!.push({ id: company.id, name: company.name, type: 'company' });\n }\n }\n \n // Only return if we found any entities\n const hasEntities = \n entities.people!.length > 0 ||\n entities.projects!.length > 0 ||\n entities.terms!.length > 0 ||\n entities.companies!.length > 0;\n \n return hasEntities ? entities : undefined;\n };\n \n // Generate title - prefer path-derived title if meaningful, otherwise use LLM\n const pathTitle = extractTitleFromPath(paths.final);\n let title: string;\n if (isMeaningfulTitle(pathTitle)) {\n title = pathTitle!;\n } else {\n log('debug', 'Path-derived title not meaningful (%s), generating from content...', pathTitle || 'empty');\n title = await generateTitleFromContent(state.enhancedText, pathTitle);\n log('info', 'Generated title: %s', title);\n \n // Rebuild output path with the generated title as the subject\n // This ensures the filename matches the title\n const contextWithTitle: Routing.RoutingContext = {\n ...routingContext,\n subjectOverride: title,\n };\n const newOutputPath = routing.buildOutputPath(routeResult, contextWithTitle);\n \n if (newOutputPath !== paths.final) {\n log('debug', 'Updating output path with generated title: %s -> %s', paths.final, newOutputPath);\n \n // Recreate output paths with the new filename\n const newPaths = output.createOutputPaths(\n input.audioFile,\n newOutputPath,\n input.hash,\n input.creation\n );\n await output.ensureDirectories(newPaths);\n \n // Update paths reference\n Object.assign(paths, newPaths);\n }\n }\n \n // Build metadata from routing decision and input\n const transcriptMetadata: Metadata.TranscriptMetadata = {\n title,\n projectId: routeResult.projectId || undefined,\n project: routeResult.projectId || undefined,\n date: input.creation,\n routing: Metadata.createRoutingMetadata(routeResult),\n tags: Metadata.extractTagsFromSignals(routeResult.signals),\n confidence: routeResult.confidence,\n entities: buildEntityReferences(),\n };\n \n await output.writeTranscript(paths, state.enhancedText, transcriptMetadata);\n }\n \n // Step 7: Generate reflection report\n log('debug', 'Generating reflection report...');\n let reflectionReport: Reflection.ReflectionReport | undefined;\n if (reflection) {\n reflectionReport = reflection.generate(\n input.audioFile,\n paths.final,\n undefined,\n state.enhancedText\n );\n \n if (paths.intermediate.reflection) {\n await reflection.save(reflectionReport, paths.intermediate.reflection);\n }\n }\n \n // Step 8: End interactive session (moved to protokoll-cli)\n log('debug', 'Finalizing session...');\n // let session: Interactive.InteractiveSession | undefined;\n // if (config.interactive) {\n // session = interactive.endSession();\n // log('debug', 'Interactive session ended: %d clarifications', session.responses.length);\n // // Save session if path available\n // if (paths.intermediate.session) {\n // await output.writeIntermediate(paths, 'session', session);\n // }\n // }\n \n // Step 9: Cleanup if needed\n if (!config.keepIntermediates && !config.debug) {\n await output.cleanIntermediates(paths);\n }\n\n // Step 10: Move audio file to processed directory\n let processedAudioPath: string | undefined;\n if (complete) {\n // Extract subject from output path for naming\n const subject = paths.final.split('/').pop()?.replace('.md', '') || undefined;\n processedAudioPath = await complete.complete(\n input.audioFile, \n input.hash, \n input.creation,\n subject\n );\n }\n \n const processingTime = Date.now() - startTime;\n \n // Compact summary output\n log('info', 'Enhancement: %d iterations, %d tools, %.1fs', \n agenticResult.iterations, toolsUsed.length, agenticDuration / 1000);\n if (agenticResult.totalTokens) {\n log('info', 'Tokens: %d total', agenticResult.totalTokens);\n }\n log('info', 'Output: %s (%.1fs total)', paths.final, processingTime / 1000);\n \n return {\n outputPath: paths.final,\n enhancedText: state.enhancedText || '',\n rawTranscript: state.rawTranscript || '',\n routedProject: routeResult.projectId,\n routingConfidence: routeResult.confidence,\n processingTime,\n toolsUsed,\n correctionsApplied: agenticResult.state.resolvedEntities.size,\n processedAudioPath,\n reflection: reflectionReport,\n // session, // Interactive moved to protokoll-cli\n intermediatePaths: paths,\n };\n \n } catch (error) {\n logger.error('Pipeline error', { error });\n throw error;\n }\n };\n \n return { process: processInput };\n};\n"],"names":["Logging.getLogger","Routing.create","Output.create","Reflection.create","Transcription.create","Reasoning.create","CompletePhase.create","Agentic.create","Metadata.createRoutingMetadata","Metadata.extractTagsFromSignals"],"mappings":"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"}
@@ -0,0 +1,161 @@
1
+ import { getLogger } from './index41.js';
2
+ import { create as create$1 } from './index12.js';
3
+ import { create as create$2 } from './index13.js';
4
+ import { transcribeAudio } from './index47.js';
5
+ import { stringifyJSON } from './index48.js';
6
+ import path__default from 'node:path';
7
+ import { create as create$4 } from './index5.js';
8
+ import { create as create$3 } from './index2.js';
9
+
10
+ const create = (config, operator, deps) => {
11
+ const logger = getLogger();
12
+ const storage$1 = create$1({ log: logger.debug });
13
+ const media$1 = create$2(logger);
14
+ const reasoning = create$3({ model: config.model || "gpt-4" });
15
+ const transcribe = async (creation, outputPath, contextPath, interimPath, filename, hash, audioFile) => {
16
+ if (!outputPath) {
17
+ throw new Error("outputPath is required for transcribe function");
18
+ }
19
+ if (!audioFile) {
20
+ throw new Error("audioFile is required for transcribe function");
21
+ }
22
+ const audioFileBasename = path__default.basename(audioFile, path__default.extname(audioFile)).replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").trim();
23
+ logger.debug(`Processed audio filename: ${audioFileBasename}`);
24
+ let transcriptOutputFilename = await operator.constructFilename(creation, "transcript", hash, { subject: audioFileBasename });
25
+ if (!transcriptOutputFilename.endsWith(".json")) {
26
+ logger.warn("constructFilename did not return a .json file for transcript, appending extension: %s", transcriptOutputFilename);
27
+ transcriptOutputFilename += ".json";
28
+ }
29
+ const transcriptOutputPath = path__default.join(interimPath, transcriptOutputFilename);
30
+ if (await storage$1.exists(transcriptOutputPath)) {
31
+ logger.info("Transcription file %s already exists, returning existing content...", transcriptOutputPath);
32
+ const existingContent = await storage$1.readFile(transcriptOutputPath, "utf8");
33
+ return JSON.parse(existingContent);
34
+ }
35
+ const baseDebugFilename = path__default.parse(transcriptOutputFilename).name;
36
+ const transcriptionDebugFile = config.debug ? path__default.join(interimPath, `${baseDebugFilename}.transcription.raw.response.json`) : void 0;
37
+ const originalFileSize = await media$1.getFileSize(audioFile);
38
+ const originalFileSizeMB = (originalFileSize / (1024 * 1024)).toFixed(1);
39
+ logger.debug(`Original audio file size: ${originalFileSize} bytes (${originalFileSizeMB} MB)`);
40
+ const maxAudioSize = typeof config.maxAudioSize === "number" ? config.maxAudioSize : 25 * 1024 * 1024;
41
+ const needsConversion = originalFileSize > maxAudioSize * 0.95;
42
+ const convertedAudioFile = needsConversion ? await media$1.convertToSupportedFormat(audioFile, interimPath, true) : await media$1.convertToSupportedFormat(audioFile, interimPath);
43
+ logger.debug(`Using audio file for transcription: ${convertedAudioFile}`);
44
+ const fileSize = await media$1.getFileSize(convertedAudioFile);
45
+ const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(1);
46
+ logger.info("Step 1/2: Transcribing audio (%s MB)...", fileSizeMB);
47
+ logger.debug(`Audio file size: ${fileSize} bytes, max size: ${maxAudioSize} bytes`);
48
+ let transcription;
49
+ if (fileSize > maxAudioSize) {
50
+ logger.info(`Audio file exceeds maximum size (${fileSize} > ${maxAudioSize} bytes), splitting into chunks`);
51
+ const tempDir = path__default.join(config.tempDirectory || "/tmp", `split_audio_${hash}`);
52
+ await storage$1.createDirectory(tempDir);
53
+ try {
54
+ const audioChunks = await media$1.splitAudioFile(convertedAudioFile, tempDir, maxAudioSize);
55
+ logger.info(`Split audio file into ${audioChunks.length} chunks`);
56
+ const transcriptions = [];
57
+ for (let i = 0; i < audioChunks.length; i++) {
58
+ const chunkPath = audioChunks[i];
59
+ logger.info(`Transcribing chunk ${i + 1}/${audioChunks.length}: ${chunkPath}`);
60
+ const chunkDebugFile = config.debug ? path__default.join(interimPath, `${baseDebugFilename}.transcription.chunk${i + 1}.raw.response.json`) : void 0;
61
+ const chunkTranscription = await transcribeAudio(chunkPath, {
62
+ model: config.transcriptionModel,
63
+ debug: config.debug,
64
+ debugFile: chunkDebugFile
65
+ });
66
+ transcriptions.push(chunkTranscription);
67
+ }
68
+ const combinedText = transcriptions.map((t) => t.text).join(" ");
69
+ transcription = { text: combinedText };
70
+ await storage$1.writeFile(
71
+ path__default.join(interimPath, `${baseDebugFilename}.transcription.combined.json`),
72
+ stringifyJSON({ chunks: transcriptions, combined: transcription }),
73
+ "utf8"
74
+ );
75
+ if (!config.debug) {
76
+ for (const chunk of audioChunks) {
77
+ try {
78
+ await storage$1.deleteFile(chunk);
79
+ } catch (error) {
80
+ logger.warn(`Failed to delete temporary chunk ${chunk}: ${error}`);
81
+ }
82
+ }
83
+ }
84
+ } catch (error) {
85
+ logger.error(`Error processing split audio files: ${error}`);
86
+ throw new Error(`Failed to process split audio files: ${error}`);
87
+ }
88
+ } else {
89
+ transcription = await transcribeAudio(convertedAudioFile, {
90
+ model: config.transcriptionModel,
91
+ debug: config.debug,
92
+ debugFile: transcriptionDebugFile
93
+ });
94
+ }
95
+ await storage$1.writeFile(transcriptOutputPath, stringifyJSON(transcription), "utf8");
96
+ logger.debug("Wrote transcription to %s", transcriptOutputPath);
97
+ const markdownOutputFilename = transcriptOutputFilename.replace(".json", ".md");
98
+ const markdownOutputPath = path__default.join(outputPath, markdownOutputFilename);
99
+ let toolsUsed = [];
100
+ let agentIterations = 0;
101
+ if (!await storage$1.exists(markdownOutputPath)) {
102
+ logger.info("Step 2/2: Processing transcript with agentic reasoning...");
103
+ logger.info("Transcript length: %d characters - model will use tools to query context as needed", transcription.text.length);
104
+ const agenticDebugFile = config.debug ? path__default.join(interimPath, `${baseDebugFilename}.agentic.session.json`) : void 0;
105
+ let markdownContent;
106
+ if (deps?.contextInstance && deps?.routingInstance) {
107
+ logger.info("Using agentic mode - model will call tools to look up people, projects, etc.");
108
+ const executor = create$4(reasoning, {
109
+ transcriptText: transcription.text,
110
+ audioDate: creation,
111
+ sourceFile: audioFile,
112
+ contextInstance: deps.contextInstance,
113
+ routingInstance: deps.routingInstance,
114
+ interactiveMode: config.interactive ?? false
115
+ });
116
+ const result = await executor.process(transcription.text);
117
+ markdownContent = result.enhancedText;
118
+ toolsUsed = result.toolsUsed;
119
+ agentIterations = result.iterations;
120
+ logger.info(
121
+ "Agentic processing complete: %d iterations, tools used: %s",
122
+ agentIterations,
123
+ toolsUsed.length > 0 ? toolsUsed.join(", ") : "none"
124
+ );
125
+ if (config.debug && agenticDebugFile) {
126
+ await storage$1.writeFile(agenticDebugFile, stringifyJSON({
127
+ toolsUsed,
128
+ iterations: agentIterations,
129
+ state: result.state
130
+ }), "utf8");
131
+ logger.debug("Wrote agentic session to %s", agenticDebugFile);
132
+ }
133
+ } else {
134
+ logger.info("No context available - using direct completion (non-agentic)");
135
+ const response = await reasoning.complete({
136
+ systemPrompt: `You are a transcript formatter. Convert the following raw transcript into clean, well-structured Markdown.
137
+ Preserve ALL content - do not summarize. Only fix obvious formatting issues and organize into paragraphs.
138
+ If you see names that might be misspelled, keep them as-is since you don't have context to verify.`,
139
+ prompt: transcription.text
140
+ });
141
+ markdownContent = response.content;
142
+ }
143
+ await storage$1.writeFile(markdownOutputPath, markdownContent, "utf8");
144
+ logger.info("Markdown transcription saved to: %s", markdownOutputPath);
145
+ } else {
146
+ logger.info("Markdown transcription file %s already exists, skipping...", markdownOutputPath);
147
+ }
148
+ return {
149
+ ...transcription,
150
+ audioFileBasename,
151
+ toolsUsed,
152
+ agentIterations
153
+ };
154
+ };
155
+ return {
156
+ transcribe
157
+ };
158
+ };
159
+
160
+ export { create };
161
+ //# sourceMappingURL=index32.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index32.js","sources":["../src/phases/transcribe.ts"],"sourcesContent":["import * as Dreadcabinet from '@utilarium/dreadcabinet';\nimport { Config } from '@/types';\nimport * as Logging from '@/logging';\nimport * as Storage from '@/util/storage';\nimport * as Media from '@/util/media';\nimport * as OpenAI from '@/util/openai';\nimport { stringifyJSON } from '@/util/general';\nimport path from 'node:path';\nimport * as Agentic from '@/agentic';\nimport * as Reasoning from '../reasoning';\nimport * as Context from '@redaksjon/context';\nimport * as Routing from '../routing';\n\nexport interface Transcription {\n text: string;\n audioFileBasename: string;\n toolsUsed?: string[];\n agentIterations?: number;\n}\n\nexport interface Instance {\n transcribe: (creation: Date, outputPath: string, contextPath: string, interimPath: string, filename: string, hash: string, audioFile: string) => Promise<Transcription>;\n}\n\nexport interface TranscribeDependencies {\n contextInstance?: Context.ContextInstance;\n routingInstance?: Routing.RoutingInstance;\n}\n\nexport const create = (config: Config, operator: Dreadcabinet.Operator, deps?: TranscribeDependencies): Instance => {\n const logger = Logging.getLogger();\n const storage = Storage.create({ log: logger.debug });\n const media = Media.create(logger);\n \n // Create reasoning instance for agentic processing\n const reasoning = Reasoning.create({ model: config.model || 'gpt-4' });\n\n const transcribe = async (creation: Date, outputPath: string, contextPath: string, interimPath: string, filename: string, hash: string, audioFile: string): Promise<Transcription> => {\n if (!outputPath) {\n throw new Error(\"outputPath is required for transcribe function\");\n }\n\n if (!audioFile) {\n throw new Error(\"audioFile is required for transcribe function\");\n }\n\n // Remove extension from audioFile and make the name filesafe\n const audioFileBasename = path.basename(audioFile, path.extname(audioFile))\n .replace(/[^a-zA-Z0-9_-]/g, '_') // Replace non-alphanumeric chars with underscore\n .replace(/_+/g, '_') // Replace multiple underscores with a single one\n .trim();\n\n logger.debug(`Processed audio filename: ${audioFileBasename}`);\n\n let transcriptOutputFilename = await operator.constructFilename(creation, 'transcript', hash, { subject: audioFileBasename });\n // Ensure the filename ends with .json\n if (!transcriptOutputFilename.endsWith('.json')) {\n logger.warn('constructFilename did not return a .json file for transcript, appending extension: %s', transcriptOutputFilename);\n transcriptOutputFilename += '.json';\n }\n\n const transcriptOutputPath = path.join(interimPath, transcriptOutputFilename);\n\n // Check if transcription already exists\n if (await storage.exists(transcriptOutputPath)) {\n logger.info('Transcription file %s already exists, returning existing content...', transcriptOutputPath);\n const existingContent = await storage.readFile(transcriptOutputPath, 'utf8');\n return JSON.parse(existingContent);\n }\n\n const baseDebugFilename = path.parse(transcriptOutputFilename).name;\n const transcriptionDebugFile = config.debug ? path.join(interimPath, `${baseDebugFilename}.transcription.raw.response.json`) : undefined;\n\n // Check original file size first\n const originalFileSize = await media.getFileSize(audioFile);\n const originalFileSizeMB = (originalFileSize / (1024 * 1024)).toFixed(1);\n logger.debug(`Original audio file size: ${originalFileSize} bytes (${originalFileSizeMB} MB)`);\n\n // Convert audio file to a supported format if necessary\n // Always convert if file is close to or over the size limit to ensure compression\n const maxAudioSize = typeof config.maxAudioSize === 'number' ? config.maxAudioSize : 25 * 1024 * 1024;\n const needsConversion = originalFileSize > (maxAudioSize * 0.95); // Convert if within 5% of limit\n const convertedAudioFile = needsConversion \n ? await media.convertToSupportedFormat(audioFile, interimPath, true) // Force conversion\n : await media.convertToSupportedFormat(audioFile, interimPath);\n logger.debug(`Using audio file for transcription: ${convertedAudioFile}`);\n\n // Check if audio file exceeds the size limit after conversion\n const fileSize = await media.getFileSize(convertedAudioFile);\n const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(1);\n logger.info('Step 1/2: Transcribing audio (%s MB)...', fileSizeMB);\n logger.debug(`Audio file size: ${fileSize} bytes, max size: ${maxAudioSize} bytes`);\n\n let transcription: OpenAI.Transcription;\n\n if (fileSize > maxAudioSize) {\n logger.info(`Audio file exceeds maximum size (${fileSize} > ${maxAudioSize} bytes), splitting into chunks`);\n\n // Create a temporary directory for the audio chunks\n const tempDir = path.join(config.tempDirectory || '/tmp', `split_audio_${hash}`);\n await storage.createDirectory(tempDir);\n\n try {\n // Split the audio file into chunks (use converted file)\n const audioChunks = await media.splitAudioFile(convertedAudioFile, tempDir, maxAudioSize);\n logger.info(`Split audio file into ${audioChunks.length} chunks`);\n\n // Transcribe each chunk\n const transcriptions: OpenAI.Transcription[] = [];\n for (let i = 0; i < audioChunks.length; i++) {\n const chunkPath = audioChunks[i];\n logger.info(`Transcribing chunk ${i + 1}/${audioChunks.length}: ${chunkPath}`);\n\n const chunkDebugFile = config.debug ?\n path.join(interimPath, `${baseDebugFilename}.transcription.chunk${i + 1}.raw.response.json`) :\n undefined;\n\n const chunkTranscription = await OpenAI.transcribeAudio(chunkPath, {\n model: config.transcriptionModel,\n debug: config.debug,\n debugFile: chunkDebugFile\n });\n\n transcriptions.push(chunkTranscription);\n }\n\n // Combine all transcriptions\n const combinedText = transcriptions.map(t => t.text).join(' ');\n transcription = { text: combinedText };\n\n // Save each individual chunk for debugging\n await storage.writeFile(\n path.join(interimPath, `${baseDebugFilename}.transcription.combined.json`),\n stringifyJSON({ chunks: transcriptions, combined: transcription }),\n 'utf8'\n );\n\n // Clean up temporary files if not in debug mode\n if (!config.debug) {\n for (const chunk of audioChunks) {\n try {\n await storage.deleteFile(chunk);\n } catch (error) {\n logger.warn(`Failed to delete temporary chunk ${chunk}: ${error}`);\n }\n }\n }\n } catch (error) {\n logger.error(`Error processing split audio files: ${error}`);\n throw new Error(`Failed to process split audio files: ${error}`);\n }\n } else {\n // If file size is within the limit, transcribe normally (use converted file)\n transcription = await OpenAI.transcribeAudio(convertedAudioFile, {\n model: config.transcriptionModel,\n debug: config.debug,\n debugFile: transcriptionDebugFile\n });\n }\n\n // Save the transcription\n await storage.writeFile(transcriptOutputPath, stringifyJSON(transcription), 'utf8');\n logger.debug('Wrote transcription to %s', transcriptOutputPath);\n\n // Create markdown version of the transcript using agentic approach\n const markdownOutputFilename = transcriptOutputFilename.replace('.json', '.md');\n const markdownOutputPath = path.join(outputPath, markdownOutputFilename);\n\n let toolsUsed: string[] = [];\n let agentIterations = 0;\n\n // Only create the markdown file if it doesn't already exist\n if (!await storage.exists(markdownOutputPath)) {\n logger.info('Step 2/2: Processing transcript with agentic reasoning...');\n logger.info('Transcript length: %d characters - model will use tools to query context as needed', transcription.text.length);\n\n // Debug file for agentic session\n const agenticDebugFile = config.debug ?\n path.join(interimPath, `${baseDebugFilename}.agentic.session.json`) :\n undefined;\n\n let markdownContent: string;\n\n // Use agentic executor if we have context/routing instances\n if (deps?.contextInstance && deps?.routingInstance) {\n logger.info('Using agentic mode - model will call tools to look up people, projects, etc.');\n \n const executor = Agentic.create(reasoning, {\n transcriptText: transcription.text,\n audioDate: creation,\n sourceFile: audioFile,\n contextInstance: deps.contextInstance,\n routingInstance: deps.routingInstance,\n interactiveMode: config.interactive ?? false,\n });\n\n const result = await executor.process(transcription.text);\n markdownContent = result.enhancedText;\n toolsUsed = result.toolsUsed;\n agentIterations = result.iterations;\n\n logger.info('Agentic processing complete: %d iterations, tools used: %s', \n agentIterations, \n toolsUsed.length > 0 ? toolsUsed.join(', ') : 'none');\n\n // Save agentic session debug info\n if (config.debug && agenticDebugFile) {\n await storage.writeFile(agenticDebugFile, stringifyJSON({\n toolsUsed,\n iterations: agentIterations,\n state: result.state,\n }), 'utf8');\n logger.debug('Wrote agentic session to %s', agenticDebugFile);\n }\n } else {\n // Fallback to simple completion if no context available\n logger.info('No context available - using direct completion (non-agentic)');\n \n const response = await reasoning.complete({\n systemPrompt: `You are a transcript formatter. Convert the following raw transcript into clean, well-structured Markdown. \nPreserve ALL content - do not summarize. Only fix obvious formatting issues and organize into paragraphs.\nIf you see names that might be misspelled, keep them as-is since you don't have context to verify.`,\n prompt: transcription.text,\n });\n \n markdownContent = response.content;\n }\n\n // Save the markdown version\n await storage.writeFile(markdownOutputPath, markdownContent, 'utf8');\n logger.info('Markdown transcription saved to: %s', markdownOutputPath);\n } else {\n logger.info('Markdown transcription file %s already exists, skipping...', markdownOutputPath);\n }\n\n return {\n ...transcription,\n audioFileBasename,\n toolsUsed,\n agentIterations,\n };\n }\n\n return {\n transcribe,\n }\n} "],"names":["Logging.getLogger","storage","Storage.create","media","Media.create","Reasoning.create","path","OpenAI.transcribeAudio","Agentic.create"],"mappings":"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"}
@@ -0,0 +1,152 @@
1
+ import { getLogger } from './index41.js';
2
+ import { create as create$1 } from './index12.js';
3
+ import { create as create$2 } from './index49.js';
4
+ import { create as create$3 } from './index50.js';
5
+ import { create as create$4 } from './index51.js';
6
+ import { stringifyJSON } from './index48.js';
7
+ import path from 'path';
8
+
9
+ const create = (config, _operator) => {
10
+ const logger = getLogger();
11
+ const storage$1 = create$1({ log: logger.debug });
12
+ let database = null;
13
+ let dbInstance = null;
14
+ let collisionDetector = null;
15
+ let textReplacer = null;
16
+ const loadDatabase = async () => {
17
+ if (database) {
18
+ return database;
19
+ }
20
+ logger.info("Loading sounds-like database for simple-replace phase");
21
+ dbInstance = create$2();
22
+ database = await dbInstance.load();
23
+ logger.info(
24
+ `Loaded sounds-like database: ${database.mappings.length} total mappings (Tier 1: ${database.tier1.length}, Tier 2: ${Array.from(database.tier2.values()).reduce((sum, arr) => sum + arr.length, 0)}, Tier 3: ${database.tier3.length})`
25
+ );
26
+ return database;
27
+ };
28
+ const getCollisionDetector = () => {
29
+ if (!collisionDetector) {
30
+ collisionDetector = create$3({
31
+ tier2MinConfidence: 0.6
32
+ });
33
+ }
34
+ return collisionDetector;
35
+ };
36
+ const getTextReplacer = () => {
37
+ if (!textReplacer) {
38
+ textReplacer = create$4();
39
+ }
40
+ return textReplacer;
41
+ };
42
+ const replace = async (transcriptionText, classification, interimPath, hash) => {
43
+ const startTime = Date.now();
44
+ logger.info("Starting simple-replace phase");
45
+ logger.debug(
46
+ `Classification context: project="${classification.project}", confidence=${classification.confidence}`
47
+ );
48
+ await loadDatabase();
49
+ const detector = getCollisionDetector();
50
+ const replacer = getTextReplacer();
51
+ const stats = {
52
+ tier1Replacements: 0,
53
+ tier2Replacements: 0,
54
+ totalReplacements: 0,
55
+ tier1MappingsConsidered: 0,
56
+ tier2MappingsConsidered: 0,
57
+ projectContext: classification.project,
58
+ classificationConfidence: classification.confidence,
59
+ processingTimeMs: 0,
60
+ appliedMappings: []
61
+ };
62
+ let resultText = transcriptionText;
63
+ const tier1Mappings = dbInstance.getTier1Mappings();
64
+ stats.tier1MappingsConsidered = tier1Mappings.length;
65
+ if (tier1Mappings.length > 0) {
66
+ logger.debug(`Applying ${tier1Mappings.length} Tier 1 (always safe) mappings`);
67
+ const tier1Result = replacer.applyReplacements(resultText, tier1Mappings);
68
+ resultText = tier1Result.text;
69
+ stats.tier1Replacements = tier1Result.count;
70
+ for (const mapping of tier1Result.appliedMappings) {
71
+ const occurrences = tier1Result.occurrences.filter(
72
+ (o) => o.mapping.soundsLike === mapping.soundsLike
73
+ ).length;
74
+ stats.appliedMappings.push({
75
+ soundsLike: mapping.soundsLike,
76
+ correctText: mapping.correctText,
77
+ tier: 1,
78
+ occurrences
79
+ });
80
+ }
81
+ }
82
+ if (classification.project) {
83
+ const tier2Mappings = dbInstance.getTier2MappingsForProject(classification.project);
84
+ stats.tier2MappingsConsidered = tier2Mappings.length;
85
+ if (tier2Mappings.length > 0) {
86
+ logger.debug(
87
+ `Applying ${tier2Mappings.length} Tier 2 (project-scoped) mappings for project "${classification.project}"`
88
+ );
89
+ const applicableTier2 = tier2Mappings.filter(
90
+ (mapping) => detector.shouldApplyTier2(mapping, classification)
91
+ );
92
+ logger.debug(
93
+ `${applicableTier2.length} of ${tier2Mappings.length} Tier 2 mappings passed confidence and project checks`
94
+ );
95
+ if (applicableTier2.length > 0) {
96
+ const tier2Result = replacer.applyReplacements(resultText, applicableTier2);
97
+ resultText = tier2Result.text;
98
+ stats.tier2Replacements = tier2Result.count;
99
+ for (const mapping of tier2Result.appliedMappings) {
100
+ const occurrences = tier2Result.occurrences.filter(
101
+ (o) => o.mapping.soundsLike === mapping.soundsLike
102
+ ).length;
103
+ stats.appliedMappings.push({
104
+ soundsLike: mapping.soundsLike,
105
+ correctText: mapping.correctText,
106
+ tier: 2,
107
+ occurrences
108
+ });
109
+ }
110
+ }
111
+ }
112
+ } else {
113
+ logger.debug("No project in classification, skipping Tier 2 replacements");
114
+ }
115
+ stats.totalReplacements = stats.tier1Replacements + stats.tier2Replacements;
116
+ stats.processingTimeMs = Date.now() - startTime;
117
+ logger.info(
118
+ `Simple-replace phase complete: ${stats.totalReplacements} replacements made (Tier 1: ${stats.tier1Replacements}, Tier 2: ${stats.tier2Replacements}) in ${stats.processingTimeMs}ms`
119
+ );
120
+ if (config.debug) {
121
+ const statsFilename = `${hash}.simple-replace.stats.json`;
122
+ const statsPath = path.join(interimPath, statsFilename);
123
+ await storage$1.writeFile(
124
+ statsPath,
125
+ stringifyJSON({
126
+ stats,
127
+ classification: {
128
+ project: classification.project,
129
+ confidence: classification.confidence
130
+ },
131
+ tier1MappingsConsidered: tier1Mappings.map((m) => ({
132
+ soundsLike: m.soundsLike,
133
+ correctText: m.correctText
134
+ }))
135
+ }),
136
+ "utf8"
137
+ );
138
+ logger.debug(`Saved simple-replace stats to ${statsPath}`);
139
+ }
140
+ return {
141
+ text: resultText,
142
+ stats,
143
+ replacementsMade: stats.totalReplacements > 0
144
+ };
145
+ };
146
+ return {
147
+ replace
148
+ };
149
+ };
150
+
151
+ export { create };
152
+ //# sourceMappingURL=index33.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index33.js","sources":["../src/phases/simple-replace.ts"],"sourcesContent":["/**\n * Simple Replace Phase\n *\n * Performs intelligent, context-aware string replacement for entity correction.\n * This phase runs after transcription and routing to correct entity names using\n * sounds_like mappings from the protokoll context.\n *\n * Part of the simple-replace optimization (Phase 2).\n */\n\nimport * as Dreadcabinet from '@utilarium/dreadcabinet';\nimport { Config } from '@/types';\nimport * as Logging from '@/logging';\nimport * as Storage from '@/util/storage';\nimport * as SoundsLikeDatabase from '@/util/sounds-like-database';\nimport * as CollisionDetector from '@/util/collision-detector';\nimport * as TextReplacer from '@/util/text-replacer';\nimport { stringifyJSON } from '@/util/general';\nimport path from 'path';\n\n/**\n * Classification/routing information for context\n */\nexport interface Classification {\n project?: string;\n confidence?: number;\n [key: string]: any;\n}\n\n/**\n * Statistics about the simple-replace phase\n */\nexport interface SimpleReplaceStats {\n /** Number of Tier 1 (always safe) replacements made */\n tier1Replacements: number;\n\n /** Number of Tier 2 (project-scoped) replacements made */\n tier2Replacements: number;\n\n /** Total replacements made */\n totalReplacements: number;\n\n /** Number of Tier 1 mappings considered */\n tier1MappingsConsidered: number;\n\n /** Number of Tier 2 mappings considered */\n tier2MappingsConsidered: number;\n\n /** Project context used (if any) */\n projectContext?: string;\n\n /** Classification confidence */\n classificationConfidence?: number;\n\n /** Processing time in milliseconds */\n processingTimeMs: number;\n\n /** Applied mappings details */\n appliedMappings: Array<{\n soundsLike: string;\n correctText: string;\n tier: number;\n occurrences: number;\n }>;\n}\n\n/**\n * Result of the simple-replace phase\n */\nexport interface SimpleReplaceResult {\n /** The text after replacements */\n text: string;\n\n /** Statistics about the replacements */\n stats: SimpleReplaceStats;\n\n /** Whether any replacements were made */\n replacementsMade: boolean;\n}\n\n/**\n * Instance interface for simple-replace phase\n */\nexport interface Instance {\n /**\n * Apply simple-replace to transcription text using routing context\n */\n replace(\n transcriptionText: string,\n classification: Classification,\n interimPath: string,\n hash: string\n ): Promise<SimpleReplaceResult>;\n}\n\n/**\n * Create a simple-replace phase instance\n */\nexport const create = (config: Config, _operator: Dreadcabinet.Operator): Instance => {\n const logger = Logging.getLogger();\n const storage = Storage.create({ log: logger.debug });\n\n // Initialize database and utilities (load once, reuse across files)\n let database: SoundsLikeDatabase.SoundsLikeDatabase | null = null;\n let dbInstance: SoundsLikeDatabase.Instance | null = null;\n let collisionDetector: CollisionDetector.Instance | null = null;\n let textReplacer: TextReplacer.Instance | null = null;\n\n /**\n * Lazy load the sounds-like database\n */\n const loadDatabase = async (): Promise<SoundsLikeDatabase.SoundsLikeDatabase> => {\n if (database) {\n return database;\n }\n\n logger.info('Loading sounds-like database for simple-replace phase');\n\n dbInstance = SoundsLikeDatabase.create();\n database = await dbInstance.load();\n\n logger.info(\n `Loaded sounds-like database: ${database.mappings.length} total mappings ` +\n `(Tier 1: ${database.tier1.length}, Tier 2: ${Array.from(database.tier2.values()).reduce((sum, arr) => sum + arr.length, 0)}, ` +\n `Tier 3: ${database.tier3.length})`\n );\n\n return database;\n };\n\n /**\n * Get or create collision detector\n */\n const getCollisionDetector = (): CollisionDetector.Instance => {\n if (!collisionDetector) {\n collisionDetector = CollisionDetector.create({\n tier2MinConfidence: 0.6,\n });\n }\n return collisionDetector;\n };\n\n /**\n * Get or create text replacer\n */\n const getTextReplacer = (): TextReplacer.Instance => {\n if (!textReplacer) {\n textReplacer = TextReplacer.create({\n // Use preserveCase: false for entity names (we want \"observasion\" → \"Observasjon\" not \"observasjon\")\n preserveCase: false,\n useWordBoundaries: true,\n caseInsensitive: true,\n });\n }\n return textReplacer;\n };\n\n /**\n * Main replace function\n */\n const replace = async (\n transcriptionText: string,\n classification: Classification,\n interimPath: string,\n hash: string\n ): Promise<SimpleReplaceResult> => {\n const startTime = Date.now();\n\n logger.info('Starting simple-replace phase');\n logger.debug(\n `Classification context: project=\"${classification.project}\", ` +\n `confidence=${classification.confidence}`\n );\n\n // Load database\n await loadDatabase();\n const detector = getCollisionDetector();\n const replacer = getTextReplacer();\n\n // Prepare stats\n const stats: SimpleReplaceStats = {\n tier1Replacements: 0,\n tier2Replacements: 0,\n totalReplacements: 0,\n tier1MappingsConsidered: 0,\n tier2MappingsConsidered: 0,\n projectContext: classification.project,\n classificationConfidence: classification.confidence,\n processingTimeMs: 0,\n appliedMappings: [],\n };\n\n let resultText = transcriptionText;\n\n // STEP 1: Apply Tier 1 replacements (always safe)\n const tier1Mappings = dbInstance!.getTier1Mappings();\n stats.tier1MappingsConsidered = tier1Mappings.length;\n\n if (tier1Mappings.length > 0) {\n logger.debug(`Applying ${tier1Mappings.length} Tier 1 (always safe) mappings`);\n\n const tier1Result = replacer.applyReplacements(resultText, tier1Mappings);\n resultText = tier1Result.text;\n stats.tier1Replacements = tier1Result.count;\n\n for (const mapping of tier1Result.appliedMappings) {\n const occurrences = tier1Result.occurrences.filter(\n o => o.mapping.soundsLike === mapping.soundsLike\n ).length;\n\n stats.appliedMappings.push({\n soundsLike: mapping.soundsLike,\n correctText: mapping.correctText,\n tier: 1,\n occurrences,\n });\n }\n }\n\n // STEP 2: Apply Tier 2 replacements (project-scoped)\n if (classification.project) {\n const tier2Mappings = dbInstance!.getTier2MappingsForProject(classification.project);\n stats.tier2MappingsConsidered = tier2Mappings.length;\n\n if (tier2Mappings.length > 0) {\n logger.debug(\n `Applying ${tier2Mappings.length} Tier 2 (project-scoped) mappings ` +\n `for project \"${classification.project}\"`\n );\n\n // Filter Tier 2 mappings by confidence and project match\n const applicableTier2 = tier2Mappings.filter(mapping =>\n detector.shouldApplyTier2(mapping, classification)\n );\n\n logger.debug(\n `${applicableTier2.length} of ${tier2Mappings.length} Tier 2 mappings passed ` +\n `confidence and project checks`\n );\n\n if (applicableTier2.length > 0) {\n const tier2Result = replacer.applyReplacements(resultText, applicableTier2);\n resultText = tier2Result.text;\n stats.tier2Replacements = tier2Result.count;\n\n for (const mapping of tier2Result.appliedMappings) {\n const occurrences = tier2Result.occurrences.filter(\n o => o.mapping.soundsLike === mapping.soundsLike\n ).length;\n\n stats.appliedMappings.push({\n soundsLike: mapping.soundsLike,\n correctText: mapping.correctText,\n tier: 2,\n occurrences,\n });\n }\n }\n }\n } else {\n logger.debug('No project in classification, skipping Tier 2 replacements');\n }\n\n // Calculate totals\n stats.totalReplacements = stats.tier1Replacements + stats.tier2Replacements;\n stats.processingTimeMs = Date.now() - startTime;\n\n // Log summary\n logger.info(\n `Simple-replace phase complete: ${stats.totalReplacements} replacements made ` +\n `(Tier 1: ${stats.tier1Replacements}, Tier 2: ${stats.tier2Replacements}) ` +\n `in ${stats.processingTimeMs}ms`\n );\n\n // Save stats to interim file if in debug mode\n if (config.debug) {\n const statsFilename = `${hash}.simple-replace.stats.json`;\n const statsPath = path.join(interimPath, statsFilename);\n\n await storage.writeFile(\n statsPath,\n stringifyJSON({\n stats,\n classification: {\n project: classification.project,\n confidence: classification.confidence,\n },\n tier1MappingsConsidered: tier1Mappings.map(m => ({\n soundsLike: m.soundsLike,\n correctText: m.correctText,\n })),\n }),\n 'utf8'\n );\n\n logger.debug(`Saved simple-replace stats to ${statsPath}`);\n }\n\n return {\n text: resultText,\n stats,\n replacementsMade: stats.totalReplacements > 0,\n };\n };\n\n return {\n replace,\n };\n};\n"],"names":["Logging.getLogger","storage","Storage.create","SoundsLikeDatabase.create","CollisionDetector.create","TextReplacer.create"],"mappings":";;;;;;;;AAkGO,MAAM,MAAA,GAAS,CAAC,MAAA,EAAgB,SAAA,KAA+C;AAClF,EAAA,MAAM,MAAA,GAASA,SAAQ,EAAU;AACjC,EAAA,MAAMC,YAAUC,QAAQ,CAAO,EAAE,GAAA,EAAK,MAAA,CAAO,OAAO,CAAA;AAGpD,EAAA,IAAI,QAAA,GAAyD,IAAA;AAC7D,EAAA,IAAI,UAAA,GAAiD,IAAA;AACrD,EAAA,IAAI,iBAAA,GAAuD,IAAA;AAC3D,EAAA,IAAI,YAAA,GAA6C,IAAA;AAKjD,EAAA,MAAM,eAAe,YAA4D;AAC7E,IAAA,IAAI,QAAA,EAAU;AACV,MAAA,OAAO,QAAA;AAAA,IACX;AAEA,IAAA,MAAA,CAAO,KAAK,uDAAuD,CAAA;AAEnE,IAAA,UAAA,GAAaC,QAAmB,EAAO;AACvC,IAAA,QAAA,GAAW,MAAM,WAAW,IAAA,EAAK;AAEjC,IAAA,MAAA,CAAO,IAAA;AAAA,MACH,CAAA,6BAAA,EAAgC,QAAA,CAAS,QAAA,CAAS,MAAM,CAAA,yBAAA,EAC5C,QAAA,CAAS,KAAA,CAAM,MAAM,CAAA,UAAA,EAAa,KAAA,CAAM,IAAA,CAAK,QAAA,CAAS,KAAA,CAAM,MAAA,EAAQ,CAAA,CAAE,MAAA,CAAO,CAAC,GAAA,EAAK,GAAA,KAAQ,GAAA,GAAM,GAAA,CAAI,MAAA,EAAQ,CAAC,CAAC,CAAA,UAAA,EAChH,QAAA,CAAS,KAAA,CAAM,MAAM,CAAA,CAAA;AAAA,KACpC;AAEA,IAAA,OAAO,QAAA;AAAA,EACX,CAAA;AAKA,EAAA,MAAM,uBAAuB,MAAkC;AAC3D,IAAA,IAAI,CAAC,iBAAA,EAAmB;AACpB,MAAA,iBAAA,GAAoBC,QAAkB,CAAO;AAAA,QACzC,kBAAA,EAAoB;AAAA,OACvB,CAAA;AAAA,IACL;AACA,IAAA,OAAO,iBAAA;AAAA,EACX,CAAA;AAKA,EAAA,MAAM,kBAAkB,MAA6B;AACjD,IAAA,IAAI,CAAC,YAAA,EAAc;AACf,MAAA,YAAA,GAAeC,QAAa,CAK3B,CAAA;AAAA,IACL;AACA,IAAA,OAAO,YAAA;AAAA,EACX,CAAA;AAKA,EAAA,MAAM,OAAA,GAAU,OACZ,iBAAA,EACA,cAAA,EACA,aACA,IAAA,KAC+B;AAC/B,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAE3B,IAAA,MAAA,CAAO,KAAK,+BAA+B,CAAA;AAC3C,IAAA,MAAA,CAAO,KAAA;AAAA,MACH,CAAA,iCAAA,EAAoC,cAAA,CAAe,OAAO,CAAA,cAAA,EAC5C,eAAe,UAAU,CAAA;AAAA,KAC3C;AAGA,IAAA,MAAM,YAAA,EAAa;AACnB,IAAA,MAAM,WAAW,oBAAA,EAAqB;AACtC,IAAA,MAAM,WAAW,eAAA,EAAgB;AAGjC,IAAA,MAAM,KAAA,GAA4B;AAAA,MAC9B,iBAAA,EAAmB,CAAA;AAAA,MACnB,iBAAA,EAAmB,CAAA;AAAA,MACnB,iBAAA,EAAmB,CAAA;AAAA,MACnB,uBAAA,EAAyB,CAAA;AAAA,MACzB,uBAAA,EAAyB,CAAA;AAAA,MACzB,gBAAgB,cAAA,CAAe,OAAA;AAAA,MAC/B,0BAA0B,cAAA,CAAe,UAAA;AAAA,MACzC,gBAAA,EAAkB,CAAA;AAAA,MAClB,iBAAiB;AAAC,KACtB;AAEA,IAAA,IAAI,UAAA,GAAa,iBAAA;AAGjB,IAAA,MAAM,aAAA,GAAgB,WAAY,gBAAA,EAAiB;AACnD,IAAA,KAAA,CAAM,0BAA0B,aAAA,CAAc,MAAA;AAE9C,IAAA,IAAI,aAAA,CAAc,SAAS,CAAA,EAAG;AAC1B,MAAA,MAAA,CAAO,KAAA,CAAM,CAAA,SAAA,EAAY,aAAA,CAAc,MAAM,CAAA,8BAAA,CAAgC,CAAA;AAE7E,MAAA,MAAM,WAAA,GAAc,QAAA,CAAS,iBAAA,CAAkB,UAAA,EAAY,aAAa,CAAA;AACxE,MAAA,UAAA,GAAa,WAAA,CAAY,IAAA;AACzB,MAAA,KAAA,CAAM,oBAAoB,WAAA,CAAY,KAAA;AAEtC,MAAA,KAAA,MAAW,OAAA,IAAW,YAAY,eAAA,EAAiB;AAC/C,QAAA,MAAM,WAAA,GAAc,YAAY,WAAA,CAAY,MAAA;AAAA,UACxC,CAAA,CAAA,KAAK,CAAA,CAAE,OAAA,CAAQ,UAAA,KAAe,OAAA,CAAQ;AAAA,SAC1C,CAAE,MAAA;AAEF,QAAA,KAAA,CAAM,gBAAgB,IAAA,CAAK;AAAA,UACvB,YAAY,OAAA,CAAQ,UAAA;AAAA,UACpB,aAAa,OAAA,CAAQ,WAAA;AAAA,UACrB,IAAA,EAAM,CAAA;AAAA,UACN;AAAA,SACH,CAAA;AAAA,MACL;AAAA,IACJ;AAGA,IAAA,IAAI,eAAe,OAAA,EAAS;AACxB,MAAA,MAAM,aAAA,GAAgB,UAAA,CAAY,0BAAA,CAA2B,cAAA,CAAe,OAAO,CAAA;AACnF,MAAA,KAAA,CAAM,0BAA0B,aAAA,CAAc,MAAA;AAE9C,MAAA,IAAI,aAAA,CAAc,SAAS,CAAA,EAAG;AAC1B,QAAA,MAAA,CAAO,KAAA;AAAA,UACH,CAAA,SAAA,EAAY,aAAA,CAAc,MAAM,CAAA,+CAAA,EAChB,eAAe,OAAO,CAAA,CAAA;AAAA,SAC1C;AAGA,QAAA,MAAM,kBAAkB,aAAA,CAAc,MAAA;AAAA,UAAO,CAAA,OAAA,KACzC,QAAA,CAAS,gBAAA,CAAiB,OAAA,EAAS,cAAc;AAAA,SACrD;AAEA,QAAA,MAAA,CAAO,KAAA;AAAA,UACH,CAAA,EAAG,eAAA,CAAgB,MAAM,CAAA,IAAA,EAAO,cAAc,MAAM,CAAA,qDAAA;AAAA,SAExD;AAEA,QAAA,IAAI,eAAA,CAAgB,SAAS,CAAA,EAAG;AAC5B,UAAA,MAAM,WAAA,GAAc,QAAA,CAAS,iBAAA,CAAkB,UAAA,EAAY,eAAe,CAAA;AAC1E,UAAA,UAAA,GAAa,WAAA,CAAY,IAAA;AACzB,UAAA,KAAA,CAAM,oBAAoB,WAAA,CAAY,KAAA;AAEtC,UAAA,KAAA,MAAW,OAAA,IAAW,YAAY,eAAA,EAAiB;AAC/C,YAAA,MAAM,WAAA,GAAc,YAAY,WAAA,CAAY,MAAA;AAAA,cACxC,CAAA,CAAA,KAAK,CAAA,CAAE,OAAA,CAAQ,UAAA,KAAe,OAAA,CAAQ;AAAA,aAC1C,CAAE,MAAA;AAEF,YAAA,KAAA,CAAM,gBAAgB,IAAA,CAAK;AAAA,cACvB,YAAY,OAAA,CAAQ,UAAA;AAAA,cACpB,aAAa,OAAA,CAAQ,WAAA;AAAA,cACrB,IAAA,EAAM,CAAA;AAAA,cACN;AAAA,aACH,CAAA;AAAA,UACL;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ,CAAA,MAAO;AACH,MAAA,MAAA,CAAO,MAAM,4DAA4D,CAAA;AAAA,IAC7E;AAGA,IAAA,KAAA,CAAM,iBAAA,GAAoB,KAAA,CAAM,iBAAA,GAAoB,KAAA,CAAM,iBAAA;AAC1D,IAAA,KAAA,CAAM,gBAAA,GAAmB,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAGtC,IAAA,MAAA,CAAO,IAAA;AAAA,MACH,CAAA,+BAAA,EAAkC,KAAA,CAAM,iBAAiB,CAAA,4BAAA,EAC7C,KAAA,CAAM,iBAAiB,CAAA,UAAA,EAAa,KAAA,CAAM,iBAAiB,CAAA,KAAA,EACjE,KAAA,CAAM,gBAAgB,CAAA,EAAA;AAAA,KAChC;AAGA,IAAA,IAAI,OAAO,KAAA,EAAO;AACd,MAAA,MAAM,aAAA,GAAgB,GAAG,IAAI,CAAA,0BAAA,CAAA;AAC7B,MAAA,MAAM,SAAA,GAAY,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,aAAa,CAAA;AAEtD,MAAA,MAAMJ,SAAA,CAAQ,SAAA;AAAA,QACV,SAAA;AAAA,QACA,aAAA,CAAc;AAAA,UACV,KAAA;AAAA,UACA,cAAA,EAAgB;AAAA,YACZ,SAAS,cAAA,CAAe,OAAA;AAAA,YACxB,YAAY,cAAA,CAAe;AAAA,WAC/B;AAAA,UACA,uBAAA,EAAyB,aAAA,CAAc,GAAA,CAAI,CAAA,CAAA,MAAM;AAAA,YAC7C,YAAY,CAAA,CAAE,UAAA;AAAA,YACd,aAAa,CAAA,CAAE;AAAA,WACnB,CAAE;AAAA,SACL,CAAA;AAAA,QACD;AAAA,OACJ;AAEA,MAAA,MAAA,CAAO,KAAA,CAAM,CAAA,8BAAA,EAAiC,SAAS,CAAA,CAAE,CAAA;AAAA,IAC7D;AAEA,IAAA,OAAO;AAAA,MACH,IAAA,EAAM,UAAA;AAAA,MACN,KAAA;AAAA,MACA,gBAAA,EAAkB,MAAM,iBAAA,GAAoB;AAAA,KAChD;AAAA,EACJ,CAAA;AAEA,EAAA,OAAO;AAAA,IACH;AAAA,GACJ;AACJ;;;;"}
@@ -0,0 +1,56 @@
1
+ import { getLogger } from './index41.js';
2
+ import { create as create$3 } from './index13.js';
3
+ import { create as create$1 } from './index12.js';
4
+ import { create as create$2 } from './index52.js';
5
+ import { DEFAULT_INTERMEDIATE_DIRECTORY } from './index16.js';
6
+ import path__default from 'node:path';
7
+
8
+ const create = (config, operator) => {
9
+ const logger = getLogger();
10
+ const storage$1 = create$1({ log: logger.debug });
11
+ const dates = create$2({ timezone: config.timezone });
12
+ const media$1 = create$3(logger);
13
+ const locate = async (audioFile) => {
14
+ logger.debug("Processing file %s", audioFile);
15
+ let creationTime = await media$1.getAudioCreationTime(audioFile);
16
+ try {
17
+ if (creationTime) {
18
+ logger.info("Audio recording time: %s", creationTime.toISOString());
19
+ } else {
20
+ logger.warn("Could not determine audio recording time for %s, using current date", audioFile);
21
+ creationTime = dates.now();
22
+ }
23
+ } catch (error) {
24
+ logger.error("Error determining audio recording time for %s: %s, using current date", audioFile, error.message);
25
+ creationTime = dates.now();
26
+ }
27
+ const hash = (await storage$1.hashFile(audioFile, 100)).substring(0, 8);
28
+ const outputPath = await operator.constructOutputDirectory(creationTime);
29
+ const transcriptionFilename = await operator.constructFilename(creationTime, "transcription", hash);
30
+ const intermediateBase = DEFAULT_INTERMEDIATE_DIRECTORY;
31
+ const shortHash = hash.substring(0, 6);
32
+ const pad = (n) => n.toString().padStart(2, "0");
33
+ const timestamp = `${creationTime.getFullYear().toString().slice(2)}${pad(creationTime.getMonth() + 1)}${pad(creationTime.getDate())}-${pad(creationTime.getHours())}${pad(creationTime.getMinutes())}`;
34
+ const sessionDir = `${timestamp}-${shortHash}`;
35
+ const interimPath = path__default.join(intermediateBase, sessionDir);
36
+ await storage$1.createDirectory(interimPath);
37
+ const contextPath = path__default.join(interimPath, "context");
38
+ await storage$1.createDirectory(contextPath);
39
+ logger.debug("Intermediate files will be stored in: %s", interimPath);
40
+ return {
41
+ creationTime,
42
+ outputPath,
43
+ contextPath,
44
+ interimPath,
45
+ transcriptionFilename,
46
+ hash,
47
+ audioFile
48
+ };
49
+ };
50
+ return {
51
+ locate
52
+ };
53
+ };
54
+
55
+ export { create };
56
+ //# sourceMappingURL=index34.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index34.js","sources":["../src/phases/locate.ts"],"sourcesContent":["import * as Logging from '@/logging';\nimport * as Media from '@/util/media';\nimport * as Storage from '@/util/storage';\nimport * as Dreadcabinet from '@utilarium/dreadcabinet';\nimport * as Dates from '@/util/dates';\nimport { Config } from '@/types';\nimport { DEFAULT_INTERMEDIATE_DIRECTORY } from '@/constants';\nimport path from 'node:path';\n\n// Helper function to promisify ffmpeg.\n\nexport interface Instance {\n locate: (audioFile: string) => Promise<{\n creationTime: Date;\n outputPath: string;\n contextPath: string;\n interimPath: string;\n transcriptionFilename: string;\n hash: string;\n audioFile: string;\n }>;\n}\n\nexport const create = (config: Config, operator: Dreadcabinet.Operator): Instance => {\n const logger = Logging.getLogger();\n const storage = Storage.create({ log: logger.debug });\n const dates = Dates.create({ timezone: config.timezone });\n const media = Media.create(logger);\n\n const locate = async (audioFile: string): Promise<{\n creationTime: Date;\n outputPath: string;\n contextPath: string;\n interimPath: string;\n transcriptionFilename: string;\n hash: string;\n audioFile: string;\n }> => {\n logger.debug('Processing file %s', audioFile);\n\n // Extract audio file creation time\n let creationTime = await media.getAudioCreationTime(audioFile);\n try {\n if (creationTime) {\n logger.info('Audio recording time: %s', creationTime.toISOString());\n } else {\n logger.warn('Could not determine audio recording time for %s, using current date', audioFile);\n creationTime = dates.now();\n }\n } catch (error: any) {\n logger.error('Error determining audio recording time for %s: %s, using current date', audioFile, error.message);\n creationTime = dates.now();\n }\n\n // Calculate the hash of file and output directory\n const hash = (await storage.hashFile(audioFile, 100)).substring(0, 8);\n const outputPath: string = await operator.constructOutputDirectory(creationTime);\n const transcriptionFilename = await operator.constructFilename(creationTime, 'transcription', hash);\n \n // Use output/protokoll for intermediate files instead of polluting output directory\n // This follows the kodrdriv pattern for debugging and intermediate file management\n const intermediateBase = DEFAULT_INTERMEDIATE_DIRECTORY;\n const shortHash = hash.substring(0, 6);\n const pad = (n: number) => n.toString().padStart(2, '0');\n const timestamp = `${creationTime.getFullYear().toString().slice(2)}${pad(creationTime.getMonth() + 1)}${pad(creationTime.getDate())}-${pad(creationTime.getHours())}${pad(creationTime.getMinutes())}`;\n const sessionDir = `${timestamp}-${shortHash}`;\n \n const interimPath: string = path.join(intermediateBase, sessionDir);\n await storage.createDirectory(interimPath);\n \n const contextPath: string = path.join(interimPath, 'context');\n await storage.createDirectory(contextPath);\n \n logger.debug('Intermediate files will be stored in: %s', interimPath);\n\n return {\n creationTime,\n outputPath,\n contextPath,\n interimPath,\n transcriptionFilename,\n hash,\n audioFile,\n };\n }\n\n return {\n locate,\n }\n}\n\n\n"],"names":["Logging.getLogger","storage","Storage.create","Dates.create","media","Media.create","path"],"mappings":"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"}