114 lines
4.0 KiB
TypeScript
114 lines
4.0 KiB
TypeScript
import "@supabase/functions-js/edge-runtime.d.ts";
|
|
|
|
const corsHeaders = {
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Access-Control-Allow-Headers":
|
|
"authorization, x-client-info, apikey, content-type",
|
|
};
|
|
|
|
interface AnalyzeRequest {
|
|
clinicName: string;
|
|
services: string[];
|
|
address: string;
|
|
scrapeData?: Record<string, unknown>;
|
|
}
|
|
|
|
Deno.serve(async (req) => {
|
|
if (req.method === "OPTIONS") {
|
|
return new Response("ok", { headers: corsHeaders });
|
|
}
|
|
|
|
try {
|
|
const { clinicName, services, address } =
|
|
(await req.json()) as AnalyzeRequest;
|
|
|
|
const PERPLEXITY_API_KEY = Deno.env.get("PERPLEXITY_API_KEY");
|
|
if (!PERPLEXITY_API_KEY) {
|
|
throw new Error("PERPLEXITY_API_KEY not configured");
|
|
}
|
|
|
|
// Run multiple Perplexity queries in parallel
|
|
const queries = [
|
|
{
|
|
id: "competitors",
|
|
prompt: `${address} 근처 ${services.slice(0, 3).join(", ")} 전문 성형외과/피부과 경쟁 병원 5곳을 분석해줘. 각 병원의 이름, 주요 시술, 온라인 평판, 마케팅 채널(블로그, 인스타그램, 유튜브)을 포함해줘. JSON 형식으로 응답해줘.`,
|
|
},
|
|
{
|
|
id: "keywords",
|
|
prompt: `한국 ${services.slice(0, 3).join(", ")} 관련 검색 키워드 트렌드를 분석해줘. 네이버와 구글에서 월간 검색량이 높은 키워드 20개, 경쟁 강도, 추천 롱테일 키워드를 JSON 형식으로 제공해줘.`,
|
|
},
|
|
{
|
|
id: "market",
|
|
prompt: `한국 ${services[0] || "성형외과"} 시장 트렌드 2025-2026을 분석해줘. 시장 규모, 성장률, 주요 트렌드(비수술 시술 증가, AI 마케팅, 외국인 환자 유치 등), 마케팅 채널별 효과를 JSON 형식으로 제공해줘.`,
|
|
},
|
|
{
|
|
id: "targetAudience",
|
|
prompt: `${clinicName || services[0] + " 병원"}의 잠재 고객을 분석해줘. 연령대별, 성별, 관심 시술, 정보 탐색 채널(강남언니, 바비톡, 네이버, 인스타), 의사결정 요인을 JSON 형식으로 제공해줘.`,
|
|
},
|
|
];
|
|
|
|
const perplexityResults = await Promise.allSettled(
|
|
queries.map(async (q) => {
|
|
const response = await fetch(
|
|
"https://api.perplexity.ai/chat/completions",
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${PERPLEXITY_API_KEY}`,
|
|
},
|
|
body: JSON.stringify({
|
|
model: "sonar",
|
|
messages: [
|
|
{
|
|
role: "system",
|
|
content:
|
|
"You are a Korean medical marketing analyst. Always respond in Korean. Provide data in valid JSON format when requested.",
|
|
},
|
|
{ role: "user", content: q.prompt },
|
|
],
|
|
temperature: 0.3,
|
|
}),
|
|
}
|
|
);
|
|
const data = await response.json();
|
|
return {
|
|
id: q.id,
|
|
content: data.choices?.[0]?.message?.content || "",
|
|
citations: data.citations || [],
|
|
};
|
|
})
|
|
);
|
|
|
|
const analysis: Record<string, unknown> = {};
|
|
for (const result of perplexityResults) {
|
|
if (result.status === "fulfilled") {
|
|
const { id, content, citations } = result.value;
|
|
let parsed = content;
|
|
const jsonMatch = content.match(/```json\n?([\s\S]*?)```/);
|
|
if (jsonMatch) {
|
|
try {
|
|
parsed = JSON.parse(jsonMatch[1]);
|
|
} catch {
|
|
// Keep as string if JSON parse fails
|
|
}
|
|
}
|
|
analysis[id] = { data: parsed, citations };
|
|
}
|
|
}
|
|
|
|
return new Response(
|
|
JSON.stringify({
|
|
success: true,
|
|
data: { clinicName, services, address, analysis, analyzedAt: new Date().toISOString() },
|
|
}),
|
|
{ headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
|
);
|
|
} catch (error) {
|
|
return new Response(
|
|
JSON.stringify({ success: false, error: error.message }),
|
|
{ status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
|
);
|
|
}
|
|
});
|