AI-Stock / app.py
GenAiPA's picture
Update app.py
8f70e83 verified
import pandas as pd
import openai
import gradio as gr
import yfinance as yf
import json
import os
import matplotlib.pyplot as plt
import io
from PIL import Image
import plotly.graph_objs as go # this is Plotly for interactive charts
import re
import datetime
openai.api_key = os.getenv('yek_oaipen')
# Helper function to safely get data from dictionaries
def safe_get(data, key, default="-"):
return data.get(key) if data.get(key) is not None else default
# Helper function to format numbers in B/M/K with up to two decimal places
def format_number(num):
if num is None:
return "N/A"
try:
num = float(num)
if num >= 1_000_000_000:
return f"{num / 1_000_000_000:.2f}B"
elif num >= 1_000_000:
return f"{num / 1_000_000:.2f}M"
elif num >= 1_000:
return f"{num / 1_000:.2f}K"
else:
return f"{num:.2f}"
except:
return "N/A"
# Function to get company overview
def get_company_overview(ticker):
try:
stock = yf.Ticker(ticker)
info = stock.info
# Safely extract company officers
company_officers = info.get("companyOfficers", [])
ceo = safe_get(info, "ceo") or (company_officers[0]['name'] if company_officers else "N/A")
overview = {
"company_name": safe_get(info, "longName"),
"ticker": safe_get(info, "symbol"),
"exchange": safe_get(info, "exchange"),
"industry": safe_get(info, "industry"),
"ceo": ceo,
"year_founded": safe_get(info, "startDate"),
"headquarters": f"{safe_get(info, 'city')}, {safe_get(info, 'state')}" if info.get("city") and info.get("state") else "N/A",
"description": safe_get(info, "longBusinessSummary"),
"website": safe_get(info, "website")
}
return overview
except Exception as e:
print(f"Error fetching company overview for {ticker}: {e}")
return {}
# Function to get financial metrics
def get_financial_metrics(ticker):
try:
stock = yf.Ticker(ticker)
info = stock.info
metrics = {
"market_cap": format_number(safe_get(info, "marketCap")),
"enterprise_value": format_number(safe_get(info, "enterpriseValue")),
"shares_outstanding": format_number(safe_get(info, "sharesOutstanding")),
"total_revenue": format_number(safe_get(info, "totalRevenue")),
"employees": format_number(safe_get(info, "fullTimeEmployees")),
"gross_profit_margin": f"{safe_get(info, 'grossMargins')*100:.2f}%" if safe_get(info, 'grossMargins') != "-" else "-",
"ebitda_margin": f"{safe_get(info, 'ebitdaMargins')*100:.2f}%" if safe_get(info, 'ebitdaMargins') != "-" else "-",
"operating_margin": f"{safe_get(info, 'operatingMargins')*100:.2f}%" if safe_get(info, 'operatingMargins') != "-" else "-",
"net_profit_margin": f"{safe_get(info, 'profitMargins')*100:.2f}%" if safe_get(info, 'profitMargins') != "-" else "-",
"eps_diluted": format_number(safe_get(info, "trailingEps")),
"pe_ratio": format_number(safe_get(info, "trailingPE")),
"forward_pe_ratio": format_number(safe_get(info, "forwardPE")),
"cash": format_number(safe_get(info, "totalCash")),
"net_debt": format_number(safe_get(info, "totalDebt") - safe_get(info, "totalCash")) if safe_get(info, "totalDebt") != "-" and safe_get(info, "totalCash") != "-" else "N/A",
"debt_to_equity": f"{safe_get(info, 'debtToEquity'):.2f}" if safe_get(info, "debtToEquity") != "-" else "-",
"ebit_to_interest": f"{(safe_get(info, 'ebitda') / safe_get(info, 'interestExpense')):.2f}" if safe_get(info, "ebitda") != "-" and safe_get(info, "interestExpense") != "-" else "N/A",
"dividendYield": f"{safe_get(info, 'dividendYield')*100:.2f}%" if safe_get(info, "dividendYield") != "-" else "-",
"payoutRatio": f"{safe_get(info, 'payoutRatio')*100:.2f}%" if safe_get(info, "payoutRatio") != "-" else "-",
"dividendRate": format_number(safe_get(info, "dividendRate")),
"revenue_3yr_cagr": "N/A", # Placeholder as actual calculation requires historical data
"eps_diluted_3yr_cagr": "N/A" # Placeholder as actual calculation requires historical data
}
return metrics
except Exception as e:
print(f"Error fetching financial metrics for {ticker}: {e}")
return {}
# Function to get recent news
def get_recent_news(ticker):
try:
stock = yf.Ticker(ticker)
news_items = stock.news[:5] # Get the latest 5 news articles
news_list = []
for item in news_items:
published_time = pd.to_datetime(item.get("providerPublishTime"), unit='s').strftime('%Y-%m-%d') if item.get("providerPublishTime") else "N/A"
news_list.append({
"title": item.get("title"),
"publisher": item.get("publisher"),
"link": item.get("link"),
"published_time": published_time
})
return news_list
except Exception as e:
print(f"Error fetching recent news for {ticker}: {e}")
return []
# Function to get stock performance
def get_stock_performance(ticker):
try:
stock = yf.Ticker(ticker)
info = stock.info
history = stock.history(period="10y")
if history.empty:
return {
"current_price": "N/A",
"52_week_range": "N/A",
"ytd_return": "N/A",
"1y_total_return": "N/A",
"5y_total_return_cagr": "N/A",
"10y_total_return_cagr": "N/A"
}
current_price = history['Close'].iloc[-1]
fifty_two_week_low = safe_get(info, "fiftyTwoWeekLow")
fifty_two_week_high = safe_get(info, "fiftyTwoWeekHigh")
try:
ytd_start_price = history['Close'].loc[history.index >= f"{pd.Timestamp.now().year}-01-01"].iloc[0]
ytd_return = ((current_price - ytd_start_price) / ytd_start_price) * 100
except IndexError:
ytd_return = "N/A"
try:
one_year_return = ((current_price - history['Close'].iloc[-252]) / history['Close'].iloc[-252]) * 100
except IndexError:
one_year_return = "N/A"
try:
five_year_return = ((current_price - history['Close'].iloc[-1260]) / history['Close'].iloc[-1260]) * 100
five_year_cagr = five_year_return / 5
except IndexError:
five_year_cagr = "N/A"
try:
ten_year_return = ((current_price - history['Close'].iloc[0]) / history['Close'].iloc[0]) * 100
ten_year_cagr = ten_year_return / 10
except IndexError:
ten_year_cagr = "N/A"
performance = {
"current_price": format_number(current_price),
"52_week_range": f"{format_number(fifty_two_week_low)} - {format_number(fifty_two_week_high)}",
"ytd_return": f"{ytd_return:.2f}%" if isinstance(ytd_return, float) else "N/A",
"1y_total_return": f"{one_year_return:.2f}%" if isinstance(one_year_return, float) else "N/A",
"5y_total_return_cagr": f"{five_year_cagr:.2f}%" if isinstance(five_year_cagr, float) else "N/A",
"10y_total_return_cagr": f"{ten_year_cagr:.2f}%" if isinstance(ten_year_cagr, float) else "N/A"
}
return performance
except Exception as e:
print(f"Error fetching stock performance for {ticker}: {e}")
return {
"current_price": "N/A",
"52_week_range": "N/A",
"ytd_return": "N/A",
"1y_total_return": "N/A",
"5y_total_return_cagr": "N/A",
"10y_total_return_cagr": "N/A"
}
# Function to create an interactive stock chart using Plotly
def create_stock_chart(ticker):
try:
stock = yf.Ticker(ticker)
history = stock.history(period="10y")
if history.empty:
fig = go.Figure()
fig.update_layout(
title=f"No historical data available for {ticker}",
xaxis_title="Date",
yaxis_title="Price (USD)",
template="plotly_white"
)
return fig
fig = go.Figure()
fig.add_trace(
go.Scatter(
x=history.index,
y=history['Close'],
mode='lines',
name='Close Price',
line=dict(color='purple'),
fill='tozeroy',
fillcolor='rgba(128, 0, 128, 0.2)' # Semi-transparent purple
)
)
fig.update_layout(
title=f"Stock Price History for {ticker}",
xaxis_title="Date",
yaxis_title="Price (USD)",
template="plotly_white",
hovermode="x unified",
plot_bgcolor='white',
paper_bgcolor='white',
xaxis=dict(
showgrid=True,
gridcolor='lightgrey'
),
yaxis=dict(
showgrid=True,
gridcolor='lightgrey'
)
)
return fig
except Exception as e:
print(f"Error creating stock chart for {ticker}: {e}")
fig = go.Figure()
fig.update_layout(
title="Error generating chart",
xaxis_title="Date",
yaxis_title="Price (USD)",
template="plotly_white"
)
return fig
# Function to get full stock report
def get_full_stock_report(ticker):
report = {
"overview": get_company_overview(ticker),
"financial_metrics": get_financial_metrics(ticker),
"recent_news": get_recent_news(ticker),
"stock_performance": get_stock_performance(ticker)
}
return report
# Function to format the stock report
def format_stock_report(report):
overview = report.get('overview', {})
financials = report.get('financial_metrics', {})
news = report.get('recent_news', [])
performance = report.get('stock_performance', {})
formatted_report = f"""
**{overview.get('company_name', 'N/A')} ({overview.get('ticker', 'N/A')}) Overview**
- **Company Name:** {overview.get('company_name', 'N/A')}
- **Ticker:** {overview.get('ticker', 'N/A')}
- **Exchange:** {overview.get('exchange', 'N/A')}
- **Industry:** {overview.get('industry', 'N/A')}
- **CEO:** {overview.get('ceo', 'N/A')}
- **Year Founded:** {overview.get('year_founded', 'N/A')}
- **Headquarters:** {overview.get('headquarters', 'N/A')}
**Description:** {overview.get('description', 'N/A')}
**Financial Metrics & Fundamentals**
- **Market Cap:** {financials.get('market_cap', 'N/A')}
- **Enterprise Value:** {financials.get('enterprise_value', 'N/A')}
- **Shares Outstanding:** {financials.get('shares_outstanding', 'N/A')}
- **Total Revenues:** {financials.get('total_revenue', 'N/A')}
- **Employees:** {financials.get('employees', 'N/A')}
- **Gross Profit Margin:** {financials.get('gross_profit_margin', 'N/A')}
- **EBITDA Margin:** {financials.get('ebitda_margin', 'N/A')}
- **Operating Margin:** {financials.get('operating_margin', 'N/A')}
- **Net Profit Margin:** {financials.get('net_profit_margin', 'N/A')}
- **EPS Diluted:** {financials.get('eps_diluted', 'N/A')}
- **P/E Ratio:** {financials.get('pe_ratio', 'N/A')}
- **Forward P/E Ratio:** {financials.get('forward_pe_ratio', 'N/A')}
**Financial Health**
- **Cash:** {financials.get('cash', 'N/A')}
- **Net Debt:** {financials.get('net_debt', 'N/A')}
- **Debt/Equity:** {financials.get('debt_to_equity', 'N/A')}
- **EBIT/Interest:** {financials.get('ebit_to_interest', 'N/A')}
**Dividends**
- **Yield:** {financials.get('dividendYield', 'N/A')}
- **Payout Ratio:** {financials.get('payoutRatio', 'N/A')}
- **DPS:** {financials.get('dividendRate', 'N/A')}
**Recent News**
"""
for item in news:
formatted_report += f"- [{item.get('title', 'N/A')}]({item.get('link', '#')}) ({item.get('publisher', 'N/A')}) - {item.get('published_time', 'N/A')}\n"
formatted_report += f"""
**Stock Performance**
- **Current Price:** {performance.get('current_price', 'N/A')}
- **52-Week Range:** {performance.get('52_week_range', 'N/A')}
- **YTD Return:** {performance.get('ytd_return', 'N/A')}
- **1-Year Total Return:** {performance.get('1y_total_return', 'N/A')}
- **5-Year Total Return CAGR:** {performance.get('5y_total_return_cagr', 'N/A')}
- **10-Year Total Return CAGR:** {performance.get('10y_total_return_cagr', 'N/A')}
**Summary**
*Provide a brief summary of the company's performance and outlook.*
"""
return formatted_report
# Function to extract company name from conversation dynamically
def get_company_name_from_conversation(conversation):
try:
# Get the last user message
user_message = conversation[-1]['content']
# Use OpenAI to extract a company name or ticker symbol
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "You are an assistant that extracts stock ticker symbols or company names from user messages."},
{"role": "user", "content": user_message}
],
max_tokens=20, # Enough tokens to capture a company name
temperature=0
)
# Extract the name or ticker symbol from the response
extracted_name = response['choices'][0]['message']['content'].strip()
# Basic validation to check if the extracted name seems like a company (could be improved)
if re.match(r'^[A-Za-z\s]+$', extracted_name):
return extracted_name
else:
return None
except Exception as e:
print(f"Error extracting company name: {e}")
return None
# Function to handle polite fallback when no specific ticker is found
def handle_no_stock_found(company_name=None):
if company_name:
return f"""
It seems like you might be asking about the performance of a company such as "{company_name}".
However, I need more specific information to proceed, such as the full name or ticker symbol of the company.
Could you please clarify further?
"""
else:
return """
It seems like you're asking about the performance of a company, but I couldn't identify a specific company name.
Could you please provide more specific information, such as the full name or ticker symbol?
"""
# Define function schemas for OpenAI's function calling
functions = [
{
"name": "get_full_stock_report",
"description": "Retrieve a full stock report for a given ticker symbol.",
"parameters": {
"type": "object",
"properties": {
"ticker": {
"type": "string",
"description": "The stock ticker symbol, e.g., 'AAPL' for Apple Inc."
}
},
"required": ["ticker"]
}
},
{
"name": "get_company_overview",
"description": "Get an overview of the company for a given ticker symbol.",
"parameters": {
"type": "object",
"properties": {
"ticker": {"type": "string", "description": "The stock ticker symbol."}
},
"required": ["ticker"]
}
},
{
"name": "get_financial_metrics",
"description": "Get financial metrics for a given ticker symbol.",
"parameters": {
"type": "object",
"properties": {
"ticker": {"type": "string", "description": "The stock ticker symbol."}
},
"required": ["ticker"]
}
},
{
"name": "get_recent_news",
"description": "Get recent news for a given ticker symbol.",
"parameters": {
"type": "object",
"properties": {
"ticker": {"type": "string", "description": "The stock ticker symbol."}
},
"required": ["ticker"]
}
},
{
"name": "get_stock_performance",
"description": "Get stock performance metrics for a given ticker symbol.",
"parameters": {
"type": "object",
"properties": {
"ticker": {"type": "string", "description": "The stock ticker symbol."}
},
"required": ["ticker"]
}
}
]
# Initialize stock_ticker state
stock_ticker = {"value": None} # Initialize without a default ticker
# Function to handle user queries and interact with OpenAI
def stock_chat(conversation):
try:
# Define the system prompt
system_prompt = """
You are a financial assistant that provides stock information. Users might refer to companies by name or ticker symbol.
When necessary, determine the correct ticker symbol from the company name. Provide responses that mix numerical data and narrative descriptions.
"""
# Prepare the messages
messages = [{"role": "system", "content": system_prompt}] + conversation
# Send the conversation to OpenAI
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo", # Ensure the model supports function calling
messages=messages,
functions=functions,
function_call="auto"
)
message = response['choices'][0]['message']
# Check if the assistant wants to call a function
if message.get("function_call"):
function_name = message["function_call"]["name"]
function_args = json.loads(message["function_call"]["arguments"])
# Retrieve the ticker if not provided
ticker = function_args.get("ticker")
if not ticker:
# Try to extract a company name from the conversation
company_name = get_company_name_from_conversation(conversation)
if not company_name:
# Handle case where neither ticker nor company name is found
return "I'm sorry, I couldn't determine the ticker symbol for the company you're referring to. Could you please provide the ticker symbol or the full company name?"
# Suggest the extracted company name to the user
return handle_no_stock_found(company_name)
# Update the stock_ticker state with the found or suggested ticker
stock_ticker["value"] = ticker
# Dynamically call the appropriate function based on the function name
if function_name == "get_full_stock_report":
report = get_full_stock_report(ticker)
if not report.get("overview"):
return "I'm sorry, I couldn't retrieve the full stock report. Please check the ticker symbol and try again."
formatted_report = format_stock_report(report)
# Append the function response to the conversation
conversation.append({"role": "function", "name": function_name, "content": formatted_report})
# Get the final assistant response
final_response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=conversation
)
assistant_message = final_response['choices'][0]['message']['content']
# Append to conversation and return
conversation.append({"role": "assistant", "content": assistant_message})
return assistant_message
elif function_name == "get_company_overview":
overview = get_company_overview(ticker)
if not overview:
return "I'm sorry, I couldn't retrieve the company overview. Please check the ticker symbol and try again."
formatted_overview = f"""
**Company Overview for {ticker}**
- **Company Name:** {overview.get('company_name', 'N/A')}
- **Industry:** {overview.get('industry', 'N/A')}
- **CEO:** {overview.get('ceo', 'N/A')}
- **Description:** {overview.get('description', 'N/A')}
"""
conversation.append({"role": "function", "name": function_name, "content": formatted_overview})
final_response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=conversation
)
assistant_message = final_response['choices'][0]['message']['content']
conversation.append({"role": "assistant", "content": assistant_message})
return assistant_message
elif function_name == "get_financial_metrics":
metrics = get_financial_metrics(ticker)
if not metrics:
return "I'm sorry, I couldn't retrieve the financial metrics. Please check the ticker symbol and try again."
formatted_metrics = f"""
**Financial Metrics for {ticker}**
- **Market Cap:** {metrics.get('market_cap', 'N/A')}
- **Enterprise Value:** {metrics.get('enterprise_value', 'N/A')}
- **Shares Outstanding:** {metrics.get('shares_outstanding', 'N/A')}
- **Total Revenue:** {metrics.get('total_revenue', 'N/A')}
- **Employees:** {metrics.get('employees', 'N/A')}
- **Gross Profit Margin:** {metrics.get('gross_profit_margin', 'N/A')}
- **EBITDA Margin:** {metrics.get('ebitda_margin', 'N/A')}
- **Operating Margin:** {metrics.get('operating_margin', 'N/A')}
- **Net Profit Margin:** {metrics.get('net_profit_margin', 'N/A')}
- **EPS Diluted:** {metrics.get('eps_diluted', 'N/A')}
- **P/E Ratio:** {metrics.get('pe_ratio', 'N/A')}
- **Forward P/E Ratio:** {metrics.get('forward_pe_ratio', 'N/A')}
**Financial Health**
- **Cash:** {metrics.get('cash', 'N/A')}
- **Net Debt:** {metrics.get('net_debt', 'N/A')}
- **Debt/Equity:** {metrics.get('debt_to_equity', 'N/A')}
- **EBIT/Interest:** {metrics.get('ebit_to_interest', 'N/A')}
**Dividends**
- **Yield:** {metrics.get('dividendYield', 'N/A')}
- **Payout Ratio:** {metrics.get('payoutRatio', 'N/A')}
- **DPS:** {metrics.get('dividendRate', 'N/A')}
"""
conversation.append({"role": "function", "name": function_name, "content": formatted_metrics})
final_response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=conversation
)
assistant_message = final_response['choices'][0]['message']['content']
conversation.append({"role": "assistant", "content": assistant_message})
return assistant_message
elif function_name == "get_recent_news":
news_items = get_recent_news(ticker)
if not news_items:
return "I'm sorry, I couldn't retrieve recent news for this ticker."
formatted_news = f"**Recent News for {ticker}**\n"
for item in news_items:
formatted_news += f"- [{item.get('title', 'N/A')}]({item.get('link', '#')}) ({item.get('publisher', 'N/A')}) - {item.get('published_time', 'N/A')}\n"
conversation.append({"role": "function", "name": function_name, "content": formatted_news})
final_response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=conversation
)
assistant_message = final_response['choices'][0]['message']['content']
conversation.append({"role": "assistant", "content": assistant_message})
return assistant_message
elif function_name == "get_stock_performance":
performance = get_stock_performance(ticker)
if not performance:
return "I'm sorry, I couldn't retrieve the stock performance metrics."
formatted_performance = f"""
**Stock Performance for {ticker}**
- **Current Price:** {performance.get('current_price', 'N/A')}
- **52-Week Range:** {performance.get('52_week_range', 'N/A')}
- **YTD Return:** {performance.get('ytd_return', 'N/A')}
- **1-Year Total Return:** {performance.get('1y_total_return', 'N/A')}
- **5-Year Total Return CAGR:** {performance.get('5y_total_return_cagr', 'N/A')}
- **10-Year Total Return CAGR:** {performance.get('10y_total_return_cagr', 'N/A')}
"""
conversation.append({"role": "function", "name": function_name, "content": formatted_performance})
final_response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=conversation
)
assistant_message = final_response['choices'][0]['message']['content']
conversation.append({"role": "assistant", "content": assistant_message})
return assistant_message
else:
return "I'm sorry, I couldn't process your request."
else:
# If no function call, return the assistant's message
assistant_response = message.get("content")
conversation.append({"role": "assistant", "content": assistant_response})
return assistant_response
except Exception as e:
print(f"Error in stock chat: {e}") # Logging the error
return "I'm sorry, something went wrong while processing your request. Could you please try again?"
# Function to handle user input and update conversation history
def chat(user_input, history):
if history is None:
history = []
# Build the conversation for stock_chat
conversation = []
for user_msg, assistant_msg in history:
conversation.append({"role": "user", "content": user_msg})
conversation.append({"role": "assistant", "content": assistant_msg})
# Append the new user input to the conversation
conversation.append({"role": "user", "content": user_input})
# Get assistant response
assistant_response = stock_chat(conversation)
# Append the assistant's response to the conversation
history.append((user_input, assistant_response))
return history, history
# Function to display stock insight
def display_stock_insight(ticker):
if not ticker:
return "Kindly mention a stock ticker in chat to view the details"
# Fetch the data using existing functions
overview = get_company_overview(ticker)
financials = get_financial_metrics(ticker)
performance = get_stock_performance(ticker)
# Check if overview data is available
if not overview:
return "Kindly mention a stock ticker in chat to view the details"
# Format the website link properly
website = overview.get('website')
website_display = f"[{website}](https://{website})" if website else "N/A"
# Format the data into sections
stock_insight_content = f"""
### Company Overview
- **Name:** {overview.get('company_name', 'N/A')}
- **CEO:** {overview.get('ceo', 'N/A')}
- **Website:** {website_display}
- **Sector:** {overview.get('industry', 'N/A')}
- **Year Founded:** {overview.get('year_founded', 'N/A')}
### Profile
- **Market Cap:** {financials.get('market_cap', 'N/A')}
- **EV:** {financials.get('enterprise_value', 'N/A')}
- **Shares Out:** {financials.get('shares_outstanding', 'N/A')}
- **Revenue:** {financials.get('total_revenue', 'N/A')}
- **Employees:** {financials.get('employees', 'N/A')}
### Margins
- **Gross Margin:** {financials.get('gross_profit_margin', 'N/A')}
- **EBITDA Margin:** {financials.get('ebitda_margin', 'N/A')}
- **Operating Margin:** {financials.get('operating_margin', 'N/A')}
- **Net Profit Margin:** {financials.get('net_profit_margin', 'N/A')}
### Stock Performance
- **Current Price:** {performance.get('current_price', 'N/A')}
- **52-Week Range:** {performance.get('52_week_range', 'N/A')}
- **YTD Return:** {performance.get('ytd_return', 'N/A')}
- **1-Year Total Return:** {performance.get('1y_total_return', 'N/A')}
### Financial Health
- **Cash:** {financials.get('cash', 'N/A')}
- **Net Debt:** {financials.get('net_debt', 'N/A')}
- **Debt/Equity:** {financials.get('debt_to_equity', 'N/A')}
- **EBIT/Interest:** {financials.get('ebit_to_interest', 'N/A')}
### Growth (CAGR)
- **Revenue 3Yr:** {financials.get('revenue_3yr_cagr', 'N/A')}
- **EPS Diluted 3Yr:** {financials.get('eps_diluted_3yr_cagr', 'N/A')}
### Dividends
- **Yield:** {financials.get('dividendYield', 'N/A')}
- **Payout Ratio:** {financials.get('payoutRatio', 'N/A')}
- **DPS:** {financials.get('dividendRate', 'N/A')}
**Description:** {overview.get('description', 'N/A')}
"""
return stock_insight_content
# Function to update stock insight
def update_stock_insight(history):
try:
if not history:
ticker = stock_ticker["value"]
else:
ticker = stock_ticker["value"]
if not ticker:
# Return a Plotly figure with a message and the markdown content
fig = go.Figure()
fig.update_layout(
title="No stock ticker selected.",
xaxis_title="Date",
yaxis_title="Price (USD)",
template="plotly_white"
)
return fig, "No stock ticker selected."
# Generate the stock insight content
content = display_stock_insight(ticker)
# Create the stock chart
fig = create_stock_chart(ticker)
return fig, content
except Exception as e:
print(f"Error updating stock insight: {e}") # Logging the error
# Return a Plotly figure with an error message and a markdown content
fig = go.Figure()
fig.update_layout(
title="Error generating stock insight.",
xaxis_title="Date",
yaxis_title="Price (USD)",
template="plotly_white"
)
return fig, "I think the information you are looking could be provided quickly if you could provid me a ticker or company name"
# Gradio Interface Function
def chat(user_input, history):
if history is None:
history = []
# Build the conversation for stock_chat
conversation = []
for user_msg, assistant_msg in history:
conversation.append({"role": "user", "content": user_msg})
conversation.append({"role": "assistant", "content": assistant_msg})
# Append the new user input to the conversation
conversation.append({"role": "user", "content": user_input})
# Get assistant response
assistant_response = stock_chat(conversation)
# Append the assistant's response to the conversation
history.append((user_input, assistant_response))
return history, history
# # # Define Gradio interface with custom layout and error handling
# with gr.Blocks(css="""
# /* Custom CSS for White Chat Background and Enhanced Appearance */
# /* Style the entire Gradio container */
# .gradio-container {
# background-color: #EEEEEE; /* White background for the entire application PA changed it to light white blue*/
# }
# /* Style individual chat messages */
# .chatbot .message {
# background-color: #EEEEEE; /* White background for messages pa changed to this */
# border-radius: 10px;
# padding: 10px;
# margin-bottom: 10px;
# box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */
# }
# /* Differentiate user and assistant messages with border accents */
# .chatbot .message.user {
# border-left: 4px solid #6c757d; /* Grey accent for user messages */
# }
# .chatbot .message.assistant {
# border-left: 4px solid #6c757d; /* Grey accent for assistant messages */
# }
# /* Optional: Style the chat scrollbar */
# .chatbot .scroll-container::-webkit-scrollbar {
# width: 8px;
# }
# .chatbot .scroll-container::-webkit-scrollbar-track {
# background: #f1f1f1;
# }
# .chatbot .scroll-container::-webkit-scrollbar-thumb {
# background: #F2EED7; /* background: #888; */
# border-radius: 4px;
# }
# .chatbot .scroll-container::-webkit-scrollbar-thumb:hover {
# background: #555;
# }
# /* Style the Stock Insight section */
# #stock_insight_section {
# background-color: #B7B7B7; /* White background */
# padding: 15px;
# border-radius: 10px;
# box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */
# }
# /* Animation for the textbox placeholder */
# @keyframes placeholderMove {
# 0% {
# opacity: 0;
# transform: translateX(0);
# }
# 10% {
# opacity: 1;
# transform: translateX(10px);
# }
# 10% {
# opacity: 0;
# transform: translateX(-10px);
# }
# }
# .animated-placeholder::placeholder {
# animation: placeholderMove 4s infinite;
# color: #433878; /* Grey color for placeholder text */
# }
# """) as demo:
# gr.Markdown("<h1><center>Talk 2 Stock</center></h1>")
# with gr.Row():
# with gr.Column(scale=6): # 60% width
# gr.Markdown("<h2><center>Chat Xchange</center></h2>")
# chatbot = gr.Chatbot()
# state = gr.State([]) # To store the conversation history
# with gr.Row():
# txt = gr.Textbox(
# show_label=False,
# placeholder="Hey Trader, want to learn more about your stock",
# elem_classes="animated-placeholder"
# )
# txt.submit(chat, inputs=[txt, state], outputs=[chatbot, state])
# txt.submit(lambda: "", None, txt) # Clear the input box after submission
# with gr.Column(scale=4): # 40% width
# gr.Markdown("<h2><center>Stock Insight</center></h2>")
# with gr.Column(elem_id="stock_insight_section"):
# stock_chart = gr.Plot()
# stock_insight = gr.Markdown()
# # Function to update stock insight
# state.change(
# update_stock_insight,
# inputs=state,
# outputs=[stock_chart, stock_insight]
# )
# # Launch the Gradio app
# demo.launch()
with gr.Blocks(css="""
/* Custom CSS for White Chat Background and Enhanced Appearance */
/* Style the entire Gradio container */
.gradio-container {
background-color: #E3F4F4; /* White background for the entire application */
color: #000000; /* Black text by default */
font-family: 'Roboto', sans-serif; /* Default font family */
}
/* Style individual chat messages */
.chatbot .message {
background-color: #ffffff; /* White background for messages */
border-radius: 10px;
padding: 10px;
margin-bottom: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */
}
/* Differentiate user and assistant messages with border accents */
.chatbot .message.user {
border-left: 4px solid #6c757d; /* Grey accent for user messages */
}
.chatbot .message.assistant {
border-left: 4px solid #6c757d; /* Grey accent for assistant messages */
}
/* Optional: Style the chat scrollbar */
.chatbot .scroll-container::-webkit-scrollbar {
width: 8px;
}
.chatbot .scroll-container::-webkit-scrollbar-track {
background: #f1f1f1;
}
.chatbot .scroll-container::-webkit-scrollbar-thumb {
background: #888;
border-radius: 4px;
}
.chatbot .scroll-container::-webkit-scrollbar-thumb:hover {
background: #555;
}
/* Style the Stock Insight section */
#stock_insight_section {
background-color: #ffffff; /* White background */
color: #3A98B9; /* Dark gray text for general content */
padding: 15px;
border-radius: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */
}
/* Stock Insight Content Styles */
#stock_insight_section h3 {
color: #3A98B9; /* Bright Blue for Subheadings */
font-family: 'Montserrat', sans-serif; /* Accent Font for Subheadings */
}
/* Animation for the textbox placeholder chat bot window background */
.dark .bubble-wrap.svelte-1e1jlin.svelte-1e1jlin.svelte-1e1jlin {
background: #fff !important;
}
/* Animation for the textbox placeholder chat bot input box */
.block.svelte-12cmxck {
background: #fff !important;
}
/* Change the loading overlay background color to white */
.loading-container {
background-color: #ffffff !important; /* White background */
}
/* Animation for the textbox placeholder chat bot input box text color*/
textarea.svelte-1f354aw.svelte-1f354aw {
background: #fff !important;
color: #000 !important;
}
#stock_insight_section p,
#stock_insight_section li {
color: #1A3636; /* Darker Gray for Paragraphs and List Items */
font-size: 14px; /* Font Size for Paragraphs and List Items */
line-height: 1.6; /* Line Height for Better Readability */
}
/* Animation for the textbox placeholder */
@keyframes placeholderMove {
0% {
opacity: 0;
transform: translateX(0);
}
15% {
opacity: 1;
transform: translateX(10px);
}
10% {
opacity: 0;
transform: translateX(-10px);
}
}
/* added after upendra help */
.gradio-container-4-44-1 b, .gradio-container-4-44-1 strong, center {
color: #000 !important;
}
.animated-placeholder::placeholder {
animation: placeholderMove 4s infinite;
color: #6c757d; /* Grey color for placeholder text */
font-style: italic; /* Italic Text */
}
""") as demo:
gr.Markdown("<h1><center>Talk 2 Stock</center></h1>")
with gr.Row():
with gr.Column(scale=6): # 60% width
gr.Markdown("<h2><center>Chat Xchange</center></h2>")
chatbot = gr.Chatbot()
state = gr.State([]) # To store the conversation history
with gr.Row():
txt = gr.Textbox(
show_label=False,
placeholder="Hey Trader, Let's chatch up with Stocks",
elem_classes="animated-placeholder"
)
txt.submit(chat, inputs=[txt, state], outputs=[chatbot, state])
txt.submit(lambda: "", None, txt) # Clear the input box after submission
with gr.Column(scale=4): # 40% width
gr.Markdown("<h2><center>Stock Insight</center></h2>")
with gr.Column(elem_id="stock_insight_section"):
stock_chart = gr.Plot()
stock_insight = gr.Markdown()
# Function to update stock insight
state.change(
update_stock_insight,
inputs=state,
outputs=[stock_chart, stock_insight]
)
# Launch the Gradio app
demo.launch()