RaghavenderReddy commited on
Commit
ebf1310
·
verified ·
1 Parent(s): e4a5bfc

Upload 8 files

Browse files
Files changed (8) hide show
  1. .env +1 -0
  2. README.md +9 -14
  3. ai_engine.py +144 -0
  4. app.py +392 -0
  5. content_db.py +210 -0
  6. main.py +125 -0
  7. requirements.txt +0 -0
  8. requirements.txtuvicorn +0 -0
.env ADDED
@@ -0,0 +1 @@
 
 
1
+ OPENAI_API_KEY=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
README.md CHANGED
@@ -1,20 +1,15 @@
1
  ---
2
- title: Culture Bot
3
- emoji: 🚀
4
- colorFrom: red
5
- colorTo: red
6
- sdk: docker
7
- app_port: 8501
8
- tags:
9
- - streamlit
10
  pinned: false
11
- short_description: CultureBot is AI app that teaches world cultures and travels
12
  license: mit
13
  ---
14
 
15
- # Welcome to Streamlit!
16
 
17
- Edit `/src/streamlit_app.py` to customize this app to your heart's desire. :heart:
18
-
19
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
20
- forums](https://discuss.streamlit.io).
 
1
  ---
2
+ title: CultureBot
3
+ emoji: 🌍
4
+ colorFrom: blue
5
+ colorTo: green
6
+ sdk: streamlit
7
+ sdk_version: 1.32.0
8
+ app_file: app.py
 
9
  pinned: false
 
10
  license: mit
11
  ---
12
 
13
+ # CultureBot
14
 
15
+ CultureBot is an AI-powered Streamlit app that helps users learn about world cultures by chatting with an assistant. Ask anything about traditions, festivals, or cultural facts!
 
 
 
ai_engine.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import openai
2
+ import os
3
+ import json
4
+ import random
5
+ from typing import Dict, List, Any
6
+ from dotenv import load_dotenv
7
+ from .content_db import CulturalDatabase
8
+
9
+ # Load environment variables
10
+ load_dotenv()
11
+
12
+ class CultureAI:
13
+ def __init__(self):
14
+ # Initialize OpenAI client with the API key
15
+ openai.api_key = os.getenv("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") # Use the environment variable for the API key
16
+ self.cultural_db = CulturalDatabase()
17
+ self.system_prompt = """
18
+ You are CultureBot, an expert AI assistant specializing in cultural knowledge from around the world.
19
+ You provide accurate, respectful, and insightful information about:
20
+ - Cultural customs and traditions
21
+ - Social etiquette and norms
22
+ - Business practices across cultures
23
+ - Food customs and dining etiquette
24
+ - Religious and spiritual practices
25
+ - Language and communication styles
26
+ - Family structures and relationships
27
+ - Festivals and celebrations
28
+
29
+ Guidelines:
30
+ 1. Always be respectful and avoid stereotypes
31
+ 2. Acknowledge cultural diversity within countries
32
+ 3. Provide context and explain the reasoning behind customs
33
+ 4. Mention when practices may vary by region or generation
34
+ 5. Be educational and engaging
35
+ 6. If unsure, acknowledge limitations and suggest further research
36
+
37
+ Keep responses informative but conversational, and always maintain cultural sensitivity.
38
+ """
39
+
40
+ async def generate_response(self, user_message: str) -> Dict[str, Any]:
41
+ """
42
+ Generate AI response using OpenAI with cultural context
43
+ """
44
+ try:
45
+ # Get relevant cultural facts from database
46
+ relevant_facts = self.cultural_db.search_facts(user_message)
47
+
48
+ # Build context from relevant facts
49
+ context = ""
50
+ if relevant_facts:
51
+ context = "\n\nRelevant cultural information:\n"
52
+ for fact in relevant_facts[:3]: # Limit to top 3 facts
53
+ context += f"- {fact['country']}: {fact['fact']} (Category: {fact['category']})\n"
54
+
55
+ # Create the full prompt
56
+ full_prompt = f"{self.system_prompt}\n\nUser question: {user_message}{context}"
57
+
58
+ # Call OpenAI API
59
+ response = openai.ChatCompletion.create( # Corrected method call
60
+ model="gpt-3.5-turbo",
61
+ messages=[
62
+ {"role": "system", "content": self.system_prompt},
63
+ {"role": "user", "content": f"{user_message}{context}"}
64
+ ],
65
+ max_tokens=500,
66
+ temperature=0.7
67
+ )
68
+
69
+ ai_response = response.choices[0].message['content'] # Corrected access to response content
70
+
71
+ # Determine category and confidence
72
+ category = self._determine_category(user_message)
73
+ confidence = self._calculate_confidence(user_message, relevant_facts)
74
+ sources = [fact['source'] for fact in relevant_facts if 'source' in fact]
75
+
76
+ return {
77
+ "response": ai_response,
78
+ "confidence": confidence,
79
+ "sources": sources,
80
+ "category": category
81
+ }
82
+
83
+ except Exception as e:
84
+ # Fallback to database-based response
85
+ return self._fallback_response(user_message)
86
+
87
+ def _fallback_response(self, user_message: str) -> Dict[str, Any]:
88
+ """
89
+ Fallback response when OpenAI is unavailable
90
+ """
91
+ relevant_facts = self.cultural_db.search_facts(user_message)
92
+
93
+ if relevant_facts:
94
+ fact = random.choice(relevant_facts)
95
+ response = f"Here's an interesting cultural insight about {fact['country']}: {fact['fact']}"
96
+ else:
97
+ response = "I'd be happy to help you learn about different cultures! Try asking about specific countries, customs, or cultural practices."
98
+
99
+ return {
100
+ "response": response,
101
+ "confidence": 0.7,
102
+ "sources": ["Cultural Database"],
103
+ "category": "general"
104
+ }
105
+
106
+ def _determine_category(self, message: str) -> str:
107
+ """
108
+ Determine the category of the user's question
109
+ """
110
+ message_lower = message.lower()
111
+
112
+ categories = {
113
+ "greeting": ["greeting", "hello", "hi", "meet", "introduction"],
114
+ "business": ["business", "work", "office", "meeting", "professional"],
115
+ "food": ["food", "eat", "dining", "meal", "restaurant", "cuisine"],
116
+ "etiquette": ["etiquette", "manners", "polite", "rude", "behavior"],
117
+ "family": ["family", "parent", "child", "marriage", "wedding"],
118
+ "religion": ["religion", "religious", "spiritual", "worship", "prayer"],
119
+ "language": ["language", "speak", "communication", "translate"],
120
+ "festival": ["festival", "celebration", "holiday", "ceremony"]
121
+ }
122
+
123
+ for category, keywords in categories.items():
124
+ if any(keyword in message_lower for keyword in keywords):
125
+ return category
126
+
127
+ return "general"
128
+
129
+ def _calculate_confidence(self, message: str, relevant_facts: List[Dict]) -> float:
130
+ """
131
+ Calculate confidence score based on available information
132
+ """
133
+ base_confidence = 0.8 # Base confidence for OpenAI responses
134
+
135
+ # Adjust based on relevant facts
136
+ if relevant_facts:
137
+ base_confidence += min(len(relevant_facts) * 0.05, 0.15)
138
+
139
+ # Adjust based on message specificity
140
+ if len(message.split()) > 5:
141
+ base_confidence += 0.05
142
+
143
+ return min(base_confidence, 0.95) # Corrected return statement
144
+
app.py ADDED
@@ -0,0 +1,392 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import requests
3
+ import json
4
+ from datetime import datetime
5
+ import os
6
+ from dotenv import load_dotenv
7
+
8
+ # Load environment variables
9
+ load_dotenv()
10
+
11
+ # Configuration
12
+ BACKEND_URL = os.getenv("BACKEND_URL", "http://localhost:8000")
13
+
14
+ # Page configuration
15
+ st.set_page_config(
16
+ page_title="CultureBot - Your AI Cultural Guide",
17
+ page_icon="🌍",
18
+ layout="wide",
19
+ initial_sidebar_state="expanded"
20
+ )
21
+
22
+ # Custom CSS for beautiful styling
23
+ st.markdown("""
24
+ <style>
25
+ .main-header {
26
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
27
+ padding: 2rem;
28
+ border-radius: 10px;
29
+ color: white;
30
+ text-align: center;
31
+ margin-bottom: 2rem;
32
+ }
33
+
34
+ .sidebar-info {
35
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
36
+ padding: 1.5rem;
37
+ border-radius: 10px;
38
+ color: white;
39
+ margin-bottom: 1rem;
40
+ }
41
+
42
+ .chat-message {
43
+ padding: 1rem;
44
+ border-radius: 10px;
45
+ margin: 0.5rem 0;
46
+ }
47
+
48
+ .user-message {
49
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
50
+ color: white;
51
+ margin-left: 2rem;
52
+ }
53
+
54
+ .bot-message {
55
+ background: #f8f9fa;
56
+ color:#333;
57
+ border-left: 4px solid #667eea;
58
+ margin-right: 2rem;
59
+ }
60
+
61
+ .fact-card {
62
+ background: linear-gradient(135deg, #ffd3a5 0%, #fd6585 100%);
63
+ color:black;
64
+ padding: 1.5rem;
65
+ border-radius: 10px;
66
+ margin: 1rem 0;
67
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
68
+ }
69
+
70
+ .metric-card {
71
+ background: white;
72
+ color:black;
73
+ padding: 1rem;
74
+ border-radius: 8px;
75
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
76
+ text-align: center;
77
+ }
78
+ </style>
79
+ """, unsafe_allow_html=True)
80
+
81
+ # Sidebar with app information
82
+ with st.sidebar:
83
+ st.markdown("""
84
+ <div class="sidebar-info">
85
+ <h1 style="font-size: 2.5rem; font-weight: bold; margin-bottom: 1rem;">CultureBot</h1>
86
+ <div style="font-size: 0.9rem; opacity: 0.9;">
87
+ <p><strong>Team:</strong> CultureCoders</p>
88
+ <p><strong>Version:</strong> 1.0</p>
89
+ <p><strong>Created:</strong> June 2025</p>
90
+ </div>
91
+ </div>
92
+ """, unsafe_allow_html=True)
93
+
94
+ st.markdown("---")
95
+
96
+ # Navigation
97
+ st.markdown("### 🧭 Navigation")
98
+ page = st.selectbox(
99
+ "Choose a page:",
100
+ ["🏠 Home", "💬 Chat with CultureBot", "📚 Cultural Facts", "ℹ️ About"],
101
+ key="navigation"
102
+ )
103
+
104
+ st.markdown("---")
105
+
106
+ # Quick stats
107
+ st.markdown("### 📊 Quick Stats")
108
+ try:
109
+ response = requests.get(f"{BACKEND_URL}/health", timeout=5)
110
+ if response.status_code == 200:
111
+ st.success("🟢 Backend Online")
112
+ else:
113
+ st.error("🔴 Backend Offline")
114
+ except:
115
+ st.error("🔴 Backend Offline")
116
+
117
+ # Random fact
118
+ st.markdown("### 🎲 Random Fact")
119
+ if st.button("Get Random Fact"):
120
+ try:
121
+ response = requests.get(f"{BACKEND_URL}/facts/random", timeout=10)
122
+ if response.status_code == 200:
123
+ fact = response.json()
124
+ st.markdown(f"""
125
+ <div class="fact-card">
126
+ <h4>{fact['country']}</h4>
127
+ <p>{fact['fact']}</p>
128
+ <small>Category: {fact['category']}</small>
129
+ </div>
130
+ """, unsafe_allow_html=True)
131
+ except Exception as e:
132
+ st.error("Unable to fetch random fact")
133
+
134
+ # Main content area
135
+ if page == "🏠 Home":
136
+ # Home page
137
+ st.markdown("""
138
+ <div class="main-header">
139
+ <h1 style="font-size: 3rem; margin-bottom: 1rem;">Welcome to CultureBot</h1>
140
+ <p style="font-size: 1.2rem; opacity: 0.9;">Your AI-powered guide to understanding cultures, traditions, and social customs from around the world</p>
141
+ </div>
142
+ """, unsafe_allow_html=True)
143
+
144
+ # Feature cards
145
+ col1, col2, col3 = st.columns(3)
146
+
147
+ with col1:
148
+ st.markdown("""
149
+ <div class="metric-card">
150
+ <h3>🌍 Global Insights</h3>
151
+ <p>Discover fascinating cultural facts and customs from countries across all continents.</p>
152
+ </div>
153
+ """, unsafe_allow_html=True)
154
+
155
+ with col2:
156
+ st.markdown("""
157
+ <div class="metric-card">
158
+ <h3>🤖 AI-Powered Chat</h3>
159
+ <p>Ask questions and get personalized responses about specific countries and cultural practices.</p>
160
+ </div>
161
+ """, unsafe_allow_html=True)
162
+
163
+ with col3:
164
+ st.markdown("""
165
+ <div class="metric-card">
166
+ <h3>📚 Learn & Explore</h3>
167
+ <p>Expand your cultural awareness and become a more informed global citizen.</p>
168
+ </div>
169
+ """, unsafe_allow_html=True)
170
+
171
+ st.markdown("---")
172
+
173
+ # Getting started
174
+ st.markdown("## 🚀 Getting Started")
175
+ st.markdown("""
176
+ 1. **Chat with CultureBot**: Ask questions about any culture or country
177
+ 2. **Explore Facts**: Browse our curated collection of cultural insights
178
+ 3. **Learn Continuously**: Discover new perspectives and traditions
179
+ """)
180
+
181
+ if st.button("Start Chatting Now", type="primary"):
182
+ st.session_state.navigation = "💬 Chat with CultureBot"
183
+ st.rerun()
184
+
185
+ elif page == "💬 Chat with CultureBot":
186
+ # Chat page
187
+ st.markdown("""
188
+ <div class="main-header">
189
+ <h1>Chat with CultureBot</h1>
190
+ <p>Ask me about any culture, country, or tradition!</p>
191
+ </div>
192
+ """, unsafe_allow_html=True)
193
+
194
+ # Initialize chat history
195
+ if "messages" not in st.session_state:
196
+ st.session_state.messages = []
197
+
198
+ # Display chat messages
199
+ for message in st.session_state.messages:
200
+ if message["role"] == "user":
201
+ st.markdown(f"""
202
+ <div class="chat-message user-message">
203
+ <strong>You:</strong> {message["content"]}
204
+ </div>
205
+ """, unsafe_allow_html=True)
206
+ else:
207
+ st.markdown(f"""
208
+ <div class="chat-message bot-message">
209
+ <strong>CultureBot:</strong> {message["content"]}
210
+ </div>
211
+ """, unsafe_allow_html=True)
212
+
213
+ # Chat input
214
+ user_input = st.chat_input("Ask about any culture or country...")
215
+
216
+ if user_input:
217
+ # Add user message to chat history
218
+ st.session_state.messages.append({"role": "user", "content": user_input})
219
+
220
+ # Get bot response
221
+ with st.spinner("CultureBot is thinking..."):
222
+ try:
223
+ response = requests.post(
224
+ f"{BACKEND_URL}/chat",
225
+ json={"message": user_input},
226
+ timeout=30
227
+ )
228
+
229
+ if response.status_code == 200:
230
+ bot_response = response.json()
231
+ st.session_state.messages.append({
232
+ "role": "assistant",
233
+ "content": bot_response["response"]
234
+ })
235
+ else:
236
+ st.session_state.messages.append({
237
+ "role": "assistant",
238
+ "content": "I'm sorry, I'm having trouble connecting to my knowledge base right now. Please try again later."
239
+ })
240
+ except Exception as e:
241
+ st.session_state.messages.append({
242
+ "role": "assistant",
243
+ "content": "I'm experiencing some technical difficulties. Please make sure the backend server is running and try again."
244
+ })
245
+
246
+ st.rerun()
247
+
248
+ # Suggested questions
249
+ st.markdown("### 💡 Try asking about:")
250
+ suggestions = [
251
+ "Tell me about Japanese business etiquette",
252
+ "What are some Indian greeting customs?",
253
+ "How do Germans view punctuality?",
254
+ "What should I know about dining in France?",
255
+ "Explain Chinese lucky numbers"
256
+ ]
257
+
258
+ cols = st.columns(len(suggestions))
259
+ for i, suggestion in enumerate(suggestions):
260
+ with cols[i]:
261
+ if st.button(suggestion, key=f"suggestion_{i}"):
262
+ st.session_state.messages.append({"role": "user", "content": suggestion})
263
+ st.rerun()
264
+
265
+ elif page == "📚 Cultural Facts":
266
+ # Cultural facts page
267
+ st.markdown("""
268
+ <div class="main-header">
269
+ <h1>Cultural Facts Explorer</h1>
270
+ <p>Browse our curated collection of cultural insights</p>
271
+ </div>
272
+ """, unsafe_allow_html=True)
273
+
274
+ # Filters
275
+ col1, col2 = st.columns(2)
276
+
277
+ with col1:
278
+ country_filter = st.selectbox(
279
+ "Filter by Country:",
280
+ ["All Countries", "Japan", "India", "Brazil", "Germany", "China", "France", "South Korea", "Mexico", "Egypt", "Russia", "Thailand", "Italy"]
281
+ )
282
+
283
+ with col2:
284
+ category_filter = st.selectbox(
285
+ "Filter by Category:",
286
+ ["All Categories", "etiquette", "business", "greeting", "food", "language", "family", "beliefs", "general"]
287
+ )
288
+
289
+ # Fetch and display facts
290
+ try:
291
+ if country_filter != "All Countries":
292
+ response = requests.get(f"{BACKEND_URL}/facts/country/{country_filter}", timeout=10)
293
+ elif category_filter != "All Categories":
294
+ response = requests.get(f"{BACKEND_URL}/facts/category/{category_filter}", timeout=10)
295
+ else:
296
+ # Get random facts for display
297
+ facts = []
298
+ for _ in range(10):
299
+ fact_response = requests.get(f"{BACKEND_URL}/facts/random", timeout=5)
300
+ if fact_response.status_code == 200:
301
+ facts.append(fact_response.json())
302
+
303
+ for fact in facts:
304
+ st.markdown(f"""
305
+ <div class="fact-card">
306
+ <h3>{fact['country']}</h3>
307
+ <p>{fact['fact']}</p>
308
+ <div style="display: flex; justify-content: space-between; margin-top: 1rem;">
309
+ <small><strong>Category:</strong> {fact['category']}</small>
310
+ <small><strong>Source:</strong> {fact['source']}</small>
311
+ </div>
312
+ </div>
313
+ """, unsafe_allow_html=True)
314
+
315
+ if country_filter != "All Countries" or category_filter != "All Categories":
316
+ if response.status_code == 200:
317
+ facts = response.json()
318
+ if facts:
319
+ for fact in facts:
320
+ st.markdown(f"""
321
+ <div class="fact-card">
322
+ <h3>{fact['country']}</h3>
323
+ <p>{fact['fact']}</p>
324
+ <div style="display: flex; justify-content: space-between; margin-top: 1rem;">
325
+ <small><strong>Category:</strong> {fact['category']}</small>
326
+ <small><strong>Source:</strong> {fact['source']}</small>
327
+ </div>
328
+ </div>
329
+ """, unsafe_allow_html=True)
330
+ else:
331
+ st.info("No facts found for the selected filters.")
332
+ else:
333
+ st.error("Unable to fetch facts from the server.")
334
+
335
+ except Exception as e:
336
+ st.error("Unable to connect to the backend server. Please make sure it's running.")
337
+
338
+ else: # About page
339
+ st.markdown("""
340
+ <div class="main-header">
341
+ <h1>About CultureBot</h1>
342
+ <p>Bridging cultures through AI-powered conversations</p>
343
+ </div>
344
+ """, unsafe_allow_html=True)
345
+
346
+ # Mission and features
347
+ col1, col2 = st.columns(2)
348
+
349
+ with col1:
350
+ st.markdown("""
351
+ ### 🎯 Our Mission
352
+ CultureBot was created to help people understand and appreciate the rich diversity of cultures around the world.
353
+ In our increasingly connected world, cultural awareness is more important than ever.
354
+
355
+ ### 🔧 Technology Stack
356
+ - **Frontend**: Streamlit (Python)
357
+ - **Backend**: FastAPI (Python)
358
+ - **AI Engine**: OpenAI GPT-3.5-turbo
359
+ - **Database**: In-memory cultural facts database
360
+ """)
361
+
362
+ with col2:
363
+ st.markdown("""
364
+ ### ✨ Features
365
+ - **Global Coverage**: Cultural insights from countries across all continents
366
+ - **AI-Powered Chat**: Natural conversation interface powered by OpenAI
367
+ - **Curated Content**: Carefully researched and verified cultural facts
368
+ - **Smart Responses**: Context-aware answers tailored to your questions
369
+ - **Real-time Interaction**: Fast and responsive chat experience
370
+ """)
371
+
372
+ st.markdown("---")
373
+
374
+ # Technical details
375
+ st.markdown("### 🏗️ Architecture")
376
+ st.markdown("""
377
+ CultureBot follows a modern microservices architecture:
378
+
379
+ 1. **Streamlit Frontend**: Beautiful, interactive user interface
380
+ 2. **FastAPI Backend**: High-performance API server
381
+ 3. **OpenAI Integration**: Advanced natural language processing
382
+ 4. **Cultural Database**: Curated collection of cultural facts and insights
383
+ """)
384
+
385
+ # Contact and support
386
+ st.markdown("### 📞 Support")
387
+ st.markdown("""
388
+ For technical support or cultural content suggestions, please contact:
389
+ - **Team**: Cultural AI Labs
390
+ - **Version**: 2.1.0
391
+ - **Last Updated**: January 15, 2024
392
+ """)
content_db.py ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import random
3
+ from typing import List, Dict, Any
4
+
5
+ class CulturalDatabase:
6
+ def __init__(self):
7
+ self.cultural_facts = [
8
+ {
9
+ "country": "Japan",
10
+ "fact": "In Japan, it's considered rude to blow your nose in public. People excuse themselves to do it privately.",
11
+ "category": "etiquette",
12
+ "source": "Japanese Cultural Studies"
13
+ },
14
+ {
15
+ "country": "Japan",
16
+ "fact": "Japanese business cards (meishi) are exchanged with both hands and should be received with respect and careful examination.",
17
+ "category": "business",
18
+ "source": "Japanese Business Etiquette Guide"
19
+ },
20
+ {
21
+ "country": "India",
22
+ "fact": "India has 22 official languages and over 1,600 spoken languages, making it one of the most linguistically diverse countries.",
23
+ "category": "language",
24
+ "source": "Indian Linguistic Survey"
25
+ },
26
+ {
27
+ "country": "India",
28
+ "fact": "In Indian culture, touching someone's feet is a sign of respect, especially for elders and teachers.",
29
+ "category": "greeting",
30
+ "source": "Indian Cultural Traditions"
31
+ },
32
+ {
33
+ "country": "Brazil",
34
+ "fact": "Brazilians typically hug and kiss on the cheek when greeting, even in business settings.",
35
+ "category": "greeting",
36
+ "source": "Brazilian Social Customs"
37
+ },
38
+ {
39
+ "country": "Brazil",
40
+ "fact": "In Brazil, the 'OK' hand gesture is considered offensive, similar to giving someone the middle finger.",
41
+ "category": "etiquette",
42
+ "source": "Brazilian Cultural Guide"
43
+ },
44
+ {
45
+ "country": "Germany",
46
+ "fact": "Germans value punctuality so much that being late is considered very disrespectful, even by a few minutes.",
47
+ "category": "business",
48
+ "source": "German Business Culture"
49
+ },
50
+ {
51
+ "country": "Germany",
52
+ "fact": "In Germany, it's customary to maintain eye contact during toasts and say 'Prost' or 'Zum Wohl'.",
53
+ "category": "food",
54
+ "source": "German Dining Etiquette"
55
+ },
56
+ {
57
+ "country": "China",
58
+ "fact": "In Chinese culture, the number 8 is considered extremely lucky because it sounds like the word for 'prosperity'.",
59
+ "category": "beliefs",
60
+ "source": "Chinese Numerology Studies"
61
+ },
62
+ {
63
+ "country": "China",
64
+ "fact": "When receiving a business card in China, accept it with both hands and take a moment to read it carefully.",
65
+ "category": "business",
66
+ "source": "Chinese Business Etiquette"
67
+ },
68
+ {
69
+ "country": "France",
70
+ "fact": "French people typically don't eat meals while walking or standing - dining is seen as a social ritual to be savored.",
71
+ "category": "food",
72
+ "source": "French Culinary Culture"
73
+ },
74
+ {
75
+ "country": "France",
76
+ "fact": "In France, it's polite to greet shopkeepers with 'Bonjour' when entering and 'Au revoir' when leaving.",
77
+ "category": "etiquette",
78
+ "source": "French Social Customs"
79
+ },
80
+ {
81
+ "country": "South Korea",
82
+ "fact": "In Korea, you should use both hands when giving or receiving business cards as a sign of respect.",
83
+ "category": "business",
84
+ "source": "Korean Business Protocol"
85
+ },
86
+ {
87
+ "country": "South Korea",
88
+ "fact": "Korean age calculation includes the time spent in the womb, so Koreans are typically 1-2 years older in 'Korean age'.",
89
+ "category": "general",
90
+ "source": "Korean Cultural Practices"
91
+ },
92
+ {
93
+ "country": "Mexico",
94
+ "fact": "Mexican families often have multiple generations living together, and family loyalty is highly valued.",
95
+ "category": "family",
96
+ "source": "Mexican Family Structures"
97
+ },
98
+ {
99
+ "country": "Mexico",
100
+ "fact": "In Mexico, personal space is smaller than in many Western cultures, and people stand closer during conversations.",
101
+ "category": "etiquette",
102
+ "source": "Mexican Social Norms"
103
+ },
104
+ {
105
+ "country": "Egypt",
106
+ "fact": "In Egypt, showing the sole of your foot to someone is considered offensive, so keep feet flat on the ground when sitting.",
107
+ "category": "etiquette",
108
+ "source": "Egyptian Cultural Guidelines"
109
+ },
110
+ {
111
+ "country": "Egypt",
112
+ "fact": "Egyptian hospitality is legendary - guests are often offered tea or coffee multiple times as a sign of welcome.",
113
+ "category": "food",
114
+ "source": "Egyptian Hospitality Traditions"
115
+ },
116
+ {
117
+ "country": "Russia",
118
+ "fact": "Russians believe that smiling without reason is insincere, so don't be surprised by serious expressions in public.",
119
+ "category": "expression",
120
+ "source": "Russian Social Behavior"
121
+ },
122
+ {
123
+ "country": "Russia",
124
+ "fact": "In Russia, it's traditional to remove shoes when entering someone's home, and slippers are often provided for guests.",
125
+ "category": "etiquette",
126
+ "source": "Russian Home Customs"
127
+ },
128
+ {
129
+ "country": "Thailand",
130
+ "fact": "In Thailand, the head is considered sacred, so never touch someone's head, even children.",
131
+ "category": "etiquette",
132
+ "source": "Thai Cultural Sensitivities"
133
+ },
134
+ {
135
+ "country": "Thailand",
136
+ "fact": "Thai people use the 'wai' greeting - pressing palms together and bowing slightly - as a sign of respect.",
137
+ "category": "greeting",
138
+ "source": "Thai Greeting Customs"
139
+ },
140
+ {
141
+ "country": "Italy",
142
+ "fact": "In Italy, cappuccino is traditionally only drunk in the morning, never after meals.",
143
+ "category": "food",
144
+ "source": "Italian Coffee Culture"
145
+ },
146
+ {
147
+ "country": "Italy",
148
+ "fact": "Italians often speak with their hands, and gestures are an integral part of communication.",
149
+ "category": "language",
150
+ "source": "Italian Communication Styles"
151
+ }
152
+ ]
153
+
154
+ def search_facts(self, query: str) -> List[Dict[str, Any]]:
155
+ """
156
+ Search for relevant cultural facts based on query
157
+ """
158
+ query_lower = query.lower()
159
+ relevant_facts = []
160
+
161
+ # Search by country
162
+ for fact in self.cultural_facts:
163
+ if fact['country'].lower() in query_lower:
164
+ relevant_facts.append(fact)
165
+
166
+ # Search by category
167
+ if not relevant_facts:
168
+ for fact in self.cultural_facts:
169
+ if fact['category'].lower() in query_lower:
170
+ relevant_facts.append(fact)
171
+
172
+ # Search by keywords in fact content
173
+ if not relevant_facts:
174
+ keywords = query_lower.split()
175
+ for fact in self.cultural_facts:
176
+ fact_text = fact['fact'].lower()
177
+ if any(keyword in fact_text for keyword in keywords):
178
+ relevant_facts.append(fact)
179
+
180
+ return relevant_facts[:5] # Return top 5 matches
181
+
182
+ def get_random_fact(self) -> Dict[str, Any]:
183
+ """
184
+ Get a random cultural fact
185
+ """
186
+ return random.choice(self.cultural_facts)
187
+
188
+ def get_facts_by_country(self, country: str) -> List[Dict[str, Any]]:
189
+ """
190
+ Get all facts for a specific country
191
+ """
192
+ return [fact for fact in self.cultural_facts if fact['country'].lower() == country.lower()]
193
+
194
+ def get_facts_by_category(self, category: str) -> List[Dict[str, Any]]:
195
+ """
196
+ Get all facts for a specific category
197
+ """
198
+ return [fact for fact in self.cultural_facts if fact['category'].lower() == category.lower()]
199
+
200
+ def get_all_countries(self) -> List[str]:
201
+ """
202
+ Get list of all countries in the database
203
+ """
204
+ return list(set(fact['country'] for fact in self.cultural_facts))
205
+
206
+ def get_all_categories(self) -> List[str]:
207
+ """
208
+ Get list of all categories in the database
209
+ """
210
+ return list(set(fact['category'] for fact in self.cultural_facts))
main.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from pydantic import BaseModel
4
+ from typing import List, Optional
5
+ import os
6
+ from dotenv import load_dotenv
7
+ from .ai_engine import CultureAI
8
+ from .content_db import CulturalDatabase
9
+
10
+ # Load environment variables
11
+ load_dotenv()
12
+
13
+ # Initialize FastAPI app
14
+ app = FastAPI(
15
+ title="CultureBot API",
16
+ description="AI-powered cultural insights and information",
17
+ version="2.1.0"
18
+ )
19
+
20
+ # Configure CORS
21
+ app.add_middleware(
22
+ CORSMiddleware,
23
+ allow_origins=["*"],
24
+ allow_credentials=True,
25
+ allow_methods=["*"],
26
+ allow_headers=["*"],
27
+ )
28
+
29
+ # Initialize AI engine and database
30
+ culture_ai = CultureAI()
31
+ cultural_db = CulturalDatabase()
32
+
33
+ # Define Pydantic models
34
+ class ChatMessage(BaseModel):
35
+ message: str
36
+ user_id: Optional[str] = "anonymous"
37
+
38
+ class ChatResponse(BaseModel):
39
+ response: str
40
+ confidence: float
41
+ sources: List[str]
42
+ category: Optional[str] = None
43
+
44
+ class CulturalFact(BaseModel):
45
+ country: str
46
+ fact: str
47
+ category: str
48
+ source: str
49
+
50
+ @app.get("/")
51
+ async def root():
52
+ return {
53
+ "message": "Welcome to CultureBot API",
54
+ "version": "2.1.0",
55
+ "status": "active"
56
+ }
57
+
58
+ @app.post("/chat", response_model=ChatResponse)
59
+ async def chat_with_bot(message: ChatMessage):
60
+ """
61
+ Main chat endpoint for interacting with CultureBot
62
+ """
63
+ try:
64
+ # Get AI response
65
+ ai_response = await culture_ai.generate_response(message.message)
66
+
67
+ # Get relevant cultural facts from database
68
+ relevant_facts = cultural_db.search_facts(message.message)
69
+
70
+ return ChatResponse(
71
+ response=ai_response["response"],
72
+ confidence=ai_response["confidence"],
73
+ sources=ai_response["sources"],
74
+ category=ai_response.get("category")
75
+ )
76
+ except Exception as e:
77
+ raise HTTPException(status_code=500, detail=f"Error processing request: {str(e)}")
78
+
79
+ @app.get("/facts/random", response_model=CulturalFact)
80
+ async def get_random_fact():
81
+ """
82
+ Get a random cultural fact
83
+ """
84
+ try:
85
+ fact = cultural_db.get_random_fact()
86
+ return CulturalFact(**fact)
87
+ except Exception as e:
88
+ raise HTTPException(status_code=500, detail=f"Error fetching fact: {str(e)}")
89
+
90
+ @app.get("/facts/country/{country}", response_model=List[CulturalFact])
91
+ async def get_country_facts(country: str):
92
+ """
93
+ Get cultural facts for a specific country
94
+ """
95
+ try:
96
+ facts = cultural_db.get_facts_by_country(country)
97
+ return [CulturalFact(**fact) for fact in facts]
98
+ except Exception as e:
99
+ raise HTTPException(status_code=500, detail=f"Error fetching country facts: {str(e)}")
100
+
101
+ @app.get("/facts/category/{category}", response_model=List[CulturalFact])
102
+ async def get_category_facts(category: str):
103
+ """
104
+ Get cultural facts for a specific category
105
+ """
106
+ try:
107
+ facts = cultural_db.get_facts_by_category(category)
108
+ return [CulturalFact(**fact) for fact in facts]
109
+ except Exception as e:
110
+ raise HTTPException(status_code=500, detail=f"Error fetching category facts: {str(e)}")
111
+
112
+ @app.get("/health")
113
+ async def health_check():
114
+ """
115
+ Health check endpoint
116
+ """
117
+ return {
118
+ "status": "healthy",
119
+ "ai_engine": "operational",
120
+ "database": "connected"
121
+ }
122
+
123
+ if __name__ == "__main__":
124
+ import uvicorn
125
+ uvicorn.run(app, host="0.0.0.0", port=8000)
requirements.txt CHANGED
Binary files a/requirements.txt and b/requirements.txt differ
 
requirements.txtuvicorn ADDED
File without changes