Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -3,24 +3,17 @@ from bs4 import BeautifulSoup
|
|
3 |
import pandas as pd
|
4 |
from io import StringIO
|
5 |
from datetime import datetime, timedelta
|
6 |
-
|
7 |
from langchain.tools import tool
|
8 |
-
from langchain.agents import initialize_agent, Tool
|
9 |
from langchain_openai import ChatOpenAI
|
|
|
10 |
|
11 |
# === Configuration ===
|
12 |
-
OPENROUTER_API_KEY = "sk-or-v1-
|
13 |
-
|
14 |
HEADERS = {
|
15 |
-
'User-Agent': (
|
16 |
-
|
17 |
-
'AppleWebKit/537.36 (KHTML, like Gecko) '
|
18 |
-
'Chrome/124.0.0.0 Safari/537.36'
|
19 |
-
),
|
20 |
-
'Accept': (
|
21 |
-
'text/html,application/xhtml+xml,application/xml;'
|
22 |
-
'q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8'
|
23 |
-
),
|
24 |
'Accept-Language': 'en-US,en;q=0.9',
|
25 |
'Referer': 'https://www.google.com/',
|
26 |
'Connection': 'keep-alive',
|
@@ -28,9 +21,10 @@ HEADERS = {
|
|
28 |
'Upgrade-Insecure-Requests': '1'
|
29 |
}
|
30 |
|
|
|
31 |
@tool("GetCurrentPrice")
|
32 |
def get_current_price(symbol: str) -> str:
|
33 |
-
"""
|
34 |
url = f'https://www.marketwatch.com/investing/stock/{symbol}'
|
35 |
response = requests.get(url, headers=HEADERS)
|
36 |
if response.status_code == 200:
|
@@ -38,7 +32,7 @@ def get_current_price(symbol: str) -> str:
|
|
38 |
price_tag = soup.find('bg-quote', class_='value')
|
39 |
if price_tag:
|
40 |
price = price_tag.get_text(strip=True)
|
41 |
-
return f"{symbol.upper()} current price: ${price}
|
42 |
else:
|
43 |
return "Stock price not found."
|
44 |
else:
|
@@ -46,7 +40,7 @@ def get_current_price(symbol: str) -> str:
|
|
46 |
|
47 |
@tool("GetHistoricalData")
|
48 |
def get_historical_data(symbol: str, days: int = 5000) -> str:
|
49 |
-
"""
|
50 |
end_date = datetime.now()
|
51 |
start_date = end_date - timedelta(days=days)
|
52 |
start_date_str = start_date.strftime('%m/%d/%Y 00:00:00')
|
@@ -61,7 +55,7 @@ def get_historical_data(symbol: str, days: int = 5000) -> str:
|
|
61 |
if response.status_code == 200:
|
62 |
try:
|
63 |
df = pd.read_csv(StringIO(response.text))
|
64 |
-
return
|
65 |
except Exception as e:
|
66 |
return f"Failed to parse CSV data: {e}"
|
67 |
else:
|
@@ -79,6 +73,7 @@ Technical Analysis: Core Concepts & Formulas
|
|
79 |
|
80 |
Key Technical Indicators and Their Formulas:
|
81 |
-------------------------------------------
|
|
|
82 |
1. Simple Moving Average (SMA): SMA(time_period) = Sum(Price_t ... Price_{t-n}) / n
|
83 |
2. Exponential Moving Average (EMA): EMA_t = (Price_t * α) + EMA_{t-1} * (1 - α), where α = 2/(n+1)
|
84 |
3. Relative Strength Index (RSI): RSI = 100 - [100 / (1 + Avg Gain / Avg Loss)]
|
@@ -144,45 +139,69 @@ Key Technical Indicators and Their Formulas:
|
|
144 |
- Hammer, Shooting Star, Engulfing, Doji, Morning/Evening Star, etc.
|
145 |
"""
|
146 |
|
|
|
147 |
tools = [
|
148 |
-
Tool.from_function(
|
149 |
-
|
150 |
-
|
151 |
-
description="Get the current price for a stock symbol (e.g., AAPL)"
|
152 |
-
),
|
153 |
-
Tool.from_function(
|
154 |
-
get_historical_data,
|
155 |
-
name="GetHistoricalData",
|
156 |
-
description="Get the last N days of historical OHLCV data for a stock symbol as CSV"
|
157 |
-
),
|
158 |
-
Tool.from_function(
|
159 |
-
get_technical_analysis_docs,
|
160 |
-
name="GetTechnicalAnalysisDocs",
|
161 |
-
description="Provide documentation for technical analysis indicators"
|
162 |
-
)
|
163 |
]
|
164 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
llm = ChatOpenAI(
|
166 |
openai_api_key=OPENROUTER_API_KEY,
|
167 |
openai_api_base="https://openrouter.ai/api/v1",
|
168 |
model_name="google/gemma-3n-e4b-it:free"
|
169 |
)
|
170 |
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
177 |
|
178 |
-
|
179 |
-
print("Welcome to the Stock Analysis Agent!")
|
180 |
-
print("Ask anything about stocks, technical analysis, or predictions.")
|
181 |
-
print("Type 'exit' to quit.")
|
182 |
-
while True:
|
183 |
-
user_input = input("\nYour question: ")
|
184 |
-
if user_input.lower() in ["exit", "quit"]:
|
185 |
-
print("Goodbye!")
|
186 |
-
break
|
187 |
-
result = agent.run(user_input)
|
188 |
-
print("\nAgent's answer:\n", result)
|
|
|
3 |
import pandas as pd
|
4 |
from io import StringIO
|
5 |
from datetime import datetime, timedelta
|
6 |
+
import gradio as gr
|
7 |
from langchain.tools import tool
|
8 |
+
from langchain.agents import initialize_agent, Tool, AgentExecutor
|
9 |
from langchain_openai import ChatOpenAI
|
10 |
+
from langchain.callbacks.base import BaseCallbackHandler
|
11 |
|
12 |
# === Configuration ===
|
13 |
+
OPENROUTER_API_KEY = "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"
|
|
|
14 |
HEADERS = {
|
15 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
|
16 |
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
'Accept-Language': 'en-US,en;q=0.9',
|
18 |
'Referer': 'https://www.google.com/',
|
19 |
'Connection': 'keep-alive',
|
|
|
21 |
'Upgrade-Insecure-Requests': '1'
|
22 |
}
|
23 |
|
24 |
+
# === Tools ===
|
25 |
@tool("GetCurrentPrice")
|
26 |
def get_current_price(symbol: str) -> str:
|
27 |
+
"""here is the doc string"""
|
28 |
url = f'https://www.marketwatch.com/investing/stock/{symbol}'
|
29 |
response = requests.get(url, headers=HEADERS)
|
30 |
if response.status_code == 200:
|
|
|
32 |
price_tag = soup.find('bg-quote', class_='value')
|
33 |
if price_tag:
|
34 |
price = price_tag.get_text(strip=True)
|
35 |
+
return f"{symbol.upper()} current price: ${price}"
|
36 |
else:
|
37 |
return "Stock price not found."
|
38 |
else:
|
|
|
40 |
|
41 |
@tool("GetHistoricalData")
|
42 |
def get_historical_data(symbol: str, days: int = 5000) -> str:
|
43 |
+
"""here is it"""
|
44 |
end_date = datetime.now()
|
45 |
start_date = end_date - timedelta(days=days)
|
46 |
start_date_str = start_date.strftime('%m/%d/%Y 00:00:00')
|
|
|
55 |
if response.status_code == 200:
|
56 |
try:
|
57 |
df = pd.read_csv(StringIO(response.text))
|
58 |
+
return df.head(10).to_csv(index=False)
|
59 |
except Exception as e:
|
60 |
return f"Failed to parse CSV data: {e}"
|
61 |
else:
|
|
|
73 |
|
74 |
Key Technical Indicators and Their Formulas:
|
75 |
-------------------------------------------
|
76 |
+
|
77 |
1. Simple Moving Average (SMA): SMA(time_period) = Sum(Price_t ... Price_{t-n}) / n
|
78 |
2. Exponential Moving Average (EMA): EMA_t = (Price_t * α) + EMA_{t-1} * (1 - α), where α = 2/(n+1)
|
79 |
3. Relative Strength Index (RSI): RSI = 100 - [100 / (1 + Avg Gain / Avg Loss)]
|
|
|
139 |
- Hammer, Shooting Star, Engulfing, Doji, Morning/Evening Star, etc.
|
140 |
"""
|
141 |
|
142 |
+
# === Register Tools ===
|
143 |
tools = [
|
144 |
+
Tool.from_function(get_current_price, name="GetCurrentPrice", description="Get current stock price."),
|
145 |
+
Tool.from_function(get_historical_data, name="GetHistoricalData", description="Get stock historical data as CSV."),
|
146 |
+
Tool.from_function(get_technical_analysis_docs, name="GetTechnicalAnalysisDocs", description="Technical indicator docs.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
147 |
]
|
148 |
|
149 |
+
# === Callback handler to stream reasoning to chat ===
|
150 |
+
class ReasoningCallbackHandler(BaseCallbackHandler):
|
151 |
+
def __init__(self, chat_callback):
|
152 |
+
self.chat_callback = chat_callback
|
153 |
+
|
154 |
+
def on_tool_start(self, serialized, input_str, **kwargs):
|
155 |
+
self.chat_callback(f"🛠️ Using Tool: {serialized['name']} with input: {input_str}")
|
156 |
+
|
157 |
+
def on_tool_end(self, output, **kwargs):
|
158 |
+
self.chat_callback(f"✅ Tool output: {output}")
|
159 |
+
|
160 |
+
def on_llm_new_token(self, token, **kwargs):
|
161 |
+
if token.strip():
|
162 |
+
self.chat_callback(token)
|
163 |
+
|
164 |
+
# === OpenAI-compatible LLM via OpenRouter ===
|
165 |
llm = ChatOpenAI(
|
166 |
openai_api_key=OPENROUTER_API_KEY,
|
167 |
openai_api_base="https://openrouter.ai/api/v1",
|
168 |
model_name="google/gemma-3n-e4b-it:free"
|
169 |
)
|
170 |
|
171 |
+
# === Agent Execution with live reasoning ===
|
172 |
+
def run_agent(question, chat_callback):
|
173 |
+
callback_handler = ReasoningCallbackHandler(chat_callback)
|
174 |
+
agent_executor = initialize_agent(
|
175 |
+
tools, llm,
|
176 |
+
agent="zero-shot-react-description",
|
177 |
+
verbose=True,
|
178 |
+
callbacks=[callback_handler]
|
179 |
+
)
|
180 |
+
try:
|
181 |
+
result = agent_executor.run(question)
|
182 |
+
except Exception as e:
|
183 |
+
result = f"❌ Error: {str(e)}"
|
184 |
+
|
185 |
+
chat_callback(f"✅ Final Answer: {result}")
|
186 |
+
|
187 |
+
# === Gradio UI ===
|
188 |
+
with gr.Blocks(theme=gr.themes.Monochrome()) as demo:
|
189 |
+
gr.Markdown("## 📈 Stock Market Analysis Agent")
|
190 |
+
chatbot = gr.Chatbot(label="Stock Agent Chat")
|
191 |
+
with gr.Row():
|
192 |
+
user_input = gr.Textbox(label="Type your question here...", scale=4)
|
193 |
+
submit_btn = gr.Button("Submit", scale=1)
|
194 |
+
|
195 |
+
def respond(msg, chat_history):
|
196 |
+
chat_history.append((msg, ""))
|
197 |
+
def chat_callback(new_msg):
|
198 |
+
chat_history.append(("", new_msg))
|
199 |
+
chatbot.value = chat_history
|
200 |
+
run_agent(msg, chat_callback)
|
201 |
+
return chat_history
|
202 |
+
|
203 |
+
|
204 |
+
|
205 |
+
submit_btn.click(respond, [user_input, chatbot], [chatbot])
|
206 |
|
207 |
+
demo.launch()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|