File size: 2,657 Bytes
75d9b3c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
"""
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)}"