Spaces:
Running
Running
| # Claude Haiku๋ก ํด๋ฌ์คํฐ์ ์๋ยทํ ๋ง๋ช ์ ๋ถ๋ฅํ๊ณ ๋ง์ผํ ์ ์๊น์ง ํ ๋ฒ์ ์์ฑํ๋ ๋ชจ๋ | |
| import os | |
| import json | |
| import anthropic | |
| MODEL = "claude-haiku-4-5" | |
| USD_TO_KRW = 1400 # ๋น์ฉ ํ์ฐ์ฉ ๋๋ต๊ฐ | |
| INTENT_LABELS = { | |
| "info": "์ ๋ณด ํ์ํ", | |
| "transactional": "๊ตฌ๋งค/๊ฑฐ๋ํ", | |
| "navigational": "๋ธ๋๋/๋ด๋น๊ฒ์ด์ ํ", | |
| "mixed": "ํผํฉํ", | |
| } | |
| SYSTEM = """๋๋ ๊ฒ์ ํค์๋ ํด๋ฌ์คํฐ๋ฅผ ๋ถ์ํ๋ ๋ง์ผํ ๋ถ์๊ฐ๋ค. ๊ฐ ํด๋ฌ์คํฐ์ ๋ํด ๋ ๊ฐ์ง๋ฅผ ํ๋จํ๋ค. | |
| 1. intent โ ๊ฒ์ ์๋๋ฅผ ์ ํํ ํ๋๋ก ๋ถ๋ฅ | |
| - info: ๋ฐฉ๋ฒยท์ถ์ฒยท๋น๊ตยทํ๊ธฐยท๊ฐ์ด๋ ๋ฑ ์ ๋ณด ํ์ | |
| - transactional: ๊ตฌ๋งคยท๊ฐ๊ฒฉยท์ต์ ๊ฐยท์ฃผ๋ฌธ ๋ฑ ๊ฑฐ๋ | |
| - navigational: ํน์ ๋ธ๋๋ยท์ฌ์ดํธ๋ก ์ด๋ | |
| - mixed: ์๊ฐ ์์ฌ ํ๋๋ก ๋จ์ ํ๊ธฐ ์ด๋ ค์ | |
| 2. theme โ ํด๋ฌ์คํฐ๋ฅผ ๋ํํ๋ 2~6์ด์ ์ ์์ฐ์ค๋ฌ์ด ํ๊ตญ์ด ํ ๋ง ๊ทธ๋ฃน๋ช (์: "์บ ํ ๊ฐ๊ตฌ", "์ด๋ณด ์ ๋ฌธ ๊ฐ์ด๋", "๋๊ณ ๋๋ฐฉ") | |
| ๊ทธ๋ฆฌ๊ณ ์ ์ฒด ํด๋ฌ์คํฐ ํจํด์ ๋ณด๊ณ ์ค์๊ธฐ์ (SMB)์ด ๋ฐ๋ก ์คํํ ์ ์๋ ๋ง์ผํ ์ก์ ์ ์ 1๊ฐ๋ฅผ 2~3๋ฌธ์ฅ์ผ๋ก ๊ตฌ์ฒด์ ์ผ๋ก ์์ฑํ๋ค. | |
| ๋ฐ๋์ JSON๋ง ์ถ๋ ฅํ๋ค. ํ์: | |
| {"clusters":[{"cluster_id":0,"intent":"transactional","theme":"์บ ํ ๊ฐ๊ตฌ"}],"marketing_suggestion":"..."}""" | |
| def _client() -> anthropic.Anthropic: | |
| return anthropic.Anthropic() # ANTHROPIC_API_KEY๋ ํ๊ฒฝ๋ณ์์์ ๋ก๋ | |
| def classify_clusters(clusters: list[dict]) -> dict: | |
| # ํด๋ฌ์คํฐ์ intent/intent_label/theme๋ฅผ ์ฑ์ฐ๊ณ , ๋๋ ๋น์คยท๋ง์ผํ ์ ์ยทํ ํฐ ์ฌ์ฉ๋์ ๋ฐํ | |
| if not clusters: | |
| return {"intent_breakdown": {}, "marketing_suggestion": None, "usage": None} | |
| listing = "\n".join( | |
| f"{c['cluster_id']}: {c['cluster_label']} โ {', '.join(c['top_keywords'])}" | |
| for c in clusters | |
| ) | |
| res = _client().messages.create( | |
| model=MODEL, | |
| max_tokens=1500, | |
| system=SYSTEM, | |
| messages=[{"role": "user", "content": f"๋ค์ ํด๋ฌ์คํฐ๋ฅผ ๋ถ์ํด๋ผ.\n{listing}"}], | |
| ) | |
| text = next(b.text for b in res.content if b.type == "text").strip() | |
| if text.startswith("```"): | |
| text = text.split("```")[1].lstrip("json").strip() | |
| parsed = json.loads(text) | |
| by_id = {item["cluster_id"]: item for item in parsed.get("clusters", [])} | |
| for c in clusters: | |
| item = by_id.get(c["cluster_id"], {}) | |
| intent = item.get("intent", "mixed") | |
| if intent not in INTENT_LABELS: | |
| intent = "mixed" | |
| c["intent"] = intent | |
| c["intent_label"] = INTENT_LABELS[intent] | |
| c["theme"] = item.get("theme") or c["cluster_label"] # ํ ๋ง๋ช , ์์ผ๋ฉด ๋ํ ํค์๋ | |
| breakdown: dict[str, int] = {} | |
| for c in clusters: | |
| breakdown[c["intent"]] = breakdown.get(c["intent"], 0) + c["total_search_volume"] | |
| usd = res.usage.input_tokens / 1e6 * 1 + res.usage.output_tokens / 1e6 * 5 | |
| return { | |
| "intent_breakdown": breakdown, | |
| "marketing_suggestion": parsed.get("marketing_suggestion"), | |
| "usage": { | |
| "input_tokens": res.usage.input_tokens, | |
| "output_tokens": res.usage.output_tokens, | |
| "cost_usd": round(usd, 5), | |
| "cost_krw": round(usd * USD_TO_KRW, 1), | |
| }, | |
| } | |