Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -9,13 +9,17 @@ import json
|
|
| 9 |
import asyncio
|
| 10 |
import aiohttp
|
| 11 |
from typing import Optional, List, Dict
|
| 12 |
-
import
|
| 13 |
|
| 14 |
# Apply nest_asyncio for async operations in Streamlit
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
-
# Hugging Face token
|
| 18 |
-
HUGGINGFACE_TOKEN =
|
| 19 |
|
| 20 |
if HUGGINGFACE_TOKEN:
|
| 21 |
try:
|
|
@@ -24,64 +28,90 @@ if HUGGINGFACE_TOKEN:
|
|
| 24 |
except Exception as e:
|
| 25 |
st.error(f"β Hugging Face login failed: {e}")
|
| 26 |
|
| 27 |
-
# Custom CSS for silver/sky blue theme
|
| 28 |
st.markdown("""
|
| 29 |
<style>
|
| 30 |
.main {
|
| 31 |
-
background
|
|
|
|
| 32 |
}
|
|
|
|
| 33 |
.stChatMessage {
|
| 34 |
-
padding:
|
| 35 |
-
border-radius:
|
| 36 |
-
margin:
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
border: 1px solid #e1e5e9;
|
| 40 |
}
|
|
|
|
| 41 |
/* User message styling */
|
| 42 |
.stChatMessage:has(div[data-testid="stChatMessageContent"] > div:first-child > div:first-child) {
|
| 43 |
-
background
|
| 44 |
-
border-left:
|
| 45 |
}
|
|
|
|
| 46 |
/* Assistant message styling */
|
| 47 |
.stChatMessage:has(div[data-testid="stChatMessageContent"] > div:first-child > div:last-child) {
|
| 48 |
-
background
|
| 49 |
-
border-left:
|
|
|
|
| 50 |
}
|
|
|
|
| 51 |
.stTextInput > div > div > input {
|
| 52 |
border: 2px solid #90caf9;
|
| 53 |
-
border-radius:
|
| 54 |
-
padding:
|
|
|
|
|
|
|
|
|
|
| 55 |
}
|
|
|
|
| 56 |
.stButton > button {
|
| 57 |
-
background
|
| 58 |
color: white;
|
| 59 |
border: none;
|
| 60 |
-
border-radius:
|
| 61 |
-
padding:
|
| 62 |
-
font-weight:
|
|
|
|
|
|
|
|
|
|
| 63 |
}
|
|
|
|
| 64 |
.stButton > button:hover {
|
| 65 |
-
|
| 66 |
-
|
| 67 |
}
|
|
|
|
| 68 |
.sidebar .sidebar-content {
|
| 69 |
-
background
|
|
|
|
| 70 |
}
|
|
|
|
| 71 |
.api-status {
|
| 72 |
-
padding:
|
| 73 |
-
border-radius:
|
| 74 |
-
margin:
|
| 75 |
-
font-size:
|
|
|
|
| 76 |
}
|
|
|
|
| 77 |
.api-success {
|
| 78 |
-
background
|
| 79 |
border-left: 4px solid #4caf50;
|
| 80 |
}
|
|
|
|
| 81 |
.api-error {
|
| 82 |
-
background
|
| 83 |
border-left: 4px solid #f44336;
|
| 84 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
</style>
|
| 86 |
""", unsafe_allow_html=True)
|
| 87 |
|
|
@@ -105,7 +135,7 @@ COMPANY_INFO = {
|
|
| 105 |
"stage": "Growth and development, focused on building sustainable processes and systems"
|
| 106 |
}
|
| 107 |
|
| 108 |
-
# API Configuration
|
| 109 |
API_CONFIG = {
|
| 110 |
"news_api": {
|
| 111 |
"url": "https://newsapi.org/v2/top-headlines",
|
|
@@ -113,14 +143,14 @@ API_CONFIG = {
|
|
| 113 |
"country": "us",
|
| 114 |
"category": "technology",
|
| 115 |
"pageSize": 5,
|
| 116 |
-
"apiKey":
|
| 117 |
}
|
| 118 |
},
|
| 119 |
"weather_api": {
|
| 120 |
"url": "https://api.openweathermap.org/data/2.5/weather",
|
| 121 |
"params": {
|
| 122 |
"q": "Lagos,NG",
|
| 123 |
-
"appid":
|
| 124 |
"units": "metric"
|
| 125 |
}
|
| 126 |
},
|
|
@@ -129,11 +159,8 @@ API_CONFIG = {
|
|
| 129 |
"params": {
|
| 130 |
"function": "GLOBAL_QUOTE",
|
| 131 |
"symbol": "AAPL",
|
| 132 |
-
"apikey":
|
| 133 |
}
|
| 134 |
-
},
|
| 135 |
-
"yah_tech_internal": {
|
| 136 |
-
"url": "http://localhost:8000" # For internal FastAPI server
|
| 137 |
}
|
| 138 |
}
|
| 139 |
|
|
@@ -151,7 +178,7 @@ class APIClient:
|
|
| 151 |
async def make_async_request(self, url: str, params: dict = None, headers: dict = None):
|
| 152 |
"""Make asynchronous API request"""
|
| 153 |
try:
|
| 154 |
-
async with self.session.get(url, params=params, headers=headers) as response:
|
| 155 |
if response.status == 200:
|
| 156 |
return await response.json()
|
| 157 |
else:
|
|
@@ -181,9 +208,9 @@ class ExternalAPIService:
|
|
| 181 |
if config["params"]["apiKey"] == "demo_key":
|
| 182 |
return {
|
| 183 |
"articles": [
|
| 184 |
-
{"title": "AI Technology Advances in 2024", "description": "Latest breakthroughs in artificial intelligence..."},
|
| 185 |
-
{"title": "Venture Studio Model Gains Popularity", "description": "More entrepreneurs adopting the venture studio approach..."},
|
| 186 |
-
{"title": "Economic Impact of Tech Startups", "description": "How technology startups are reshaping economies..."}
|
| 187 |
]
|
| 188 |
}
|
| 189 |
|
|
@@ -197,9 +224,10 @@ class ExternalAPIService:
|
|
| 197 |
|
| 198 |
if config["params"]["appid"] == "demo_key":
|
| 199 |
return {
|
| 200 |
-
"weather": [{"description": "clear sky"}],
|
| 201 |
-
"main": {"temp": 28, "humidity": 65},
|
| 202 |
-
"name": city
|
|
|
|
| 203 |
}
|
| 204 |
|
| 205 |
result = await self.api_client.make_async_request(config["url"], config["params"])
|
|
@@ -213,6 +241,7 @@ class ExternalAPIService:
|
|
| 213 |
if config["params"]["apikey"] == "demo_key":
|
| 214 |
return {
|
| 215 |
"Global Quote": {
|
|
|
|
| 216 |
"05. price": "185.50",
|
| 217 |
"09. change": "+1.25",
|
| 218 |
"10. change percent": "+0.68%"
|
|
@@ -223,7 +252,8 @@ class ExternalAPIService:
|
|
| 223 |
return result
|
| 224 |
|
| 225 |
def get_crypto_data(self, coin: str = "bitcoin"):
|
| 226 |
-
"""Get cryptocurrency data
|
|
|
|
| 227 |
url = f"https://api.coingecko.com/api/v3/simple/price"
|
| 228 |
params = {
|
| 229 |
"ids": coin,
|
|
@@ -234,27 +264,27 @@ class ExternalAPIService:
|
|
| 234 |
result = self.api_client.make_sync_request(url, params)
|
| 235 |
return result
|
| 236 |
|
| 237 |
-
# Knowledge base for the AI
|
| 238 |
KNOWLEDGE_BASE = {
|
| 239 |
"personal": {
|
| 240 |
-
"who are you": f"I'm {PERSONAL_INFO['name']}
|
| 241 |
-
"what are your goals": f"My goals include
|
| 242 |
-
"what do you do": f"I'm the CEO of YAH Tech, focused on {PERSONAL_INFO['goals'][2]}
|
| 243 |
-
"tell me about yourself": f"I'm {PERSONAL_INFO['name']}
|
| 244 |
},
|
| 245 |
"company": {
|
| 246 |
-
"what is yah tech": f"{COMPANY_INFO['name']} is a {COMPANY_INFO['type']}. Our purpose is to {COMPANY_INFO['purpose'].lower()}
|
| 247 |
-
"what does yah tech do": f"We specialize in {COMPANY_INFO['primary_activity'].lower()}
|
| 248 |
-
"company philosophy": f"Our philosophy is: '{COMPANY_INFO['philosophy']}'
|
| 249 |
-
"company stage": f"We're currently in the {COMPANY_INFO['stage']} phase.",
|
| 250 |
-
"venture studio": "As a venture studio, we don't just build apps - we build complete businesses with scalable systems and futuristic solutions.",
|
| 251 |
},
|
| 252 |
"api_capabilities": {
|
| 253 |
-
"what can you do": "I can fetch real-time data like tech news
|
| 254 |
-
"get news": "I can fetch the latest technology news
|
| 255 |
-
"weather": "I can check weather information for any city.",
|
| 256 |
-
"stock": "I can get stock market data for companies.",
|
| 257 |
-
"crypto": "I can fetch cryptocurrency prices and changes.",
|
| 258 |
}
|
| 259 |
}
|
| 260 |
|
|
@@ -269,7 +299,7 @@ class YAHBot:
|
|
| 269 |
def _load_model(self):
|
| 270 |
"""Load the Hugging Face model"""
|
| 271 |
try:
|
| 272 |
-
with st.spinner("π Loading AI model..."):
|
| 273 |
self.tokenizer = AutoTokenizer.from_pretrained(
|
| 274 |
"Adedoyinjames/YAH-Tech-Chat-Bot",
|
| 275 |
use_auth_token=HUGGINGFACE_TOKEN if HUGGINGFACE_TOKEN else True
|
|
@@ -279,16 +309,16 @@ class YAHBot:
|
|
| 279 |
use_auth_token=HUGGINGFACE_TOKEN if HUGGINGFACE_TOKEN else True,
|
| 280 |
torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
|
| 281 |
)
|
| 282 |
-
st.success("β
AI model loaded successfully!")
|
| 283 |
except Exception as e:
|
| 284 |
st.error(f"β Failed to load custom model: {e}")
|
| 285 |
st.info("π Falling back to standard FLAN-T5-small model...")
|
| 286 |
try:
|
| 287 |
self.tokenizer = AutoTokenizer.from_pretrained(self.model_name)
|
| 288 |
self.model = AutoModelForSeq2SeqLM.from_pretrained(self.model_name)
|
| 289 |
-
st.success("β
Standard model loaded successfully!")
|
| 290 |
except Exception as e2:
|
| 291 |
-
st.error(f"β Failed to load
|
| 292 |
|
| 293 |
def _get_knowledge_response(self, user_input):
|
| 294 |
"""Check if the input matches any knowledge base entries"""
|
|
@@ -316,29 +346,29 @@ class YAHBot:
|
|
| 316 |
if any(word in user_input_lower for word in ["news", "headlines", "tech news"]):
|
| 317 |
news_data = await self.api_service.get_tech_news()
|
| 318 |
if "articles" in news_data:
|
| 319 |
-
articles = news_data["articles"][:3]
|
| 320 |
-
response = "π° **Latest
|
| 321 |
for i, article in enumerate(articles, 1):
|
| 322 |
-
response += f"{i}.
|
| 323 |
response += f" {article.get('description', 'No description available')}\n\n"
|
| 324 |
return response
|
| 325 |
else:
|
| 326 |
return "β Could not fetch news at the moment. Please try again later."
|
| 327 |
|
| 328 |
elif any(word in user_input_lower for word in ["weather", "temperature"]):
|
| 329 |
-
# Extract city name if mentioned
|
| 330 |
city = "Lagos"
|
| 331 |
for word in user_input_lower.split():
|
| 332 |
-
if word not in ["weather", "temperature", "what's", "the"] and len(word) > 2:
|
| 333 |
city = word.capitalize()
|
| 334 |
break
|
| 335 |
|
| 336 |
weather_data = await self.api_service.get_weather(city)
|
| 337 |
if "weather" in weather_data:
|
| 338 |
temp = weather_data["main"]["temp"]
|
| 339 |
-
desc = weather_data["weather"][0]["description"]
|
| 340 |
humidity = weather_data["main"]["humidity"]
|
| 341 |
-
|
|
|
|
| 342 |
else:
|
| 343 |
return "β Could not fetch weather data. Please try again later."
|
| 344 |
|
|
@@ -349,7 +379,7 @@ class YAHBot:
|
|
| 349 |
price = quote.get("05. price", "N/A")
|
| 350 |
change = quote.get("09. change", "N/A")
|
| 351 |
change_percent = quote.get("10. change percent", "N/A")
|
| 352 |
-
return f"π **Apple Stock (AAPL):**\n\
|
| 353 |
else:
|
| 354 |
return "β Could not fetch stock data. Please try again later."
|
| 355 |
|
|
@@ -359,7 +389,17 @@ class YAHBot:
|
|
| 359 |
btc_data = crypto_data["bitcoin"]
|
| 360 |
price = btc_data.get("usd", "N/A")
|
| 361 |
change = btc_data.get("usd_24h_change", "N/A")
|
| 362 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 363 |
else:
|
| 364 |
return "β Could not fetch cryptocurrency data. Please try again later."
|
| 365 |
|
|
@@ -381,7 +421,7 @@ class YAHBot:
|
|
| 381 |
if self.model and self.tokenizer:
|
| 382 |
try:
|
| 383 |
# Prepare input with context
|
| 384 |
-
context = "You are YAH Bot, an AI assistant for
|
| 385 |
full_input = f"{context}\n\nConversation:\n" + "\n".join([f"Human: {msg['content']}\nAI: {msg['content']}"
|
| 386 |
for msg in conversation_history[-3:]]) + f"\nHuman: {user_input}\nAI:"
|
| 387 |
|
|
@@ -390,7 +430,7 @@ class YAHBot:
|
|
| 390 |
with torch.no_grad():
|
| 391 |
outputs = self.model.generate(
|
| 392 |
inputs,
|
| 393 |
-
max_length=
|
| 394 |
num_return_sequences=1,
|
| 395 |
temperature=0.7,
|
| 396 |
do_sample=True,
|
|
@@ -401,14 +441,14 @@ class YAHBot:
|
|
| 401 |
return response
|
| 402 |
|
| 403 |
except Exception as e:
|
| 404 |
-
return f"I encountered an error: {str(e)}. However, I can tell you that at YAH Tech, we're focused on building scalable systems that drive economic growth."
|
| 405 |
|
| 406 |
-
|
| 407 |
fallback_responses = [
|
| 408 |
-
"That's an interesting question! At
|
| 409 |
-
"I'd be happy to discuss that. As a venture studio, we focus on building technology-driven ventures that create both profit and societal value
|
| 410 |
-
"Great question! Our approach at
|
| 411 |
-
f"From my perspective as {PERSONAL_INFO['name']}, I focus on building systems that reshape the economic landscape through technology."
|
| 412 |
]
|
| 413 |
return random.choice(fallback_responses)
|
| 414 |
|
|
@@ -420,89 +460,93 @@ def initialize_session_state():
|
|
| 420 |
st.session_state.bot = YAHBot()
|
| 421 |
if "conversation_started" not in st.session_state:
|
| 422 |
st.session_state.conversation_started = False
|
| 423 |
-
if "api_status" not in st.session_state:
|
| 424 |
-
st.session_state.api_status = {}
|
| 425 |
|
| 426 |
def display_api_status():
|
| 427 |
"""Display API status in sidebar"""
|
| 428 |
-
st.sidebar.subheader("API Status")
|
| 429 |
|
| 430 |
-
#
|
| 431 |
statuses = {
|
| 432 |
-
"
|
| 433 |
-
"
|
| 434 |
-
"
|
| 435 |
-
"
|
| 436 |
-
"
|
| 437 |
}
|
| 438 |
|
| 439 |
for api, status in statuses.items():
|
| 440 |
-
|
| 441 |
-
st.sidebar.write(f"{color} {api}: {status}")
|
| 442 |
|
| 443 |
def main():
|
| 444 |
# Page configuration
|
| 445 |
st.set_page_config(
|
| 446 |
-
page_title="YAH Tech
|
| 447 |
-
page_icon="
|
| 448 |
-
layout="centered"
|
|
|
|
| 449 |
)
|
| 450 |
|
| 451 |
# Initialize session state
|
| 452 |
initialize_session_state()
|
| 453 |
|
| 454 |
-
# Header
|
| 455 |
col1, col2 = st.columns([1, 4])
|
| 456 |
with col1:
|
| 457 |
-
st.image("https://via.placeholder.com/
|
| 458 |
with col2:
|
| 459 |
-
st.
|
| 460 |
-
st.caption("Powered by AI β’
|
| 461 |
|
| 462 |
st.markdown("---")
|
| 463 |
|
| 464 |
# Sidebar
|
| 465 |
with st.sidebar:
|
| 466 |
-
st.header("About YAH Tech")
|
| 467 |
st.markdown(f"""
|
| 468 |
-
|
| 469 |
-
|
| 470 |
|
| 471 |
-
|
| 472 |
-
|
| 473 |
-
|
| 474 |
|
| 475 |
-
|
| 476 |
""")
|
| 477 |
|
| 478 |
# API Status
|
| 479 |
display_api_status()
|
| 480 |
|
| 481 |
st.markdown("---")
|
| 482 |
-
st.subheader("
|
| 483 |
st.markdown("""
|
| 484 |
-
|
| 485 |
-
-
|
| 486 |
-
-
|
| 487 |
-
-
|
| 488 |
-
-
|
| 489 |
-
-
|
| 490 |
-
-
|
| 491 |
""")
|
| 492 |
|
| 493 |
-
st.
|
| 494 |
-
st.subheader("Quick Actions")
|
| 495 |
-
if st.button("π Test APIs"):
|
| 496 |
-
st.info("API testing feature would be implemented here")
|
| 497 |
-
|
| 498 |
-
if st.button("ποΈ Clear Chat"):
|
| 499 |
st.session_state.messages = []
|
| 500 |
st.session_state.conversation_started = False
|
| 501 |
st.rerun()
|
| 502 |
|
| 503 |
# Chat interface
|
| 504 |
if not st.session_state.conversation_started:
|
| 505 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 506 |
st.session_state.conversation_started = True
|
| 507 |
|
| 508 |
# Display chat messages
|
|
@@ -511,7 +555,7 @@ def main():
|
|
| 511 |
st.markdown(message["content"])
|
| 512 |
|
| 513 |
# Chat input
|
| 514 |
-
if prompt := st.chat_input("Ask me about YAH Tech, get
|
| 515 |
# Add user message to chat history
|
| 516 |
st.session_state.messages.append({"role": "user", "content": prompt})
|
| 517 |
with st.chat_message("user"):
|
|
@@ -519,10 +563,15 @@ def main():
|
|
| 519 |
|
| 520 |
# Generate and display assistant response
|
| 521 |
with st.chat_message("assistant"):
|
| 522 |
-
with st.spinner("π€
|
| 523 |
# Use asyncio to handle async API calls
|
| 524 |
-
|
| 525 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 526 |
|
| 527 |
st.session_state.messages.append({"role": "assistant", "content": response})
|
| 528 |
|
|
|
|
| 9 |
import asyncio
|
| 10 |
import aiohttp
|
| 11 |
from typing import Optional, List, Dict
|
| 12 |
+
import os
|
| 13 |
|
| 14 |
# Apply nest_asyncio for async operations in Streamlit
|
| 15 |
+
try:
|
| 16 |
+
import nest_asyncio
|
| 17 |
+
nest_asyncio.apply()
|
| 18 |
+
except ImportError:
|
| 19 |
+
pass
|
| 20 |
|
| 21 |
+
# Get Hugging Face token from environment variables (set in HF Spaces secrets)
|
| 22 |
+
HUGGINGFACE_TOKEN = os.environ.get("HUGGINGFACE_TOKEN", "")
|
| 23 |
|
| 24 |
if HUGGINGFACE_TOKEN:
|
| 25 |
try:
|
|
|
|
| 28 |
except Exception as e:
|
| 29 |
st.error(f"β Hugging Face login failed: {e}")
|
| 30 |
|
| 31 |
+
# Custom CSS for beautiful silver/sky blue theme
|
| 32 |
st.markdown("""
|
| 33 |
<style>
|
| 34 |
.main {
|
| 35 |
+
background: linear-gradient(135deg, #f8f9fa 0%, #e3f2fd 100%);
|
| 36 |
+
font-family: 'Inter', sans-serif;
|
| 37 |
}
|
| 38 |
+
|
| 39 |
.stChatMessage {
|
| 40 |
+
padding: 20px;
|
| 41 |
+
border-radius: 16px;
|
| 42 |
+
margin: 12px 0;
|
| 43 |
+
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
| 44 |
+
border: none;
|
|
|
|
| 45 |
}
|
| 46 |
+
|
| 47 |
/* User message styling */
|
| 48 |
.stChatMessage:has(div[data-testid="stChatMessageContent"] > div:first-child > div:first-child) {
|
| 49 |
+
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
|
| 50 |
+
border-left: 6px solid #2196f3;
|
| 51 |
}
|
| 52 |
+
|
| 53 |
/* Assistant message styling */
|
| 54 |
.stChatMessage:has(div[data-testid="stChatMessageContent"] > div:first-child > div:last-child) {
|
| 55 |
+
background: linear-gradient(135deg, #ffffff 0%, #f5f5f5 100%);
|
| 56 |
+
border-left: 6px solid #78909c;
|
| 57 |
+
border: 1px solid #e0e0e0;
|
| 58 |
}
|
| 59 |
+
|
| 60 |
.stTextInput > div > div > input {
|
| 61 |
border: 2px solid #90caf9;
|
| 62 |
+
border-radius: 25px;
|
| 63 |
+
padding: 15px 20px;
|
| 64 |
+
font-size: 16px;
|
| 65 |
+
background: white;
|
| 66 |
+
box-shadow: 0 2px 10px rgba(33, 150, 243, 0.1);
|
| 67 |
}
|
| 68 |
+
|
| 69 |
.stButton > button {
|
| 70 |
+
background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%);
|
| 71 |
color: white;
|
| 72 |
border: none;
|
| 73 |
+
border-radius: 25px;
|
| 74 |
+
padding: 12px 28px;
|
| 75 |
+
font-weight: 600;
|
| 76 |
+
font-size: 16px;
|
| 77 |
+
box-shadow: 0 4px 12px rgba(33, 150, 243, 0.3);
|
| 78 |
+
transition: all 0.3s ease;
|
| 79 |
}
|
| 80 |
+
|
| 81 |
.stButton > button:hover {
|
| 82 |
+
transform: translateY(-2px);
|
| 83 |
+
box-shadow: 0 6px 16px rgba(33, 150, 243, 0.4);
|
| 84 |
}
|
| 85 |
+
|
| 86 |
.sidebar .sidebar-content {
|
| 87 |
+
background: linear-gradient(180deg, #eceff1 0%, #cfd8dc 100%);
|
| 88 |
+
border-right: 1px solid #b0bec5;
|
| 89 |
}
|
| 90 |
+
|
| 91 |
.api-status {
|
| 92 |
+
padding: 12px;
|
| 93 |
+
border-radius: 10px;
|
| 94 |
+
margin: 8px 0;
|
| 95 |
+
font-size: 14px;
|
| 96 |
+
font-weight: 500;
|
| 97 |
}
|
| 98 |
+
|
| 99 |
.api-success {
|
| 100 |
+
background: linear-gradient(135deg, #e8f5e8 0%, #c8e6c9 100%);
|
| 101 |
border-left: 4px solid #4caf50;
|
| 102 |
}
|
| 103 |
+
|
| 104 |
.api-error {
|
| 105 |
+
background: linear-gradient(135deg, #ffebee 0%, #ffcdd2 100%);
|
| 106 |
border-left: 4px solid #f44336;
|
| 107 |
}
|
| 108 |
+
|
| 109 |
+
.header-gradient {
|
| 110 |
+
background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%);
|
| 111 |
+
-webkit-background-clip: text;
|
| 112 |
+
-webkit-text-fill-color: transparent;
|
| 113 |
+
background-clip: text;
|
| 114 |
+
}
|
| 115 |
</style>
|
| 116 |
""", unsafe_allow_html=True)
|
| 117 |
|
|
|
|
| 135 |
"stage": "Growth and development, focused on building sustainable processes and systems"
|
| 136 |
}
|
| 137 |
|
| 138 |
+
# API Configuration with environment variables
|
| 139 |
API_CONFIG = {
|
| 140 |
"news_api": {
|
| 141 |
"url": "https://newsapi.org/v2/top-headlines",
|
|
|
|
| 143 |
"country": "us",
|
| 144 |
"category": "technology",
|
| 145 |
"pageSize": 5,
|
| 146 |
+
"apiKey": os.environ.get("NEWS_API_KEY", "demo_key")
|
| 147 |
}
|
| 148 |
},
|
| 149 |
"weather_api": {
|
| 150 |
"url": "https://api.openweathermap.org/data/2.5/weather",
|
| 151 |
"params": {
|
| 152 |
"q": "Lagos,NG",
|
| 153 |
+
"appid": os.environ.get("WEATHER_API_KEY", "demo_key"),
|
| 154 |
"units": "metric"
|
| 155 |
}
|
| 156 |
},
|
|
|
|
| 159 |
"params": {
|
| 160 |
"function": "GLOBAL_QUOTE",
|
| 161 |
"symbol": "AAPL",
|
| 162 |
+
"apikey": os.environ.get("ALPHA_VANTAGE_KEY", "demo_key")
|
| 163 |
}
|
|
|
|
|
|
|
|
|
|
| 164 |
}
|
| 165 |
}
|
| 166 |
|
|
|
|
| 178 |
async def make_async_request(self, url: str, params: dict = None, headers: dict = None):
|
| 179 |
"""Make asynchronous API request"""
|
| 180 |
try:
|
| 181 |
+
async with self.session.get(url, params=params, headers=headers, timeout=10) as response:
|
| 182 |
if response.status == 200:
|
| 183 |
return await response.json()
|
| 184 |
else:
|
|
|
|
| 208 |
if config["params"]["apiKey"] == "demo_key":
|
| 209 |
return {
|
| 210 |
"articles": [
|
| 211 |
+
{"title": "π AI Technology Advances in 2024", "description": "Latest breakthroughs in artificial intelligence and machine learning transforming industries..."},
|
| 212 |
+
{"title": "πΌ Venture Studio Model Gains Popularity", "description": "More entrepreneurs adopting the venture studio approach for scalable business creation..."},
|
| 213 |
+
{"title": "π Economic Impact of Tech Startups", "description": "How technology startups are reshaping global economies and creating new opportunities..."}
|
| 214 |
]
|
| 215 |
}
|
| 216 |
|
|
|
|
| 224 |
|
| 225 |
if config["params"]["appid"] == "demo_key":
|
| 226 |
return {
|
| 227 |
+
"weather": [{"description": "clear sky", "main": "Clear"}],
|
| 228 |
+
"main": {"temp": 28, "humidity": 65, "feels_like": 30},
|
| 229 |
+
"name": city,
|
| 230 |
+
"sys": {"country": "NG"}
|
| 231 |
}
|
| 232 |
|
| 233 |
result = await self.api_client.make_async_request(config["url"], config["params"])
|
|
|
|
| 241 |
if config["params"]["apikey"] == "demo_key":
|
| 242 |
return {
|
| 243 |
"Global Quote": {
|
| 244 |
+
"01. symbol": symbol,
|
| 245 |
"05. price": "185.50",
|
| 246 |
"09. change": "+1.25",
|
| 247 |
"10. change percent": "+0.68%"
|
|
|
|
| 252 |
return result
|
| 253 |
|
| 254 |
def get_crypto_data(self, coin: str = "bitcoin"):
|
| 255 |
+
"""Get cryptocurrency data"""
|
| 256 |
+
# Using CoinGecko API (no key required for basic usage)
|
| 257 |
url = f"https://api.coingecko.com/api/v3/simple/price"
|
| 258 |
params = {
|
| 259 |
"ids": coin,
|
|
|
|
| 264 |
result = self.api_client.make_sync_request(url, params)
|
| 265 |
return result
|
| 266 |
|
| 267 |
+
# Knowledge base for the AI
|
| 268 |
KNOWLEDGE_BASE = {
|
| 269 |
"personal": {
|
| 270 |
+
"who are you": f"π€΅ I'm **{PERSONAL_INFO['name']}**, {PERSONAL_INFO['role']}.",
|
| 271 |
+
"what are your goals": f"π― My goals include:\nβ’ {PERSONAL_INFO['goals'][0]}\nβ’ {PERSONAL_INFO['goals'][1]}\nβ’ {PERSONAL_INFO['goals'][2]}",
|
| 272 |
+
"what do you do": f"πΌ I'm the CEO of YAH Tech, focused on **{PERSONAL_INFO['goals'][2]}**.",
|
| 273 |
+
"tell me about yourself": f"π I'm **{PERSONAL_INFO['name']}**, {PERSONAL_INFO['role']}. My mission is to **{PERSONAL_INFO['goals'][0].lower()}** and **{PERSONAL_INFO['goals'][1].lower()}** through innovative technology solutions.",
|
| 274 |
},
|
| 275 |
"company": {
|
| 276 |
+
"what is yah tech": f"π’ **{COMPANY_INFO['name']}** is a {COMPANY_INFO['type']}. Our purpose is to **{COMPANY_INFO['purpose'].lower()}**.",
|
| 277 |
+
"what does yah tech do": f"π We specialize in **{COMPANY_INFO['primary_activity'].lower()}**. {COMPANY_INFO['purpose']}.",
|
| 278 |
+
"company philosophy": f"π‘ Our philosophy is: **'{COMPANY_INFO['philosophy']}'**",
|
| 279 |
+
"company stage": f"π We're currently in the **{COMPANY_INFO['stage']}** phase.",
|
| 280 |
+
"venture studio": "π― As a venture studio, we don't just build apps - we build complete businesses with scalable systems and futuristic solutions that drive economic growth.",
|
| 281 |
},
|
| 282 |
"api_capabilities": {
|
| 283 |
+
"what can you do": "π§ I can fetch real-time data like:\nβ’ π° Latest tech news\nβ’ π€οΈ Weather information\nβ’ π Stock market data\nβ’ βΏ Cryptocurrency prices\n\nI also have extensive knowledge about YAH Tech and Adedoyin James!",
|
| 284 |
+
"get news": "π° I can fetch the latest technology news to keep you updated with industry trends.",
|
| 285 |
+
"weather": "π€οΈ I can check weather information for any city worldwide.",
|
| 286 |
+
"stock": "π I can get real-time stock market data for major companies.",
|
| 287 |
+
"crypto": "βΏ I can fetch current cryptocurrency prices and market changes.",
|
| 288 |
}
|
| 289 |
}
|
| 290 |
|
|
|
|
| 299 |
def _load_model(self):
|
| 300 |
"""Load the Hugging Face model"""
|
| 301 |
try:
|
| 302 |
+
with st.spinner("π Loading YAH Tech AI model..."):
|
| 303 |
self.tokenizer = AutoTokenizer.from_pretrained(
|
| 304 |
"Adedoyinjames/YAH-Tech-Chat-Bot",
|
| 305 |
use_auth_token=HUGGINGFACE_TOKEN if HUGGINGFACE_TOKEN else True
|
|
|
|
| 309 |
use_auth_token=HUGGINGFACE_TOKEN if HUGGINGFACE_TOKEN else True,
|
| 310 |
torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
|
| 311 |
)
|
| 312 |
+
st.success("β
YAH Tech AI model loaded successfully!")
|
| 313 |
except Exception as e:
|
| 314 |
st.error(f"β Failed to load custom model: {e}")
|
| 315 |
st.info("π Falling back to standard FLAN-T5-small model...")
|
| 316 |
try:
|
| 317 |
self.tokenizer = AutoTokenizer.from_pretrained(self.model_name)
|
| 318 |
self.model = AutoModelForSeq2SeqLM.from_pretrained(self.model_name)
|
| 319 |
+
st.success("β
Standard AI model loaded successfully!")
|
| 320 |
except Exception as e2:
|
| 321 |
+
st.error(f"β Failed to load AI model: {e2}")
|
| 322 |
|
| 323 |
def _get_knowledge_response(self, user_input):
|
| 324 |
"""Check if the input matches any knowledge base entries"""
|
|
|
|
| 346 |
if any(word in user_input_lower for word in ["news", "headlines", "tech news"]):
|
| 347 |
news_data = await self.api_service.get_tech_news()
|
| 348 |
if "articles" in news_data:
|
| 349 |
+
articles = news_data["articles"][:3]
|
| 350 |
+
response = "π° **Latest Technology News:**\n\n"
|
| 351 |
for i, article in enumerate(articles, 1):
|
| 352 |
+
response += f"**{i}. {article.get('title', 'No title')}**\n"
|
| 353 |
response += f" {article.get('description', 'No description available')}\n\n"
|
| 354 |
return response
|
| 355 |
else:
|
| 356 |
return "β Could not fetch news at the moment. Please try again later."
|
| 357 |
|
| 358 |
elif any(word in user_input_lower for word in ["weather", "temperature"]):
|
|
|
|
| 359 |
city = "Lagos"
|
| 360 |
for word in user_input_lower.split():
|
| 361 |
+
if word not in ["weather", "temperature", "what's", "the", "in", "for"] and len(word) > 2:
|
| 362 |
city = word.capitalize()
|
| 363 |
break
|
| 364 |
|
| 365 |
weather_data = await self.api_service.get_weather(city)
|
| 366 |
if "weather" in weather_data:
|
| 367 |
temp = weather_data["main"]["temp"]
|
| 368 |
+
desc = weather_data["weather"][0]["description"].title()
|
| 369 |
humidity = weather_data["main"]["humidity"]
|
| 370 |
+
feels_like = weather_data["main"].get("feels_like", temp)
|
| 371 |
+
return f"π€οΈ **Weather in {weather_data.get('name', city)}:**\n\nβ’ Temperature: **{temp}Β°C** (Feels like: {feels_like}Β°C)\nβ’ Conditions: **{desc}**\nβ’ Humidity: **{humidity}%**"
|
| 372 |
else:
|
| 373 |
return "β Could not fetch weather data. Please try again later."
|
| 374 |
|
|
|
|
| 379 |
price = quote.get("05. price", "N/A")
|
| 380 |
change = quote.get("09. change", "N/A")
|
| 381 |
change_percent = quote.get("10. change percent", "N/A")
|
| 382 |
+
return f"π **Apple Stock (AAPL):**\n\nβ’ Current Price: **${price}**\nβ’ Change: **{change}** ({change_percent})"
|
| 383 |
else:
|
| 384 |
return "β Could not fetch stock data. Please try again later."
|
| 385 |
|
|
|
|
| 389 |
btc_data = crypto_data["bitcoin"]
|
| 390 |
price = btc_data.get("usd", "N/A")
|
| 391 |
change = btc_data.get("usd_24h_change", "N/A")
|
| 392 |
+
if isinstance(price, (int, float)):
|
| 393 |
+
price_str = f"${price:,.2f}"
|
| 394 |
+
else:
|
| 395 |
+
price_str = str(price)
|
| 396 |
+
|
| 397 |
+
if isinstance(change, (int, float)):
|
| 398 |
+
change_str = f"{change:.2f}%"
|
| 399 |
+
else:
|
| 400 |
+
change_str = str(change)
|
| 401 |
+
|
| 402 |
+
return f"βΏ **Bitcoin Price:**\n\nβ’ Current: **{price_str}**\nβ’ 24h Change: **{change_str}**"
|
| 403 |
else:
|
| 404 |
return "β Could not fetch cryptocurrency data. Please try again later."
|
| 405 |
|
|
|
|
| 421 |
if self.model and self.tokenizer:
|
| 422 |
try:
|
| 423 |
# Prepare input with context
|
| 424 |
+
context = f"You are YAH Bot, an AI assistant for {COMPANY_INFO['name']}. You represent {PERSONAL_INFO['name']}, {PERSONAL_INFO['role']}. Be helpful, professional and focus on technology, entrepreneurship, venture studios, and business development. Our philosophy: {COMPANY_INFO['philosophy']}"
|
| 425 |
full_input = f"{context}\n\nConversation:\n" + "\n".join([f"Human: {msg['content']}\nAI: {msg['content']}"
|
| 426 |
for msg in conversation_history[-3:]]) + f"\nHuman: {user_input}\nAI:"
|
| 427 |
|
|
|
|
| 430 |
with torch.no_grad():
|
| 431 |
outputs = self.model.generate(
|
| 432 |
inputs,
|
| 433 |
+
max_length=200,
|
| 434 |
num_return_sequences=1,
|
| 435 |
temperature=0.7,
|
| 436 |
do_sample=True,
|
|
|
|
| 441 |
return response
|
| 442 |
|
| 443 |
except Exception as e:
|
| 444 |
+
return f"I encountered an error: {str(e)}. However, I can tell you that at YAH Tech, we're focused on building scalable systems that drive economic growth through our venture studio model."
|
| 445 |
|
| 446 |
+
# Fallback responses
|
| 447 |
fallback_responses = [
|
| 448 |
+
f"π That's an interesting question! At {COMPANY_INFO['name']}, we believe in **{COMPANY_INFO['philosophy']}** to create solutions that matter.",
|
| 449 |
+
f"π I'd be happy to discuss that. As a venture studio, we focus on building technology-driven ventures that create both **profit and societal value**.",
|
| 450 |
+
f"π‘ Great question! Our approach at {COMPANY_INFO['name']} is to develop futuristic solutions through careful evaluation and systematic creation.",
|
| 451 |
+
f"π― From my perspective as {PERSONAL_INFO['name']}, I focus on building systems that reshape the economic landscape through innovative technology and scalable business models."
|
| 452 |
]
|
| 453 |
return random.choice(fallback_responses)
|
| 454 |
|
|
|
|
| 460 |
st.session_state.bot = YAHBot()
|
| 461 |
if "conversation_started" not in st.session_state:
|
| 462 |
st.session_state.conversation_started = False
|
|
|
|
|
|
|
| 463 |
|
| 464 |
def display_api_status():
|
| 465 |
"""Display API status in sidebar"""
|
| 466 |
+
st.sidebar.subheader("π API Status")
|
| 467 |
|
| 468 |
+
# Check API status based on environment variables
|
| 469 |
statuses = {
|
| 470 |
+
"π€ AI Model": "β
Connected" if HUGGINGFACE_TOKEN else "β οΈ Using Standard Model",
|
| 471 |
+
"π° News API": "β
Connected" if os.environ.get("NEWS_API_KEY") and os.environ.get("NEWS_API_KEY") != "demo_key" else "π‘ Demo Mode",
|
| 472 |
+
"π€οΈ Weather API": "β
Connected" if os.environ.get("WEATHER_API_KEY") and os.environ.get("WEATHER_API_KEY") != "demo_key" else "π‘ Demo Mode",
|
| 473 |
+
"π Stock API": "β
Connected" if os.environ.get("ALPHA_VANTAGE_KEY") and os.environ.get("ALPHA_VANTAGE_KEY") != "demo_key" else "π‘ Demo Mode",
|
| 474 |
+
"βΏ Crypto API": "β
Connected"
|
| 475 |
}
|
| 476 |
|
| 477 |
for api, status in statuses.items():
|
| 478 |
+
st.sidebar.write(f"{api}: {status}")
|
|
|
|
| 479 |
|
| 480 |
def main():
|
| 481 |
# Page configuration
|
| 482 |
st.set_page_config(
|
| 483 |
+
page_title="YAH Tech Assistant",
|
| 484 |
+
page_icon="π",
|
| 485 |
+
layout="centered",
|
| 486 |
+
initial_sidebar_state="expanded"
|
| 487 |
)
|
| 488 |
|
| 489 |
# Initialize session state
|
| 490 |
initialize_session_state()
|
| 491 |
|
| 492 |
+
# Header with beautiful gradient
|
| 493 |
col1, col2 = st.columns([1, 4])
|
| 494 |
with col1:
|
| 495 |
+
st.image("https://via.placeholder.com/100/2196f3/ffffff?text=YT", width=100)
|
| 496 |
with col2:
|
| 497 |
+
st.markdown('<h1 class="header-gradient">YAH Tech Assistant</h1>', unsafe_allow_html=True)
|
| 498 |
+
st.caption("π Powered by AI β’ πΌ Venture Studio β’ π Economic Innovation")
|
| 499 |
|
| 500 |
st.markdown("---")
|
| 501 |
|
| 502 |
# Sidebar
|
| 503 |
with st.sidebar:
|
| 504 |
+
st.header("π’ About YAH Tech")
|
| 505 |
st.markdown(f"""
|
| 506 |
+
**π€ Founder**: {PERSONAL_INFO['name']}
|
| 507 |
+
**πΌ Role**: {PERSONAL_INFO['role']}
|
| 508 |
|
| 509 |
+
**π’ Company**: {COMPANY_INFO['name']}
|
| 510 |
+
**π― Focus**: {COMPANY_INFO['type']}
|
| 511 |
+
**π Stage**: {COMPANY_INFO['stage']}
|
| 512 |
|
| 513 |
+
**π‘ Philosophy**: *{COMPANY_INFO['philosophy']}*
|
| 514 |
""")
|
| 515 |
|
| 516 |
# API Status
|
| 517 |
display_api_status()
|
| 518 |
|
| 519 |
st.markdown("---")
|
| 520 |
+
st.subheader("π§ Quick Actions")
|
| 521 |
st.markdown("""
|
| 522 |
+
Try asking me:
|
| 523 |
+
- *"What's the latest tech news?"* π°
|
| 524 |
+
- *"Weather in Lagos"* π€οΈ
|
| 525 |
+
- *"Apple stock price"* π
|
| 526 |
+
- *"Bitcoin price"* βΏ
|
| 527 |
+
- *"Tell me about YAH Tech"* π’
|
| 528 |
+
- *"What are your goals?"* π―
|
| 529 |
""")
|
| 530 |
|
| 531 |
+
if st.button("ποΈ Clear Chat History", use_container_width=True):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 532 |
st.session_state.messages = []
|
| 533 |
st.session_state.conversation_started = False
|
| 534 |
st.rerun()
|
| 535 |
|
| 536 |
# Chat interface
|
| 537 |
if not st.session_state.conversation_started:
|
| 538 |
+
welcome_msg = f"""
|
| 539 |
+
π **Hello! I'm YAH Bot, your AI assistant for everything related to {PERSONAL_INFO['name']} and {COMPANY_INFO['name']}!**
|
| 540 |
+
|
| 541 |
+
I can help you with:
|
| 542 |
+
β’ π Company information and venture studio details
|
| 543 |
+
β’ π― Adedoyin's vision and goals
|
| 544 |
+
β’ π Real-time data (news, weather, stocks, crypto)
|
| 545 |
+
β’ π‘ Business and technology insights
|
| 546 |
+
|
| 547 |
+
**How can I assist you today?** π
|
| 548 |
+
"""
|
| 549 |
+
st.info(welcome_msg)
|
| 550 |
st.session_state.conversation_started = True
|
| 551 |
|
| 552 |
# Display chat messages
|
|
|
|
| 555 |
st.markdown(message["content"])
|
| 556 |
|
| 557 |
# Chat input
|
| 558 |
+
if prompt := st.chat_input("π¬ Ask me about YAH Tech, get real-time data, or anything else..."):
|
| 559 |
# Add user message to chat history
|
| 560 |
st.session_state.messages.append({"role": "user", "content": prompt})
|
| 561 |
with st.chat_message("user"):
|
|
|
|
| 563 |
|
| 564 |
# Generate and display assistant response
|
| 565 |
with st.chat_message("assistant"):
|
| 566 |
+
with st.spinner("π€ Processing your request..."):
|
| 567 |
# Use asyncio to handle async API calls
|
| 568 |
+
try:
|
| 569 |
+
response = asyncio.run(st.session_state.bot.generate_response(prompt, st.session_state.messages))
|
| 570 |
+
st.markdown(response)
|
| 571 |
+
except Exception as e:
|
| 572 |
+
error_msg = f"β οΈ I encountered an issue: {str(e)}\n\nBut at YAH Tech, we always find solutions! Feel free to ask me something else about our venture studio or business philosophy."
|
| 573 |
+
st.markdown(error_msg)
|
| 574 |
+
response = error_msg
|
| 575 |
|
| 576 |
st.session_state.messages.append({"role": "assistant", "content": response})
|
| 577 |
|