antenna-fyi 1.3.26 ā 1.3.28
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/lib/cli.js +4 -6
- package/lib/core.js +62 -0
- package/package.json +1 -1
package/lib/cli.js
CHANGED
|
@@ -66,12 +66,11 @@ export async function handleScan(f) {
|
|
|
66
66
|
|
|
67
67
|
export async function handleProfile(f) {
|
|
68
68
|
const id = resolveId(f);
|
|
69
|
-
if (!id) return console.error("Usage: antenna profile --id <platform>:<user_id> [--name Yi --
|
|
69
|
+
if (!id) return console.error("Usage: antenna profile --id <platform>:<user_id> [--name Yi --personal-description '...' --looking-for '...' --conversation-style '...'].']");
|
|
70
70
|
if (f.name || f["personal-description"] || f["looking-for"] || f["conversation-style"] || f["more-information"] || f.visible !== undefined || f.hide !== undefined) {
|
|
71
71
|
const visible = f.hide ? false : (f.visible !== undefined ? f.visible === 'true' || f.visible === true : undefined);
|
|
72
72
|
const payload = { device_id: id };
|
|
73
73
|
if (f.name) payload.display_name = f.name;
|
|
74
|
-
if (f.emoji) payload.emoji = f.emoji;
|
|
75
74
|
if (f["personal-description"] !== undefined) payload.line1 = f["personal-description"];
|
|
76
75
|
if (f["looking-for"] !== undefined) payload.line2 = f["looking-for"];
|
|
77
76
|
if (f["conversation-style"] !== undefined) payload.line3 = f["conversation-style"];
|
|
@@ -337,7 +336,6 @@ export async function handleSetup(f) {
|
|
|
337
336
|
if (!id) { rl.close(); return console.error("Device ID is required."); }
|
|
338
337
|
|
|
339
338
|
const name = await ask("Display name: ");
|
|
340
|
-
const emoji = (await ask("Emoji (default š¤): ")) || "š¤";
|
|
341
339
|
const personalDesc = await ask("Personal description ā who you are, what you do: ");
|
|
342
340
|
const lookingFor = await ask("Looking for ā the kind of people you want to meet: ");
|
|
343
341
|
const convStyle = await ask("Conversation style ā the type of conversations you want: ");
|
|
@@ -347,14 +345,14 @@ export async function handleSetup(f) {
|
|
|
347
345
|
const data = await setProfile({
|
|
348
346
|
device_id: id,
|
|
349
347
|
display_name: name || null,
|
|
350
|
-
|
|
348
|
+
|
|
351
349
|
line1: personalDesc || null,
|
|
352
350
|
line2: lookingFor || null,
|
|
353
351
|
line3: convStyle || null,
|
|
354
352
|
});
|
|
355
353
|
|
|
356
354
|
console.log("\nā
Profile saved!\n");
|
|
357
|
-
console.log(` ${
|
|
355
|
+
console.log(` ${name || "Anonymous"}`);
|
|
358
356
|
if (personalDesc) console.log(` ${personalDesc}`);
|
|
359
357
|
if (lookingFor) console.log(` ${lookingFor}`);
|
|
360
358
|
if (convStyle) console.log(` ${convStyle}`);
|
|
@@ -997,7 +995,7 @@ export function printHelp() {
|
|
|
997
995
|
Usage:
|
|
998
996
|
antenna scan --lat 39.99 --lng 116.48 [--radius 500] (max 1000) [--id <platform>:<user_id>]
|
|
999
997
|
antenna checkin --id <platform>:<user_id> --lat 39.99 --lng 116.48
|
|
1000
|
-
antenna profile --id <platform>:<user_id> [--name Yi --
|
|
998
|
+
antenna profile --id <platform>:<user_id> [--name Yi --personal-description '...']
|
|
1001
999
|
antenna accept --id <platform>:<user_id> --target <ref_or_device_id> [--contact 'WeChat: yi']
|
|
1002
1000
|
antenna pass --id <platform>:<user_id> --target <ref_or_device_id> (or --ref 1)
|
|
1003
1001
|
antenna matches --id <platform>:<user_id>
|
package/lib/core.js
CHANGED
|
@@ -45,6 +45,22 @@ async function generateMatchReason(myLines, theirLines) {
|
|
|
45
45
|
} catch { return null; }
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
async function generateArchetypeReason(archetype, profileText) {
|
|
49
|
+
try {
|
|
50
|
+
const res = await fetch(`${_url || DEFAULT_URL}/functions/v1/generate-archetype`, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: {
|
|
53
|
+
"Content-Type": "application/json",
|
|
54
|
+
"Authorization": `Bearer ${process.env.ANTENNA_SUPABASE_KEY || process.env.ANTENNA_KEY || DEFAULT_KEY}`,
|
|
55
|
+
},
|
|
56
|
+
body: JSON.stringify({ archetype, profile_text: profileText }),
|
|
57
|
+
});
|
|
58
|
+
if (!res.ok) return null;
|
|
59
|
+
const data = await res.json();
|
|
60
|
+
return data || null;
|
|
61
|
+
} catch { return null; }
|
|
62
|
+
}
|
|
63
|
+
|
|
48
64
|
export function getClient(url, key) {
|
|
49
65
|
const u = url || process.env.ANTENNA_SUPABASE_URL || process.env.ANTENNA_URL || DEFAULT_URL;
|
|
50
66
|
const k = key || process.env.ANTENNA_SUPABASE_KEY || process.env.ANTENNA_KEY || DEFAULT_KEY;
|
|
@@ -311,6 +327,7 @@ export async function setProfile({
|
|
|
311
327
|
// Read back profile to get slug for public page link
|
|
312
328
|
let publicUrl = null;
|
|
313
329
|
let bindUrl = null;
|
|
330
|
+
let archetypeResult = null;
|
|
314
331
|
try {
|
|
315
332
|
const profile = await getProfile({ device_id, supabaseUrl, supabaseKey });
|
|
316
333
|
if (profile?.profile_slug) {
|
|
@@ -318,6 +335,50 @@ export async function setProfile({
|
|
|
318
335
|
}
|
|
319
336
|
} catch {}
|
|
320
337
|
|
|
338
|
+
// Generate personalized archetype description via LLM
|
|
339
|
+
try {
|
|
340
|
+
const profileText = [line1, line2, line3, matching_context].filter(Boolean).join(". ");
|
|
341
|
+
if (profileText) {
|
|
342
|
+
// Simple keyword-based archetype detection (same logic as frontend)
|
|
343
|
+
const corpus = profileText.toLowerCase();
|
|
344
|
+
const archetypeKeywords = {
|
|
345
|
+
Prometheus: ["ai", "agent", "llm", "founder", "startup", "build", "developer", "hacker", "tools", "\u667a\u80fd\u4f53", "\u521b\u4e1a", "\u5f00\u53d1"],
|
|
346
|
+
Athena: ["product", "strategy", "research", "design", "craft", "pm", "ux", "\u4ea7\u54c1", "\u8bbe\u8ba1", "\u7814\u7a76"],
|
|
347
|
+
Hermes: ["network", "connect", "community", "social", "bridge", "\u793e\u4ea4", "\u8fde\u63a5", "\u793e\u533a"],
|
|
348
|
+
Apollo: ["music", "media", "content", "creator", "writing", "taste", "\u97f3\u4e50", "\u5185\u5bb9", "\u521b\u4f5c"],
|
|
349
|
+
Artemis: ["independent", "explore", "freelance", "health", "outdoor", "\u72ec\u7acb", "\u63a2\u7d22"],
|
|
350
|
+
Aphrodite: ["beauty", "brand", "fashion", "relationship", "\u7f8e", "\u54c1\u724c", "\u65f6\u5c1a"],
|
|
351
|
+
Dionysus: ["event", "culture", "party", "art", "festival", "\u6d3b\u52a8", "\u6587\u5316", "\u827a\u672f"],
|
|
352
|
+
Hades: ["finance", "invest", "infrastructure", "backend", "security", "\u6295\u8d44", "\u91d1\u878d", "\u67b6\u6784"],
|
|
353
|
+
Persephone: ["transform", "cross", "research", "academic", "bridge", "\u8de8\u754c", "\u7814\u7a76", "\u5b66\u672f"],
|
|
354
|
+
Odysseus: ["founder", "journey", "resilience", "travel", "startup", "\u521b\u4e1a", "\u65c5\u884c"],
|
|
355
|
+
};
|
|
356
|
+
let bestArchetype = "Prometheus";
|
|
357
|
+
let bestScore = 0;
|
|
358
|
+
for (const [role, keywords] of Object.entries(archetypeKeywords)) {
|
|
359
|
+
const score = keywords.reduce((s, kw) => s + (corpus.includes(kw) ? 1 : 0), 0);
|
|
360
|
+
if (score > bestScore) { bestScore = score; bestArchetype = role; }
|
|
361
|
+
}
|
|
362
|
+
archetypeResult = await generateArchetypeReason(bestArchetype, profileText);
|
|
363
|
+
if (archetypeResult?.reason) {
|
|
364
|
+
archetypeResult.archetype = bestArchetype;
|
|
365
|
+
// Write archetype back to matching_context so dashboard can display it
|
|
366
|
+
try {
|
|
367
|
+
const profile = await getProfile({ device_id, supabaseUrl, supabaseKey });
|
|
368
|
+
let ctx = {};
|
|
369
|
+
try { ctx = JSON.parse(profile?.matching_context || "{}"); } catch {}
|
|
370
|
+
ctx.archetypeOverride = { name: bestArchetype, reason: archetypeResult.reason, reasonZh: archetypeResult.reasonZh };
|
|
371
|
+
await sb.rpc("upsert_profile", {
|
|
372
|
+
p_device_id: device_id,
|
|
373
|
+
p_matching_context: JSON.stringify(ctx),
|
|
374
|
+
});
|
|
375
|
+
} catch {}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
} catch (e) {
|
|
379
|
+
console.error("Archetype generation failed (non-fatal):", e.message);
|
|
380
|
+
}
|
|
381
|
+
|
|
321
382
|
// Auto-generate GPS bind link
|
|
322
383
|
try {
|
|
323
384
|
const bind = await createBindToken({ device_id, supabaseUrl, supabaseKey });
|
|
@@ -328,6 +389,7 @@ export async function setProfile({
|
|
|
328
389
|
...data,
|
|
329
390
|
public_url: publicUrl,
|
|
330
391
|
gps_bind_url: bindUrl,
|
|
392
|
+
archetype: archetypeResult || null,
|
|
331
393
|
next_step: "Send the public_url and gps_bind_url to the user. The GPS link should be opened on their phone to share location.",
|
|
332
394
|
};
|
|
333
395
|
}
|