fix: split Perplexity into 3 focused queries matching research methodology
Single mega-query returns empty results. Split into: B4a. Instagram + YouTube (most important, focused search) B4b. Facebook + TikTok + Naver Blog + Kakao B4c. 강남언니 + review platforms Each query is short and focused — matches the proven pattern of 2-5 keyword searches that Perplexity handles well. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>claude/bold-hawking
parent
ac2da7a4ac
commit
5157cf446a
|
|
@ -284,83 +284,89 @@ Deno.serve(async (req) => {
|
||||||
} catch { /* skip */ }
|
} catch { /* skip */ }
|
||||||
})());
|
})());
|
||||||
|
|
||||||
// ─── B4. Perplexity sonar-pro: Online Presence 종합 리서치 에이전트 ───
|
// ─── B4. Perplexity: 3 separate focused queries (like the research methodology) ───
|
||||||
let perplexityResearch: Record<string, unknown> | null = null;
|
let perplexityResearch: Record<string, unknown> | null = null;
|
||||||
|
|
||||||
if (PERPLEXITY_API_KEY) {
|
if (PERPLEXITY_API_KEY) {
|
||||||
|
const ppxHeaders = { "Content-Type": "application/json", Authorization: `Bearer ${PERPLEXITY_API_KEY}` };
|
||||||
|
const ppxSystem = "You are a social media researcher. Search the web and find accounts. Respond ONLY with valid JSON, no explanation.";
|
||||||
|
|
||||||
|
// B4a. Instagram + YouTube 검색 (가장 중요)
|
||||||
stageBTasks.push((async () => {
|
stageBTasks.push((async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch("https://api.perplexity.ai/chat/completions", {
|
const res = await fetch("https://api.perplexity.ai/chat/completions", {
|
||||||
method: "POST",
|
method: "POST", headers: ppxHeaders,
|
||||||
headers: { "Content-Type": "application/json", Authorization: `Bearer ${PERPLEXITY_API_KEY}` },
|
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
model: "sonar",
|
model: "sonar",
|
||||||
messages: [
|
messages: [
|
||||||
{ role: "system", content: RESEARCH_SYSTEM_PROMPT },
|
{ role: "system", content: ppxSystem },
|
||||||
{ role: "user", content: buildResearchUserPrompt(resolvedName, url) },
|
{ role: "user", content: `${resolvedName} 성형외과 공식 인스타그램 계정과 유튜브 채널을 찾아줘. 인스타는 여러 계정(국문, 영문, 원장 등)이 있을 수 있어.\n\n{"instagram": ["@handle1", "@handle2"], "youtube": ["@handle_or_url"]}` },
|
||||||
],
|
],
|
||||||
temperature: 0.1,
|
temperature: 0.1,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
let text = data.choices?.[0]?.message?.content || "";
|
let text = data.choices?.[0]?.message?.content || "";
|
||||||
// Strip markdown code blocks
|
const m = text.match(/\{[\s\S]*\}/);
|
||||||
const jsonMatch = text.match(/```(?:json)?\n?([\s\S]*?)```/);
|
if (m) {
|
||||||
if (jsonMatch) text = jsonMatch[1];
|
const parsed = JSON.parse(m[0]);
|
||||||
// Try to find JSON in mixed text
|
const ig = Array.isArray(parsed.instagram) ? parsed.instagram : parsed.instagram ? [parsed.instagram] : [];
|
||||||
const jsonStart = text.indexOf('{');
|
const yt = Array.isArray(parsed.youtube) ? parsed.youtube : parsed.youtube ? [parsed.youtube] : [];
|
||||||
const jsonEnd = text.lastIndexOf('}');
|
ig.forEach((h: unknown) => { if (h && typeof h === 'string') apiHandles.instagram!.push(h); });
|
||||||
if (jsonStart >= 0 && jsonEnd > jsonStart) {
|
yt.forEach((h: unknown) => { if (h && typeof h === 'string') apiHandles.youtube!.push(h); });
|
||||||
text = text.slice(jsonStart, jsonEnd + 1);
|
|
||||||
}
|
}
|
||||||
const parsed = JSON.parse(text);
|
} catch { /* skip */ }
|
||||||
|
})());
|
||||||
|
|
||||||
|
// B4b. Facebook + TikTok + 네이버 블로그 + 카카오
|
||||||
|
stageBTasks.push((async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetch("https://api.perplexity.ai/chat/completions", {
|
||||||
|
method: "POST", headers: ppxHeaders,
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: "sonar",
|
||||||
|
messages: [
|
||||||
|
{ role: "system", content: ppxSystem },
|
||||||
|
{ role: "user", content: `${resolvedName} 병원의 페이스북, 틱톡, 네이버블로그, 카카오채널 계정을 검색해줘.\n\n{"facebook": "page_or_url", "tiktok": "@handle", "naverBlog": "blogId", "kakao": "channelId"}` },
|
||||||
|
],
|
||||||
|
temperature: 0.1,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
let text = data.choices?.[0]?.message?.content || "";
|
||||||
|
const m = text.match(/\{[\s\S]*\}/);
|
||||||
|
if (m) {
|
||||||
|
const parsed = JSON.parse(m[0]);
|
||||||
|
if (parsed.facebook && typeof parsed.facebook === 'string') apiHandles.facebook!.push(parsed.facebook);
|
||||||
|
if (parsed.tiktok && typeof parsed.tiktok === 'string') apiHandles.tiktok!.push(parsed.tiktok);
|
||||||
|
if (parsed.naverBlog && typeof parsed.naverBlog === 'string') apiHandles.naverBlog!.push(parsed.naverBlog);
|
||||||
|
if (parsed.kakao && typeof parsed.kakao === 'string') apiHandles.kakao!.push(parsed.kakao);
|
||||||
|
}
|
||||||
|
} catch { /* skip */ }
|
||||||
|
})());
|
||||||
|
|
||||||
|
// B4c. 강남언니 + 리뷰 플랫폼
|
||||||
|
stageBTasks.push((async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetch("https://api.perplexity.ai/chat/completions", {
|
||||||
|
method: "POST", headers: ppxHeaders,
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: "sonar",
|
||||||
|
messages: [
|
||||||
|
{ role: "system", content: ppxSystem },
|
||||||
|
{ role: "user", content: `${resolvedName} 병원이 강남언니(gangnamunni.com)에 등록되어있는지 검색해줘. URL도 찾아줘.\n\n{"gangnamUnni": {"registered": true, "url": "https://gangnamunni.com/hospitals/...", "rating": 9.5, "reviews": 1000}}` },
|
||||||
|
],
|
||||||
|
temperature: 0.1,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
let text = data.choices?.[0]?.message?.content || "";
|
||||||
|
const m = text.match(/\{[\s\S]*\}/);
|
||||||
|
if (m) {
|
||||||
|
const parsed = JSON.parse(m[0]);
|
||||||
perplexityResearch = parsed;
|
perplexityResearch = parsed;
|
||||||
|
if (parsed.gangnamUnni?.url) gangnamUnniHintUrl = String(parsed.gangnamUnni.url);
|
||||||
// Extract handles from structured channels data
|
|
||||||
const ch = parsed.channels || {};
|
|
||||||
|
|
||||||
// Instagram
|
|
||||||
const igAccounts = Array.isArray(ch.instagram) ? ch.instagram : [];
|
|
||||||
for (const ig of igAccounts) {
|
|
||||||
const handle = typeof ig === 'string' ? ig : (ig?.handle || ig?.url || '');
|
|
||||||
if (handle) apiHandles.instagram!.push(String(handle));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// YouTube
|
|
||||||
const ytChannels = Array.isArray(ch.youtube) ? ch.youtube : ch.youtube ? [ch.youtube] : [];
|
|
||||||
for (const yt of ytChannels) {
|
|
||||||
const handle = typeof yt === 'string' ? yt : (yt?.handle || yt?.channelUrl || '');
|
|
||||||
if (handle) apiHandles.youtube!.push(String(handle));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Facebook
|
|
||||||
if (ch.facebook) {
|
|
||||||
const fb = typeof ch.facebook === 'string' ? ch.facebook : (ch.facebook?.handle || ch.facebook?.url || '');
|
|
||||||
if (fb) apiHandles.facebook!.push(String(fb));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TikTok
|
|
||||||
if (ch.tiktok) {
|
|
||||||
const tk = typeof ch.tiktok === 'string' ? ch.tiktok : (ch.tiktok?.handle || ch.tiktok?.url || '');
|
|
||||||
if (tk) apiHandles.tiktok!.push(String(tk));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Naver Blog
|
|
||||||
if (ch.naverBlog) {
|
|
||||||
const nb = typeof ch.naverBlog === 'string' ? ch.naverBlog : (ch.naverBlog?.blogId || ch.naverBlog?.url || '');
|
|
||||||
if (nb) apiHandles.naverBlog!.push(String(nb));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kakao
|
|
||||||
if (ch.kakao) {
|
|
||||||
const kk = typeof ch.kakao === 'string' ? ch.kakao : (ch.kakao?.channelId || ch.kakao?.url || '');
|
|
||||||
if (kk) apiHandles.kakao!.push(String(kk));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Platform presence hints
|
|
||||||
const platforms = parsed.platforms || {};
|
|
||||||
if (platforms.gangnamUnni?.url) gangnamUnniHintUrl = String(platforms.gangnamUnni.url);
|
|
||||||
|
|
||||||
} catch { /* skip */ }
|
} catch { /* skip */ }
|
||||||
})());
|
})());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue