deepadata-edm-sdk 0.6.0-alpha

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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +240 -0
  3. package/dist/assembler.d.ts +37 -0
  4. package/dist/assembler.d.ts.map +1 -0
  5. package/dist/assembler.js +204 -0
  6. package/dist/assembler.js.map +1 -0
  7. package/dist/extractors/domain-extractors.d.ts +8 -0
  8. package/dist/extractors/domain-extractors.d.ts.map +1 -0
  9. package/dist/extractors/domain-extractors.js +173 -0
  10. package/dist/extractors/domain-extractors.js.map +1 -0
  11. package/dist/extractors/image-analyzer.d.ts +38 -0
  12. package/dist/extractors/image-analyzer.d.ts.map +1 -0
  13. package/dist/extractors/image-analyzer.js +101 -0
  14. package/dist/extractors/image-analyzer.js.map +1 -0
  15. package/dist/extractors/kimi-extractor.d.ts +22 -0
  16. package/dist/extractors/kimi-extractor.d.ts.map +1 -0
  17. package/dist/extractors/kimi-extractor.js +137 -0
  18. package/dist/extractors/kimi-extractor.js.map +1 -0
  19. package/dist/extractors/llm-extractor.d.ts +43 -0
  20. package/dist/extractors/llm-extractor.d.ts.map +1 -0
  21. package/dist/extractors/llm-extractor.js +295 -0
  22. package/dist/extractors/llm-extractor.js.map +1 -0
  23. package/dist/extractors/openai-extractor.d.ts +17 -0
  24. package/dist/extractors/openai-extractor.d.ts.map +1 -0
  25. package/dist/extractors/openai-extractor.js +97 -0
  26. package/dist/extractors/openai-extractor.js.map +1 -0
  27. package/dist/extractors/profile-prompts.d.ts +32 -0
  28. package/dist/extractors/profile-prompts.d.ts.map +1 -0
  29. package/dist/extractors/profile-prompts.js +283 -0
  30. package/dist/extractors/profile-prompts.js.map +1 -0
  31. package/dist/index.d.ts +38 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +59 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/schema/edm-schema.d.ts +1645 -0
  36. package/dist/schema/edm-schema.d.ts.map +1 -0
  37. package/dist/schema/edm-schema.js +345 -0
  38. package/dist/schema/edm-schema.js.map +1 -0
  39. package/dist/schema/types.d.ts +94 -0
  40. package/dist/schema/types.d.ts.map +1 -0
  41. package/dist/schema/types.js +79 -0
  42. package/dist/schema/types.js.map +1 -0
  43. package/dist/stateless.d.ts +28 -0
  44. package/dist/stateless.d.ts.map +1 -0
  45. package/dist/stateless.js +100 -0
  46. package/dist/stateless.js.map +1 -0
  47. package/dist/validator.d.ts +24 -0
  48. package/dist/validator.d.ts.map +1 -0
  49. package/dist/validator.js +154 -0
  50. package/dist/validator.js.map +1 -0
  51. package/package.json +59 -0
