Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -14,7 +14,7 @@ summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
|
|
14 |
# Polygon API Key
|
15 |
POLYGON_API_KEY = os.getenv("POLYGON_API_KEY")
|
16 |
|
17 |
-
# Sector Averages
|
18 |
sector_averages = {
|
19 |
"Technology": {"P/E Ratio": 25, "P/S Ratio": 5, "P/B Ratio": 6},
|
20 |
"Healthcare": {"P/E Ratio": 20, "P/S Ratio": 4, "P/B Ratio": 3},
|
@@ -22,7 +22,8 @@ sector_averages = {
|
|
22 |
"Energy": {"P/E Ratio": 12, "P/S Ratio": 1.2, "P/B Ratio": 1.3},
|
23 |
}
|
24 |
|
25 |
-
# Helper Functions
|
|
|
26 |
def safe_request(url):
|
27 |
try:
|
28 |
response = requests.get(url)
|
@@ -40,7 +41,6 @@ def get_company_info(symbol):
|
|
40 |
print("DEBUG: API Key is missing!")
|
41 |
return None
|
42 |
url = f"https://api.polygon.io/v3/reference/tickers/{symbol}?apiKey={api_key}"
|
43 |
-
print(f"DEBUG: Fetching company info from URL: {url}")
|
44 |
response = safe_request(url)
|
45 |
if response:
|
46 |
data = response.json().get('results', {})
|
@@ -56,7 +56,6 @@ def get_company_info(symbol):
|
|
56 |
def get_current_price(symbol):
|
57 |
api_key = os.getenv("POLYGON_API_KEY")
|
58 |
url = f"https://api.polygon.io/v2/aggs/ticker/{symbol}/prev?adjusted=true&apiKey={api_key}"
|
59 |
-
print(f"DEBUG: Fetching current price from URL: {url}")
|
60 |
response = safe_request(url)
|
61 |
if response:
|
62 |
data = response.json()['results'][0]
|
@@ -118,17 +117,34 @@ def answer_investing_question(question):
|
|
118 |
response = summarizer(basic_prompt, max_length=150, min_length=50, do_sample=False)[0]['summary_text']
|
119 |
return response
|
120 |
|
121 |
-
|
122 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
|
124 |
def stock_research(symbol, assumed_eps=5.0, growth_rate=0.1, book_value=500000000):
|
125 |
-
if assumed_eps is None:
|
126 |
-
assumed_eps = 5.0
|
127 |
-
if growth_rate is None:
|
128 |
-
growth_rate = 0.1
|
129 |
-
if book_value is None:
|
130 |
-
book_value = 500000000
|
131 |
-
|
132 |
info = get_company_info(symbol)
|
133 |
price = get_current_price(symbol)
|
134 |
dividends = get_dividends(symbol)
|
@@ -139,7 +155,10 @@ def stock_research(symbol, assumed_eps=5.0, growth_rate=0.1, book_value=50000000
|
|
139 |
|
140 |
ratios = calculate_ratios(info['Market Cap'], info['Total Revenue'], price, dividends['Dividend Amount'], assumed_eps, growth_rate, book_value)
|
141 |
summary = generate_summary(info, ratios)
|
142 |
-
|
|
|
|
|
|
|
143 |
|
144 |
fig, ax = plt.subplots()
|
145 |
ax.plot(dates, prices, label=f"{symbol} Price")
|
@@ -149,13 +168,10 @@ def stock_research(symbol, assumed_eps=5.0, growth_rate=0.1, book_value=50000000
|
|
149 |
ax.legend()
|
150 |
ax.grid(True)
|
151 |
|
152 |
-
# ✅ Format info_table
|
153 |
info_table = pd.DataFrame({
|
154 |
"Metric": list(info.keys()),
|
155 |
"Value": [f"${v:,.0f}" if isinstance(v, (int, float)) and abs(v) > 1000 else v for v in info.values()]
|
156 |
})
|
157 |
-
|
158 |
-
# ✅ Format ratios_table
|
159 |
ratios_table = pd.DataFrame({
|
160 |
"Ratio": list(ratios.keys()),
|
161 |
"Value": [f"{v:.3f}" if isinstance(v, float) else v for v in ratios.values()]
|
@@ -163,7 +179,6 @@ def stock_research(symbol, assumed_eps=5.0, growth_rate=0.1, book_value=50000000
|
|
163 |
|
164 |
return summary, info_table, ratios_table, sector_comp, fig
|
165 |
|
166 |
-
|
167 |
def download_report(info_table, ratios_table, sector_comp, summary):
|
168 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".csv", mode='w') as f:
|
169 |
info_table.to_csv(f, index=False)
|
@@ -176,13 +191,14 @@ def download_report(info_table, ratios_table, sector_comp, summary):
|
|
176 |
file_path = f.name
|
177 |
return file_path
|
178 |
|
179 |
-
# Gradio UI
|
|
|
180 |
with gr.Blocks() as iface:
|
181 |
with gr.Row():
|
182 |
-
symbol = gr.Textbox(label="Stock Symbol (e.g., AAPL)"
|
183 |
-
eps = gr.Number(label="Assumed EPS", value=5.0
|
184 |
-
growth = gr.Number(label="Assumed Growth Rate", value=0.1
|
185 |
-
book = gr.Number(label="Assumed Book Value", value=500000000
|
186 |
|
187 |
with gr.Tabs():
|
188 |
with gr.Tab("AI Research Summary"):
|
@@ -195,22 +211,21 @@ with gr.Blocks() as iface:
|
|
195 |
output_sector = gr.Dataframe()
|
196 |
with gr.Tab("Historical Price Chart"):
|
197 |
output_chart = gr.Plot()
|
|
|
|
|
|
|
|
|
|
|
198 |
|
199 |
submit_btn = gr.Button("Run Analysis")
|
200 |
download_btn = gr.Button("Download Report")
|
201 |
file_output = gr.File()
|
202 |
|
203 |
-
submit_btn.click(
|
204 |
-
|
205 |
-
inputs=[symbol, eps, growth, book],
|
206 |
-
outputs=[output_summary, output_info, output_ratios, output_sector, output_chart]
|
207 |
-
)
|
208 |
|
209 |
-
download_btn.click(
|
210 |
-
|
211 |
-
inputs=[output_info, output_ratios, output_sector, output_summary],
|
212 |
-
outputs=file_output
|
213 |
-
)
|
214 |
|
215 |
if __name__ == "__main__":
|
216 |
iface.launch()
|
|
|
14 |
# Polygon API Key
|
15 |
POLYGON_API_KEY = os.getenv("POLYGON_API_KEY")
|
16 |
|
17 |
+
# Sector Averages
|
18 |
sector_averages = {
|
19 |
"Technology": {"P/E Ratio": 25, "P/S Ratio": 5, "P/B Ratio": 6},
|
20 |
"Healthcare": {"P/E Ratio": 20, "P/S Ratio": 4, "P/B Ratio": 3},
|
|
|
22 |
"Energy": {"P/E Ratio": 12, "P/S Ratio": 1.2, "P/B Ratio": 1.3},
|
23 |
}
|
24 |
|
25 |
+
# --- Helper Functions ---
|
26 |
+
|
27 |
def safe_request(url):
|
28 |
try:
|
29 |
response = requests.get(url)
|
|
|
41 |
print("DEBUG: API Key is missing!")
|
42 |
return None
|
43 |
url = f"https://api.polygon.io/v3/reference/tickers/{symbol}?apiKey={api_key}"
|
|
|
44 |
response = safe_request(url)
|
45 |
if response:
|
46 |
data = response.json().get('results', {})
|
|
|
56 |
def get_current_price(symbol):
|
57 |
api_key = os.getenv("POLYGON_API_KEY")
|
58 |
url = f"https://api.polygon.io/v2/aggs/ticker/{symbol}/prev?adjusted=true&apiKey={api_key}"
|
|
|
59 |
response = safe_request(url)
|
60 |
if response:
|
61 |
data = response.json()['results'][0]
|
|
|
117 |
response = summarizer(basic_prompt, max_length=150, min_length=50, do_sample=False)[0]['summary_text']
|
118 |
return response
|
119 |
|
120 |
+
def calculate_ratios(market_cap, total_revenue, price, dividend_amount, assumed_eps=5.0, growth_rate=0.1, book_value=500000000):
|
121 |
+
pe_ratio = price / assumed_eps if assumed_eps else 0
|
122 |
+
ps_ratio = market_cap / total_revenue if total_revenue else 0
|
123 |
+
pb_ratio = market_cap / book_value if book_value else 0
|
124 |
+
peg_ratio = pe_ratio / (growth_rate * 100) if growth_rate else 0
|
125 |
+
dividend_yield = (dividend_amount / price) * 100 if price else 0
|
126 |
+
return {
|
127 |
+
'P/E Ratio': pe_ratio,
|
128 |
+
'P/S Ratio': ps_ratio,
|
129 |
+
'P/B Ratio': pb_ratio,
|
130 |
+
'PEG Ratio': peg_ratio,
|
131 |
+
'Dividend Yield (%)': dividend_yield
|
132 |
+
}
|
133 |
+
|
134 |
+
def compare_to_sector(sector, ratios):
|
135 |
+
if sector.lower() == 'stocks':
|
136 |
+
sector = 'Technology' # Fallback
|
137 |
+
averages = sector_averages.get(sector, None)
|
138 |
+
if not averages:
|
139 |
+
return pd.DataFrame({"Metric": ["Sector data not available"], "Value": ["N/A"]})
|
140 |
+
comparison = {}
|
141 |
+
for key in averages:
|
142 |
+
stock_value = ratios.get(key, 0)
|
143 |
+
sector_value = averages[key]
|
144 |
+
comparison[key] = f"{stock_value:.2f} vs Sector Avg {sector_value:.2f}"
|
145 |
+
return pd.DataFrame({"Ratio": list(comparison.keys()), "Comparison": list(comparison.values())})
|
146 |
|
147 |
def stock_research(symbol, assumed_eps=5.0, growth_rate=0.1, book_value=500000000):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
148 |
info = get_company_info(symbol)
|
149 |
price = get_current_price(symbol)
|
150 |
dividends = get_dividends(symbol)
|
|
|
155 |
|
156 |
ratios = calculate_ratios(info['Market Cap'], info['Total Revenue'], price, dividends['Dividend Amount'], assumed_eps, growth_rate, book_value)
|
157 |
summary = generate_summary(info, ratios)
|
158 |
+
|
159 |
+
# Apply fallback for sector
|
160 |
+
sector = info.get('Sector', 'Technology')
|
161 |
+
sector_comp = compare_to_sector(sector, ratios)
|
162 |
|
163 |
fig, ax = plt.subplots()
|
164 |
ax.plot(dates, prices, label=f"{symbol} Price")
|
|
|
168 |
ax.legend()
|
169 |
ax.grid(True)
|
170 |
|
|
|
171 |
info_table = pd.DataFrame({
|
172 |
"Metric": list(info.keys()),
|
173 |
"Value": [f"${v:,.0f}" if isinstance(v, (int, float)) and abs(v) > 1000 else v for v in info.values()]
|
174 |
})
|
|
|
|
|
175 |
ratios_table = pd.DataFrame({
|
176 |
"Ratio": list(ratios.keys()),
|
177 |
"Value": [f"{v:.3f}" if isinstance(v, float) else v for v in ratios.values()]
|
|
|
179 |
|
180 |
return summary, info_table, ratios_table, sector_comp, fig
|
181 |
|
|
|
182 |
def download_report(info_table, ratios_table, sector_comp, summary):
|
183 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".csv", mode='w') as f:
|
184 |
info_table.to_csv(f, index=False)
|
|
|
191 |
file_path = f.name
|
192 |
return file_path
|
193 |
|
194 |
+
# --- Gradio UI ---
|
195 |
+
|
196 |
with gr.Blocks() as iface:
|
197 |
with gr.Row():
|
198 |
+
symbol = gr.Textbox(label="Stock Symbol (e.g., AAPL)")
|
199 |
+
eps = gr.Number(label="Assumed EPS", value=5.0)
|
200 |
+
growth = gr.Number(label="Assumed Growth Rate", value=0.1)
|
201 |
+
book = gr.Number(label="Assumed Book Value", value=500000000)
|
202 |
|
203 |
with gr.Tabs():
|
204 |
with gr.Tab("AI Research Summary"):
|
|
|
211 |
output_sector = gr.Dataframe()
|
212 |
with gr.Tab("Historical Price Chart"):
|
213 |
output_chart = gr.Plot()
|
214 |
+
with gr.Tab("Ask About Investing"):
|
215 |
+
user_question = gr.Textbox(label="Ask a question about investing...")
|
216 |
+
answer_box = gr.Textbox(label="Answer")
|
217 |
+
ask_button = gr.Button("Get Answer")
|
218 |
+
ask_button.click(fn=answer_investing_question, inputs=[user_question], outputs=[answer_box])
|
219 |
|
220 |
submit_btn = gr.Button("Run Analysis")
|
221 |
download_btn = gr.Button("Download Report")
|
222 |
file_output = gr.File()
|
223 |
|
224 |
+
submit_btn.click(fn=stock_research, inputs=[symbol, eps, growth, book],
|
225 |
+
outputs=[output_summary, output_info, output_ratios, output_sector, output_chart])
|
|
|
|
|
|
|
226 |
|
227 |
+
download_btn.click(fn=download_report, inputs=[output_info, output_ratios, output_sector, output_summary],
|
228 |
+
outputs=file_output)
|
|
|
|
|
|
|
229 |
|
230 |
if __name__ == "__main__":
|
231 |
iface.launch()
|