Spaces:
Running
Running
File size: 6,130 Bytes
aa99ac2 3e0f53f aa99ac2 |
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 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
import faiss
import numpy as np
import yfinance as yf
import os
import streamlit as st
from dotenv import load_dotenv
from sentence_transformers import SentenceTransformer
from groq import Groq
# Hide Hugging Face Spaces top bar
hide_hf_bar = """
<style>
header {visibility: hidden;}
</style>
"""
st.markdown(hide_hf_bar, unsafe_allow_html=True)
# Load environment variables
load_dotenv()
groq_api_key = os.getenv("GROQ_API_KEY")
if not groq_api_key:
st.error("GROQ_API_KEY is missing. Set it in Railway's environment variables.")
st.stop()
client = Groq(api_key=groq_api_key)
# Initialize session state for dark mode (default: True)
if "dark_mode" not in st.session_state:
st.session_state.dark_mode = True
# Icon switch
icon = "π" if st.session_state.dark_mode else "π"
# Custom CSS to remove container and position icon in the top-right corner
st.markdown(
"""
<style>
.stButton > button {
background: none !important;
border: none !important;
box-shadow: none !important;
font-size: 24px !important;
position: absolute !important;
top: 10px !important;
right: 10px !important;
cursor: pointer !important;
}
</style>
""",
unsafe_allow_html=True,
)
# Toggle button (tap to switch modes)
if st.button(icon, key="dark_mode_toggle"):
st.session_state.dark_mode = not st.session_state.dark_mode
st.rerun()
# Apply styles for dark & light modes
if st.session_state.dark_mode:
st.markdown(
"""
<style>
body, .stApp { background-color: #0A192F; color: #E0E5EC; font-family: 'Segoe UI', sans-serif; }
h1, h2, h3, p, label { color: white !important; }
.stTextInput > div > div > input {
background-color: #112240;
color: #E0E5EC;
border-radius: 8px;
padding: 10px;
border: 2px solid transparent;
box-shadow: 0px 0px 10px rgba(255, 255, 255, 0.2);
}
</style>
""",
unsafe_allow_html=True,
)
else:
st.markdown(
"""
<style>
body, .stApp { background-color: #ffffff; color: #333; }
h1, h2, h3, p, label { color: #333 !important; }
.stTextInput > div > div > input {
background-color: #f8f9fa;
color: #333;
border-radius: 8px;
padding: 10px;
border: 1px solid #ccc;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
}
</style>
""",
unsafe_allow_html=True,
)
# Hide Streamlit UI elements
st.markdown(
"""
<style>
#MainMenu {visibility: hidden;}
footer {visibility: hidden;}
header {visibility: hidden;}
</style>
""",
unsafe_allow_html=True
)
# Load Sentence-Transformer Model (22MB)
embedding_model = SentenceTransformer("sentence-transformers/paraphrase-MiniLM-L3-v2")
def get_embeddings(text):
"""Fetch embeddings using the local MiniLM model."""
return np.array(embedding_model.encode(text))
def get_stock_info(symbol: str) -> dict:
"""Retrieve stock information and description from Yahoo Finance."""
try:
data = yf.Ticker(symbol)
stock_info = data.info
description = stock_info.get("longBusinessSummary", "No description available.")
return {"symbol": symbol, "description": description}
except Exception as e:
return {"symbol": symbol, "description": f"Error retrieving stock info: {str(e)}"}
# Determine embedding size dynamically
test_embedding = get_embeddings("Test")
d = test_embedding.shape[0]
# Initialize FAISS index
index = faiss.IndexFlatL2(d)
stock_metadata = {}
def store_stock_embeddings(stock_list):
"""Store stock embeddings in FAISS index."""
global stock_metadata
vectors = []
metadata = []
for stock in stock_list:
description = stock["description"]
symbol = stock["symbol"]
embedding = get_embeddings(description)
if np.any(embedding):
vectors.append(embedding)
metadata.append({"symbol": symbol, "description": description})
if vectors:
index.add(np.array(vectors))
for i, meta in enumerate(metadata):
stock_metadata[len(stock_metadata)] = meta
def find_similar_stocks(query):
"""Find similar stocks based on query embedding."""
if index.ntotal == 0:
return []
query_embedding = get_embeddings(query).reshape(1, -1)
D, I = index.search(query_embedding, k=10)
return [stock_metadata[idx] for idx in I[0] if idx in stock_metadata]
def analyze_stocks(query, stocks):
"""Generate stock analysis using Groq's Llama model."""
if not stocks:
return "No relevant stocks found."
context = "\n".join([f"Symbol: {s['symbol']}, Description: {s['description']}" for s in stocks])
prompt = f"""
You are a financial assistant. Analyze the following stocks based on the given query: {query}.
Stock data:
{context}
Provide insights based on performance, trends, and any notable aspects.
"""
try:
response = client.chat.completions.create(
model="llama-3.2-11b-vision-preview",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
except Exception as e:
return f"Error generating analysis: {str(e)}"
# Load stock data at startup
default_stocks = ["AAPL", "MSFT", "GOOGL", "AMZN", "TSLA"]
stock_data = [get_stock_info(symbol) for symbol in default_stocks]
store_stock_embeddings(stock_data)
# Streamlit UI
st.title('Stock Analysis Dashboard')
with st.container():
query = st.text_input('Ask About Stocks:', '')
if st.button('Get Stock Info'):
stocks = find_similar_stocks(query)
analysis = analyze_stocks(query, stocks)
st.markdown("### Stock Insights:")
st.markdown(f"<div class='stMarkdown'>{analysis}</div>", unsafe_allow_html=True)
st.markdown("---")
if not stocks:
st.error("No relevant stocks found.")
|