""" Perplexity API Client — Thin async wrapper for deep financial research queries. Uses the Sonar model for fast, web-grounded responses. """ import logging import os import httpx logger = logging.getLogger(__name__) PERPLEXITY_BASE_URL = "https://api.perplexity.ai" DEFAULT_MODEL = "sonar" RESEARCH_SYSTEM_PROMPT = """You are a financial research analyst. Provide concise, data-backed answers to investment and market questions. Focus on: - Current market data and trends - Specific numbers, dates, and percentages - Impact on the user's portfolio holdings - Actionable insights Keep responses under 200 words. Use bullet points for clarity. Include source attribution where possible.""" async def research(query: str, context: str = "") -> str: """ Perform deep financial research via Perplexity API. Returns a structured research summary. Args: query: The research question context: Optional context about user's portfolio """ api_key = os.getenv("PERPLEXITY_API_KEY", "").strip() if not api_key: return "Perplexity API key not configured. Unable to perform deep research." messages = [ {"role": "system", "content": RESEARCH_SYSTEM_PROMPT}, ] if context: messages.append({"role": "user", "content": f"Context about my portfolio: {context}"}) messages.append({"role": "assistant", "content": "Understood. I'll factor in your portfolio context."}) messages.append({"role": "user", "content": query}) try: async with httpx.AsyncClient(timeout=30) as client: resp = await client.post( f"{PERPLEXITY_BASE_URL}/chat/completions", json={ "model": DEFAULT_MODEL, "messages": messages, "temperature": 0.1, "max_tokens": 1000, }, headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", }, ) resp.raise_for_status() data = resp.json() content = data["choices"][0]["message"]["content"] logger.info(f"Perplexity research completed for: {query[:60]}...") return content except httpx.HTTPStatusError as e: logger.error(f"Perplexity API error: {e.response.status_code} — {e.response.text[:200]}") return f"Research API error (status {e.response.status_code}). Please try again." except Exception as e: logger.error(f"Perplexity client error: {e}") return f"Unable to perform research: {str(e)}"