Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,530 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import torch
|
| 3 |
+
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
|
| 4 |
+
from huggingface_hub import login
|
| 5 |
+
import random
|
| 6 |
+
import time
|
| 7 |
+
import requests
|
| 8 |
+
import json
|
| 9 |
+
import asyncio
|
| 10 |
+
import aiohttp
|
| 11 |
+
from typing import Optional, List, Dict
|
| 12 |
+
import nest_asyncio
|
| 13 |
+
|
| 14 |
+
# Apply nest_asyncio for async operations in Streamlit
|
| 15 |
+
nest_asyncio.apply()
|
| 16 |
+
|
| 17 |
+
# Hugging Face token setup
|
| 18 |
+
HUGGINGFACE_TOKEN = st.secrets.get("HUGGINGFACE_TOKEN", "")
|
| 19 |
+
|
| 20 |
+
if HUGGINGFACE_TOKEN:
|
| 21 |
+
try:
|
| 22 |
+
login(token=HUGGINGFACE_TOKEN)
|
| 23 |
+
st.success("β
Successfully connected to Hugging Face")
|
| 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-color: #f8f9fa;
|
| 32 |
+
}
|
| 33 |
+
.stChatMessage {
|
| 34 |
+
padding: 16px;
|
| 35 |
+
border-radius: 12px;
|
| 36 |
+
margin: 8px 0;
|
| 37 |
+
}
|
| 38 |
+
.stChatMessage[data-testid="stChatMessage"] {
|
| 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-color: #e3f2fd;
|
| 44 |
+
border-left: 4px solid #2196f3;
|
| 45 |
+
}
|
| 46 |
+
/* Assistant message styling */
|
| 47 |
+
.stChatMessage:has(div[data-testid="stChatMessageContent"] > div:first-child > div:last-child) {
|
| 48 |
+
background-color: #ffffff;
|
| 49 |
+
border-left: 4px solid #78909c;
|
| 50 |
+
}
|
| 51 |
+
.stTextInput > div > div > input {
|
| 52 |
+
border: 2px solid #90caf9;
|
| 53 |
+
border-radius: 20px;
|
| 54 |
+
padding: 12px 16px;
|
| 55 |
+
}
|
| 56 |
+
.stButton > button {
|
| 57 |
+
background-color: #2196f3;
|
| 58 |
+
color: white;
|
| 59 |
+
border: none;
|
| 60 |
+
border-radius: 20px;
|
| 61 |
+
padding: 10px 24px;
|
| 62 |
+
font-weight: 500;
|
| 63 |
+
}
|
| 64 |
+
.stButton > button:hover {
|
| 65 |
+
background-color: #1976d2;
|
| 66 |
+
color: white;
|
| 67 |
+
}
|
| 68 |
+
.sidebar .sidebar-content {
|
| 69 |
+
background-color: #eceff1;
|
| 70 |
+
}
|
| 71 |
+
.api-status {
|
| 72 |
+
padding: 8px;
|
| 73 |
+
border-radius: 6px;
|
| 74 |
+
margin: 5px 0;
|
| 75 |
+
font-size: 0.8em;
|
| 76 |
+
}
|
| 77 |
+
.api-success {
|
| 78 |
+
background-color: #e8f5e8;
|
| 79 |
+
border-left: 4px solid #4caf50;
|
| 80 |
+
}
|
| 81 |
+
.api-error {
|
| 82 |
+
background-color: #ffebee;
|
| 83 |
+
border-left: 4px solid #f44336;
|
| 84 |
+
}
|
| 85 |
+
</style>
|
| 86 |
+
""", unsafe_allow_html=True)
|
| 87 |
+
|
| 88 |
+
# Personal and Company Information
|
| 89 |
+
PERSONAL_INFO = {
|
| 90 |
+
"name": "Adedoyin Ifeoluwa James",
|
| 91 |
+
"role": "Entrepreneur, Founder & CEO of YAH Tech",
|
| 92 |
+
"goals": [
|
| 93 |
+
"Build profitable systems that matter",
|
| 94 |
+
"Reshaping the economical world",
|
| 95 |
+
"Use software development to create flexibility and contribute to economic growth"
|
| 96 |
+
]
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
COMPANY_INFO = {
|
| 100 |
+
"name": "YAH Tech",
|
| 101 |
+
"type": "Venture studio / app development company focused on solving problems with futuristic solutions",
|
| 102 |
+
"purpose": "Build and launch technology-driven ventures that generate profit and societal value",
|
| 103 |
+
"primary_activity": "App development and creation of scalable business systems",
|
| 104 |
+
"philosophy": "Learn, understand, create, and evaluate",
|
| 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",
|
| 112 |
+
"params": {
|
| 113 |
+
"country": "us",
|
| 114 |
+
"category": "technology",
|
| 115 |
+
"pageSize": 5,
|
| 116 |
+
"apiKey": st.secrets.get("NEWS_API_KEY", "demo_key")
|
| 117 |
+
}
|
| 118 |
+
},
|
| 119 |
+
"weather_api": {
|
| 120 |
+
"url": "https://api.openweathermap.org/data/2.5/weather",
|
| 121 |
+
"params": {
|
| 122 |
+
"q": "Lagos,NG",
|
| 123 |
+
"appid": st.secrets.get("WEATHER_API_KEY", "demo_key"),
|
| 124 |
+
"units": "metric"
|
| 125 |
+
}
|
| 126 |
+
},
|
| 127 |
+
"financial_api": {
|
| 128 |
+
"url": "https://www.alphavantage.co/query",
|
| 129 |
+
"params": {
|
| 130 |
+
"function": "GLOBAL_QUOTE",
|
| 131 |
+
"symbol": "AAPL",
|
| 132 |
+
"apikey": st.secrets.get("ALPHA_VANTAGE_KEY", "demo_key")
|
| 133 |
+
}
|
| 134 |
+
},
|
| 135 |
+
"yah_tech_internal": {
|
| 136 |
+
"url": "http://localhost:8000" # For internal FastAPI server
|
| 137 |
+
}
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
class APIClient:
|
| 141 |
+
def __init__(self):
|
| 142 |
+
self.session = None
|
| 143 |
+
|
| 144 |
+
async def __aenter__(self):
|
| 145 |
+
self.session = aiohttp.ClientSession()
|
| 146 |
+
return self
|
| 147 |
+
|
| 148 |
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
| 149 |
+
await self.session.close()
|
| 150 |
+
|
| 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:
|
| 158 |
+
return {"error": f"API returned status code {response.status}"}
|
| 159 |
+
except Exception as e:
|
| 160 |
+
return {"error": str(e)}
|
| 161 |
+
|
| 162 |
+
def make_sync_request(self, url: str, params: dict = None, headers: dict = None):
|
| 163 |
+
"""Make synchronous API request"""
|
| 164 |
+
try:
|
| 165 |
+
response = requests.get(url, params=params, headers=headers, timeout=10)
|
| 166 |
+
if response.status_code == 200:
|
| 167 |
+
return response.json()
|
| 168 |
+
else:
|
| 169 |
+
return {"error": f"API returned status code {response.status_code}"}
|
| 170 |
+
except Exception as e:
|
| 171 |
+
return {"error": str(e)}
|
| 172 |
+
|
| 173 |
+
class ExternalAPIService:
|
| 174 |
+
def __init__(self):
|
| 175 |
+
self.api_client = APIClient()
|
| 176 |
+
|
| 177 |
+
async def get_tech_news(self):
|
| 178 |
+
"""Get latest technology news"""
|
| 179 |
+
config = API_CONFIG["news_api"]
|
| 180 |
+
# For demo purposes, return mock data if no API key
|
| 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 |
+
|
| 190 |
+
result = await self.api_client.make_async_request(config["url"], config["params"])
|
| 191 |
+
return result
|
| 192 |
+
|
| 193 |
+
async def get_weather(self, city: str = "Lagos"):
|
| 194 |
+
"""Get weather information"""
|
| 195 |
+
config = API_CONFIG["weather_api"]
|
| 196 |
+
config["params"]["q"] = city
|
| 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"])
|
| 206 |
+
return result
|
| 207 |
+
|
| 208 |
+
async def get_stock_info(self, symbol: str = "AAPL"):
|
| 209 |
+
"""Get stock market information"""
|
| 210 |
+
config = API_CONFIG["financial_api"]
|
| 211 |
+
config["params"]["symbol"] = symbol
|
| 212 |
+
|
| 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%"
|
| 219 |
+
}
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
result = await self.api_client.make_async_request(config["url"], config["params"])
|
| 223 |
+
return result
|
| 224 |
+
|
| 225 |
+
def get_crypto_data(self, coin: str = "bitcoin"):
|
| 226 |
+
"""Get cryptocurrency data (synchronous for simplicity)"""
|
| 227 |
+
url = f"https://api.coingecko.com/api/v3/simple/price"
|
| 228 |
+
params = {
|
| 229 |
+
"ids": coin,
|
| 230 |
+
"vs_currencies": "usd",
|
| 231 |
+
"include_24hr_change": "true"
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
result = self.api_client.make_sync_request(url, params)
|
| 235 |
+
return result
|
| 236 |
+
|
| 237 |
+
# Knowledge base for the AI (updated with API capabilities)
|
| 238 |
+
KNOWLEDGE_BASE = {
|
| 239 |
+
"personal": {
|
| 240 |
+
"who are you": f"I'm {PERSONAL_INFO['name']}, {PERSONAL_INFO['role']}.",
|
| 241 |
+
"what are your goals": f"My goals include: {', '.join(PERSONAL_INFO['goals'])}.",
|
| 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']}, {PERSONAL_INFO['role']}. My mission is to {PERSONAL_INFO['goals'][0].lower()} and {PERSONAL_INFO['goals'][1].lower()}.",
|
| 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()}. {COMPANY_INFO['purpose']}.",
|
| 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, weather, stock prices, and cryptocurrency data. I also have knowledge about YAH Tech and Adedoyin James.",
|
| 254 |
+
"get news": "I can fetch the latest technology news for you.",
|
| 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 |
+
|
| 261 |
+
class YAHBot:
|
| 262 |
+
def __init__(self):
|
| 263 |
+
self.model_name = "google/flan-t5-small"
|
| 264 |
+
self.tokenizer = None
|
| 265 |
+
self.model = None
|
| 266 |
+
self.api_service = ExternalAPIService()
|
| 267 |
+
self._load_model()
|
| 268 |
+
|
| 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
|
| 276 |
+
)
|
| 277 |
+
self.model = AutoModelForSeq2SeqLM.from_pretrained(
|
| 278 |
+
"Adedoyinjames/YAH-Tech-Chat-Bot",
|
| 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 standard model: {e2}")
|
| 292 |
+
|
| 293 |
+
def _get_knowledge_response(self, user_input):
|
| 294 |
+
"""Check if the input matches any knowledge base entries"""
|
| 295 |
+
user_input_lower = user_input.lower()
|
| 296 |
+
|
| 297 |
+
# Check all knowledge bases
|
| 298 |
+
for category in KNOWLEDGE_BASE.values():
|
| 299 |
+
for key, response in category.items():
|
| 300 |
+
if key in user_input_lower:
|
| 301 |
+
return response
|
| 302 |
+
|
| 303 |
+
# Specific patterns
|
| 304 |
+
if any(word in user_input_lower for word in ["adedoyin", "ifeoluwa", "james"]):
|
| 305 |
+
return KNOWLEDGE_BASE["personal"]["who are you"]
|
| 306 |
+
|
| 307 |
+
if any(word in user_input_lower for word in ["yah tech", "your company"]):
|
| 308 |
+
return KNOWLEDGE_BASE["company"]["what is yah tech"]
|
| 309 |
+
|
| 310 |
+
return None
|
| 311 |
+
|
| 312 |
+
async def _handle_api_requests(self, user_input):
|
| 313 |
+
"""Handle API-based queries"""
|
| 314 |
+
user_input_lower = user_input.lower()
|
| 315 |
+
|
| 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] # Show top 3
|
| 320 |
+
response = "π° **Latest Tech News:**\n\n"
|
| 321 |
+
for i, article in enumerate(articles, 1):
|
| 322 |
+
response += f"{i}. **{article.get('title', 'No title')}**\n"
|
| 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 |
+
return f"π€οΈ **Weather in {weather_data.get('name', city)}:**\n\nTemperature: {temp}Β°C\nConditions: {desc}\nHumidity: {humidity}%"
|
| 342 |
+
else:
|
| 343 |
+
return "β Could not fetch weather data. Please try again later."
|
| 344 |
+
|
| 345 |
+
elif any(word in user_input_lower for word in ["stock", "price", "apple", "aapl"]):
|
| 346 |
+
stock_data = await self.api_service.get_stock_info()
|
| 347 |
+
if "Global Quote" in stock_data:
|
| 348 |
+
quote = stock_data["Global Quote"]
|
| 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\nPrice: ${price}\nChange: {change} ({change_percent})"
|
| 353 |
+
else:
|
| 354 |
+
return "β Could not fetch stock data. Please try again later."
|
| 355 |
+
|
| 356 |
+
elif any(word in user_input_lower for word in ["crypto", "bitcoin", "ethereum"]):
|
| 357 |
+
crypto_data = self.api_service.get_crypto_data()
|
| 358 |
+
if "bitcoin" in crypto_data:
|
| 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 |
+
return f"βΏ **Bitcoin Price:**\n\nCurrent: ${price:,.2f}\n24h Change: {change:.2f}%"
|
| 363 |
+
else:
|
| 364 |
+
return "β Could not fetch cryptocurrency data. Please try again later."
|
| 365 |
+
|
| 366 |
+
return None
|
| 367 |
+
|
| 368 |
+
async def generate_response(self, user_input, conversation_history):
|
| 369 |
+
"""Generate response using knowledge base, API calls, or AI model"""
|
| 370 |
+
# First check knowledge base
|
| 371 |
+
knowledge_response = self._get_knowledge_response(user_input)
|
| 372 |
+
if knowledge_response:
|
| 373 |
+
return knowledge_response
|
| 374 |
+
|
| 375 |
+
# Check for API-based queries
|
| 376 |
+
api_response = await self._handle_api_requests(user_input)
|
| 377 |
+
if api_response:
|
| 378 |
+
return api_response
|
| 379 |
+
|
| 380 |
+
# Use AI model for other queries
|
| 381 |
+
if self.model and self.tokenizer:
|
| 382 |
+
try:
|
| 383 |
+
# Prepare input with context
|
| 384 |
+
context = "You are YAH Bot, an AI assistant for YAH Tech. Be helpful, professional and focus on technology, entrepreneurship, and business development."
|
| 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 |
+
|
| 388 |
+
inputs = self.tokenizer.encode(full_input, return_tensors="pt", max_length=512, truncation=True)
|
| 389 |
+
|
| 390 |
+
with torch.no_grad():
|
| 391 |
+
outputs = self.model.generate(
|
| 392 |
+
inputs,
|
| 393 |
+
max_length=150,
|
| 394 |
+
num_return_sequences=1,
|
| 395 |
+
temperature=0.7,
|
| 396 |
+
do_sample=True,
|
| 397 |
+
pad_token_id=self.tokenizer.eos_token_id
|
| 398 |
+
)
|
| 399 |
+
|
| 400 |
+
response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
|
| 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 |
+
# Fallback responses
|
| 407 |
+
fallback_responses = [
|
| 408 |
+
"That's an interesting question! At YAH Tech, we believe in learning, understanding, and creating solutions that matter.",
|
| 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 YAH Tech is to develop futuristic solutions through careful evaluation and systematic creation.",
|
| 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 |
+
|
| 415 |
+
def initialize_session_state():
|
| 416 |
+
"""Initialize session state variables"""
|
| 417 |
+
if "messages" not in st.session_state:
|
| 418 |
+
st.session_state.messages = []
|
| 419 |
+
if "bot" not in st.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 |
+
# Mock API status for demo
|
| 431 |
+
statuses = {
|
| 432 |
+
"News API": "β
Connected" if API_CONFIG["news_api"]["params"]["apiKey"] != "demo_key" else "β οΈ Demo Mode",
|
| 433 |
+
"Weather API": "β
Connected" if API_CONFIG["weather_api"]["params"]["appid"] != "demo_key" else "β οΈ Demo Mode",
|
| 434 |
+
"Financial API": "β
Connected" if API_CONFIG["financial_api"]["params"]["apikey"] != "demo_key" else "β οΈ Demo Mode",
|
| 435 |
+
"Crypto API": "β
Connected",
|
| 436 |
+
"Internal API": "π Not Connected" # FastAPI server would be separate
|
| 437 |
+
}
|
| 438 |
+
|
| 439 |
+
for api, status in statuses.items():
|
| 440 |
+
color = "π’" if "β
" in status else "π‘" if "β οΈ" in status else "π΄"
|
| 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 Chatbot",
|
| 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/80/2196f3/ffffff?text=YT", width=80)
|
| 458 |
+
with col2:
|
| 459 |
+
st.title("YAH Tech Assistant")
|
| 460 |
+
st.caption("Powered by AI β’ Built for Innovation β’ API-Enabled")
|
| 461 |
+
|
| 462 |
+
st.markdown("---")
|
| 463 |
+
|
| 464 |
+
# Sidebar
|
| 465 |
+
with st.sidebar:
|
| 466 |
+
st.header("About YAH Tech")
|
| 467 |
+
st.markdown(f"""
|
| 468 |
+
**Founder**: {PERSONAL_INFO['name']}
|
| 469 |
+
**Role**: {PERSONAL_INFO['role']}
|
| 470 |
+
|
| 471 |
+
**Company**: {COMPANY_INFO['name']}
|
| 472 |
+
**Focus**: {COMPANY_INFO['type']}
|
| 473 |
+
**Stage**: {COMPANY_INFO['stage']}
|
| 474 |
+
|
| 475 |
+
**Philosophy**: *{COMPANY_INFO['philosophy']}*
|
| 476 |
+
""")
|
| 477 |
+
|
| 478 |
+
# API Status
|
| 479 |
+
display_api_status()
|
| 480 |
+
|
| 481 |
+
st.markdown("---")
|
| 482 |
+
st.subheader("API Capabilities")
|
| 483 |
+
st.markdown("""
|
| 484 |
+
Ask me to:
|
| 485 |
+
- **Get tech news** π°
|
| 486 |
+
- **Check weather** π€οΈ
|
| 487 |
+
- **Stock prices** π
|
| 488 |
+
- **Crypto data** βΏ
|
| 489 |
+
- **YAH Tech info** π’
|
| 490 |
+
- **Business advice** πΌ
|
| 491 |
+
""")
|
| 492 |
+
|
| 493 |
+
st.markdown("---")
|
| 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 |
+
st.info(f"π Hello! I'm YAH Bot, your AI assistant for everything related to {PERSONAL_INFO['name']} and {COMPANY_INFO['name']}. I can also fetch real-time data through APIs! How can I help you today?")
|
| 506 |
+
st.session_state.conversation_started = True
|
| 507 |
+
|
| 508 |
+
# Display chat messages
|
| 509 |
+
for message in st.session_state.messages:
|
| 510 |
+
with st.chat_message(message["role"]):
|
| 511 |
+
st.markdown(message["content"])
|
| 512 |
+
|
| 513 |
+
# Chat input
|
| 514 |
+
if prompt := st.chat_input("Ask me about YAH Tech, get news, check weather, or anything else..."):
|
| 515 |
+
# Add user message to chat history
|
| 516 |
+
st.session_state.messages.append({"role": "user", "content": prompt})
|
| 517 |
+
with st.chat_message("user"):
|
| 518 |
+
st.markdown(prompt)
|
| 519 |
+
|
| 520 |
+
# Generate and display assistant response
|
| 521 |
+
with st.chat_message("assistant"):
|
| 522 |
+
with st.spinner("π€ Thinking..."):
|
| 523 |
+
# Use asyncio to handle async API calls
|
| 524 |
+
response = asyncio.run(st.session_state.bot.generate_response(prompt, st.session_state.messages))
|
| 525 |
+
st.markdown(response)
|
| 526 |
+
|
| 527 |
+
st.session_state.messages.append({"role": "assistant", "content": response})
|
| 528 |
+
|
| 529 |
+
if __name__ == "__main__":
|
| 530 |
+
main()
|