@@ -0,0 +1,295 @@
1
+ /**
2
+ * LLM Extractor for EDM v0.6.0
3
+ * Uses Anthropic Claude to extract emotional data from content
4
+ * Supports profile-aware extraction (core/extended/full)
5
+ */
6
+ import Anthropic from "@anthropic-ai/sdk";
7
+ import { LlmExtractedFieldsSchema } from "../schema/edm-schema.js";
8
+ import { getProfilePrompt, calculateProfileConfidence } from "./profile-prompts.js";
9
+ /**
10
+ * System prompt for EDM extraction - Updated for v0.4.0 canonical schema
11
+ * Reconciled field names from system-prompt-B.ts:
12
+ * - archetype_energy → narrative_archetype
13
+ * - meaning_inference → expressed_insight
14
+ * - transcendent_moment → transformational_pivot
15
+ * - REMOVED: active_motivational_state, media_context, memory_layers, tether_target, moral_valence
16
+ * - reentry_score → recurrence_pattern (type changed: number → enum)
17
+ * - ADDED: somatic_signature
18
+ */
19
+ export const EXTRACTION_SYSTEM_PROMPT = `
20
+ You classify emotionally rich memories into a JSON object. Input may include text and an image.
21
+
22
+ Rules
23
+ - Fuse text + image. Treat text as primary; use image only to add grounded specifics (place, event, symbols, people).
24
+ - Keep fields to single words or short phrases (1–3 words). Only "narrative" is multi-sentence (3–5).
25
+ - No invention. If not supported by input, use null.
26
+ - Always include every top-level key and sub-key from the schema, even if the value is null or an empty array.
27
+ - Do not omit fields; if unknown, return null.
28
+ - Output JSON only — no commentary, markdown, or extra text.
29
+ - If motivation is ambiguous, choose the most conservative option (e.g., "curiosity" vs "fear") or return null.
30
+
31
+ CRITICAL: Enum Field Constraints
32
+ - Many fields below are STRICT ENUMS with a fixed set of allowed values.
33
+ - You MUST use ONLY the values listed in the enum sets. Do not invent similar values.
34
+ - Cross-contamination warning: Each enum field has its own distinct value set. Do not use values from one field in another.
35
+ Example: "milestone" is valid for memory_type but NOT for narrative_arc.
36
+ Example: "confront" is valid for both drive_state and coping_style - check which field you're populating.
37
+ - If none of the allowed enum values adequately capture the expressed content, use the closest match. Do not invent alternatives.
38
+
39
+ Normalization (very important)
40
+ - Emit lowercase for all string fields except proper names in arrays like associated_people.
41
+ - For array fields (emotion_subtone, recall_triggers, retrieval_keys, nearby_themes, resilience_markers, associated_people):
42
+ • use short tokens/phrases without punctuation;
43
+ • avoid duplicates;
44
+ • prefer singular nouns where reasonable ("tradition" not "traditions").
45
+ - Never put boolean-like strings ("true"/"false") into fields that are boolean; use real booleans.
46
+
47
+ Schema
48
+ {
49
+ "core": {
50
+ "anchor": "", // central theme (e.g., "dad's toolbox", "nana's traditions")
51
+ "spark": "", // what triggered the memory (e.g., "finding the cassette", "first snow")
52
+ "wound": "", // The specific vulnerability, loss, or pain present — NOT generic labels like 'loss' or 'grief' but what exactly was lost or why it hurts. Examples: 'unlived travel dream', 'war silence never spoken', 'father died before I knew him', 'shame of not fitting in'. If no wound is present, use null.
53
+ "fuel": "", // what energized the experience (e.g., "shared laughter", "curiosity")
54
+ "bridge": "", // connection between past and present (e.g., "replaying old tape", "returning to the porch")
55
+ "echo": "", // what still resonates (e.g., "her laugh", "smell of oil", "city lights on water")
56
+ "narrative": "" // 3–5 sentences; include ≥1 sensory detail, ≥1 temporal cue, and a symbolic callback; faithful and concise
57
+ },
58
+ "constellation": {
59
+ "emotion_primary": "", // STRICT ENUM: joy | sadness | fear | anger | wonder | peace | tenderness | reverence | pride | anxiety | gratitude | longing | hope (pick best-fit from these 13 ONLY)
60
+ "emotion_subtone": [], // 2–4 short words (e.g., bittersweet, grateful) — free text array
61
+ "higher_order_emotion": "", // free text: e.g., awe, forgiveness, pride, moral_elevation (or null)
62
+ "meta_emotional_state": "", // free text: e.g., acceptance, confusion, curiosity (or null)
63
+ "interpersonal_affect": "", // free text: e.g., warmth, openness, defensiveness (or null)
64
+ "narrative_arc": "", // STRICT ENUM: overcoming | transformation | connection | reflection | closure (pick ONE or null)
65
+ "relational_dynamics": "", // STRICT ENUM: parent_child | romantic_partnership | sibling_bond | family | friendship | companionship | mentorship | reunion | community_ritual | grief | self_reflection | professional | therapeutic | service | adversarial (pick ONE)
66
+ "temporal_context": "", // STRICT ENUM: childhood | early_adulthood | midlife | late_life | recent | future | timeless (pick ONE or null)
67
+ "memory_type": "", // STRICT ENUM: legacy_artifact | fleeting_moment | milestone | reflection | formative_experience (pick ONE or null)
68
+ "media_format": "", // photo, video, audio, text, photo_with_story (or null)
69
+ "narrative_archetype": "", // STRICT ENUM: hero | caregiver | seeker | sage | lover | outlaw | innocent | magician | creator | everyman | jester | ruler | mentor (pick ONE or null; lowercase)
70
+ "symbolic_anchor": "", // concrete object/place/ritual (or null)
71
+ "relational_perspective": "", // STRICT ENUM: self | partner | family | friends | community | humanity (pick ONE or null)
72
+ "temporal_rhythm": "", // STRICT ENUM: still | sudden | rising | fading | recurring | spiraling | dragging | suspended | looping | cyclic (pick ONE or null)
73
+ "identity_thread": "", // short sentence
74
+ "expressed_insight": "", // brief insight explicitly stated by subject (extracted, not inferred)
75
+ "transformational_pivot": false, // true if subject explicitly identifies this as life-changing
76
+ "somatic_signature": "" // bodily sensations explicitly described (e.g., "chest tightness", "warmth spreading") or null
77
+ },
78
+ "milky_way": {
79
+ "event_type": "", // e.g., family gathering, farewell, birthday (or null)
80
+ "location_context": "", // place from text or image (or null)
81
+ "associated_people": [], // names or roles (proper case allowed)
82
+ "visibility_context": "", // STRICT ENUM: private | family_only | shared_publicly (pick ONE or null)
83
+ "tone_shift": "" // e.g., loss to gratitude (or null)
84
+ },
85
+ "gravity": {
86
+ "emotional_weight": 0.0, // 0.0–1.0 (felt intensity IN THE MOMENT)
87
+ "emotional_density": "", // STRICT ENUM: low | medium | high (pick ONE or null)
88
+ "valence": "", // STRICT ENUM: positive | negative | mixed (pick ONE or null)
89
+ "viscosity": "", // STRICT ENUM: low | medium | high | enduring | fluid (pick ONE or null)
90
+ "gravity_type": "", // short phrase (e.g., symbolic resonance)
91
+ "tether_type": "", // STRICT ENUM: person | symbol | event | place | ritual | object | tradition | identity | self (pick ONE or null)
92
+ "recall_triggers": [], // sensory or symbolic cues (lowercase tokens)
93
+ "retrieval_keys": [], // compact hooks (3–6 tokens recommended)
94
+ "nearby_themes": [], // adjacent concepts
95
+ "legacy_embed": false,
96
+ "recurrence_pattern": "", // STRICT ENUM: cyclical | isolated | chronic | emerging (pick ONE or null)
97
+ "strength_score": 0.0, // 0.0–1.0 (how BOUND/STUCK this memory is)
98
+ "temporal_decay": "", // STRICT ENUM: fast | moderate | slow (pick ONE or null)
99
+ "resilience_markers": [], // 1–3 (e.g., acceptance, optimism, continuity)
100
+ "adaptation_trajectory": "" // STRICT ENUM: improving | stable | declining | integrative | emerging (pick ONE or null)
101
+ },
102
+ "impulse": {
103
+ "primary_energy": "", // free text: e.g., curiosity, fear, compassion (or null; lowercase)
104
+ "drive_state": "", // STRICT ENUM: explore | approach | avoid | repair | persevere | share | confront | protect | process (pick ONE or null)
105
+ "motivational_orientation": "", // STRICT ENUM: belonging | safety | mastery | meaning | autonomy (pick ONE or null)
106
+ "temporal_focus": "", // STRICT ENUM: past | present | future (pick ONE or null)
107
+ "directionality": "", // STRICT ENUM: inward | outward | transcendent (pick ONE or null)
108
+ "social_visibility": "", // STRICT ENUM: private | relational | collective (pick ONE or null)
109
+ "urgency": "", // STRICT ENUM: calm | elevated | pressing | acute (pick ONE or null)
110
+ "risk_posture": "", // STRICT ENUM: cautious | balanced | bold (pick ONE or null)
111
+ "agency_level": "", // STRICT ENUM: low | medium | high (pick ONE or null)
112
+ "regulation_state": "", // STRICT ENUM: regulated | wavering | dysregulated (pick ONE or null)
113
+ "attachment_style": "", // STRICT ENUM: secure | anxious | avoidant | disorganized (pick ONE or null)
114
+ "coping_style": "" // STRICT ENUM: reframe_meaning | seek_support | distract | ritualize | confront | detach | process (pick ONE or null)
115
+ }
116
+
117
+ // Calibration — Impulse (helps apply the fields consistently)
118
+ // - temporal_focus: past (reminisce), present (here-and-now coping), future (plans/longing).
119
+ // - directionality: inward (self-processing), outward (toward others), transcendent (beyond self).
120
+ // - social_visibility: private (to self or 1:1), relational (friends/family), collective (community-wide).
121
+ // - If uncertain, choose the most conservative option or null.
122
+
123
+ // CROSS-CONTAMINATION DISAMBIGUATION (read carefully)
124
+ //
125
+ // temporal_rhythm vs urgency:
126
+ // - temporal_rhythm describes the CADENCE or PACE of time in the memory experience
127
+ // (still, sudden, rising, fading, recurring, spiraling, dragging, suspended, looping, cyclic)
128
+ // - urgency describes the INTENSITY of motivational pressure RIGHT NOW
129
+ // (calm, elevated, pressing, acute)
130
+ // - "pressing" belongs ONLY in urgency, NEVER in temporal_rhythm
131
+ //
132
+ // temporal_rhythm vs viscosity:
133
+ // - temporal_rhythm is about TIME MOVEMENT in the memory
134
+ // - viscosity is about EMOTIONAL PERSISTENCE over time
135
+ // (low=fleeting, medium=moderate, high=sticky, enduring=long-lasting, fluid=changeable)
136
+ // - "enduring" belongs ONLY in viscosity, NEVER in temporal_rhythm
137
+ //
138
+ // relational_dynamics vs relational_perspective:
139
+ // - relational_dynamics: the TYPE of relationship (parent_child, friendship, mentorship, etc.)
140
+ // - relational_perspective: WHOSE viewpoint the narrative is told from (self, partner, family, etc.)
141
+ // - "family" can appear in BOTH fields with different meanings
142
+ //
143
+ // drive_state vs coping_style:
144
+ // - drive_state: the MOTIVATIONAL direction (explore, approach, avoid, confront, etc.)
145
+ // - coping_style: the STRATEGY for managing emotions (reframe_meaning, seek_support, confront, etc.)
146
+ // - "confront" is valid in BOTH - use drive_state for action impulse, coping_style for emotion management
147
+ //
148
+ // emotion_primary (STRICT ENUM) vs higher_order_emotion (free text):
149
+ // - emotion_primary MUST be one of the 13 listed values ONLY
150
+ // - Do NOT put free-text emotions like "compassion", "reflection", "frustration" in emotion_primary
151
+ // - Use higher_order_emotion for complex emotions not in the primary list
152
+ //
153
+ // narrative_arc (CRITICAL - common error):
154
+ // - Describes the STORY TRAJECTORY (overcoming, transformation, connection, reflection, closure)
155
+ // - "confrontation" is NOT a valid arc — it describes an event/scene, not a trajectory
156
+ // - If the story involves confronting something, use "overcoming" (challenge faced and resolved)
157
+ // or "transformation" (fundamental change through conflict)
158
+ // - "confront" belongs in drive_state or coping_style, NOT in narrative_arc
159
+ //
160
+ // emotional_weight vs strength_score (CRITICAL - different concepts):
161
+ // - emotional_weight: The felt INTENSITY of the experience in the moment.
162
+ // A heated argument = high weight (0.8). A routine check-in = low weight (0.2).
163
+ // - strength_score: How BOUND/STUCK this memory is — through association, ritual, retelling, or identity.
164
+ // A childhood memory retold for decades = high strength (0.9) even if emotional weight was moderate.
165
+ // A customer complaint = may have high weight (0.8) but low strength (0.3) — intense but fades quickly.
166
+ // - These should NOT always correlate.
167
+ // Ask: "How heavy does this feel RIGHT NOW?" (weight) vs "How stuck/persistent is this memory?" (strength)
168
+ //
169
+ // SYNONYM CORRECTIONS (use the canonical form):
170
+ // - drive_state: Use "process" NOT "reflect". The enum value is "process" for internal processing/reflection.
171
+ // - narrative_archetype: Use "caregiver" NOT "caretaker". The Jungian archetype label is "caregiver".
172
+ }
173
+ `;
174
+ /**
175
+ * Extract EDM fields from content using Anthropic Claude
176
+ *
177
+ * @param client - Anthropic client
178
+ * @param input - Content to extract from
179
+ * @param model - Model to use (default: claude-sonnet-4-20250514)
180
+ * @param profile - EDM profile (default: 'full')
181
+ */
182
+ export async function extractWithLlm(client, input, model = "claude-sonnet-4-20250514", profile = "full") {
183
+ const userContent = [];
184
+ // Add text content
185
+ if (input.text) {
186
+ userContent.push({
187
+ type: "text",
188
+ text: input.text,
189
+ });
190
+ }
191
+ // Add image if provided
192
+ if (input.image) {
193
+ userContent.push({
194
+ type: "image",
195
+ source: {
196
+ type: "base64",
197
+ media_type: input.imageMediaType ?? "image/jpeg",
198
+ data: input.image,
199
+ },
200
+ });
201
+ }
202
+ // Select profile-specific prompt or use full extraction prompt
203
+ const profilePrompt = getProfilePrompt(profile);
204
+ const systemPrompt = profilePrompt || EXTRACTION_SYSTEM_PROMPT;
205
+ const response = await client.messages.create({
206
+ model,
207
+ max_tokens: 4096,
208
+ system: systemPrompt,
209
+ messages: [
210
+ {
211
+ role: "user",
212
+ content: userContent,
213
+ },
214
+ ],
215
+ });
216
+ // Extract text response
217
+ const textBlock = response.content.find((block) => block.type === "text");
218
+ if (!textBlock || textBlock.type !== "text") {
219
+ throw new Error("No text response from LLM");
220
+ }
221
+ // Parse JSON response (strip markdown code fences if present)
222
+ let jsonText = textBlock.text.trim();
223
+ const fenceMatch = jsonText.match(/^```(?:json)?\s*\n?([\s\S]*?)\n?\s*```$/);
224
+ if (fenceMatch?.[1]) {
225
+ jsonText = fenceMatch[1].trim();
226
+ }
227
+ let parsed;
228
+ try {
229
+ parsed = JSON.parse(jsonText);
230
+ }
231
+ catch {
232
+ throw new Error(`Failed to parse LLM response as JSON: ${textBlock.text.slice(0, 200)}...`);
233
+ }
234
+ // Validate against schema
235
+ const result = LlmExtractedFieldsSchema.safeParse(parsed);
236
+ if (!result.success) {
237
+ const errorDetails = result.error.errors
238
+ .map((e) => `${e.path.join(".")}: ${e.message}`)
239
+ .join("; ");
240
+ throw new Error(`LLM response failed schema validation: ${errorDetails}`);
241
+ }
242
+ // Calculate profile-aware confidence
243
+ const confidence = calculateProfileConfidence(result.data, profile);
244
+ return {
245
+ extracted: result.data,
246
+ confidence,
247
+ model,
248
+ profile,
249
+ notes: null,
250
+ };
251
+ }
252
+ /**
253
+ * Calculate extraction confidence based on field population
254
+ */
255
+ export function calculateConfidence(extracted) {
256
+ const weights = {
257
+ core: 0.25,
258
+ constellation: 0.25,
259
+ milky_way: 0.15,
260
+ gravity: 0.2,
261
+ impulse: 0.15,
262
+ };
263
+ let totalScore = 0;
264
+ // Core domain
265
+ const coreFields = Object.values(extracted.core);
266
+ const corePopulated = coreFields.filter((v) => v !== null && v !== "").length;
267
+ totalScore += weights.core * (corePopulated / coreFields.length);
268
+ // Constellation domain - check required and optional
269
+ const constellationRequired = ["emotion_subtone", "transformational_pivot"];
270
+ const constellationOptional = Object.keys(extracted.constellation).filter((k) => !constellationRequired.includes(k));
271
+ const constellationPopulated = constellationOptional.filter((k) => {
272
+ const val = extracted.constellation[k];
273
+ return val !== null && val !== "";
274
+ }).length + 2; // +2 for required fields
275
+ totalScore += weights.constellation * (constellationPopulated / Object.keys(extracted.constellation).length);
276
+ // MilkyWay domain
277
+ const milkyWayPopulated = Object.values(extracted.milky_way).filter((v) => v !== null && v !== "" && (Array.isArray(v) ? v.length > 0 : true)).length;
278
+ totalScore += weights.milky_way * (milkyWayPopulated / Object.keys(extracted.milky_way).length);
279
+ // Gravity domain
280
+ const gravityPopulated = Object.values(extracted.gravity).filter((v) => v !== null && v !== "" && (Array.isArray(v) ? v.length > 0 : true)).length;
281
+ totalScore += weights.gravity * (gravityPopulated / Object.keys(extracted.gravity).length);
282
+ // Impulse domain
283
+ const impulsePopulated = Object.values(extracted.impulse).filter((v) => v !== null && v !== "").length;
284
+ totalScore += weights.impulse * (impulsePopulated / Object.keys(extracted.impulse).length);
285
+ return Math.round(totalScore * 100) / 100;
286
+ }
287
+ /**
288
+ * Create an Anthropic client
289
+ */
290
+ export function createAnthropicClient(apiKey) {
291
+ return new Anthropic({
292
+ apiKey: apiKey ?? process.env["ANTHROPIC_API_KEY"],
293
+ });
294
+ }
295
+ //# sourceMappingURL=llm-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-extractor.js","sourceRoot":"","sources":["../../src/extractors/llm-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * OpenAI Extractor for EDM v0.6.0
3
+ * Uses OpenAI GPT models to extract emotional data from content
4
+ * Supports profile-aware extraction (core/extended/full)
5
+ */
6
+ import OpenAI from "openai";
7
+ import type { ExtractionInput, EdmProfile } from "../schema/types.js";
8
+ import { type LlmExtractionResult } from "./llm-extractor.js";
9
+ /**
10
+ * Extract EDM fields from content using OpenAI
11
+ */
12
+ export declare function extractWithOpenAI(client: OpenAI, input: ExtractionInput, model?: string, temperature?: number, profile?: EdmProfile): Promise<LlmExtractionResult>;
13
+ /**
14
+ * Create an OpenAI client
15
+ */
16
+ export declare function createOpenAIClient(apiKey?: string): OpenAI;
17
+ //# sourceMappingURL=openai-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-extractor.d.ts","sourceRoot":"","sources":["../../src/extractors/openai-extractor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,OAAO,KAAK,EAAsB,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE1F,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAG5B;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,eAAe,EACtB,KAAK,GAAE,MAAsB,EAC7B,WAAW,GAAE,MAAU,EACvB,OAAO,GAAE,UAAmB,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CAoF9B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAQ1D"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * OpenAI Extractor for EDM v0.6.0
3
+ * Uses OpenAI GPT models to extract emotional data from content
4
+ * Supports profile-aware extraction (core/extended/full)
5
+ */
6
+ import OpenAI from "openai";
7
+ import { LlmExtractedFieldsSchema } from "../schema/edm-schema.js";
8
+ import { EXTRACTION_SYSTEM_PROMPT, } from "./llm-extractor.js";
9
+ import { getProfilePrompt, calculateProfileConfidence } from "./profile-prompts.js";
10
+ /**
11
+ * Extract EDM fields from content using OpenAI
12
+ */
13
+ export async function extractWithOpenAI(client, input, model = "gpt-4o-mini", temperature = 0, profile = "full") {
14
+ const userContent = [];
15
+ // Add text content
16
+ if (input.text) {
17
+ userContent.push({
18
+ type: "text",
19
+ text: input.text,
20
+ });
21
+ }
22
+ // Add image if provided (OpenAI uses image_url with data URI)
23
+ if (input.image) {
24
+ const mediaType = input.imageMediaType ?? "image/jpeg";
25
+ userContent.push({
26
+ type: "image_url",
27
+ image_url: {
28
+ url: `data:${mediaType};base64,${input.image}`,
29
+ },
30
+ });
31
+ }
32
+ // Select profile-specific prompt or use full extraction prompt
33
+ const profilePrompt = getProfilePrompt(profile);
34
+ const systemPrompt = profilePrompt || EXTRACTION_SYSTEM_PROMPT;
35
+ const response = await client.chat.completions.create({
36
+ model,
37
+ max_tokens: 4096,
38
+ response_format: { type: "json_object" },
39
+ temperature,
40
+ messages: [
41
+ {
42
+ role: "system",
43
+ content: systemPrompt,
44
+ },
45
+ {
46
+ role: "user",
47
+ content: userContent,
48
+ },
49
+ ],
50
+ });
51
+ // Extract text response
52
+ const text = response.choices[0]?.message?.content;
53
+ if (!text) {
54
+ throw new Error("No text response from OpenAI");
55
+ }
56
+ // Parse JSON response (strip markdown code fences if present)
57
+ let jsonText = text.trim();
58
+ const fenceMatch = jsonText.match(/^```(?:json)?\s*\n?([\s\S]*?)\n?\s*```$/);
59
+ if (fenceMatch?.[1]) {
60
+ jsonText = fenceMatch[1].trim();
61
+ }
62
+ let parsed;
63
+ try {
64
+ parsed = JSON.parse(jsonText);
65
+ }
66
+ catch {
67
+ throw new Error(`Failed to parse OpenAI response as JSON: ${text.slice(0, 200)}...`);
68
+ }
69
+ // Validate against schema
70
+ const result = LlmExtractedFieldsSchema.safeParse(parsed);
71
+ if (!result.success) {
72
+ const errorDetails = result.error.errors
73
+ .map((e) => `${e.path.join(".")}: ${e.message}`)
74
+ .join("; ");
75
+ throw new Error(`OpenAI response failed schema validation: ${errorDetails}`);
76
+ }
77
+ // Calculate profile-aware confidence
78
+ const confidence = calculateProfileConfidence(result.data, profile);
79
+ return {
80
+ extracted: result.data,
81
+ confidence,
82
+ model,
83
+ profile,
84
+ notes: null,
85
+ };
86
+ }
87
+ /**
88
+ * Create an OpenAI client
89
+ */
90
+ export function createOpenAIClient(apiKey) {
91
+ const key = apiKey ?? process.env["OPENAI_API_KEY"];
92
+ if (!key) {
93
+ throw new Error("OpenAI API key is required. Set OPENAI_API_KEY environment variable or pass apiKey directly.");
94
+ }
95
+ return new OpenAI({ apiKey: key });
96
+ }
97
+ //# sourceMappingURL=openai-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-extractor.js","sourceRoot":"","sources":["../../src/extractors/openai-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Profile-specific extraction prompts for EDM v0.6.0
3
+ *
4
+ * Core Profile: ~20 required fields for memory platforms
5
+ * Extended Profile: ~45 fields for journaling apps
6
+ * Full Profile: all 96 fields for therapy/clinical tools
7
+ */
8
+ import type { EdmProfile } from "../schema/types.js";
9
+ /**
10
+ * Core Profile System Prompt (~20 fields)
11
+ * Target: memory platforms, agent frameworks, AI assistants
12
+ */
13
+ export declare const CORE_PROFILE_PROMPT = "\nYou classify emotionally rich memories into a JSON object. Input may include text and an image.\n\nPROFILE: CORE (~20 fields)\nThis is a minimal extraction for memory platforms. Focus ONLY on the required fields.\nAll other fields should be explicitly null.\n\nRules\n- Fuse text + image. Treat text as primary; use image only to add grounded specifics.\n- Keep fields to single words or short phrases (1\u20133 words). Only \"narrative\" is multi-sentence (3\u20135).\n- No invention. If not supported by input, use null.\n- Output JSON only \u2014 no commentary, markdown, or extra text.\n- Emit lowercase for all string fields except proper names.\n\nCORE PROFILE SCHEMA (extract these fields ONLY):\n{\n \"core\": {\n \"anchor\": \"\", // central theme\n \"spark\": \"\", // what triggered the memory\n \"wound\": \"\", // vulnerability or loss (or null)\n \"fuel\": \"\", // what energized the experience\n \"bridge\": \"\", // connection between past and present\n \"echo\": \"\", // what still resonates\n \"narrative\": \"\" // 3\u20135 sentences\n },\n \"constellation\": {\n \"emotion_primary\": \"\", // STRICT ENUM: joy | sadness | fear | anger | wonder | peace | tenderness | reverence | pride | anxiety | gratitude | longing | hope | shame\n \"emotion_subtone\": [], // 2\u20134 short words\n \"narrative_arc\": \"\", // STRICT ENUM: overcoming | transformation | connection | reflection | closure\n // ALL OTHER constellation fields must be null\n \"higher_order_emotion\": null,\n \"meta_emotional_state\": null,\n \"interpersonal_affect\": null,\n \"relational_dynamics\": null,\n \"temporal_context\": null,\n \"memory_type\": null,\n \"media_format\": null,\n \"narrative_archetype\": null,\n \"symbolic_anchor\": null,\n \"relational_perspective\": null,\n \"temporal_rhythm\": null,\n \"identity_thread\": null,\n \"expressed_insight\": null,\n \"transformational_pivot\": false,\n \"somatic_signature\": null\n },\n \"milky_way\": {\n \"event_type\": null,\n \"location_context\": null,\n \"associated_people\": [],\n \"visibility_context\": null,\n \"tone_shift\": null\n },\n \"gravity\": {\n \"emotional_weight\": 0.0,\n \"emotional_density\": null,\n \"valence\": null,\n \"viscosity\": null,\n \"gravity_type\": null,\n \"tether_type\": null,\n \"recall_triggers\": [],\n \"retrieval_keys\": [],\n \"nearby_themes\": [],\n \"legacy_embed\": false,\n \"recurrence_pattern\": null,\n \"strength_score\": 0.0,\n \"temporal_decay\": null,\n \"resilience_markers\": null,\n \"adaptation_trajectory\": null\n },\n \"impulse\": {\n \"primary_energy\": null,\n \"drive_state\": null,\n \"motivational_orientation\": null,\n \"temporal_focus\": null,\n \"directionality\": null,\n \"social_visibility\": null,\n \"urgency\": null,\n \"risk_posture\": null,\n \"agency_level\": null,\n \"regulation_state\": null,\n \"attachment_style\": null,\n \"coping_style\": null\n }\n}\n";
14
+ /**
15
+ * Extended Profile System Prompt (~45 fields)
16
+ * Target: journaling apps, companion AI, workplace wellness
17
+ */
18
+ export declare const EXTENDED_PROFILE_PROMPT = "\nYou classify emotionally rich memories into a JSON object. Input may include text and an image.\n\nPROFILE: EXTENDED (~45 fields)\nThis extraction adds full Constellation and key Gravity/Milky_Way fields.\nImpulse domain remains null except for key fields.\n\nRules\n- Fuse text + image. Treat text as primary; use image only to add grounded specifics.\n- Keep fields to single words or short phrases (1\u20133 words). Only \"narrative\" is multi-sentence (3\u20135).\n- No invention. If not supported by input, use null.\n- Output JSON only \u2014 no commentary, markdown, or extra text.\n- Emit lowercase for all string fields except proper names.\n- For array fields, use short tokens without punctuation; avoid duplicates.\n\nEXTENDED PROFILE SCHEMA:\n{\n \"core\": {\n \"anchor\": \"\",\n \"spark\": \"\",\n \"wound\": \"\",\n \"fuel\": \"\",\n \"bridge\": \"\",\n \"echo\": \"\",\n \"narrative\": \"\"\n },\n \"constellation\": {\n \"emotion_primary\": \"\", // STRICT ENUM: joy | sadness | fear | anger | wonder | peace | tenderness | reverence | pride | anxiety | gratitude | longing | hope | shame\n \"emotion_subtone\": [],\n \"higher_order_emotion\": \"\",\n \"meta_emotional_state\": \"\",\n \"interpersonal_affect\": \"\",\n \"narrative_arc\": \"\", // STRICT ENUM: overcoming | transformation | connection | reflection | closure\n \"relational_dynamics\": \"\", // STRICT ENUM: parent_child | grandparent_grandchild | romantic_partnership | couple | sibling_bond | family | friendship | friend | companionship | colleague | mentorship | reunion | community_ritual | grief | self_reflection | professional | therapeutic | service | adversarial\n \"temporal_context\": \"\", // STRICT ENUM: childhood | early_adulthood | midlife | late_life | recent | future | timeless\n \"memory_type\": \"\", // STRICT ENUM: legacy_artifact | fleeting_moment | milestone | reflection | formative_experience\n \"media_format\": \"\",\n \"narrative_archetype\": \"\", // STRICT ENUM: hero | caregiver | seeker | sage | lover | outlaw | innocent | orphan | magician | creator | everyman | jester | ruler | mentor\n \"symbolic_anchor\": \"\",\n \"relational_perspective\": \"\", // STRICT ENUM: self | partner | family | friends | community | humanity\n \"temporal_rhythm\": \"\", // STRICT ENUM: still | sudden | rising | fading | recurring | spiraling | dragging | suspended | looping | cyclic\n \"identity_thread\": \"\",\n \"expressed_insight\": \"\",\n \"transformational_pivot\": false,\n \"somatic_signature\": \"\"\n },\n \"milky_way\": {\n \"event_type\": \"\",\n \"location_context\": \"\",\n \"associated_people\": [],\n \"visibility_context\": \"\", // STRICT ENUM: private | family_only | shared_publicly\n \"tone_shift\": \"\"\n },\n \"gravity\": {\n \"emotional_weight\": 0.0, // 0.0\u20131.0\n \"emotional_density\": null,\n \"valence\": \"\", // STRICT ENUM: positive | negative | mixed\n \"viscosity\": null,\n \"gravity_type\": null,\n \"tether_type\": \"\", // STRICT ENUM: person | symbol | event | place | ritual | object | tradition | identity | self\n \"recall_triggers\": [],\n \"retrieval_keys\": [],\n \"nearby_themes\": [],\n \"legacy_embed\": false,\n \"recurrence_pattern\": \"\", // STRICT ENUM: cyclical | isolated | chronic | emerging\n \"strength_score\": 0.0,\n \"temporal_decay\": null,\n \"resilience_markers\": null,\n \"adaptation_trajectory\": null\n },\n \"impulse\": {\n \"primary_energy\": null,\n \"drive_state\": null,\n \"motivational_orientation\": null,\n \"temporal_focus\": null,\n \"directionality\": null,\n \"social_visibility\": null,\n \"urgency\": null,\n \"risk_posture\": null,\n \"agency_level\": null,\n \"regulation_state\": null,\n \"attachment_style\": null,\n \"coping_style\": null\n }\n}\n";
19
+ /**
20
+ * Get the appropriate system prompt for a profile
21
+ */
22
+ export declare function getProfilePrompt(profile: EdmProfile): string;
23
+ /**
24
+ * Required fields for each profile (used for confidence scoring)
25
+ */
26
+ export declare const PROFILE_REQUIRED_FIELDS: Record<EdmProfile, string[]>;
27
+ /**
28
+ * Calculate profile-aware confidence score
29
+ * Only scores required fields for the declared profile
30
+ */
31
+ export declare function calculateProfileConfidence(extracted: Record<string, Record<string, unknown>>, profile: EdmProfile): number;
32
+ //# sourceMappingURL=profile-prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-prompts.d.ts","sourceRoot":"","sources":["../../src/extractors/profile-prompts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;GAGG;AACH,eAAO,MAAM,mBAAmB,smGAqF/B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,uBAAuB,69HAqFnC,CAAC;AAEF;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAW5D;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,CAiDhE,CAAC;AAEF;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAClD,OAAO,EAAE,UAAU,GAClB,MAAM,CAsBR"}