@dxos/plugin-transcription 0.8.2-main.12df754 → 0.8.2-main.30e4dbb

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 (202) hide show
  1. package/dist/lib/browser/{TranscriptContainer-4D4BHE7G.mjs → TranscriptContainer-3LU3XBEB.mjs} +3 -3
  2. package/dist/lib/browser/app-graph-builder-YXELPN6F.mjs +349 -0
  3. package/dist/lib/browser/app-graph-builder-YXELPN6F.mjs.map +7 -0
  4. package/dist/lib/browser/{chunk-DR3NBV6Q.mjs → chunk-GWY2Q2NE.mjs} +105 -78
  5. package/dist/lib/browser/chunk-GWY2Q2NE.mjs.map +7 -0
  6. package/dist/lib/browser/{chunk-RHHJZQPM.mjs → chunk-HNIKXVCG.mjs} +135 -117
  7. package/dist/lib/browser/chunk-HNIKXVCG.mjs.map +7 -0
  8. package/dist/lib/browser/chunk-HRDAILQX.mjs +27 -0
  9. package/dist/lib/browser/chunk-HRDAILQX.mjs.map +7 -0
  10. package/dist/lib/browser/{chunk-5BE6RTNC.mjs → chunk-LTIQFX4W.mjs} +1 -1
  11. package/dist/lib/browser/{chunk-5BE6RTNC.mjs.map → chunk-LTIQFX4W.mjs.map} +1 -1
  12. package/dist/lib/browser/{chunk-5Q3R53U3.mjs → chunk-TGOKX32G.mjs} +21 -31
  13. package/dist/lib/browser/chunk-TGOKX32G.mjs.map +7 -0
  14. package/dist/lib/browser/index.mjs +29 -17
  15. package/dist/lib/browser/index.mjs.map +3 -3
  16. package/dist/lib/browser/{intent-resolver-ZQQEH27F.mjs → intent-resolver-BBB3DWV4.mjs} +4 -4
  17. package/dist/lib/browser/{intent-resolver-ZQQEH27F.mjs.map → intent-resolver-BBB3DWV4.mjs.map} +2 -2
  18. package/dist/lib/browser/{meeting-transcription-state-5D52VTHU.mjs → meeting-transcription-state-MNA2XROE.mjs} +2 -2
  19. package/dist/lib/browser/meta.json +1 -1
  20. package/dist/lib/browser/{react-surface-HETJ5XY6.mjs → react-surface-R277DACJ.mjs} +18 -7
  21. package/dist/lib/browser/react-surface-R277DACJ.mjs.map +7 -0
  22. package/dist/lib/browser/settings-I226DZ27.mjs +24 -0
  23. package/dist/lib/browser/settings-I226DZ27.mjs.map +7 -0
  24. package/dist/lib/browser/{transcriber-SMRLU2KY.mjs → transcriber-QRSS6X6S.mjs} +4 -4
  25. package/dist/lib/browser/types/index.mjs +3 -3
  26. package/dist/lib/node/{TranscriptContainer-ZWP6UKY6.cjs → TranscriptContainer-DICOMZLM.cjs} +8 -8
  27. package/dist/lib/node/{TranscriptContainer-ZWP6UKY6.cjs.map → TranscriptContainer-DICOMZLM.cjs.map} +2 -2
  28. package/dist/lib/node/app-graph-builder-I6LYVIYY.cjs +350 -0
  29. package/dist/lib/node/app-graph-builder-I6LYVIYY.cjs.map +7 -0
  30. package/dist/lib/node/{chunk-3QEJ5EBO.cjs → chunk-34WFY7M7.cjs} +22 -32
  31. package/dist/lib/node/chunk-34WFY7M7.cjs.map +7 -0
  32. package/dist/lib/node/{chunk-KO6MKCED.cjs → chunk-4JOJCZPJ.cjs} +138 -119
  33. package/dist/lib/node/chunk-4JOJCZPJ.cjs.map +7 -0
  34. package/dist/lib/node/{chunk-HYGDHS6X.cjs → chunk-JUGOXWES.cjs} +4 -4
  35. package/dist/lib/node/{chunk-HYGDHS6X.cjs.map → chunk-JUGOXWES.cjs.map} +1 -1
  36. package/dist/lib/node/{chunk-WXG4Z2EZ.cjs → chunk-K553L7CZ.cjs} +23 -8
  37. package/dist/lib/node/chunk-K553L7CZ.cjs.map +7 -0
  38. package/dist/lib/node/{chunk-LA73IHCB.cjs → chunk-RK4BEN5E.cjs} +108 -80
  39. package/dist/lib/node/chunk-RK4BEN5E.cjs.map +7 -0
  40. package/dist/lib/node/index.cjs +46 -34
  41. package/dist/lib/node/index.cjs.map +3 -3
  42. package/dist/lib/node/{intent-resolver-VY3XWYAA.cjs → intent-resolver-7XY3WITN.cjs} +8 -8
  43. package/dist/lib/node/{intent-resolver-VY3XWYAA.cjs.map → intent-resolver-7XY3WITN.cjs.map} +2 -2
  44. package/dist/lib/node/{meeting-transcription-state-OYWCY5XE.cjs → meeting-transcription-state-5XLTMWPA.cjs} +6 -6
  45. package/dist/lib/node/meta.json +1 -1
  46. package/dist/lib/node/{react-surface-M2JQIIDY.cjs → react-surface-HUSWAORU.cjs} +20 -11
  47. package/dist/lib/node/react-surface-HUSWAORU.cjs.map +7 -0
  48. package/dist/lib/node/settings-NDMU3EWQ.cjs +38 -0
  49. package/dist/lib/node/settings-NDMU3EWQ.cjs.map +7 -0
  50. package/dist/lib/node/{transcriber-E6AAB4SU.cjs → transcriber-UZJMG44C.cjs} +10 -10
  51. package/dist/lib/node/types/index.cjs +8 -8
  52. package/dist/lib/node/types/index.cjs.map +1 -1
  53. package/dist/lib/node-esm/{TranscriptContainer-3HJ752CP.mjs → TranscriptContainer-K4E4P5T6.mjs} +3 -3
  54. package/dist/lib/node-esm/app-graph-builder-6FY2UQOH.mjs +350 -0
  55. package/dist/lib/node-esm/app-graph-builder-6FY2UQOH.mjs.map +7 -0
  56. package/dist/lib/node-esm/chunk-3I7AC3D3.mjs +28 -0
  57. package/dist/lib/node-esm/chunk-3I7AC3D3.mjs.map +7 -0
  58. package/dist/lib/node-esm/{chunk-YXZOLOFT.mjs → chunk-5E2MR5XK.mjs} +1 -1
  59. package/dist/lib/node-esm/{chunk-YXZOLOFT.mjs.map → chunk-5E2MR5XK.mjs.map} +1 -1
  60. package/dist/lib/node-esm/{chunk-SDMGJZLN.mjs → chunk-6C34FO4C.mjs} +135 -117
  61. package/dist/lib/node-esm/chunk-6C34FO4C.mjs.map +7 -0
  62. package/dist/lib/node-esm/{chunk-K3R3YK3S.mjs → chunk-CKANLRS4.mjs} +105 -78
  63. package/dist/lib/node-esm/chunk-CKANLRS4.mjs.map +7 -0
  64. package/dist/lib/node-esm/{chunk-54HDN33F.mjs → chunk-KUQ3ZTRX.mjs} +21 -31
  65. package/dist/lib/node-esm/chunk-KUQ3ZTRX.mjs.map +7 -0
  66. package/dist/lib/node-esm/index.mjs +29 -17
  67. package/dist/lib/node-esm/index.mjs.map +3 -3
  68. package/dist/lib/node-esm/{intent-resolver-FCTNJPWY.mjs → intent-resolver-ACGAPLDZ.mjs} +4 -4
  69. package/dist/lib/node-esm/{intent-resolver-FCTNJPWY.mjs.map → intent-resolver-ACGAPLDZ.mjs.map} +2 -2
  70. package/dist/lib/node-esm/{meeting-transcription-state-XMZJ45P4.mjs → meeting-transcription-state-3WOZ52BQ.mjs} +2 -2
  71. package/dist/lib/node-esm/meta.json +1 -1
  72. package/dist/lib/node-esm/{react-surface-PXFSIM6V.mjs → react-surface-G2OY4MWL.mjs} +18 -7
  73. package/dist/lib/node-esm/react-surface-G2OY4MWL.mjs.map +7 -0
  74. package/dist/lib/node-esm/settings-O7X2UQQG.mjs +25 -0
  75. package/dist/lib/node-esm/settings-O7X2UQQG.mjs.map +7 -0
  76. package/dist/lib/node-esm/{transcriber-REAGRCPY.mjs → transcriber-NVVFH7IF.mjs} +4 -4
  77. package/dist/lib/node-esm/types/index.mjs +3 -3
  78. package/dist/types/src/TranscriptionPlugin.d.ts.map +1 -1
  79. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  80. package/dist/types/src/capabilities/capabilities.d.ts +1 -1
  81. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  82. package/dist/types/src/capabilities/index.d.ts +1 -0
  83. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  84. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  85. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  86. package/dist/types/src/capabilities/settings.d.ts +4 -0
  87. package/dist/types/src/capabilities/settings.d.ts.map +1 -0
  88. package/dist/types/src/components/Transcript/Transcript.d.ts +6 -4
  89. package/dist/types/src/components/Transcript/Transcript.d.ts.map +1 -1
  90. package/dist/types/src/components/Transcript/Transcript.stories.d.ts +8 -4
  91. package/dist/types/src/components/Transcript/Transcript.stories.d.ts.map +1 -1
  92. package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts +27 -0
  93. package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts.map +1 -0
  94. package/dist/types/src/components/Transcript/transcript-extension.d.ts +4 -4
  95. package/dist/types/src/components/Transcript/transcript-extension.d.ts.map +1 -1
  96. package/dist/types/src/components/TranscriptContainer.d.ts.map +1 -1
  97. package/dist/types/src/components/TranscriptionSettings/TranscriptionSettings.d.ts +6 -0
  98. package/dist/types/src/components/TranscriptionSettings/TranscriptionSettings.d.ts.map +1 -0
  99. package/dist/types/src/components/TranscriptionSettings/index.d.ts +2 -0
  100. package/dist/types/src/components/TranscriptionSettings/index.d.ts.map +1 -0
  101. package/dist/types/src/components/index.d.ts +1 -0
  102. package/dist/types/src/components/index.d.ts.map +1 -1
  103. package/dist/types/src/components/transcription.stories.d.ts +6 -3
  104. package/dist/types/src/components/transcription.stories.d.ts.map +1 -1
  105. package/dist/types/src/entity-extraction/entity-extraction.d.ts +33 -7
  106. package/dist/types/src/entity-extraction/entity-extraction.d.ts.map +1 -1
  107. package/dist/types/src/hooks/useAudioFile.d.ts.map +1 -1
  108. package/dist/types/src/hooks/useAudioTrack.d.ts.map +1 -1
  109. package/dist/types/src/hooks/useQueueModelAdapter.d.ts +2 -2
  110. package/dist/types/src/hooks/useQueueModelAdapter.d.ts.map +1 -1
  111. package/dist/types/src/hooks/useTranscriber.d.ts.map +1 -1
  112. package/dist/types/src/hooks/useVoiceInput.d.ts.map +1 -1
  113. package/dist/types/src/model/model.d.ts +23 -23
  114. package/dist/types/src/model/model.d.ts.map +1 -1
  115. package/dist/types/src/testing/index.d.ts +2 -0
  116. package/dist/types/src/testing/index.d.ts.map +1 -0
  117. package/dist/types/src/testing/testing.d.ts +40 -0
  118. package/dist/types/src/testing/testing.d.ts.map +1 -0
  119. package/dist/types/src/transcriber/transcriber.d.ts +2 -2
  120. package/dist/types/src/transcriber/transcriber.d.ts.map +1 -1
  121. package/dist/types/src/transcriber/transcription-manager.d.ts +17 -15
  122. package/dist/types/src/transcriber/transcription-manager.d.ts.map +1 -1
  123. package/dist/types/src/translations.d.ts +3 -18
  124. package/dist/types/src/translations.d.ts.map +1 -1
  125. package/dist/types/src/types/schema.d.ts +26 -40
  126. package/dist/types/src/types/schema.d.ts.map +1 -1
  127. package/dist/types/src/types/types.d.ts +11 -7
  128. package/dist/types/src/types/types.d.ts.map +1 -1
  129. package/dist/types/src/util/array.d.ts.map +1 -1
  130. package/dist/types/src/util/get-time-str.d.ts.map +1 -1
  131. package/dist/types/src/util/monitor-audio-level.d.ts.map +1 -1
  132. package/dist/types/tsconfig.tsbuildinfo +1 -1
  133. package/package.json +51 -46
  134. package/src/TranscriptionPlugin.tsx +29 -12
  135. package/src/capabilities/app-graph-builder.ts +99 -29
  136. package/src/capabilities/capabilities.ts +1 -1
  137. package/src/capabilities/index.ts +1 -0
  138. package/src/capabilities/intent-resolver.ts +2 -2
  139. package/src/capabilities/react-surface.tsx +12 -4
  140. package/src/capabilities/settings.ts +20 -0
  141. package/src/components/Transcript/Transcript.stories.tsx +72 -36
  142. package/src/components/Transcript/Transcript.tsx +37 -30
  143. package/src/components/Transcript/deprecated/{Transcript.tsx → OldTranscript.tsx} +30 -1
  144. package/src/components/Transcript/transcript-extension.ts +20 -17
  145. package/src/components/TranscriptContainer.tsx +6 -4
  146. package/src/components/TranscriptionSettings/TranscriptionSettings.tsx +26 -0
  147. package/src/components/TranscriptionSettings/index.ts +5 -0
  148. package/src/components/index.ts +1 -0
  149. package/src/components/transcription.stories.tsx +84 -34
  150. package/src/entity-extraction/entity-extraction.test.ts +75 -10
  151. package/src/entity-extraction/entity-extraction.ts +110 -55
  152. package/src/entity-extraction/system-prompt.tpl +38 -9
  153. package/src/hooks/useQueueModelAdapter.ts +44 -11
  154. package/src/model/model.test.ts +90 -44
  155. package/src/model/model.ts +59 -59
  156. package/src/testing/index.ts +5 -0
  157. package/src/testing/testing.ts +221 -0
  158. package/src/transcriber/transcriber.browser.test.ts +3 -3
  159. package/src/transcriber/transcriber.ts +19 -10
  160. package/src/transcriber/transcription-manager.ts +66 -57
  161. package/src/translations.ts +2 -0
  162. package/src/types/schema.ts +10 -31
  163. package/src/types/types.ts +17 -7
  164. package/dist/lib/browser/app-graph-builder-I4SSIQMW.mjs +0 -168
  165. package/dist/lib/browser/app-graph-builder-I4SSIQMW.mjs.map +0 -7
  166. package/dist/lib/browser/chunk-5Q3R53U3.mjs.map +0 -7
  167. package/dist/lib/browser/chunk-DR3NBV6Q.mjs.map +0 -7
  168. package/dist/lib/browser/chunk-GI5LZ4SV.mjs +0 -8
  169. package/dist/lib/browser/chunk-GI5LZ4SV.mjs.map +0 -7
  170. package/dist/lib/browser/chunk-RHHJZQPM.mjs.map +0 -7
  171. package/dist/lib/browser/react-surface-HETJ5XY6.mjs.map +0 -7
  172. package/dist/lib/node/app-graph-builder-WWC4WNTG.cjs +0 -177
  173. package/dist/lib/node/app-graph-builder-WWC4WNTG.cjs.map +0 -7
  174. package/dist/lib/node/chunk-3QEJ5EBO.cjs.map +0 -7
  175. package/dist/lib/node/chunk-KO6MKCED.cjs.map +0 -7
  176. package/dist/lib/node/chunk-LA73IHCB.cjs.map +0 -7
  177. package/dist/lib/node/chunk-WXG4Z2EZ.cjs.map +0 -7
  178. package/dist/lib/node/react-surface-M2JQIIDY.cjs.map +0 -7
  179. package/dist/lib/node-esm/app-graph-builder-PPJQAFSI.mjs +0 -169
  180. package/dist/lib/node-esm/app-graph-builder-PPJQAFSI.mjs.map +0 -7
  181. package/dist/lib/node-esm/chunk-54HDN33F.mjs.map +0 -7
  182. package/dist/lib/node-esm/chunk-K3R3YK3S.mjs.map +0 -7
  183. package/dist/lib/node-esm/chunk-SDMGJZLN.mjs.map +0 -7
  184. package/dist/lib/node-esm/chunk-XY22OP6H.mjs +0 -10
  185. package/dist/lib/node-esm/chunk-XY22OP6H.mjs.map +0 -7
  186. package/dist/lib/node-esm/react-surface-PXFSIM6V.mjs.map +0 -7
  187. package/dist/types/src/components/Transcript/deprecated/Transcript.d.ts +0 -13
  188. package/dist/types/src/components/Transcript/deprecated/Transcript.d.ts.map +0 -1
  189. package/dist/types/src/components/Transcript/testings.d.ts +0 -51
  190. package/dist/types/src/components/Transcript/testings.d.ts.map +0 -1
  191. package/dist/types/src/testing/test-data.d.ts +0 -73
  192. package/dist/types/src/testing/test-data.d.ts.map +0 -1
  193. package/src/components/Transcript/testings.ts +0 -182
  194. package/src/testing/test-data.ts +0 -314
  195. /package/dist/lib/browser/{TranscriptContainer-4D4BHE7G.mjs.map → TranscriptContainer-3LU3XBEB.mjs.map} +0 -0
  196. /package/dist/lib/browser/{meeting-transcription-state-5D52VTHU.mjs.map → meeting-transcription-state-MNA2XROE.mjs.map} +0 -0
  197. /package/dist/lib/browser/{transcriber-SMRLU2KY.mjs.map → transcriber-QRSS6X6S.mjs.map} +0 -0
  198. /package/dist/lib/node/{meeting-transcription-state-OYWCY5XE.cjs.map → meeting-transcription-state-5XLTMWPA.cjs.map} +0 -0
  199. /package/dist/lib/node/{transcriber-E6AAB4SU.cjs.map → transcriber-UZJMG44C.cjs.map} +0 -0
  200. /package/dist/lib/node-esm/{TranscriptContainer-3HJ752CP.mjs.map → TranscriptContainer-K4E4P5T6.mjs.map} +0 -0
  201. /package/dist/lib/node-esm/{meeting-transcription-state-XMZJ45P4.mjs.map → meeting-transcription-state-3WOZ52BQ.mjs.map} +0 -0
  202. /package/dist/lib/node-esm/{transcriber-REAGRCPY.mjs.map → transcriber-NVVFH7IF.mjs.map} +0 -0
