| |
| |
| |
|
|
| from typing import Literal |
|
|
| DEPTH_PROMPTS = { |
| "Summary bullets": """ |
| You are a personal finance analyst reviewing a year or more of credit card statements. |
| Based on the data provided, give a concise bullet-point analysis covering: |
| |
| β’ 3-5 standout spending patterns or anomalies |
| β’ Any suspicious or duplicate-looking charges |
| β’ Quick wins β subscriptions or recurring charges the user could cancel |
| β’ One overall financial habit observation |
| |
| Keep it brief and scannable. Use plain language, no jargon. |
| """, |
| "Deep narrative analysis": """ |
| You are an expert personal finance analyst reviewing a year or more of credit card statements. |
| Based on the data provided, write a thorough narrative analysis covering: |
| |
| 1. **Spending Personality** β What do these statements reveal about this person's lifestyle and habits? |
| 2. **Anomalies & Red Flags** β Any duplicate charges, unusual timing, or charges that don't fit the pattern? |
| 3. **Subscription Audit** β Evaluate all recurring and subscription charges. Which ones seem worth it? Which seem forgotten or wasteful? |
| 4. **Year-over-Year Trends** β What's growing? What's declining? Is spending trending in a healthy or concerning direction? |
| 5. **Category Analysis** β Where is the bulk of money going? Is it balanced? |
| 6. **Missed Savings Opportunities** β Specific charges where better options likely exist (e.g. switching providers, bundling services) |
| 7. **Action Items** β A prioritized list of 5 concrete things this person should do after reading this analysis |
| |
| Be specific, reference actual merchants and amounts from the data. Write for a smart adult who wants honest, direct insight. |
| """, |
| } |
|
|
|
|
| def build_prompt(data_summary: str, depth: str) -> str: |
| system_section = DEPTH_PROMPTS.get(depth, DEPTH_PROMPTS["Summary bullets"]) |
| return f"""{system_section} |
| |
| Here is the spending data to analyze: |
| |
| {data_summary} |
| """ |
|
|
|
|
| def call_openai(prompt: str, api_key: str) -> str: |
| try: |
| from openai import OpenAI |
| client = OpenAI(api_key=api_key) |
| response = client.chat.completions.create( |
| model="gpt-4o", |
| messages=[ |
| { |
| "role": "system", |
| "content": "You are an expert personal finance analyst. Be direct, specific, and helpful.", |
| }, |
| {"role": "user", "content": prompt}, |
| ], |
| max_tokens=2000, |
| temperature=0.4, |
| ) |
| return response.choices[0].message.content |
| except Exception as e: |
| return f"β OpenAI error: {str(e)}" |
|
|
|
|
| def call_gemini(prompt: str, api_key: str) -> str: |
| try: |
| import google.generativeai as genai |
| genai.configure(api_key=api_key) |
| model = genai.GenerativeModel("gemini-1.5-pro") |
| response = model.generate_content(prompt) |
| return response.text |
| except Exception as e: |
| return f"β Gemini error: {str(e)}" |
|
|
|
|
| def call_anthropic(prompt: str, api_key: str) -> str: |
| try: |
| import anthropic |
| client = anthropic.Anthropic(api_key=api_key) |
| response = client.messages.create( |
| model="claude-sonnet-4-20250514", |
| max_tokens=2000, |
| system="You are an expert personal finance analyst. Be direct, specific, and helpful.", |
| messages=[{"role": "user", "content": prompt}], |
| ) |
| return response.content[0].text |
| except Exception as e: |
| return f"β Anthropic error: {str(e)}" |
|
|
|
|
| def get_ai_insights( |
| data_summary: str, |
| provider: str, |
| api_key: str, |
| depth: str = "Summary bullets", |
| ) -> str: |
| prompt = build_prompt(data_summary, depth) |
| if provider == "OpenAI (GPT-4o)": |
| return call_openai(prompt, api_key) |
| elif provider == "Google Gemini": |
| return call_gemini(prompt, api_key) |
| elif provider == "Anthropic Claude": |
| return call_anthropic(prompt, api_key) |
| return "Unknown provider selected." |
|
|