@gonzih/meet-the-one-ai 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +41 -0
- package/.node-version +1 -0
- package/basis/BERNAYS.md +233 -0
- package/basis/FOUNDING_TRANSCRIPT.md +218 -0
- package/basis/TECH_SPEC.md +303 -0
- package/basis/VALS.md +255 -0
- package/basis/layers/L1_IDENTITY_AUTH.md +78 -0
- package/basis/layers/L2_CONVERSATION.md +159 -0
- package/basis/layers/L3_RECORDING_STORE.md +104 -0
- package/basis/layers/L4_ANALYSIS_PIPELINE.md +257 -0
- package/basis/layers/L5_MATCHING_ENGINE.md +164 -0
- package/basis/layers/L6_CONSENT_INTRODUCTION.md +143 -0
- package/basis/layers/L7_PORTABLE_IDENTITY.md +139 -0
- package/basis/layers/STACK.md +64 -0
- package/basis/schema.sql +203 -0
- package/dist/agent.d.ts +2 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +114 -0
- package/dist/agent.js.map +1 -0
- package/dist/api/routes/auth.d.ts +2 -0
- package/dist/api/routes/auth.d.ts.map +1 -0
- package/dist/api/routes/auth.js +79 -0
- package/dist/api/routes/auth.js.map +1 -0
- package/dist/api/routes/identity.d.ts +2 -0
- package/dist/api/routes/identity.d.ts.map +1 -0
- package/dist/api/routes/identity.js +92 -0
- package/dist/api/routes/identity.js.map +1 -0
- package/dist/api/routes/text-submission.d.ts +2 -0
- package/dist/api/routes/text-submission.d.ts.map +1 -0
- package/dist/api/routes/text-submission.js +56 -0
- package/dist/api/routes/text-submission.js.map +1 -0
- package/dist/api/webhooks/twilio.d.ts +2 -0
- package/dist/api/webhooks/twilio.d.ts.map +1 -0
- package/dist/api/webhooks/twilio.js +144 -0
- package/dist/api/webhooks/twilio.js.map +1 -0
- package/dist/api/webhooks/vapi.d.ts +2 -0
- package/dist/api/webhooks/vapi.d.ts.map +1 -0
- package/dist/api/webhooks/vapi.js +177 -0
- package/dist/api/webhooks/vapi.js.map +1 -0
- package/dist/bot.d.ts +3 -0
- package/dist/bot.d.ts.map +1 -0
- package/dist/bot.js +39 -0
- package/dist/bot.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/jobs/compact-identity.d.ts +2 -0
- package/dist/jobs/compact-identity.d.ts.map +1 -0
- package/dist/jobs/compact-identity.js +159 -0
- package/dist/jobs/compact-identity.js.map +1 -0
- package/dist/jobs/consent-call.d.ts +2 -0
- package/dist/jobs/consent-call.d.ts.map +1 -0
- package/dist/jobs/consent-call.js +70 -0
- package/dist/jobs/consent-call.js.map +1 -0
- package/dist/jobs/export-identity.d.ts +2 -0
- package/dist/jobs/export-identity.d.ts.map +1 -0
- package/dist/jobs/export-identity.js +129 -0
- package/dist/jobs/export-identity.js.map +1 -0
- package/dist/jobs/introduction-call.d.ts +2 -0
- package/dist/jobs/introduction-call.d.ts.map +1 -0
- package/dist/jobs/introduction-call.js +86 -0
- package/dist/jobs/introduction-call.js.map +1 -0
- package/dist/jobs/reanalyze-identity.d.ts +2 -0
- package/dist/jobs/reanalyze-identity.d.ts.map +1 -0
- package/dist/jobs/reanalyze-identity.js +56 -0
- package/dist/jobs/reanalyze-identity.js.map +1 -0
- package/dist/jobs/run-matching.d.ts +2 -0
- package/dist/jobs/run-matching.d.ts.map +1 -0
- package/dist/jobs/run-matching.js +200 -0
- package/dist/jobs/run-matching.js.map +1 -0
- package/dist/jobs/scheduled-matching.d.ts +2 -0
- package/dist/jobs/scheduled-matching.d.ts.map +1 -0
- package/dist/jobs/scheduled-matching.js +44 -0
- package/dist/jobs/scheduled-matching.js.map +1 -0
- package/dist/jobs/transcribe-session.d.ts +2 -0
- package/dist/jobs/transcribe-session.d.ts.map +1 -0
- package/dist/jobs/transcribe-session.js +66 -0
- package/dist/jobs/transcribe-session.js.map +1 -0
- package/dist/lib/anthropic.d.ts +4 -0
- package/dist/lib/anthropic.d.ts.map +1 -0
- package/dist/lib/anthropic.js +32 -0
- package/dist/lib/anthropic.js.map +1 -0
- package/dist/lib/config.d.ts +57 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +73 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/deepgram.d.ts +15 -0
- package/dist/lib/deepgram.d.ts.map +1 -0
- package/dist/lib/deepgram.js +37 -0
- package/dist/lib/deepgram.js.map +1 -0
- package/dist/lib/inngest.d.ts +42 -0
- package/dist/lib/inngest.d.ts.map +1 -0
- package/dist/lib/inngest.js +7 -0
- package/dist/lib/inngest.js.map +1 -0
- package/dist/lib/openai.d.ts +3 -0
- package/dist/lib/openai.d.ts.map +1 -0
- package/dist/lib/openai.js +13 -0
- package/dist/lib/openai.js.map +1 -0
- package/dist/lib/prompts.d.ts +8 -0
- package/dist/lib/prompts.d.ts.map +1 -0
- package/dist/lib/prompts.js +258 -0
- package/dist/lib/prompts.js.map +1 -0
- package/dist/lib/r2.d.ts +7 -0
- package/dist/lib/r2.d.ts.map +1 -0
- package/dist/lib/r2.js +49 -0
- package/dist/lib/r2.js.map +1 -0
- package/dist/lib/session-helpers.d.ts +8 -0
- package/dist/lib/session-helpers.d.ts.map +1 -0
- package/dist/lib/session-helpers.js +31 -0
- package/dist/lib/session-helpers.js.map +1 -0
- package/dist/lib/supabase.d.ts +2 -0
- package/dist/lib/supabase.d.ts.map +1 -0
- package/dist/lib/supabase.js +11 -0
- package/dist/lib/supabase.js.map +1 -0
- package/dist/lib/twilio.d.ts +7 -0
- package/dist/lib/twilio.d.ts.map +1 -0
- package/dist/lib/twilio.js +34 -0
- package/dist/lib/twilio.js.map +1 -0
- package/dist/lib/vapi.d.ts +4 -0
- package/dist/lib/vapi.d.ts.map +1 -0
- package/dist/lib/vapi.js +59 -0
- package/dist/lib/vapi.js.map +1 -0
- package/dist/mcp-server.d.ts +3 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +177 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/types/index.d.ts +104 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +28 -0
- package/railway.json +14 -0
- package/src/agent.ts +123 -0
- package/src/api/routes/auth.ts +95 -0
- package/src/api/routes/identity.ts +112 -0
- package/src/api/routes/text-submission.ts +64 -0
- package/src/api/webhooks/twilio.ts +181 -0
- package/src/api/webhooks/vapi.ts +219 -0
- package/src/bot.ts +44 -0
- package/src/index.ts +11 -0
- package/src/jobs/compact-identity.ts +211 -0
- package/src/jobs/consent-call.ts +87 -0
- package/src/jobs/export-identity.ts +166 -0
- package/src/jobs/introduction-call.ts +101 -0
- package/src/jobs/reanalyze-identity.ts +65 -0
- package/src/jobs/run-matching.ts +243 -0
- package/src/jobs/scheduled-matching.ts +59 -0
- package/src/jobs/transcribe-session.ts +77 -0
- package/src/lib/anthropic.ts +37 -0
- package/src/lib/config.ts +81 -0
- package/src/lib/deepgram.ts +57 -0
- package/src/lib/inngest.ts +33 -0
- package/src/lib/openai.ts +14 -0
- package/src/lib/prompts.ts +266 -0
- package/src/lib/r2.ts +79 -0
- package/src/lib/session-helpers.ts +37 -0
- package/src/lib/supabase.ts +15 -0
- package/src/lib/twilio.ts +49 -0
- package/src/lib/vapi.ts +80 -0
- package/src/mcp-server.ts +195 -0
- package/src/types/index.ts +146 -0
- package/supabase/.branches/_current_branch +1 -0
- package/supabase/.temp/cli-latest +1 -0
- package/supabase/.temp/gotrue-version +1 -0
- package/supabase/.temp/pooler-url +1 -0
- package/supabase/.temp/postgres-version +1 -0
- package/supabase/.temp/project-ref +1 -0
- package/supabase/.temp/rest-version +1 -0
- package/supabase/.temp/storage-migration +1 -0
- package/supabase/.temp/storage-version +1 -0
- package/supabase/config.toml +384 -0
- package/supabase/migrations/20260303000000_initial_schema.sql +203 -0
- package/supabase/migrations/20260304000000_brand_consents.sql +13 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { inngest } from "../lib/inngest.js";
|
|
2
|
+
import { supabase } from "../lib/supabase.js";
|
|
3
|
+
// Triggered manually or after prompt changes
|
|
4
|
+
// Replays all completed sessions through the current prompt version
|
|
5
|
+
// by re-firing session/transcribed for each session in order
|
|
6
|
+
export const reanalyze_identity = inngest.createFunction({ id: "reanalyze-identity", retries: 1 }, { event: "identity/reanalyze" }, async ({ event, step }) => {
|
|
7
|
+
const { user_id } = event.data;
|
|
8
|
+
// Load all completed sessions in chronological order
|
|
9
|
+
const sessions = await step.run("load-sessions", async () => {
|
|
10
|
+
const { data, error } = await supabase
|
|
11
|
+
.from("sessions")
|
|
12
|
+
.select("id, transcript_r2_key, raw_text, analysis_status")
|
|
13
|
+
.eq("user_id", user_id)
|
|
14
|
+
.in("analysis_status", ["complete", "error"])
|
|
15
|
+
.order("created_at", { ascending: true });
|
|
16
|
+
if (error)
|
|
17
|
+
throw new Error(`Failed to load sessions: ${error.message}`);
|
|
18
|
+
return data ?? [];
|
|
19
|
+
});
|
|
20
|
+
if (sessions.length === 0) {
|
|
21
|
+
return { skipped: true, reason: "no completed sessions" };
|
|
22
|
+
}
|
|
23
|
+
// Reset identity
|
|
24
|
+
await step.run("reset-identity", async () => {
|
|
25
|
+
await supabase
|
|
26
|
+
.from("identities")
|
|
27
|
+
.update({
|
|
28
|
+
base_profile: {},
|
|
29
|
+
modality_weights: {},
|
|
30
|
+
signal_completeness_score: 0,
|
|
31
|
+
session_count: 0,
|
|
32
|
+
ready_for_matching: false,
|
|
33
|
+
last_updated: new Date().toISOString(),
|
|
34
|
+
})
|
|
35
|
+
.eq("user_id", user_id);
|
|
36
|
+
// Clear all modality embeddings
|
|
37
|
+
await supabase
|
|
38
|
+
.from("identity_modality_embeddings")
|
|
39
|
+
.delete()
|
|
40
|
+
.eq("user_id", user_id);
|
|
41
|
+
});
|
|
42
|
+
// Re-fire each session through compact-identity sequentially
|
|
43
|
+
// Inngest will process them in order via event fan-out
|
|
44
|
+
for (const session of sessions) {
|
|
45
|
+
await step.sendEvent(`replay-${session.id}`, {
|
|
46
|
+
name: "session/transcribed",
|
|
47
|
+
data: {
|
|
48
|
+
user_id,
|
|
49
|
+
session_id: session.id,
|
|
50
|
+
transcript_r2_key: session.transcript_r2_key ?? "",
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return { user_id, replayed: sessions.length };
|
|
55
|
+
});
|
|
56
|
+
//# sourceMappingURL=reanalyze-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reanalyze-identity.js","sourceRoot":"","sources":["../../src/jobs/reanalyze-identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,6CAA6C;AAC7C,oEAAoE;AACpE,6DAA6D;AAC7D,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC,cAAc,CACtD,EAAE,EAAE,EAAE,oBAAoB,EAAE,OAAO,EAAE,CAAC,EAAE,EACxC,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAC/B,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE;IACxB,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;IAE/B,qDAAqD;IACrD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ;aACnC,IAAI,CAAC,UAAU,CAAC;aAChB,MAAM,CAAC,kDAAkD,CAAC;aAC1D,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC;aACtB,EAAE,CAAC,iBAAiB,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;aAC5C,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,IAAI,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACxE,OAAO,IAAI,IAAI,EAAE,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,uBAAuB,EAAE,CAAC;IAC5D,CAAC;IAED,iBAAiB;IACjB,MAAM,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,QAAQ;aACX,IAAI,CAAC,YAAY,CAAC;aAClB,MAAM,CAAC;YACN,YAAY,EAAE,EAAE;YAChB,gBAAgB,EAAE,EAAE;YACpB,yBAAyB,EAAE,CAAC;YAC5B,aAAa,EAAE,CAAC;YAChB,kBAAkB,EAAE,KAAK;YACzB,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACvC,CAAC;aACD,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAE1B,gCAAgC;QAChC,MAAM,QAAQ;aACX,IAAI,CAAC,8BAA8B,CAAC;aACpC,MAAM,EAAE;aACR,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,6DAA6D;IAC7D,uDAAuD;IACvD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,CAAC,SAAS,CAAC,UAAU,OAAO,CAAC,EAAE,EAAE,EAAE;YAC3C,IAAI,EAAE,qBAAqB;YAC3B,IAAI,EAAE;gBACJ,OAAO;gBACP,UAAU,EAAE,OAAO,CAAC,EAAE;gBACtB,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,IAAI,EAAE;aACnD;SACF,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;AAChD,CAAC,CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-matching.d.ts","sourceRoot":"","sources":["../../src/jobs/run-matching.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,YAAY,KAoNxB,CAAC"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { inngest } from "../lib/inngest.js";
|
|
2
|
+
import { supabase } from "../lib/supabase.js";
|
|
3
|
+
import { complete, extract_json } from "../lib/anthropic.js";
|
|
4
|
+
import { SYSTEM_MATCH_VALIDATION } from "../lib/prompts.js";
|
|
5
|
+
const WORLD_VIEW_DELTA_MAX = 0.5;
|
|
6
|
+
const CONFIDENCE_THRESHOLD = 0.70;
|
|
7
|
+
const MAX_MATCHES_IN_QUEUE = 10;
|
|
8
|
+
const VECTOR_CANDIDATES_PER_MODALITY = 30;
|
|
9
|
+
// Triggered when a user's identity is updated
|
|
10
|
+
// 1. Vector search per active modality via pgvector RPC
|
|
11
|
+
// 2. Hard-filter on worldview bifurcations
|
|
12
|
+
// 3. LLM-validate each candidate
|
|
13
|
+
// 4. Insert confirmed matches + fire match/confirmed
|
|
14
|
+
export const run_matching = inngest.createFunction({ id: "run-matching", retries: 2 }, { event: "identity/updated" }, async ({ event, step }) => {
|
|
15
|
+
const { user_id } = event.data;
|
|
16
|
+
// ── Load identity ─────────────────────────────────────────────────────────
|
|
17
|
+
const identity = await step.run("load-identity", async () => {
|
|
18
|
+
const { data, error } = await supabase
|
|
19
|
+
.from("identities")
|
|
20
|
+
.select("base_profile, modality_weights, signal_completeness_score, ready_for_matching")
|
|
21
|
+
.eq("user_id", user_id)
|
|
22
|
+
.single();
|
|
23
|
+
if (error || !data)
|
|
24
|
+
throw new Error("Identity not found");
|
|
25
|
+
return data;
|
|
26
|
+
});
|
|
27
|
+
if (!identity.ready_for_matching) {
|
|
28
|
+
return { skipped: true, reason: "not ready for matching" };
|
|
29
|
+
}
|
|
30
|
+
// ── Check queue capacity ──────────────────────────────────────────────────
|
|
31
|
+
const { count: pending_count } = await supabase
|
|
32
|
+
.from("matches")
|
|
33
|
+
.select("*", { count: "exact", head: true })
|
|
34
|
+
.or(`user_a_id.eq.${user_id},user_b_id.eq.${user_id}`)
|
|
35
|
+
.eq("status", "pending_consent");
|
|
36
|
+
if ((pending_count ?? 0) >= MAX_MATCHES_IN_QUEUE) {
|
|
37
|
+
return { skipped: true, reason: "match queue full" };
|
|
38
|
+
}
|
|
39
|
+
const slots_available = MAX_MATCHES_IN_QUEUE - (pending_count ?? 0);
|
|
40
|
+
// ── Load user's modality embeddings ───────────────────────────────────────
|
|
41
|
+
const my_embeddings = await step.run("load-embeddings", async () => {
|
|
42
|
+
const { data } = await supabase
|
|
43
|
+
.from("identity_modality_embeddings")
|
|
44
|
+
.select("modality, embedding")
|
|
45
|
+
.eq("user_id", user_id);
|
|
46
|
+
return data ?? [];
|
|
47
|
+
});
|
|
48
|
+
if (my_embeddings.length === 0) {
|
|
49
|
+
return { skipped: true, reason: "no embeddings yet" };
|
|
50
|
+
}
|
|
51
|
+
// ── Build exclusion set (existing matches + declined pairs) ───────────────
|
|
52
|
+
const [existing_matches, declined_pairs] = await Promise.all([
|
|
53
|
+
supabase
|
|
54
|
+
.from("matches")
|
|
55
|
+
.select("user_a_id, user_b_id")
|
|
56
|
+
.or(`user_a_id.eq.${user_id},user_b_id.eq.${user_id}`),
|
|
57
|
+
supabase
|
|
58
|
+
.from("declined_pairs")
|
|
59
|
+
.select("user_a_id, user_b_id")
|
|
60
|
+
.or(`user_a_id.eq.${user_id},user_b_id.eq.${user_id}`),
|
|
61
|
+
]);
|
|
62
|
+
const excluded_ids = new Set([user_id]); // always exclude self
|
|
63
|
+
for (const p of existing_matches.data ?? []) {
|
|
64
|
+
excluded_ids.add(p.user_a_id);
|
|
65
|
+
excluded_ids.add(p.user_b_id);
|
|
66
|
+
}
|
|
67
|
+
for (const p of declined_pairs.data ?? []) {
|
|
68
|
+
excluded_ids.add(p.user_a_id);
|
|
69
|
+
excluded_ids.add(p.user_b_id);
|
|
70
|
+
}
|
|
71
|
+
// ── Vector search per active modality ─────────────────────────────────────
|
|
72
|
+
// Best similarity per candidate across all modality searches
|
|
73
|
+
const candidate_scores = new Map();
|
|
74
|
+
const vector_results = await step.run("vector-search", async () => {
|
|
75
|
+
const results = [];
|
|
76
|
+
for (const { modality, embedding } of my_embeddings) {
|
|
77
|
+
const { data, error } = await supabase.rpc("match_identities", {
|
|
78
|
+
p_user_id: user_id,
|
|
79
|
+
p_modality: modality,
|
|
80
|
+
p_embedding: embedding,
|
|
81
|
+
p_limit: VECTOR_CANDIDATES_PER_MODALITY,
|
|
82
|
+
});
|
|
83
|
+
if (error) {
|
|
84
|
+
console.error(`match_identities RPC error for modality ${modality}:`, error);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
for (const row of data ?? []) {
|
|
88
|
+
results.push(row);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return results;
|
|
92
|
+
});
|
|
93
|
+
for (const row of vector_results) {
|
|
94
|
+
if (excluded_ids.has(row.user_id))
|
|
95
|
+
continue;
|
|
96
|
+
const existing = candidate_scores.get(row.user_id);
|
|
97
|
+
if (!existing || row.similarity > existing.similarity) {
|
|
98
|
+
candidate_scores.set(row.user_id, {
|
|
99
|
+
similarity: row.similarity,
|
|
100
|
+
modality: row.modality,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Sort by similarity descending, take top 20 for LLM validation
|
|
105
|
+
const ranked_candidates = Array.from(candidate_scores.entries())
|
|
106
|
+
.sort((a, b) => b[1].similarity - a[1].similarity)
|
|
107
|
+
.slice(0, 20)
|
|
108
|
+
.map(([cid, meta]) => ({ user_id: cid, ...meta }));
|
|
109
|
+
if (ranked_candidates.length === 0) {
|
|
110
|
+
return { user_id, confirmed_matches: 0, reason: "no vector candidates" };
|
|
111
|
+
}
|
|
112
|
+
// ── Load candidate full profiles ──────────────────────────────────────────
|
|
113
|
+
const candidate_ids = ranked_candidates.map((c) => c.user_id);
|
|
114
|
+
const { data: candidate_profiles } = await supabase
|
|
115
|
+
.from("identities")
|
|
116
|
+
.select("user_id, base_profile, modality_weights")
|
|
117
|
+
.in("user_id", candidate_ids);
|
|
118
|
+
const profile_map = new Map((candidate_profiles ?? []).map((p) => [p.user_id, p]));
|
|
119
|
+
// ── Hard filter: worldview bifurcation gates ──────────────────────────────
|
|
120
|
+
const a_wv = identity.base_profile.worldview;
|
|
121
|
+
const passing_candidates = ranked_candidates.filter((c) => {
|
|
122
|
+
const profile = profile_map.get(c.user_id);
|
|
123
|
+
if (!profile)
|
|
124
|
+
return false;
|
|
125
|
+
const b_wv = profile.base_profile.worldview;
|
|
126
|
+
const danger_delta = Math.abs(a_wv.world_danger_adventure - b_wv.world_danger_adventure);
|
|
127
|
+
const people_delta = Math.abs(a_wv.people_good_bad - b_wv.people_good_bad);
|
|
128
|
+
return danger_delta <= WORLD_VIEW_DELTA_MAX && people_delta <= WORLD_VIEW_DELTA_MAX;
|
|
129
|
+
});
|
|
130
|
+
// ── LLM validation ────────────────────────────────────────────────────────
|
|
131
|
+
const confirmed_matches = [];
|
|
132
|
+
for (const candidate of passing_candidates) {
|
|
133
|
+
if (confirmed_matches.length >= slots_available)
|
|
134
|
+
break;
|
|
135
|
+
const profile = profile_map.get(candidate.user_id);
|
|
136
|
+
const primary_modality = dominant_shared_modality(identity.modality_weights, profile.modality_weights);
|
|
137
|
+
const assessment_raw = await step.run(`validate-${candidate.user_id}`, async () => complete("matching", SYSTEM_MATCH_VALIDATION, [
|
|
138
|
+
`Person A profile (${primary_modality} lens):\n${JSON.stringify(identity.base_profile, null, 2)}`,
|
|
139
|
+
`Person A modality weights: ${JSON.stringify(identity.modality_weights)}`,
|
|
140
|
+
`\nPerson B profile (${primary_modality} lens):\n${JSON.stringify(profile.base_profile, null, 2)}`,
|
|
141
|
+
`Person B modality weights: ${JSON.stringify(profile.modality_weights)}`,
|
|
142
|
+
`\nVector similarity score: ${candidate.similarity.toFixed(3)} (modality: ${candidate.modality})`,
|
|
143
|
+
].join("\n\n")));
|
|
144
|
+
let assessment;
|
|
145
|
+
try {
|
|
146
|
+
assessment = JSON.parse(extract_json(assessment_raw));
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
console.error(`Failed to parse assessment for ${candidate.user_id}`);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (!assessment.compatible || assessment.tension_fatal)
|
|
153
|
+
continue;
|
|
154
|
+
if (assessment.confidence < CONFIDENCE_THRESHOLD)
|
|
155
|
+
continue;
|
|
156
|
+
// Insert match and capture the generated UUID
|
|
157
|
+
const { data: match_row, error: insert_error } = await supabase
|
|
158
|
+
.from("matches")
|
|
159
|
+
.insert({
|
|
160
|
+
user_a_id: user_id,
|
|
161
|
+
user_b_id: candidate.user_id,
|
|
162
|
+
primary_modality,
|
|
163
|
+
cross_modality: assessment.cross_modality ?? false,
|
|
164
|
+
cross_modality_bridge: assessment.cross_modality_bridge ?? null,
|
|
165
|
+
confidence_score: assessment.confidence,
|
|
166
|
+
resonances: assessment.resonances ?? [],
|
|
167
|
+
tensions: assessment.tensions ?? [],
|
|
168
|
+
tension_fatal: false,
|
|
169
|
+
consent_call_framing: assessment.consent_call_framing ?? "",
|
|
170
|
+
status: "pending_consent",
|
|
171
|
+
created_at: new Date().toISOString(),
|
|
172
|
+
})
|
|
173
|
+
.select("id")
|
|
174
|
+
.single();
|
|
175
|
+
if (insert_error || !match_row) {
|
|
176
|
+
console.error("Failed to insert match:", insert_error);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
confirmed_matches.push(candidate.user_id);
|
|
180
|
+
await step.sendEvent(`match-confirmed-${match_row.id}`, {
|
|
181
|
+
name: "match/confirmed",
|
|
182
|
+
data: { match_id: match_row.id },
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return { user_id, confirmed_matches: confirmed_matches.length };
|
|
186
|
+
});
|
|
187
|
+
function dominant_shared_modality(a, b) {
|
|
188
|
+
const modalities = Object.keys(a);
|
|
189
|
+
let best = modalities[0];
|
|
190
|
+
let best_score = 0;
|
|
191
|
+
for (const m of modalities) {
|
|
192
|
+
const score = Math.min(a[m], b[m]);
|
|
193
|
+
if (score > best_score) {
|
|
194
|
+
best_score = score;
|
|
195
|
+
best = m;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return best;
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=run-matching.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-matching.js","sourceRoot":"","sources":["../../src/jobs/run-matching.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAG5D,MAAM,oBAAoB,GAAG,GAAG,CAAC;AACjC,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAClC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAChC,MAAM,8BAA8B,GAAG,EAAE,CAAC;AAE1C,8CAA8C;AAC9C,wDAAwD;AACxD,2CAA2C;AAC3C,iCAAiC;AACjC,qDAAqD;AACrD,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC,cAAc,CAChD,EAAE,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,EAAE,EAClC,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAC7B,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE;IACxB,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;IAE/B,6EAA6E;IAC7E,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ;aACnC,IAAI,CAAC,YAAY,CAAC;aAClB,MAAM,CAAC,+EAA+E,CAAC;aACvF,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC;aACtB,MAAM,EAAE,CAAC;QACZ,IAAI,KAAK,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,kBAAkB,EAAE,CAAC;QACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;IAC7D,CAAC;IAED,6EAA6E;IAC7E,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,MAAM,QAAQ;SAC5C,IAAI,CAAC,SAAS,CAAC;SACf,MAAM,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;SAC3C,EAAE,CAAC,gBAAgB,OAAO,iBAAiB,OAAO,EAAE,CAAC;SACrD,EAAE,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;IAEnC,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC,IAAI,oBAAoB,EAAE,CAAC;QACjD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IACvD,CAAC;IAED,MAAM,eAAe,GAAG,oBAAoB,GAAG,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC;IAEpE,6EAA6E;IAC7E,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,QAAQ;aAC5B,IAAI,CAAC,8BAA8B,CAAC;aACpC,MAAM,CAAC,qBAAqB,CAAC;aAC7B,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC1B,OAAO,IAAI,IAAI,EAAE,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACxD,CAAC;IAED,6EAA6E;IAC7E,MAAM,CAAC,gBAAgB,EAAE,cAAc,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC3D,QAAQ;aACL,IAAI,CAAC,SAAS,CAAC;aACf,MAAM,CAAC,sBAAsB,CAAC;aAC9B,EAAE,CAAC,gBAAgB,OAAO,iBAAiB,OAAO,EAAE,CAAC;QACxD,QAAQ;aACL,IAAI,CAAC,gBAAgB,CAAC;aACtB,MAAM,CAAC,sBAAsB,CAAC;aAC9B,EAAE,CAAC,gBAAgB,OAAO,iBAAiB,OAAO,EAAE,CAAC;KACzD,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,sBAAsB;IACvE,KAAK,MAAM,CAAC,IAAI,gBAAgB,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;QAC5C,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC9B,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAChC,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,cAAc,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;QAC1C,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC9B,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAChC,CAAC;IAED,6EAA6E;IAC7E,6DAA6D;IAC7D,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAoD,CAAC;IAErF,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,OAAO,GAAqE,EAAE,CAAC;QAErF,KAAK,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,aAAa,EAAE,CAAC;YACpD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,kBAAkB,EAAE;gBAC7D,SAAS,EAAE,OAAO;gBAClB,UAAU,EAAE,QAAQ;gBACpB,WAAW,EAAE,SAAS;gBACtB,OAAO,EAAE,8BAA8B;aACxC,CAAC,CAAC;YACH,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,CAAC,KAAK,CAAC,2CAA2C,QAAQ,GAAG,EAAE,KAAK,CAAC,CAAC;gBAC7E,SAAS;YACX,CAAC;YACD,KAAK,MAAM,GAAG,IAAI,IAAI,IAAI,EAAE,EAAE,CAAC;gBAC7B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACpB,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;QACjC,IAAI,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,SAAS;QAC5C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,QAAQ,IAAI,GAAG,CAAC,UAAU,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAC;YACtD,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE;gBAChC,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,QAAQ,EAAE,GAAG,CAAC,QAAQ;aACvB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,MAAM,iBAAiB,GAAG,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC;SAC7D,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;SACjD,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;SACZ,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;IAErD,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;IAC3E,CAAC;IAED,6EAA6E;IAC7E,MAAM,aAAa,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAC9D,MAAM,EAAE,IAAI,EAAE,kBAAkB,EAAE,GAAG,MAAM,QAAQ;SAChD,IAAI,CAAC,YAAY,CAAC;SAClB,MAAM,CAAC,yCAAyC,CAAC;SACjD,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAEhC,MAAM,WAAW,GAAG,IAAI,GAAG,CACzB,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CACtD,CAAC;IAEF,6EAA6E;IAC7E,MAAM,IAAI,GAAG,QAAQ,CAAC,YAAY,CAAC,SAAS,CAAC;IAE7C,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACxD,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAC3B,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC;QAC5C,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACzF,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC;QAC3E,OAAO,YAAY,IAAI,oBAAoB,IAAI,YAAY,IAAI,oBAAoB,CAAC;IACtF,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,MAAM,iBAAiB,GAAa,EAAE,CAAC;IAEvC,KAAK,MAAM,SAAS,IAAI,kBAAkB,EAAE,CAAC;QAC3C,IAAI,iBAAiB,CAAC,MAAM,IAAI,eAAe;YAAE,MAAM;QAEvD,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAE,CAAC;QACpD,MAAM,gBAAgB,GAAG,wBAAwB,CAC/C,QAAQ,CAAC,gBAAgB,EACzB,OAAO,CAAC,gBAAgB,CACzB,CAAC;QAEF,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,GAAG,CACnC,YAAY,SAAS,CAAC,OAAO,EAAE,EAC/B,KAAK,IAAI,EAAE,CACT,QAAQ,CACN,UAAU,EACV,uBAAuB,EACvB;YACE,qBAAqB,gBAAgB,YAAY,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;YACjG,8BAA8B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE;YACzE,uBAAuB,gBAAgB,YAAY,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;YAClG,8BAA8B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE;YACxE,8BAA8B,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,SAAS,CAAC,QAAQ,GAAG;SAClG,CAAC,IAAI,CAAC,MAAM,CAAC,CACf,CACJ,CAAC;QAEF,IAAI,UAAmC,CAAC;QACxC,IAAI,CAAC;YACH,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,kCAAkC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;YACrE,SAAS;QACX,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,UAAU,IAAI,UAAU,CAAC,aAAa;YAAE,SAAS;QACjE,IAAK,UAAU,CAAC,UAAqB,GAAG,oBAAoB;YAAE,SAAS;QAEvE,8CAA8C;QAC9C,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,MAAM,QAAQ;aAC5D,IAAI,CAAC,SAAS,CAAC;aACf,MAAM,CAAC;YACN,SAAS,EAAE,OAAO;YAClB,SAAS,EAAE,SAAS,CAAC,OAAO;YAC5B,gBAAgB;YAChB,cAAc,EAAE,UAAU,CAAC,cAAc,IAAI,KAAK;YAClD,qBAAqB,EAAE,UAAU,CAAC,qBAAqB,IAAI,IAAI;YAC/D,gBAAgB,EAAE,UAAU,CAAC,UAAU;YACvC,UAAU,EAAE,UAAU,CAAC,UAAU,IAAI,EAAE;YACvC,QAAQ,EAAE,UAAU,CAAC,QAAQ,IAAI,EAAE;YACnC,aAAa,EAAE,KAAK;YACpB,oBAAoB,EAAE,UAAU,CAAC,oBAAoB,IAAI,EAAE;YAC3D,MAAM,EAAE,iBAAiB;YACzB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACrC,CAAC;aACD,MAAM,CAAC,IAAI,CAAC;aACZ,MAAM,EAAE,CAAC;QAEZ,IAAI,YAAY,IAAI,CAAC,SAAS,EAAE,CAAC;YAC/B,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,YAAY,CAAC,CAAC;YACvD,SAAS;QACX,CAAC;QAED,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAE1C,MAAM,IAAI,CAAC,SAAS,CAAC,mBAAmB,SAAS,CAAC,EAAE,EAAE,EAAE;YACtD,IAAI,EAAE,iBAAiB;YACvB,IAAI,EAAE,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,EAAE;SACjC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,MAAM,EAAE,CAAC;AAClE,CAAC,CACF,CAAC;AAEF,SAAS,wBAAwB,CAAC,CAAkB,EAAE,CAAkB;IACtE,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAe,CAAC;IAChD,IAAI,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnC,IAAI,KAAK,GAAG,UAAU,EAAE,CAAC;YACvB,UAAU,GAAG,KAAK,CAAC;YACnB,IAAI,GAAG,CAAC,CAAC;QACX,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduled-matching.d.ts","sourceRoot":"","sources":["../../src/jobs/scheduled-matching.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,kBAAkB,KAmD9B,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { inngest } from "../lib/inngest.js";
|
|
2
|
+
import { supabase } from "../lib/supabase.js";
|
|
3
|
+
const MAX_MATCHES_IN_QUEUE = 10;
|
|
4
|
+
// Hourly cron — finds all ready users with queue capacity and re-runs matching
|
|
5
|
+
// Ensures new users get found by existing users even without a new session
|
|
6
|
+
export const scheduled_matching = inngest.createFunction({ id: "scheduled-matching", retries: 1 }, { cron: "0 * * * *" }, // every hour on the hour
|
|
7
|
+
async ({ step }) => {
|
|
8
|
+
// Find all users ready for matching
|
|
9
|
+
const eligible_users = await step.run("find-eligible-users", async () => {
|
|
10
|
+
const { data, error } = await supabase
|
|
11
|
+
.from("identities")
|
|
12
|
+
.select("user_id")
|
|
13
|
+
.eq("ready_for_matching", true);
|
|
14
|
+
if (error)
|
|
15
|
+
throw new Error(`Failed to load eligible users: ${error.message}`);
|
|
16
|
+
return data ?? [];
|
|
17
|
+
});
|
|
18
|
+
if (eligible_users.length === 0) {
|
|
19
|
+
return { triggered: 0 };
|
|
20
|
+
}
|
|
21
|
+
// Filter to those with queue capacity
|
|
22
|
+
const user_ids = eligible_users.map((u) => u.user_id);
|
|
23
|
+
const { data: queue_counts } = await supabase
|
|
24
|
+
.from("matches")
|
|
25
|
+
.select("user_a_id, user_b_id")
|
|
26
|
+
.or(user_ids.map((id) => `user_a_id.eq.${id},user_b_id.eq.${id}`).join(","))
|
|
27
|
+
.eq("status", "pending_consent");
|
|
28
|
+
// Count pending matches per user
|
|
29
|
+
const pending_per_user = new Map();
|
|
30
|
+
for (const row of queue_counts ?? []) {
|
|
31
|
+
pending_per_user.set(row.user_a_id, (pending_per_user.get(row.user_a_id) ?? 0) + 1);
|
|
32
|
+
pending_per_user.set(row.user_b_id, (pending_per_user.get(row.user_b_id) ?? 0) + 1);
|
|
33
|
+
}
|
|
34
|
+
const users_with_capacity = user_ids.filter((id) => (pending_per_user.get(id) ?? 0) < MAX_MATCHES_IN_QUEUE);
|
|
35
|
+
// Fan out identity/updated events — run_matching handles each
|
|
36
|
+
if (users_with_capacity.length > 0) {
|
|
37
|
+
await step.sendEvent("scheduled-matching-fanout", users_with_capacity.map((user_id) => ({
|
|
38
|
+
name: "identity/updated",
|
|
39
|
+
data: { user_id },
|
|
40
|
+
})));
|
|
41
|
+
}
|
|
42
|
+
return { triggered: users_with_capacity.length, total_eligible: eligible_users.length };
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=scheduled-matching.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduled-matching.js","sourceRoot":"","sources":["../../src/jobs/scheduled-matching.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcribe-session.d.ts","sourceRoot":"","sources":["../../src/jobs/transcribe-session.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,kBAAkB,KAqE9B,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { inngest } from "../lib/inngest.js";
|
|
2
|
+
import { supabase } from "../lib/supabase.js";
|
|
3
|
+
import { transcribe_url, user_speech_only } from "../lib/deepgram.js";
|
|
4
|
+
import { generate_presigned_get_url, upload_json } from "../lib/r2.js";
|
|
5
|
+
// Triggered when a voice session recording lands in R2
|
|
6
|
+
// Runs transcription, stores result, fires next event
|
|
7
|
+
export const transcribe_session = inngest.createFunction({ id: "transcribe-session", retries: 3 }, { event: "session/completed" }, async ({ event, step }) => {
|
|
8
|
+
const { user_id, session_id } = event.data;
|
|
9
|
+
// Mark as processing
|
|
10
|
+
await step.run("mark-processing", async () => {
|
|
11
|
+
await supabase
|
|
12
|
+
.from("sessions")
|
|
13
|
+
.update({ analysis_status: "processing" })
|
|
14
|
+
.eq("id", session_id);
|
|
15
|
+
});
|
|
16
|
+
// Get session record to find audio key
|
|
17
|
+
const session = await step.run("get-session", async () => {
|
|
18
|
+
const { data, error } = await supabase
|
|
19
|
+
.from("sessions")
|
|
20
|
+
.select("audio_r2_key")
|
|
21
|
+
.eq("id", session_id)
|
|
22
|
+
.single();
|
|
23
|
+
if (error || !data)
|
|
24
|
+
throw new Error(`Session not found: ${session_id}`);
|
|
25
|
+
if (!data.audio_r2_key)
|
|
26
|
+
throw new Error(`No audio_r2_key for session: ${session_id}`);
|
|
27
|
+
return data;
|
|
28
|
+
});
|
|
29
|
+
// Generate presigned URL for Deepgram to fetch audio from R2
|
|
30
|
+
const audio_url = await step.run("presign-url", async () => {
|
|
31
|
+
return generate_presigned_get_url(session.audio_r2_key, 3600);
|
|
32
|
+
});
|
|
33
|
+
// Transcribe via Deepgram
|
|
34
|
+
const result = await step.run("transcribe", async () => {
|
|
35
|
+
return transcribe_url(audio_url);
|
|
36
|
+
});
|
|
37
|
+
// Extract user-only speech (speaker 0 = user)
|
|
38
|
+
const user_transcript = user_speech_only(result);
|
|
39
|
+
// Store transcript JSON to R2
|
|
40
|
+
const transcript_r2_key = `transcripts/${user_id}/${session_id}.json`;
|
|
41
|
+
await step.run("store-transcript", async () => {
|
|
42
|
+
await upload_json(transcript_r2_key, {
|
|
43
|
+
full: result,
|
|
44
|
+
text: user_transcript,
|
|
45
|
+
stored_at: new Date().toISOString(),
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
// Update session record
|
|
49
|
+
await step.run("update-session", async () => {
|
|
50
|
+
await supabase
|
|
51
|
+
.from("sessions")
|
|
52
|
+
.update({
|
|
53
|
+
transcript_r2_key,
|
|
54
|
+
analysis_status: "pending", // reset so compact-identity picks it up
|
|
55
|
+
duration_seconds: Math.round(result.duration_seconds),
|
|
56
|
+
})
|
|
57
|
+
.eq("id", session_id);
|
|
58
|
+
});
|
|
59
|
+
// Fire next job
|
|
60
|
+
await step.sendEvent("trigger-analysis", {
|
|
61
|
+
name: "session/transcribed",
|
|
62
|
+
data: { user_id, session_id, transcript_r2_key },
|
|
63
|
+
});
|
|
64
|
+
return { session_id, duration_seconds: result.duration_seconds };
|
|
65
|
+
});
|
|
66
|
+
//# sourceMappingURL=transcribe-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcribe-session.js","sourceRoot":"","sources":["../../src/jobs/transcribe-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const anthropic: any;
|
|
2
|
+
export declare function extract_json(raw: string): string;
|
|
3
|
+
export declare function complete(model: "conversation" | "analysis" | "matching", system: string, user: string, max_tokens?: number): Promise<string>;
|
|
4
|
+
//# sourceMappingURL=anthropic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/lib/anthropic.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,SAAS,KAEpB,CAAC;AAGH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQhD;AAGD,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,cAAc,GAAG,UAAU,GAAG,UAAU,EAC/C,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CAYjB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
+
import { config } from "./config.js";
|
|
3
|
+
export const anthropic = new Anthropic({
|
|
4
|
+
apiKey: config.anthropic.api_key,
|
|
5
|
+
});
|
|
6
|
+
// Strip markdown code fences from LLM output and return raw JSON string
|
|
7
|
+
export function extract_json(raw) {
|
|
8
|
+
const fence = raw.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
9
|
+
if (fence)
|
|
10
|
+
return fence[1].trim();
|
|
11
|
+
// Try to find first { or [ and last } or ]
|
|
12
|
+
const start = raw.search(/[{[]/);
|
|
13
|
+
const end = Math.max(raw.lastIndexOf("}"), raw.lastIndexOf("]"));
|
|
14
|
+
if (start !== -1 && end !== -1 && end > start)
|
|
15
|
+
return raw.slice(start, end + 1);
|
|
16
|
+
return raw.trim();
|
|
17
|
+
}
|
|
18
|
+
// Thin wrapper — returns text content from a single-turn message
|
|
19
|
+
export async function complete(model, system, user, max_tokens) {
|
|
20
|
+
const default_tokens = model === "analysis" ? 8192 : 4096;
|
|
21
|
+
const response = await anthropic.messages.create({
|
|
22
|
+
model: config.anthropic.models[model],
|
|
23
|
+
max_tokens: max_tokens ?? default_tokens,
|
|
24
|
+
system,
|
|
25
|
+
messages: [{ role: "user", content: user }],
|
|
26
|
+
});
|
|
27
|
+
const block = response.content[0];
|
|
28
|
+
if (block.type !== "text")
|
|
29
|
+
throw new Error("Unexpected non-text response");
|
|
30
|
+
return block.text;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/lib/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC;IACrC,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,OAAO;CACjC,CAAC,CAAC;AAEH,wEAAwE;AACxE,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IACxD,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAClC,2CAA2C;IAC3C,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IACjE,IAAI,KAAK,KAAK,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,KAAK;QAAE,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;IAChF,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,iEAAiE;AACjE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,KAA+C,EAC/C,MAAc,EACd,IAAY,EACZ,UAAmB;IAEnB,MAAM,cAAc,GAAG,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1D,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC/C,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC;QACrC,UAAU,EAAE,UAAU,IAAI,cAAc;QACxC,MAAM;QACN,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;KAC5C,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAClC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAC3E,OAAO,KAAK,CAAC,IAAI,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
export declare const config: {
|
|
3
|
+
readonly supabase: {
|
|
4
|
+
readonly url: string;
|
|
5
|
+
readonly service_role_key: string;
|
|
6
|
+
};
|
|
7
|
+
readonly twilio: {
|
|
8
|
+
readonly account_sid: string;
|
|
9
|
+
readonly auth_token: string;
|
|
10
|
+
readonly verify_service_sid: string;
|
|
11
|
+
readonly numbers: {
|
|
12
|
+
readonly "meet-the-one": string;
|
|
13
|
+
readonly casual: any;
|
|
14
|
+
readonly kink: any;
|
|
15
|
+
readonly adventure: any;
|
|
16
|
+
readonly "open-poly": any;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
readonly vapi: {
|
|
20
|
+
readonly api_key: string;
|
|
21
|
+
readonly intake_assistant_id: string;
|
|
22
|
+
readonly consent_assistant_id: string;
|
|
23
|
+
};
|
|
24
|
+
readonly anthropic: {
|
|
25
|
+
readonly api_key: string;
|
|
26
|
+
readonly models: {
|
|
27
|
+
readonly conversation: "claude-sonnet-4-6";
|
|
28
|
+
readonly analysis: "claude-opus-4-6";
|
|
29
|
+
readonly matching: "claude-sonnet-4-6";
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
readonly openai: {
|
|
33
|
+
readonly api_key: string;
|
|
34
|
+
readonly embedding_model: "text-embedding-3-large";
|
|
35
|
+
readonly embedding_dimensions: 1536;
|
|
36
|
+
};
|
|
37
|
+
readonly deepgram: {
|
|
38
|
+
readonly api_key: string;
|
|
39
|
+
readonly model: "nova-2";
|
|
40
|
+
};
|
|
41
|
+
readonly r2: {
|
|
42
|
+
readonly account_id: string;
|
|
43
|
+
readonly access_key_id: string;
|
|
44
|
+
readonly secret_access_key: string;
|
|
45
|
+
readonly bucket: string;
|
|
46
|
+
readonly endpoint: `https://${string}.r2.cloudflarestorage.com`;
|
|
47
|
+
};
|
|
48
|
+
readonly inngest: {
|
|
49
|
+
readonly event_key: string;
|
|
50
|
+
readonly signing_key: string;
|
|
51
|
+
};
|
|
52
|
+
readonly app: {
|
|
53
|
+
readonly url: any;
|
|
54
|
+
readonly port: number;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AAQvB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwET,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
function require_env(key) {
|
|
3
|
+
const val = process.env[key];
|
|
4
|
+
if (!val)
|
|
5
|
+
throw new Error(`Missing required env var: ${key}`);
|
|
6
|
+
return val;
|
|
7
|
+
}
|
|
8
|
+
export const config = {
|
|
9
|
+
// Supabase
|
|
10
|
+
supabase: {
|
|
11
|
+
url: require_env("SUPABASE_URL"),
|
|
12
|
+
service_role_key: require_env("SUPABASE_SERVICE_ROLE_KEY"),
|
|
13
|
+
},
|
|
14
|
+
// Twilio
|
|
15
|
+
twilio: {
|
|
16
|
+
account_sid: require_env("TWILIO_ACCOUNT_SID"),
|
|
17
|
+
auth_token: require_env("TWILIO_AUTH_TOKEN"),
|
|
18
|
+
verify_service_sid: require_env("TWILIO_VERIFY_SERVICE_SID"),
|
|
19
|
+
// Phone numbers per brand
|
|
20
|
+
numbers: {
|
|
21
|
+
"meet-the-one": require_env("TWILIO_NUMBER_FLAGSHIP"),
|
|
22
|
+
casual: process.env["TWILIO_NUMBER_CASUAL"] ?? "",
|
|
23
|
+
kink: process.env["TWILIO_NUMBER_KINK"] ?? "",
|
|
24
|
+
adventure: process.env["TWILIO_NUMBER_ADVENTURE"] ?? "",
|
|
25
|
+
"open-poly": process.env["TWILIO_NUMBER_OPEN_POLY"] ?? "",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
// Vapi (voice AI — v0.1)
|
|
29
|
+
vapi: {
|
|
30
|
+
api_key: require_env("VAPI_API_KEY"),
|
|
31
|
+
intake_assistant_id: require_env("VAPI_INTAKE_ASSISTANT_ID"),
|
|
32
|
+
consent_assistant_id: require_env("VAPI_CONSENT_ASSISTANT_ID"),
|
|
33
|
+
},
|
|
34
|
+
// Anthropic
|
|
35
|
+
anthropic: {
|
|
36
|
+
api_key: require_env("ANTHROPIC_API_KEY"),
|
|
37
|
+
models: {
|
|
38
|
+
conversation: "claude-sonnet-4-6",
|
|
39
|
+
analysis: "claude-opus-4-6",
|
|
40
|
+
matching: "claude-sonnet-4-6",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
// OpenAI (embeddings)
|
|
44
|
+
openai: {
|
|
45
|
+
api_key: require_env("OPENAI_API_KEY"),
|
|
46
|
+
embedding_model: "text-embedding-3-large",
|
|
47
|
+
embedding_dimensions: 1536, // truncated — pgvector local limit is 2000
|
|
48
|
+
},
|
|
49
|
+
// Deepgram (transcription)
|
|
50
|
+
deepgram: {
|
|
51
|
+
api_key: require_env("DEEPGRAM_API_KEY"),
|
|
52
|
+
model: "nova-2",
|
|
53
|
+
},
|
|
54
|
+
// Cloudflare R2 (audio/transcript storage)
|
|
55
|
+
r2: {
|
|
56
|
+
account_id: require_env("CLOUDFLARE_ACCOUNT_ID"),
|
|
57
|
+
access_key_id: require_env("R2_ACCESS_KEY_ID"),
|
|
58
|
+
secret_access_key: require_env("R2_SECRET_ACCESS_KEY"),
|
|
59
|
+
bucket: require_env("R2_BUCKET_NAME"),
|
|
60
|
+
endpoint: `https://${require_env("CLOUDFLARE_ACCOUNT_ID")}.r2.cloudflarestorage.com`,
|
|
61
|
+
},
|
|
62
|
+
// Inngest
|
|
63
|
+
inngest: {
|
|
64
|
+
event_key: require_env("INNGEST_EVENT_KEY"),
|
|
65
|
+
signing_key: require_env("INNGEST_SIGNING_KEY"),
|
|
66
|
+
},
|
|
67
|
+
// App
|
|
68
|
+
app: {
|
|
69
|
+
url: process.env["APP_URL"] ?? "http://localhost:3000",
|
|
70
|
+
port: parseInt(process.env["PORT"] ?? "3000", 10),
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AAEvB,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,EAAE,CAAC,CAAC;IAC9D,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,WAAW;IACX,QAAQ,EAAE;QACR,GAAG,EAAE,WAAW,CAAC,cAAc,CAAC;QAChC,gBAAgB,EAAE,WAAW,CAAC,2BAA2B,CAAC;KAC3D;IAED,SAAS;IACT,MAAM,EAAE;QACN,WAAW,EAAE,WAAW,CAAC,oBAAoB,CAAC;QAC9C,UAAU,EAAE,WAAW,CAAC,mBAAmB,CAAC;QAC5C,kBAAkB,EAAE,WAAW,CAAC,2BAA2B,CAAC;QAC5D,0BAA0B;QAC1B,OAAO,EAAE;YACP,cAAc,EAAE,WAAW,CAAC,wBAAwB,CAAC;YACrD,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,IAAI,EAAE;YACjD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,EAAE;YAC7C,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,IAAI,EAAE;YACvD,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,IAAI,EAAE;SAC1D;KACF;IAED,yBAAyB;IACzB,IAAI,EAAE;QACJ,OAAO,EAAE,WAAW,CAAC,cAAc,CAAC;QACpC,mBAAmB,EAAE,WAAW,CAAC,0BAA0B,CAAC;QAC5D,oBAAoB,EAAE,WAAW,CAAC,2BAA2B,CAAC;KAC/D;IAED,YAAY;IACZ,SAAS,EAAE;QACT,OAAO,EAAE,WAAW,CAAC,mBAAmB,CAAC;QACzC,MAAM,EAAE;YACN,YAAY,EAAE,mBAAmB;YACjC,QAAQ,EAAE,iBAAiB;YAC3B,QAAQ,EAAE,mBAAmB;SAC9B;KACF;IAED,sBAAsB;IACtB,MAAM,EAAE;QACN,OAAO,EAAE,WAAW,CAAC,gBAAgB,CAAC;QACtC,eAAe,EAAE,wBAAwB;QACzC,oBAAoB,EAAE,IAAI,EAAE,2CAA2C;KACxE;IAED,2BAA2B;IAC3B,QAAQ,EAAE;QACR,OAAO,EAAE,WAAW,CAAC,kBAAkB,CAAC;QACxC,KAAK,EAAE,QAAQ;KAChB;IAED,2CAA2C;IAC3C,EAAE,EAAE;QACF,UAAU,EAAE,WAAW,CAAC,uBAAuB,CAAC;QAChD,aAAa,EAAE,WAAW,CAAC,kBAAkB,CAAC;QAC9C,iBAAiB,EAAE,WAAW,CAAC,sBAAsB,CAAC;QACtD,MAAM,EAAE,WAAW,CAAC,gBAAgB,CAAC;QACrC,QAAQ,EAAE,WAAW,WAAW,CAAC,uBAAuB,CAAC,2BAA2B;KACrF;IAED,UAAU;IACV,OAAO,EAAE;QACP,SAAS,EAAE,WAAW,CAAC,mBAAmB,CAAC;QAC3C,WAAW,EAAE,WAAW,CAAC,qBAAqB,CAAC;KAChD;IAED,MAAM;IACN,GAAG,EAAE;QACH,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,uBAAuB;QACtD,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,MAAM,EAAE,EAAE,CAAC;KAClD;CACO,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const deepgram: any;
|
|
2
|
+
export interface TranscriptResult {
|
|
3
|
+
transcript: string;
|
|
4
|
+
words: Array<{
|
|
5
|
+
word: string;
|
|
6
|
+
start: number;
|
|
7
|
+
end: number;
|
|
8
|
+
confidence: number;
|
|
9
|
+
speaker: number;
|
|
10
|
+
}>;
|
|
11
|
+
duration_seconds: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function transcribe_url(audio_url: string): Promise<TranscriptResult>;
|
|
14
|
+
export declare function user_speech_only(result: TranscriptResult): string;
|
|
15
|
+
//# sourceMappingURL=deepgram.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deepgram.d.ts","sourceRoot":"","sources":["../../src/lib/deepgram.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,QAAQ,KAAwC,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;IACH,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAGD,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,CAAC,CA4B3B;AAGD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAKjE"}
|