@@ -7,23 +7,39 @@ import { Schema } from 'effect';
7
7
  import { createTemplate, Message, structuredOutputParser } from '@dxos/artifact';
8
8
  import type { AIServiceClient } from '@dxos/assistant';
9
9
  import { MixedStreamParser } from '@dxos/assistant';
10
- import { raise } from '@dxos/debug';
11
- import { create } from '@dxos/echo-schema';
12
- import type { BaseEchoObject } from '@dxos/echo-schema';
10
+ import { asyncTimeout } from '@dxos/async';
11
+ import { type BaseEchoObject, create, ObjectId } from '@dxos/echo-schema';
12
+ import { DXN } from '@dxos/keys';
13
+ import { log } from '@dxos/log';
14
+ import { DataType } from '@dxos/schema';
13
15
 
14
16
  import SYSTEM_PROMPT from './system-prompt.tpl?raw';
15
- import type { TranscriptBlock } from '../types';
16
17
 
17
- type ProcessTranscriptBlockParams = {
18
- block: TranscriptBlock;
18
+ type ProcessTranscriptMessageParams = {
19
+ message: DataType.Message;
19
20
  aiService: AIServiceClient;
20
21
  context: {
21
22
  objects?: BaseEchoObject[];
22
23
  };
24
+
25
+ options?: {
26
+ /**
27
+ * Timeout for the entity extraction.
28
+ */
29
+ timeout?: number;
30
+
31
+ /**
32
+ * Fallback to raw text if the entity extraction fails.
33
+ * Otherwise the function will throw an error.
34
+ * @default false
35
+ */
36
+ fallbackToRaw?: boolean;
37
+ };
23
38
  };
24
39
 
25
- type ProcessTranscriptBlockResult = {
26
- block: TranscriptBlock;
40
+ type ProcessTranscriptMessageResult = {
41
+ message: DataType.Message;
42
+ timeElapsed: number;
27
43
  };
28
44
 
29
45
  /**
@@ -34,61 +50,100 @@ const createSystemPrompt = (): string => {
34
50
  return template({});
35
51
  };
36
52
 
37
- export const processTranscriptBlock = async (
38
- params: ProcessTranscriptBlockParams,
39
- ): Promise<ProcessTranscriptBlockResult> => {
40
- // TODO(dmaretskyi): Move context to a vector search index.
41
- const systemPrompt = `
42
- ${createSystemPrompt()}
43
- Context:
44
- ${JSON.stringify(params.context.objects)}
45
- `;
46
-
47
- const outputParser = structuredOutputParser(
53
+ const ReferencedQuotes = Schema.Struct({
54
+ references: Schema.Array(
48
55
  Schema.Struct({
49
- segments: Schema.Array(Schema.String).annotations({
50
- description: 'The enhanced text of the transcript segments, keep the order and structure exactly as is',
51
- }),
56
+ quote: Schema.String,
57
+ id: Schema.String,
52
58
  }),
53
- );
54
- const result = outputParser.getResult(
55
- await new MixedStreamParser().parse(
56
- await params.aiService.execStream({
57
- model: '@anthropic/claude-3-5-haiku-20241022',
58
- systemPrompt,
59
- history: [
60
- create(Message, {
61
- role: 'user',
62
- content: [
63
- {
64
- type: 'text',
65
- text: JSON.stringify(params.block),
66
- },
59
+ ).annotations({
60
+ description:
61
+ 'The references to the context objects that are mentioned in the transcript. quote should match the original transcript text exactly, while id is the id of the context object.',
62
+ }),
63
+ });
64
+ interface ReferencedQuotes extends Schema.Schema.Type<typeof ReferencedQuotes> {}
65
+
66
+ // TODO(dmaretskyi): Move context to a vector search index.
67
+ export const processTranscriptMessage = async (
68
+ params: ProcessTranscriptMessageParams,
69
+ ): Promise<ProcessTranscriptMessageResult> => {
70
+ try {
71
+ const outputParser = structuredOutputParser(ReferencedQuotes);
72
+ const runParser = async (): Promise<ProcessTranscriptMessageResult> => {
73
+ const startTime = performance.now();
74
+ const result = outputParser.getResult(
75
+ await new MixedStreamParser().parse(
76
+ await params.aiService.execStream({
77
+ model: '@anthropic/claude-3-5-haiku-20241022',
78
+ systemPrompt: createSystemPrompt(),
79
+ history: [
80
+ create(Message, {
81
+ role: 'user',
82
+ content: [
83
+ {
84
+ type: 'text',
85
+ text: `<context>${JSON.stringify(params.context.objects)}</context>`,
86
+ },
87
+ {
88
+ type: 'text',
89
+ text: `<transcript>${JSON.stringify(params.message.blocks)}</transcript>`,
90
+ },
91
+ ],
92
+ }),
67
93
  ],
94
+ tools: [outputParser.tool],
68
95
  }),
69
- ],
70
- tools: [outputParser.tool],
71
- }),
72
- ),
73
- );
96
+ ),
97
+ );
98
+ log.info('entity extraction result', { refs: result.references });
74
99
 
75
- return {
76
- block: {
77
- ...params.block,
78
- segments: params.block.segments.map((segment, i) => ({
79
- ...segment,
80
- text: postprocessText(result?.segments[i] ?? raise(new Error('failed to process email'))),
81
- })),
82
- },
83
- };
100
+ return {
101
+ message: create(DataType.Message, {
102
+ ...params.message,
103
+ blocks: params.message.blocks.map((block, i) =>
104
+ block.type !== 'transcription'
105
+ ? block
106
+ : {
107
+ ...block,
108
+ text: postprocessText(block.text, result),
109
+ },
110
+ ),
111
+ }),
112
+ timeElapsed: performance.now() - startTime,
113
+ };
114
+ };
115
+
116
+ if (params.options?.timeout && params.options.timeout > 0) {
117
+ return await asyncTimeout(runParser(), params.options.timeout);
118
+ } else {
119
+ return await runParser();
120
+ }
121
+ } catch (error) {
122
+ if (params.options?.fallbackToRaw) {
123
+ log.warn('failed to process transcript message, falling back to raw text', { error });
124
+ return {
125
+ message: params.message,
126
+ timeElapsed: 0,
127
+ };
128
+ } else {
129
+ throw error;
130
+ }
131
+ }
84
132
  };
85
133
 
86
134
  /**
87
- * Finds and replaces all inline references with DXNs references.
135
+ * Finds and replaces all quotes with DXNs references.
88
136
  */
89
137
  // TODO(dmaretskyi): Lookup and verifiy ids from provided context.
90
- const postprocessText = (text: string) => {
91
- return text.replace(/\n/g, ' ').replace(/\[([^\]]+)\]\[([A-Z0-9]+)\]/g, (match, name, id) => {
92
- return `[${name}][dxn:echo:@:${id}]`;
93
- });
138
+ export const postprocessText = (text: string, quotes: ReferencedQuotes) => {
139
+ for (const quote of quotes.references) {
140
+ if (!ObjectId.isValid(quote.id)) {
141
+ continue;
142
+ }
143
+
144
+ // Use a case-insensitive regular expression to replace the quote
145
+ const regex = new RegExp(quote.quote.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
146
+ text = text.replace(regex, `[${quote.quote}][${DXN.fromLocalObjectId(quote.id).toString()}]`);
147
+ }
148
+ return text;
94
149
  };
@@ -1,9 +1,38 @@
1
- You are a helpful assistant that processes transcripts.
2
- Your goal is to enhance the transcript with entity references.
3
- Insert inline references to the entities in the transcript.
4
- Keep the transcript structure and text as is.
5
- Call the submit_result tool to submit your result.
6
-
7
- The inline reference syntax is as follows:
8
- - [<optional name>][<ID>] or just [<ID>]
9
- - Example: [Earnings Report][01JT0JP9AX0XKGZX4MV4B69VT6]
1
+ You are an AI assistant specialized in processing and enhancing transcripts with contextual information.
2
+ Your task is to analyze a given transcript and extract references to the context objects.
3
+
4
+ The context and transcript are provided in the user message in `context` and `transcript` XML tags.
5
+
6
+ Here are your instructions:
7
+
8
+ 1. Read the transcript and context information provided above.
9
+
10
+ 2. Process each segment of the transcript separately.
11
+
12
+ 3. For each segment:
13
+ a. Analyze the content and identify relevant information from the context.
14
+ b. Extract a number of references to the context objects that are mentioned in the segment.
15
+ c. Output the references in the format `{ "quote": "earnings report", "id": "01JT0JP9AX0XKGZX4MV4B69VT6" }`.
16
+ d. If there are no references, just output an empty array.
17
+
18
+ 4. Maintain the exact order and structure of the original transcript segments.
19
+
20
+ Output Format:
21
+ The final output should be a JSON array of references.
22
+
23
+ Example output structure:
24
+ ```json
25
+ {
26
+ "references": [
27
+ { "quote": "earnings report", "id": "01JT0JP9AX0XKGZX4MV4B69VT6" },
28
+ { "quote": "John", "id": "01JT0VM0VN3ZKN7GDBM8CV9BA7" }
29
+ ]
30
+ }
31
+ ```
32
+
33
+ Remember:
34
+ - Only quote the text that is in the transcript.
35
+ - Analyze each segment carefully before processing it.
36
+ - Only reference objects that appear in the context and exactly by their id, If the object is not in the context, do not insert a reference.
37
+
38
+ Now, process the transcript and context provided below according to these instructions.
@@ -2,29 +2,62 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { useMemo, useEffect } from 'react';
5
+ import { useMemo, useEffect, useState } from 'react';
6
6
 
7
7
  import { type Queue } from '@dxos/react-client/echo';
8
8
 
9
- import { type Block, BlockModel, type BlockRenderer } from '../model';
9
+ import { type Chunk, type ChunkRenderer, SerializationModel } from '../model';
10
10
 
11
11
  /**
12
12
  * Model adapter for a queue.
13
13
  */
14
- export const useQueueModelAdapter = <T extends Block>(
15
- renderer: BlockRenderer<T>,
14
+ export const useQueueModelAdapter = <T extends Chunk>(
15
+ renderer: ChunkRenderer<T>,
16
16
  queue: Queue<T> | undefined,
17
- initialBlocks: T[] = [],
18
- ): BlockModel<T> => {
19
- const model = useMemo(() => new BlockModel<T>(renderer, initialBlocks), [queue]);
17
+ initialChunks: T[] = [],
18
+ ): SerializationModel<T> => {
19
+ const model = useMemo(() => new SerializationModel<T>(renderer, initialChunks), [queue]);
20
+ const [loaded, setLoaded] = useState(false);
21
+
22
+ // Set initial blocks.
23
+ useEffect(() => {
24
+ if (!queue) {
25
+ return;
26
+ }
27
+
28
+ const update = () => {
29
+ for (const block of queue?.items ?? []) {
30
+ model.appendChunk(block);
31
+ }
32
+
33
+ setLoaded(true);
34
+ };
35
+
36
+ // TODO(burdon): This is a hack to ensure the queue is loaded.
37
+ let i: NodeJS.Timeout | undefined;
38
+ if (queue.isLoading) {
39
+ i = setInterval(() => {
40
+ if (!queue?.isLoading) {
41
+ clearInterval(i);
42
+ update();
43
+ }
44
+ }, 1_000);
45
+ } else {
46
+ update();
47
+ }
48
+
49
+ return () => clearTimeout(i);
50
+ }, [model, queue]);
51
+
52
+ // TODO(burdon): Can we listen for queue events?
20
53
  useEffect(() => {
21
- if (!queue?.items.length) {
54
+ if (!loaded || !queue || model.chunks.length === queue.items.length) {
22
55
  return;
23
56
  }
24
57
 
25
- const block = queue.items[queue.items.length - 1];
26
- model.appendBlock(block);
27
- }, [model, queue?.items.length]);
58
+ const chunk = queue.items[queue.items.length - 1];
59
+ model.appendChunk(chunk);
60
+ }, [model, loaded, queue?.items.length]);
28
61
 
29
62
  return model;
30
63
  };
@@ -5,71 +5,101 @@
5
5
  import { EditorView } from '@codemirror/view';
6
6
  import { describe, test } from 'vitest';
7
7
 
8
- import { BlockModel, DocumentAdapter, type BlockRenderer } from './model';
9
- import { type TranscriptBlock } from '../types';
10
-
11
- const blockToMarkdown: BlockRenderer<TranscriptBlock> = (block: TranscriptBlock, debug = true): string[] => {
12
- return [`###### ${block.authorName}`, ...block.segments.map((segment) => segment.text), ''];
8
+ import { type DataType } from '@dxos/schema';
9
+
10
+ import { SerializationModel, DocumentAdapter, type ChunkRenderer } from './model';
11
+
12
+ const blockToMarkdown: ChunkRenderer<DataType.Message> = (
13
+ message: DataType.Message,
14
+ index: number,
15
+ debug = true,
16
+ ): string[] => {
17
+ return [
18
+ `###### ${message.sender.name}`,
19
+ ...message.blocks.filter((block) => block.type === 'transcription').map((block) => block.text),
20
+ '',
21
+ ];
13
22
  };
14
23
 
15
24
  const createDate = () => new Date().toISOString();
16
25
 
17
- describe('BlockModel', () => {
26
+ describe('SerializationModel', () => {
18
27
  test('basic', ({ expect }) => {
19
- const model = new BlockModel<TranscriptBlock>(blockToMarkdown);
20
- expect(model.blocks.length).to.eq(0);
28
+ const model = new SerializationModel<DataType.Message>(blockToMarkdown);
29
+ expect(model.chunks.length).to.eq(0);
21
30
  expect(model.doc.toString()).to.eq('');
22
31
 
23
- // Create block.
24
- const block = {
32
+ // Create message.
33
+ const message: DataType.Message = {
25
34
  id: '1',
26
- authorName: 'Alice',
27
- segments: [{ started: createDate(), text: 'Hello world!' }],
35
+ created: createDate(),
36
+ sender: { name: 'Alice' },
37
+ blocks: [
38
+ {
39
+ type: 'transcription',
40
+ started: createDate(),
41
+ text: 'Hello world!',
42
+ },
43
+ ],
28
44
  };
29
- model.appendBlock(block);
45
+ model.appendChunk(message);
30
46
  {
31
47
  const text = model.doc.toString();
32
48
  expect(text).to.eq('###### Alice\nHello world!\n\n');
33
- expect(model.blocks.length).to.eq(1);
49
+ expect(model.chunks.length).to.eq(1);
34
50
  }
35
51
 
36
- // Update block.
37
- block.segments.push({ started: new Date().toISOString(), text: 'Hello again!' });
38
- model.updateBlock(block);
52
+ // Update message.
53
+ message.blocks.push({ type: 'transcription', started: createDate(), text: 'Hello again!' });
54
+ model.updateChunk(message);
39
55
  {
40
56
  const text = model.doc.toString();
41
57
  expect(text).to.eq('###### Alice\nHello world!\nHello again!\n\n');
42
- expect(model.blocks.length).to.eq(1);
58
+ expect(model.chunks.length).to.eq(1);
43
59
  }
44
60
  });
45
61
 
46
62
  test('sync - append', ({ expect }) => {
47
63
  const view = new EditorView({ extensions: [], doc: '' });
48
- const model = new BlockModel<TranscriptBlock>(blockToMarkdown);
64
+ const model = new SerializationModel<DataType.Message>(blockToMarkdown);
49
65
  const adapter = new DocumentAdapter(view);
50
66
  expect(adapter.lineCount()).to.eq(0);
51
67
  expect(view.state.doc.toString()).to.eq('');
52
68
 
53
- // Append block.
69
+ // Append message.
54
70
  {
55
- const block = {
71
+ const message: DataType.Message = {
56
72
  id: '1',
57
- authorName: 'Alice',
58
- segments: [{ started: createDate(), text: 'Hello world!' }],
73
+ created: createDate(),
74
+ sender: { name: 'Alice' },
75
+ blocks: [
76
+ {
77
+ type: 'transcription',
78
+ started: createDate(),
79
+ text: 'Hello world!',
80
+ },
81
+ ],
59
82
  };
60
- model.appendBlock(block);
83
+ model.appendChunk(message);
61
84
  model.sync(adapter);
62
85
  expect(view.state.doc.toString()).to.eq('###### Alice\nHello world!\n\n');
63
86
  }
64
87
 
65
- // Append block.
88
+ // Append message.
66
89
  {
67
- const block = {
90
+ const message: DataType.Message = {
68
91
  id: '2',
69
- authorName: 'Bob',
70
- segments: [{ started: createDate(), text: 'Hello world!' }],
92
+ created: createDate(),
93
+ sender: { name: 'Bob' },
94
+ blocks: [
95
+ {
96
+ type: 'transcription',
97
+ started: createDate(),
98
+ text: 'Hello world!',
99
+ },
100
+ ],
71
101
  };
72
- model.appendBlock(block);
102
+ model.appendChunk(message);
73
103
  model.sync(adapter);
74
104
  expect(view.state.doc.toString()).to.eq('###### Alice\nHello world!\n\n###### Bob\nHello world!\n\n');
75
105
  }
@@ -77,40 +107,56 @@ describe('BlockModel', () => {
77
107
 
78
108
  test('sync - append, update, delete', ({ expect }) => {
79
109
  const view = new EditorView({ extensions: [], doc: '' });
80
- const model = new BlockModel<TranscriptBlock>(blockToMarkdown);
110
+ const model = new SerializationModel<DataType.Message>(blockToMarkdown);
81
111
  const adapter = new DocumentAdapter(view);
82
112
  expect(adapter.lineCount()).to.eq(0);
83
113
 
84
- // Append block.
114
+ // Append message.
85
115
  {
86
- const block = { id: '1', authorName: 'Alice', segments: [{ started: createDate(), text: 'Hello world!' }] };
87
- model.appendBlock(block);
116
+ const message: DataType.Message = {
117
+ id: '1',
118
+ created: createDate(),
119
+ sender: { name: 'Alice' },
120
+ blocks: [
121
+ {
122
+ type: 'transcription',
123
+ started: createDate(),
124
+ text: 'Hello world!',
125
+ },
126
+ ],
127
+ };
128
+ model.appendChunk(message);
88
129
  model.sync(adapter);
89
130
  expect(view.state.doc.toString()).to.eq('###### Alice\nHello world!\n\n');
90
131
 
91
- // Update block (add segment).
92
- block.segments.push({ started: createDate(), text: 'Hello again!' });
93
- model.updateBlock(block);
132
+ // Update message (add block).
133
+ message.blocks.push({ type: 'transcription', started: createDate(), text: 'Hello again!' });
134
+ model.updateChunk(message);
94
135
  model.sync(adapter);
95
136
  expect(view.state.doc.toString()).to.eq('###### Alice\nHello world!\nHello again!\n\n');
96
137
 
97
- // Update block (remove segment).
98
- block.segments.splice(0, 1);
99
- model.updateBlock(block);
138
+ // Update message (remove block).
139
+ message.blocks.splice(0, 1);
140
+ model.updateChunk(message);
100
141
  model.sync(adapter);
101
142
  expect(view.state.doc.toString()).to.eq('###### Alice\nHello again!\n\n');
102
143
 
103
- expect(model.getBlockAtLine(1)).to.eq(block);
144
+ expect(model.getChunkAtLine(1)).to.eq(message);
104
145
  }
105
146
 
106
- // Append block.
147
+ // Append message.
107
148
  {
108
- const block = { id: '2', authorName: 'Bob', segments: [{ started: createDate(), text: 'Hello again!' }] };
109
- model.appendBlock(block);
149
+ const message: DataType.Message = {
150
+ id: '2',
151
+ created: createDate(),
152
+ sender: { name: 'Bob' },
153
+ blocks: [{ type: 'transcription', started: createDate(), text: 'Hello again!' }],
154
+ };
155
+ model.appendChunk(message);
110
156
  model.sync(adapter);
111
157
  expect(view.state.doc.toString()).to.eq('###### Alice\nHello again!\n\n###### Bob\nHello again!\n\n');
112
158
 
113
- expect(model.getBlockAtLine(4)).to.eq(block);
159
+ expect(model.getChunkAtLine(4)).to.eq(message);
114
160
  }
115
161
 
116
162
  // Delete block.