lucifer7210's picture
Update app.py
f796d5d verified
import gradio as gr
from urllib.request import urlopen
import certifi
import json
import pandas as pd
import os
import warnings
import re
warnings.filterwarnings("ignore")
from langchain_community.document_loaders import CSVLoader
from langchain_community.vectorstores import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
from langchain_community.llms import HuggingFacePipeline
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
# Hugging Face API Key
os.environ["HUGGINGFACEHUB_API_TOKEN"] = os.environ.get("HUGGINGFACEHUB_API_TOKEN")
# Load Falcon LLM
model_id = "tiiuae/Falcon3-3B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id)
pipe = pipeline(
"text-generation",
model=model,
tokenizer=tokenizer,
max_new_tokens=512,
do_sample=True,
temperature=0.1,
top_k=50,
top_p=0.95,
eos_token_id=tokenizer.eos_token_id,
)
llm = HuggingFacePipeline(pipeline=pipe)
# Enhanced Prompt Template
template = """
You are a Financial Market Expert. Analyze the provided market data and create a comprehensive financial report.
Market Data: {context}
Company: {question}
Please provide a detailed analysis including:
1. Current stock performance metrics
2. Price movements and trends
3. Market capitalization details
4. Trading volume analysis
5. Key financial indicators
Format the response as a clear, professional financial report with proper sections and bullet points.
"""
PROMPT = PromptTemplate(input_variables=["context", "question"], template=template)
def format_currency(value):
"""Format currency values"""
try:
if isinstance(value, (int, float)):
return f"${value:,.2f}"
return str(value)
except:
return str(value)
def format_percentage(value):
"""Format percentage values"""
try:
if isinstance(value, (int, float)):
return f"{value:.2f}%"
return str(value)
except:
return str(value)
def create_html_report(data, llm_analysis):
"""Create a formatted HTML report"""
if not data or len(data) == 0:
return "<div class='error'>No data available for this ticker.</div>"
# Get the first data point (assuming it's the most relevant)
stock_data = data[0] if isinstance(data, list) else data
# Extract key metrics
symbol = stock_data.get('symbol', 'N/A')
name = stock_data.get('name', 'N/A')
price = stock_data.get('price', 0)
change = stock_data.get('change', 0)
change_percent = stock_data.get('changesPercentage', 0)
market_cap = stock_data.get('marketCap', 0)
volume = stock_data.get('volume', 0)
avg_volume = stock_data.get('avgVolume', 0)
pe_ratio = stock_data.get('pe', 'N/A')
eps = stock_data.get('eps', 'N/A')
# Determine trend color
trend_color = "#22c55e" if change >= 0 else "#ef4444"
trend_icon = "πŸ“ˆ" if change >= 0 else "πŸ“‰"
html = f"""
<div style="font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; max-width: 800px; margin: 0 auto;">
<!-- Header Section -->
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 25px; border-radius: 12px; margin-bottom: 20px; box-shadow: 0 4px 15px rgba(0,0,0,0.1);">
<h1 style="margin: 0 0 10px 0; font-size: 28px; font-weight: 600;">{symbol} - Financial Report</h1>
<h2 style="margin: 0; font-size: 18px; font-weight: 400; opacity: 0.9;">{name}</h2>
<div style="margin-top: 15px; font-size: 14px; opacity: 0.8;">
πŸ“… Generated on {pd.Timestamp.now().strftime('%Y-%m-%d %H:%M:%S')}
</div>
</div>
<!-- Key Metrics Grid -->
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-bottom: 25px;">
<!-- Current Price Card -->
<div style="background: white; border-radius: 10px; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); border-left: 4px solid #3b82f6;">
<div style="color: #6b7280; font-size: 14px; margin-bottom: 5px;">Current Price</div>
<div style="font-size: 24px; font-weight: 700; color: #1f2937;">{format_currency(price)}</div>
</div>
<!-- Price Change Card -->
<div style="background: white; border-radius: 10px; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); border-left: 4px solid {trend_color};">
<div style="color: #6b7280; font-size: 14px; margin-bottom: 5px;">Price Change {trend_icon}</div>
<div style="font-size: 18px; font-weight: 600; color: {trend_color};">
{format_currency(change)} ({format_percentage(change_percent)})
</div>
</div>
<!-- Market Cap Card -->
<div style="background: white; border-radius: 10px; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); border-left: 4px solid #10b981;">
<div style="color: #6b7280; font-size: 14px; margin-bottom: 5px;">Market Cap</div>
<div style="font-size: 18px; font-weight: 600; color: #1f2937;">
{format_currency(market_cap) if market_cap else 'N/A'}
</div>
</div>
<!-- Volume Card -->
<div style="background: white; border-radius: 10px; padding: 20px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); border-left: 4px solid #f59e0b;">
<div style="color: #6b7280; font-size: 14px; margin-bottom: 5px;">Volume</div>
<div style="font-size: 18px; font-weight: 600; color: #1f2937;">
{f"{volume:,}" if volume else 'N/A'}
</div>
</div>
</div>
<!-- Additional Metrics Table -->
<div style="background: white; border-radius: 10px; padding: 25px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); margin-bottom: 25px;">
<h3 style="margin: 0 0 20px 0; color: #1f2937; font-size: 20px; font-weight: 600; border-bottom: 2px solid #e5e7eb; padding-bottom: 10px;">
πŸ“Š Detailed Metrics
</h3>
<table style="width: 100%; border-collapse: collapse;">
<tr style="border-bottom: 1px solid #e5e7eb;">
<td style="padding: 12px 0; font-weight: 600; color: #374151; width: 40%;">P/E Ratio</td>
<td style="padding: 12px 0; color: #6b7280;">{pe_ratio}</td>
</tr>
<tr style="border-bottom: 1px solid #e5e7eb;">
<td style="padding: 12px 0; font-weight: 600; color: #374151;">Earnings Per Share (EPS)</td>
<td style="padding: 12px 0; color: #6b7280;">{format_currency(eps) if eps != 'N/A' else 'N/A'}</td>
</tr>
<tr style="border-bottom: 1px solid #e5e7eb;">
<td style="padding: 12px 0; font-weight: 600; color: #374151;">Average Volume</td>
<td style="padding: 12px 0; color: #6b7280;">{f"{avg_volume:,}" if avg_volume else 'N/A'}</td>
</tr>
<tr>
<td style="padding: 12px 0; font-weight: 600; color: #374151;">Exchange</td>
<td style="padding: 12px 0; color: #6b7280;">{stock_data.get('exchange', 'N/A')}</td>
</tr>
</table>
</div>
<!-- AI Analysis Section -->
<div style="background: white; border-radius: 10px; padding: 25px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
<h3 style="margin: 0 0 20px 0; color: #1f2937; font-size: 20px; font-weight: 600; border-bottom: 2px solid #e5e7eb; padding-bottom: 10px;">
πŸ€– AI Analysis
</h3>
<div style="background: #f8fafc; border-radius: 8px; padding: 20px; border-left: 4px solid #6366f1;">
<pre style="white-space: pre-wrap; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; line-height: 1.6; color: #374151;">{llm_analysis}</pre>
</div>
</div>
<!-- Footer -->
<div style="text-align: center; margin-top: 25px; padding: 20px; color: #6b7280; font-size: 14px; border-top: 1px solid #e5e7eb;">
<p style="margin: 0;">⚠️ This report is for informational purposes only and should not be considered as investment advice.</p>
</div>
</div>
"""
return html
def generate_report(ticker: str, exchange: str):
"""Generate enhanced financial report"""
api_key = "C1HRSweTniWdBuLmTTse9w8KpkoiouM5"
if not ticker.strip():
return "<div style='color: red; padding: 20px; text-align: center;'>❌ Please enter a valid ticker symbol.</div>"
try:
# Show loading message
loading_html = """
<div style="text-align: center; padding: 40px; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;">
<div style="display: inline-block; padding: 20px; background: #f0f9ff; border-radius: 10px; border: 1px solid #0ea5e9;">
<div style="font-size: 18px; color: #0369a1; margin-bottom: 10px;">πŸ”„ Generating Report...</div>
<div style="color: #64748b;">Fetching data and running AI analysis</div>
</div>
</div>
"""
# Fetch Data
ticker = ticker.upper().strip()
if exchange == "NSE":
url = f"https://financialmodelingprep.com/api/v3/search?query={ticker}&exchange=NSE&apikey={api_key}"
else:
url = f"https://financialmodelingprep.com/api/v3/quote/{ticker}?apikey={api_key}"
response = urlopen(url, cafile=certifi.where())
data = json.loads(response.read().decode("utf-8"))
if not data:
return "<div style='color: red; padding: 20px; text-align: center;'>❌ No data found for ticker: " + ticker + "</div>"
# Save to CSV for RAG processing
df = pd.DataFrame(data)
if 'timestamp' in df.columns:
df['timestamp'] = pd.to_datetime(df['timestamp'], errors='coerce')
if 'earningsAnnouncement' in df.columns:
df['earningsAnnouncement'] = pd.to_datetime(df['earningsAnnouncement'], errors='coerce')
df.to_csv("eco_ind.csv", index=False)
# Create vector store and run LLM analysis
loader = CSVLoader("eco_ind.csv")
documents = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=20)
texts = splitter.split_documents(documents)
embeddings = HuggingFaceEmbeddings()
chroma = Chroma.from_documents(
documents=texts,
collection_name="economic_data",
embedding=embeddings,
persist_directory="docs/chroma_rag"
)
retriever = chroma.as_retriever(search_kwargs={"k": 3})
qa = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
chain_type_kwargs={"prompt": PROMPT},
retriever=retriever,
return_source_documents=False
)
# Get LLM analysis
query = f"Provide a comprehensive financial analysis for {ticker}"
result = qa({"query": query})
llm_analysis = result["result"]
# Create and return formatted HTML report
return create_html_report(data, llm_analysis)
except Exception as e:
error_html = f"""
<div style="font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; max-width: 600px; margin: 20px auto; padding: 25px; background: #fef2f2; border-radius: 10px; border: 1px solid #fecaca;">
<h3 style="color: #dc2626; margin: 0 0 15px 0; display: flex; align-items: center;">
❌ Error Occurred
</h3>
<div style="background: white; padding: 15px; border-radius: 6px; border: 1px solid #f3f4f6;">
<strong>Details:</strong> {str(e)}
</div>
<div style="margin-top: 15px; color: #6b7280; font-size: 14px;">
Please check your ticker symbol and try again. Make sure you have a stable internet connection.
</div>
</div>
"""
return error_html
# Custom CSS for better styling
custom_css = """
#component-0 {
max-width: 1200px !important;
margin: 0 auto !important;
}
.gradio-container {
background-color: black !important;
min-height: 100vh !important;
}
#title {
text-align: center !important;
color: white !important;
font-size: 2.5rem !important;
font-weight: 700 !important;
margin-bottom: 1rem !important;
text-shadow: 0 2px 4px rgba(0,0,0,0.1) !important;
}
#description {
text-align: center !important;
color: white !important;
font-size: 1.1rem !important;
margin-bottom: 2rem !important;
}
.input-container {
background: white !important;
border-radius: 5px !important;
padding: 3px !important;
box-shadow: 0 10px 30px rgba(0,0,0,0.1) !important;
margin-bottom: 20px !important;
}
.output-container {
background: transparent !important;
border-radius: 15px !important;
padding: 10px;
border: 2px white solid ;
overflow: hidden !important;
box-shadow: 0 10px 30px rgba(0,0,0,0.2) !important;
}
"""
# Create the Gradio interface with sidebar for inputs
with gr.Blocks(css=custom_css, title="πŸ“Š Financial Report Generator") as iface:
gr.HTML('<div id="title">πŸ“Š AI-Powered Financial Report Generator</div>')
gr.HTML('<div id="description">Enter a stock ticker and exchange to get a comprehensive AI-generated financial analysis</div>')
# Sidebar for inputs
with gr.Sidebar():
gr.Markdown("## πŸ“₯ Input Parameters")
ticker_input = gr.Textbox(
label="🎯 Stock Ticker Symbol",
placeholder="e.g., MSFT, AAPL, GOOGL",
info="Enter the stock symbol you want to analyze"
)
exchange_input = gr.Radio(
choices=["US", "NSE"],
label="🏒 Exchange",
value="US",
info="Select the stock exchange"
)
generate_btn = gr.Button(
"πŸš€ Generate Report",
variant="primary"
)
clear_btn = gr.Button(
"πŸ”„ Clear",
variant="secondary"
)
# Output section
with gr.Row(elem_classes=["output-container"]):
output = gr.HTML(label="πŸ“Š Financial Report")
# Event handlers
generate_btn.click(
fn=generate_report,
inputs=[ticker_input, exchange_input],
outputs=output
)
clear_btn.click(
lambda: ["", "US", ""],
outputs=[ticker_input, exchange_input, output]
)
ticker_input.submit(
fn=generate_report,
inputs=[ticker_input, exchange_input],
outputs=output
)
if __name__ == "__main__":
iface.launch(
share=True,
show_error=True
)