Spaces:
Sleeping
Sleeping
| """Step 1: LLM turns the topic/keywords/brief into optimized web-search queries.""" | |
| from __future__ import annotations | |
| import json | |
| import re | |
| from typing import List | |
| from huggingface_hub import InferenceClient | |
| from . import config, llm | |
| _SYSTEM = ( | |
| "You are an SEO research assistant. Given a blog topic, its target keywords, and a " | |
| "brief, produce a small set of high-signal web search queries that will surface the " | |
| "most authoritative, information-rich sources to write the post from. Vary angle and " | |
| "specificity. Return ONLY a JSON array of query strings, nothing else." | |
| ) | |
| def _fallback_terms(topic: str, primary: str, secondary: str) -> List[str]: | |
| base = [t for t in [topic, primary, secondary] if t] | |
| extra = [f"{topic} {primary}".strip(), f"{topic} guide", f"{topic} best practices"] | |
| seen, out = set(), [] | |
| for t in base + extra: | |
| t = t.strip() | |
| if t and t.lower() not in seen: | |
| seen.add(t.lower()) | |
| out.append(t) | |
| return out[: config.N_SEARCH_TERMS] | |
| def generate_search_terms( | |
| client: InferenceClient, | |
| topic: str, | |
| primary_keyword: str, | |
| secondary_keyword: str, | |
| brief: str, | |
| ) -> List[str]: | |
| user = ( | |
| f"Topic: {topic}\n" | |
| f"Primary keyword: {primary_keyword}\n" | |
| f"Secondary keyword: {secondary_keyword}\n" | |
| f"Brief: {brief}\n\n" | |
| f"Return {config.N_SEARCH_TERMS} search queries as a JSON array." | |
| ) | |
| try: | |
| raw = llm.chat( | |
| client, config.MODEL_REASONING, _SYSTEM, user, | |
| max_tokens=400, temperature=0.4, | |
| ) | |
| terms = _parse_terms(raw) | |
| if terms: | |
| return terms[: config.N_SEARCH_TERMS] | |
| except Exception: | |
| pass | |
| return _fallback_terms(topic, primary_keyword, secondary_keyword) | |
| def _parse_terms(raw: str) -> List[str]: | |
| """Extract a list of strings from a (possibly fenced) LLM response.""" | |
| match = re.search(r"\[.*\]", raw, re.DOTALL) | |
| if match: | |
| try: | |
| data = json.loads(match.group(0)) | |
| return [str(t).strip() for t in data if str(t).strip()] | |
| except Exception: | |
| pass | |
| # line-based fallback | |
| lines = [re.sub(r'^[\s\-\*\d\.\)"]+', "", ln).strip().strip('"') for ln in raw.splitlines()] | |
| return [ln for ln in lines if ln] | |