Adedoyinjames commited on
Commit
f5215d5
Β·
verified Β·
1 Parent(s): 0b52af4

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +530 -0
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()