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.
- package/LICENSE +21 -0
- package/README.md +240 -0
- package/dist/assembler.d.ts +37 -0
- package/dist/assembler.d.ts.map +1 -0
- package/dist/assembler.js +204 -0
- package/dist/assembler.js.map +1 -0
- package/dist/extractors/domain-extractors.d.ts +8 -0
- package/dist/extractors/domain-extractors.d.ts.map +1 -0
- package/dist/extractors/domain-extractors.js +173 -0
- package/dist/extractors/domain-extractors.js.map +1 -0
- package/dist/extractors/image-analyzer.d.ts +38 -0
- package/dist/extractors/image-analyzer.d.ts.map +1 -0
- package/dist/extractors/image-analyzer.js +101 -0
- package/dist/extractors/image-analyzer.js.map +1 -0
- package/dist/extractors/kimi-extractor.d.ts +22 -0
- package/dist/extractors/kimi-extractor.d.ts.map +1 -0
- package/dist/extractors/kimi-extractor.js +137 -0
- package/dist/extractors/kimi-extractor.js.map +1 -0
- package/dist/extractors/llm-extractor.d.ts +43 -0
- package/dist/extractors/llm-extractor.d.ts.map +1 -0
- package/dist/extractors/llm-extractor.js +295 -0
- package/dist/extractors/llm-extractor.js.map +1 -0
- package/dist/extractors/openai-extractor.d.ts +17 -0
- package/dist/extractors/openai-extractor.d.ts.map +1 -0
- package/dist/extractors/openai-extractor.js +97 -0
- package/dist/extractors/openai-extractor.js.map +1 -0
- package/dist/extractors/profile-prompts.d.ts +32 -0
- package/dist/extractors/profile-prompts.d.ts.map +1 -0
- package/dist/extractors/profile-prompts.js +283 -0
- package/dist/extractors/profile-prompts.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/schema/edm-schema.d.ts +1645 -0
- package/dist/schema/edm-schema.d.ts.map +1 -0
- package/dist/schema/edm-schema.js +345 -0
- package/dist/schema/edm-schema.js.map +1 -0
- package/dist/schema/types.d.ts +94 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +79 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/stateless.d.ts +28 -0
- package/dist/stateless.d.ts.map +1 -0
- package/dist/stateless.js +100 -0
- package/dist/stateless.js.map +1 -0
- package/dist/validator.d.ts +24 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +154 -0
- package/dist/validator.js.map +1 -0
- 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"}
|