Spaces:
Build error
Build error
File size: 7,138 Bytes
37d460f 65c8966 37d460f |
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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# agent_graph.py
import re
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate
from tools import get_price, buying_power_tool
import os
from dotenv import load_dotenv
import yfinance as yf
# Load environment variables from .env file
load_dotenv()
# Get the OpenAI API key from the .env file
openai_api_key = os.getenv("OPENAI_API_KEY")
if not openai_api_key:
raise ValueError("OpenAI API key is missing in the .env file")
# Initialize the LLM
llm = ChatOpenAI(
model="gpt-4",
temperature=0,
openai_api_key=openai_api_key
)
# Common stock tickers for validation
COMMON_TICKERS = {
# Tech stocks
'AAPL': 'Apple',
'MSFT': 'Microsoft',
'GOOGL': 'Google',
'AMZN': 'Amazon',
'META': 'Meta',
'TSLA': 'Tesla',
'NVDA': 'NVIDIA',
'AMD': 'AMD',
'INTC': 'Intel',
'CRM': 'Salesforce',
# Financial stocks
'JPM': 'JPMorgan Chase',
'BAC': 'Bank of America',
'WFC': 'Wells Fargo',
'GS': 'Goldman Sachs',
'MS': 'Morgan Stanley',
# Retail stocks
'WMT': 'Walmart',
'TGT': 'Target',
'COST': 'Costco',
'HD': 'Home Depot',
'SBUX': 'Starbucks',
'KO': 'Coca-Cola'
}
def extract_potential_ticker(text):
"""Extract potential stock ticker from text, handling various formats."""
# First, look for tickers in the format "TICKER" or "$TICKER"
patterns = [
r'\b[A-Z]{1,5}\b', # 1-5 capital letters
r'\$[A-Z]{1,5}\b', # Tickers with $ prefix
]
# Convert common company names to tickers
text_upper = text.upper()
for ticker, company in COMMON_TICKERS.items():
if company.upper() in text_upper:
return ticker
# Look for exact matches in common tickers first
words = text_upper.split()
for word in words:
clean_word = word.strip('$')
if clean_word in COMMON_TICKERS:
return clean_word
# Then try pattern matching
for pattern in patterns:
matches = re.findall(pattern, text_upper)
if matches:
# Filter out common English words and other noise
for match in matches:
clean_match = match.replace('$', '')
# Skip if it's a common word that got caught
if clean_match in ['A', 'I', 'ME', 'MY', 'AM', 'PM', 'THE', 'FOR', 'IN', 'IS', 'IT', 'BE', 'AS', 'AT', 'SO', 'WE', 'HE', 'BY', 'OR', 'ON', 'DO', 'IF', 'ME', 'UP', 'AN', 'GO', 'NO', 'US', 'OF']:
continue
return clean_match
return None
def is_valid_ticker(ticker):
"""Validate if a ticker is valid and has current market data."""
if not ticker:
return False
# Check if it's in our common tickers list first
if ticker in COMMON_TICKERS:
return True
try:
stock = yf.Ticker(ticker)
info = stock.info
return 'regularMarketPrice' in info and info['regularMarketPrice'] is not None
except:
return False
def agent_node(state):
input_text = state["input"]
chat_history = state.get("chat_history", [])
# Extract potential ticker from input
potential_ticker = extract_potential_ticker(input_text)
# Look for context in chat history
last_valid_ticker = None
last_valid_amount = None
# Scan recent history for context
for msg in reversed(chat_history[:-1]): # Exclude current message
if msg["role"] == "user":
hist_ticker = extract_potential_ticker(msg["content"])
if hist_ticker and is_valid_ticker(hist_ticker):
last_valid_ticker = hist_ticker
# Look for amount in the same message
amount_match = re.search(r'\$?(\d+(?:,\d+)*(?:\.\d+)?)', msg["content"])
if amount_match:
last_valid_amount = float(amount_match.group(1).replace(',', ''))
break
# If no ticker in current input but we have context, use it
if not potential_ticker and last_valid_ticker and any(word in input_text.lower() for word in ['it', 'this', 'that', 'stock', 'price', 'shares']):
potential_ticker = last_valid_ticker
# If no potential ticker found in a way that looks like a stock query
if not potential_ticker and any(word in input_text.lower() for word in ['stock', 'price', 'ticker', 'share', 'market']):
return {
"output": """I noticed you're asking about stocks, but I couldn't identify a specific ticker symbol.
Here are some examples of valid queries:
- Just type a ticker (e.g., 'AAPL' for Apple)
- Ask for a price (e.g., 'What's the price of MSFT?')
- Calculate shares (e.g., 'How many GOOGL shares can I buy with $10000?')
Common tickers:
- AAPL (Apple)
- MSFT (Microsoft)
- GOOGL (Google)
- AMZN (Amazon)
- META (Meta)
- TSLA (Tesla)"""
}
# If no stock-related terms found at all
if not potential_ticker and not any(word in input_text.lower() for word in ['stock', 'price', 'ticker', 'share', 'market', 'buy', 'worth', 'cost', 'it', 'this', 'that']):
return {
"output": """I can help you with:
1. Getting stock prices (e.g., 'AAPL' or 'What's MSFT trading at?')
2. Calculating how many shares you can buy (e.g., 'How many GOOGL shares for $10000?')
Try typing a ticker symbol to get started!"""
}
# If we found a potential ticker, verify it
if potential_ticker and not is_valid_ticker(potential_ticker):
similar_tickers = [t for t in COMMON_TICKERS.keys() if any(c1 == c2 for c1, c2 in zip(t, potential_ticker))]
suggestion = f"\n\nDid you mean one of these?\n" + "\n".join([f"- {t} ({COMMON_TICKERS[t]})" for t in similar_tickers]) if similar_tickers else ""
return {"output": f"'{potential_ticker}' doesn't appear to be a valid stock ticker. Please check the symbol and try again.{suggestion}"}
# Process the query
try:
# Check if the query is about buying power
if any(word in input_text.lower() for word in ['buy', 'afford', 'purchase', 'get', 'shares']):
# Extract amount from the query if present
amount_match = re.search(r'\$?(\d+(?:,\d+)*(?:\.\d+)?)', input_text)
amount = None
if amount_match:
amount = float(amount_match.group(1).replace(',', ''))
elif last_valid_amount: # Use amount from context if available
amount = last_valid_amount
if amount:
result = buying_power_tool(f"{potential_ticker},{amount}")
else:
result = "Please specify a dollar amount to calculate how many shares you can buy. For example:\n'How many AAPL shares can I buy with $10000?'"
else:
# Default to getting the price
result = get_price(potential_ticker)
return {"output": result}
except Exception as e:
print(f"[LangGraph] Error: {e}")
return {"output": "I encountered an error while processing your request. Please try again with a different query."}
|