KarthikGarlapati commited on
Commit
b70c076
·
verified ·
1 Parent(s): e90857c

Upload 9 files

Browse files
src/Dockerfile ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9-slim
2
+
3
+ WORKDIR /app
4
+
5
+ RUN apt-get update && apt-get install -y \
6
+ build-essential \
7
+ curl \
8
+ software-properties-common \
9
+ git \
10
+ && rm -rf /var/lib/apt/lists/*
11
+
12
+ COPY requirements.txt ./
13
+ COPY src/ ./src/
14
+
15
+ RUN pip3 install -r requirements.txt
16
+
17
+ EXPOSE 8501
18
+
19
+ HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
20
+
21
+ ENTRYPOINT ["streamlit", "run", "src/streamlit_app.py", "--server.port=8501", "--server.address=0.0.0.0"]
src/README.md ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # WikiFit - Health & Fitness App with AI Integration
2
+
3
+ WikiFit is a comprehensive health and fitness application that provides information from Wikimedia sources,
4
+ alongside AI-powered health Q&A capabilities using Hugging Face transformers.
5
+
6
+ ## Features
7
+
8
+ - **Daily Health Tips**: Random health and fitness tips (now with seasonal recommendations)
9
+ - **Health Search**: Wikipedia-based health information search
10
+ - **Workout Plans**: Various workout routines (full-body, cardio, strength, flexibility)
11
+ - **Home Remedies**: Traditional home remedies for common ailments
12
+ - **Health Facts**: Interesting health-related facts
13
+ - **Interactive Quiz**: Test your health knowledge
14
+ - **BMI Calculator**: Calculate BMI with support for different height units (m, cm, feet)
15
+ - **AI Health Q&A**: Ask health questions with AI-powered answers (requires transformers)
16
+ - **Knowledge Center**: Comprehensive search across all Wikimedia projects:
17
+ - Wikipedia: General encyclopedic knowledge
18
+ - Wiktionary: Definitions and terminology
19
+ - Wikiquote: Health and fitness quotes
20
+ - Wikibooks: Educational health content
21
+ - Wikimedia Commons: Health-related images
22
+ - Wikisource: Historical health documents
23
+ - Wikiversity: Educational health resources
24
+ - Wikispecies: Biological species information
25
+ - Wikidata: Structured health data
26
+ - **Progress Tracker**: Track workouts and quiz scores
27
+
28
+ ## Installation
29
+
30
+ 1. Clone the repository
31
+ 2. Create a virtual environment (recommended):
32
+ ```
33
+ python -m venv .venv
34
+ source .venv/bin/activate # On Windows: .venv\Scripts\activate
35
+ ```
36
+ 3. Install core dependencies:
37
+ ```
38
+ pip install streamlit requests pandas numpy
39
+ ```
40
+ 4. For AI features, install additional dependencies:
41
+ ```
42
+ pip install transformers torch
43
+ ```
44
+ 5. Or install all dependencies at once:
45
+ ```
46
+ pip install -r requirements.txt
47
+ ```
48
+
49
+ ## Running the Application
50
+
51
+ ### Full Version (with AI features)
52
+ ```
53
+ streamlit run ai.py
54
+ ```
55
+
56
+ ### Basic Version (no advanced dependencies)
57
+ If you encounter compatibility issues:
58
+ ```
59
+ streamlit run wikifit_basic.py
60
+ ```
61
+
62
+ ## Troubleshooting
63
+
64
+ ### NumPy/Pandas Compatibility Issues
65
+ If you see errors like `numpy.dtype size changed`, try:
66
+ ```
67
+ pip install numpy==1.24.3 pandas==2.0.3
68
+ ```
69
+
70
+ ### AI Features Not Working
71
+ The AI features require additional libraries. If you don't need these features,
72
+ use the basic version instead, or install the required packages:
73
+ ```
74
+ pip install transformers torch
75
+ ```
76
+
77
+ ## Project Structure
78
+
79
+ ### Key Files
80
+
81
+ - `ai.py` - Main Streamlit application with full features including AI capabilities
82
+ - `wikifit_basic.py` - Simplified version without AI dependencies
83
+ - `wikimedia.py` - Core module containing all Wikimedia API integrations
84
+ - `wiki.py` - Backward-compatibility adapter for existing code
85
+ - `requirements.txt` - Package dependencies
86
+
87
+ ### Module Architecture
88
+
89
+ The application uses a modular architecture:
90
+
91
+ 1. **wikimedia.py** - Core module with all Wikimedia API functions:
92
+ - Handles all direct API calls to various Wikimedia services
93
+ - Provides error handling and consistent response formatting
94
+ - Centralizes logging and request management
95
+ - Offers a unified search function across all Wikimedia sources
96
+
97
+ 2. **ai.py and wikifit_basic.py** - Application entry points:
98
+ - Import functions from wikimedia module
99
+ - Apply caching for performance optimization
100
+ - Handle UI/UX and user interaction
101
+ - Provide feature-specific functionality
102
+
103
+ ## Requirements
104
+
105
+ - Python 3.7+
106
+ - Core: Streamlit, Requests, Pandas, NumPy
107
+ - Optional: Transformers, PyTorch
108
+
109
+ ## Notes
110
+
111
+ - This application is for educational purposes only
112
+ - The AI health advice should not replace professional medical consultation
113
+ - Session state is used to track progress across app restarts
src/ai.py ADDED
@@ -0,0 +1,758 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import random
3
+ import logging # For better error tracking
4
+ import pandas as pd # For chart data
5
+ from datetime import datetime # For progress tracking
6
+ import wikimedia # Import our Wikimedia module
7
+
8
+ # Set page config first before any other st commands
9
+ st.set_page_config(page_title="WikiFit", page_icon="💪")
10
+
11
+ # Setup basic logging
12
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
13
+
14
+ # Check for transformers library after setting page config
15
+ try:
16
+ from transformers import pipeline
17
+ AI_AVAILABLE = True
18
+ except ImportError:
19
+ AI_AVAILABLE = False
20
+
21
+ # WikiFit - Health & Fitness App with AI Integration
22
+ #
23
+ # Required packages:
24
+ # - streamlit
25
+ # - requests
26
+ # - transformers
27
+ # - torch (automatically installed with transformers)
28
+ #
29
+ # To install all requirements:
30
+ # pip install streamlit requests transformers torch
31
+
32
+ # -------------------------------
33
+ # Utils
34
+ # -------------------------------
35
+
36
+ # Cache the Wikimedia functions using Streamlit's caching decorator
37
+ @st.cache_data(ttl=3600)
38
+ def get_wikipedia_summary(term):
39
+ """Get summary of a topic from Wikipedia."""
40
+ result = wikimedia.get_wikipedia_summary(term)
41
+ return result
42
+
43
+ @st.cache_data(ttl=3600)
44
+ def get_wiktionary_definition(term):
45
+ """Get word definitions from Wiktionary"""
46
+ return wikimedia.get_wiktionary_definition(term)
47
+
48
+ @st.cache_data(ttl=3600)
49
+ def get_wikiquote_quotes(term):
50
+ """Get quotes related to a topic from Wikiquote"""
51
+ return wikimedia.get_wikiquote_quotes(term)
52
+
53
+ @st.cache_data(ttl=3600)
54
+ def get_wikibooks_content(term):
55
+ """Get educational content from Wikibooks"""
56
+ return wikimedia.get_wikibooks_content(term)
57
+
58
+ @st.cache_data(ttl=3600)
59
+ def get_wikimedia_commons_images(term, limit=5):
60
+ """Get relevant images from Wikimedia Commons"""
61
+ return wikimedia.get_wikimedia_commons_images(term, limit)
62
+
63
+ @st.cache_data(ttl=3600)
64
+ def get_wikisource_texts(term):
65
+ """Get health-related texts from Wikisource"""
66
+ return wikimedia.get_wikisource_texts(term)
67
+
68
+ @st.cache_data(ttl=3600)
69
+ def get_wikiversity_resources(term):
70
+ """Get educational resources from Wikiversity"""
71
+ return wikimedia.get_wikiversity_resources(term)
72
+
73
+ @st.cache_data(ttl=3600)
74
+ def get_wikispecies_info(species_name):
75
+ """Get species information from Wikispecies"""
76
+ return wikimedia.get_wikispecies_info(species_name)
77
+
78
+ @st.cache_data(ttl=3600)
79
+ def get_wikidata_health_info(term):
80
+ """Get structured health data from Wikidata"""
81
+ return wikimedia.get_wikidata_health_info(term)
82
+
83
+ # Add a new function to search across all Wikimedia sources at once
84
+ @st.cache_data(ttl=3600)
85
+ def search_all_wikimedia(term):
86
+ """Search for a term across all Wikimedia platforms."""
87
+ return wikimedia.search_all_wikimedia(term)
88
+
89
+
90
+ def get_random_health_tip():
91
+ # Get current month to provide seasonal tips
92
+ current_month = datetime.now().month
93
+
94
+ # Base tips that apply all year
95
+ base_tips = [
96
+ "Drink at least 2 liters of water every day.",
97
+ "Do at least 30 minutes of physical activity daily.",
98
+ "Maintain a regular sleep schedule.",
99
+ "Include fruits and vegetables in every meal.",
100
+ "Take short breaks during long sitting hours.",
101
+ "Practice mindfulness meditation for 10 minutes daily.",
102
+ "Reduce sodium intake to help control blood pressure.",
103
+ "Limit screen time before bedtime for better sleep.",
104
+ "Choose whole grains over refined carbohydrates.",
105
+ "Incorporate strength training at least twice a week."
106
+ ]
107
+
108
+ # Seasonal tips
109
+ seasonal_tips = {
110
+ # Winter (Dec-Feb)
111
+ "winter": [
112
+ "Increase vitamin D intake during winter months.",
113
+ "Stay hydrated even when it's cold - indoor heating dehydrates you.",
114
+ "Wash hands frequently to prevent seasonal colds and flu.",
115
+ "Keep exercise routines indoor when weather is harsh.",
116
+ "Moisturize skin more frequently in dry winter air."
117
+ ],
118
+ # Spring (Mar-May)
119
+ "spring": [
120
+ "Consider seasonal allergy preparations before symptoms start.",
121
+ "Spring clean your diet - add fresh seasonal produce.",
122
+ "Gradually increase outdoor exercise as weather improves.",
123
+ "Check and replace air filters to reduce spring allergens.",
124
+ "Stay hydrated as temperatures begin to rise."
125
+ ],
126
+ # Summer (Jun-Aug)
127
+ "summer": [
128
+ "Apply sunscreen 30 minutes before sun exposure.",
129
+ "Stay extra hydrated during hot days.",
130
+ "Exercise during cooler parts of the day to avoid heat exhaustion.",
131
+ "Include electrolytes if sweating heavily.",
132
+ "Check for signs of dehydration in hot weather."
133
+ ],
134
+ # Fall (Sep-Nov)
135
+ "fall": [
136
+ "Boost immune system as cold and flu season approaches.",
137
+ "Adjust exercise routines for cooling temperatures.",
138
+ "Incorporate seasonal produce like pumpkins and apples.",
139
+ "Keep up vitamin D as sunlight exposure decreases.",
140
+ "Prepare indoor exercise options for colder days ahead."
141
+ ]
142
+ }
143
+
144
+ # Determine current season
145
+ if current_month in [12, 1, 2]:
146
+ season = "winter"
147
+ elif current_month in [3, 4, 5]:
148
+ season = "spring"
149
+ elif current_month in [6, 7, 8]:
150
+ season = "summer"
151
+ else: # 9, 10, 11
152
+ season = "fall"
153
+
154
+ # Combine base tips with seasonal tips
155
+ all_tips = base_tips + seasonal_tips[season]
156
+ return random.choice(all_tips)
157
+
158
+
159
+ def generate_quiz():
160
+ """Generate a random health quiz question with multiple choice options"""
161
+ questions = [
162
+ ("How many bones are there in the human body?", ["206", "201", "212", "195"], "206"),
163
+ ("What vitamin do we get from sunlight?", ["Vitamin A", "Vitamin B12", "Vitamin D", "Vitamin C"], "Vitamin D"),
164
+ ("Which organ uses the most oxygen?", ["Heart", "Brain", "Lungs", "Liver"], "Brain"),
165
+ ("What percentage of the human body is water?", ["50-60%", "60-70%", "70-80%", "80-90%"], "60-70%"),
166
+ ("Which nutrient is the primary source of energy for the body?", ["Protein", "Fats", "Carbohydrates", "Vitamins"], "Carbohydrates")
167
+ ]
168
+ return random.choice(questions)
169
+
170
+
171
+ def calculate_bmi(weight, height, unit="m"):
172
+ """Calculate BMI (Body Mass Index).
173
+
174
+ Args:
175
+ weight: Weight in kilograms
176
+ height: Height in meters, centimeters, or feet (with decimal for inches)
177
+ unit: Unit of height measurement ("m", "cm", or "ft")
178
+
179
+ Returns:
180
+ tuple: (bmi_value, bmi_category)
181
+ """
182
+ if weight <= 0 or height <= 0:
183
+ return None, None
184
+
185
+ # Convert height to meters for calculation
186
+ if unit == "cm":
187
+ height = height / 100.0
188
+ elif unit == "ft":
189
+ # Convert feet/inches to meters (1 foot = 0.3048 meters)
190
+ feet_whole = int(height)
191
+ inches = (height - feet_whole) * 10
192
+ height = feet_whole * 0.3048 + inches * 0.0254
193
+
194
+ bmi = weight / (height ** 2)
195
+
196
+ if bmi < 18.5:
197
+ category = "Underweight"
198
+ elif 18.5 <= bmi < 25:
199
+ category = "Normal weight"
200
+ elif 25 <= bmi < 30:
201
+ category = "Overweight"
202
+ else:
203
+ category = "Obese"
204
+
205
+ return round(bmi, 2), category
206
+
207
+
208
+ def get_workout_plan(workout_type="full_body"):
209
+ workouts = {
210
+ "full_body": [
211
+ "10 Jumping Jacks",
212
+ "10 Push-ups",
213
+ "15 Squats",
214
+ "20-second Plank",
215
+ "10 Lunges (each leg)",
216
+ "Repeat 3 times"
217
+ ],
218
+ "cardio": [
219
+ "30 seconds Jumping Jacks",
220
+ "30 seconds High Knees",
221
+ "30 seconds Butt Kicks",
222
+ "30 seconds Mountain Climbers",
223
+ "30 seconds rest",
224
+ "Repeat 4 times"
225
+ ],
226
+ "strength": [
227
+ "12 Push-ups",
228
+ "15 Squats with 5 second hold",
229
+ "10 Tricep Dips",
230
+ "10 Glute Bridges",
231
+ "8 Superman Holds",
232
+ "Repeat 3 times"
233
+ ],
234
+ "flexibility": [
235
+ "30 seconds Hamstring Stretch",
236
+ "30 seconds Quad Stretch (each leg)",
237
+ "30 seconds Child's Pose",
238
+ "30 seconds Cat-Cow Stretch",
239
+ "30 seconds Butterfly Stretch",
240
+ "Repeat 2 times"
241
+ ]
242
+ }
243
+ return workouts.get(workout_type, workouts["full_body"])
244
+
245
+
246
+ def get_wikibooks_remedies():
247
+ # Placeholder text simulating Wikibooks data
248
+ return [
249
+ ("Turmeric Milk", "Used for colds and inflammation."),
250
+ ("Honey & Ginger", "Relieves sore throat and cough."),
251
+ ("Amla Juice", "Boosts immunity and rich in Vitamin C."),
252
+ ("Mint Tea", "Aids digestion and relieves headaches."),
253
+ ("Aloe Vera Gel", "Soothes skin irritation and burns."),
254
+ ("Fenugreek Seeds", "Helps control blood sugar levels.")
255
+ ]
256
+
257
+
258
+ def get_did_you_know_fact():
259
+ facts = [
260
+ "The human body has 206 bones.",
261
+ "Your heart beats about 100,000 times a day.",
262
+ "The skin is the body's largest organ.",
263
+ "The brain uses around 20% of the body's oxygen.",
264
+ "Laughter is good for your heart and can reduce stress.",
265
+ "Adults have fewer bones than babies. Babies are born with 300 bones, but some fuse together.",
266
+ "The strongest muscle in your body is your masseter (jaw muscle).",
267
+ "Your stomach acid is strong enough to dissolve zinc and sometimes metal.",
268
+ "The human nose can detect over 1 trillion different scents."
269
+ ]
270
+ return random.choice(facts)
271
+
272
+
273
+ @st.cache_resource
274
+ def load_qa_pipeline():
275
+ if not AI_AVAILABLE:
276
+ return None
277
+
278
+ try:
279
+ return pipeline("question-answering", model="distilbert-base-cased-distilled-squad")
280
+ except Exception as e:
281
+ logging.error(f"Error loading QA model: {str(e)}")
282
+ return None
283
+
284
+ # Load the pipeline at startup
285
+ qa_pipeline = load_qa_pipeline()
286
+
287
+ def answer_health_question(question, context):
288
+ """
289
+ Process a health-related question using the QA pipeline and provided context
290
+
291
+ Args:
292
+ question: The user's question as a string
293
+ context: Health information context for the model to use
294
+
295
+ Returns:
296
+ Answer string or error message
297
+ """
298
+ if qa_pipeline is None:
299
+ return "AI model is not available. Please check if transformers and torch are installed correctly."
300
+
301
+ try:
302
+ # Add disclaimer for health info
303
+ if len(question) < 5:
304
+ return "Please ask a more specific question."
305
+
306
+ # Process the question
307
+ result = qa_pipeline(
308
+ question=question,
309
+ context=context,
310
+ max_answer_len=100, # Limit very long answers
311
+ handle_impossible_answer=True
312
+ )
313
+
314
+ # Check confidence score
315
+ if result.get('score', 0) < 0.1:
316
+ return "I don't have enough information to answer that question accurately. Please try a different question related to the topics covered."
317
+
318
+ return result['answer']
319
+ except Exception as e:
320
+ logging.error(f"QA error: {str(e)}")
321
+ return f"Sorry, I couldn't process your question. Error: {str(e)}"
322
+
323
+
324
+ # -------------------------------
325
+ # UI
326
+ # -------------------------------
327
+
328
+ st.title("💪 WikiFit – Health & Fitness from Wikimedia")
329
+
330
+ # Initialize session state for visit_history first
331
+ if 'visit_history' not in st.session_state:
332
+ st.session_state.visit_history = []
333
+
334
+ # Get time of day for personalized welcome
335
+ current_hour = datetime.now().hour
336
+ if 5 <= current_hour < 12:
337
+ greeting = "Good morning"
338
+ elif 12 <= current_hour < 17:
339
+ greeting = "Good afternoon"
340
+ else:
341
+ greeting = "Good evening"
342
+
343
+ # Welcome message in the sidebar
344
+ st.sidebar.markdown(f"### {greeting}!")
345
+ st.sidebar.markdown("Welcome to WikiFit, your personal health assistant.")
346
+
347
+ # Display current date and streak
348
+ st.sidebar.markdown(f"**Today**: {datetime.now().strftime('%B %d, %Y')}")
349
+ days_visited = len(st.session_state.visit_history)
350
+ if days_visited > 0:
351
+ st.sidebar.markdown(f"**Streak**: {days_visited} days")
352
+
353
+ current_date = datetime.now().strftime("%Y-%m-%d")
354
+ if current_date not in st.session_state.visit_history:
355
+ st.session_state.visit_history.append(current_date)
356
+
357
+ # Initialize session state for tracking progress
358
+ if 'workout_completed' not in st.session_state:
359
+ st.session_state.workout_completed = 0
360
+ if 'quiz_score' not in st.session_state:
361
+ st.session_state.quiz_score = 0
362
+ if 'last_visit' not in st.session_state:
363
+ st.session_state.last_visit = None
364
+ # visit_history is already initialized above
365
+
366
+ # Check if this is a new day visit
367
+ current_date = datetime.now().strftime("%Y-%m-%d")
368
+ if st.session_state.last_visit != current_date:
369
+ st.session_state.last_visit = current_date
370
+ # Add this date to visit history if not already there
371
+ if current_date not in st.session_state.visit_history:
372
+ st.session_state.visit_history.append(current_date)
373
+ st.sidebar.success("Welcome to a new day of health & fitness!")
374
+
375
+ # Main navigation
376
+ menu = st.sidebar.selectbox("Navigate", [
377
+ "Daily Tip",
378
+ "Health Search",
379
+ "Workout Plans",
380
+ "Home Remedies",
381
+ "Did You Know?",
382
+ "Fitness Quiz",
383
+ "BMI Calculator",
384
+ "AI Health Q&A",
385
+ "Knowledge Center", # New Wikimedia endpoints integration
386
+ "Progress Tracker" # Added progress tracker option
387
+ ])
388
+
389
+ if menu == "Daily Tip":
390
+ st.subheader("📆 Daily Fitness/Nutrition Tip")
391
+ tip = get_random_health_tip()
392
+ st.success(tip)
393
+
394
+ # Determine if this is a seasonal tip
395
+ current_month = datetime.now().month
396
+ if any(keyword in tip.lower() for keyword in ["winter", "vitamin d", "cold", "indoor", "flu"]) and current_month in [12, 1, 2]:
397
+ st.info("💡 This is a seasonal winter health tip.")
398
+ elif any(keyword in tip.lower() for keyword in ["spring", "allergy", "pollen", "seasonal"]) and current_month in [3, 4, 5]:
399
+ st.info("💡 This is a seasonal spring health tip.")
400
+ elif any(keyword in tip.lower() for keyword in ["summer", "sun", "heat", "hydrated", "sunscreen"]) and current_month in [6, 7, 8]:
401
+ st.info("💡 This is a seasonal summer health tip.")
402
+ elif any(keyword in tip.lower() for keyword in ["fall", "autumn", "immune", "cooling"]) and current_month in [9, 10, 11]:
403
+ st.info("💡 This is a seasonal fall health tip.")
404
+
405
+ elif menu == "Health Search":
406
+ st.subheader("🔍 Search Health Info from Wikipedia")
407
+ query = st.text_input("Enter a health topic (e.g., Vitamin D, Yoga)")
408
+ if query:
409
+ result = get_wikipedia_summary(query.replace(" ", "_"))
410
+ st.info(result)
411
+
412
+ elif menu == "Workout Plans":
413
+ st.subheader("🏋️‍♀️ Basic Workout Plans from Wikibooks")
414
+ workout_type = st.selectbox("Choose workout type", ["full_body", "cardio", "strength", "flexibility"])
415
+ plan = get_workout_plan(workout_type)
416
+ for step in plan:
417
+ st.write(f"- {step}")
418
+
419
+ if st.button("Mark as Completed"):
420
+ st.session_state.workout_completed += 1
421
+ st.success(f"Great job! You've completed {st.session_state.workout_completed} workouts.")
422
+
423
+ elif menu == "Home Remedies":
424
+ st.subheader("🌿 Traditional Remedies from Wikibooks")
425
+ remedies = get_wikibooks_remedies()
426
+ for title, desc in remedies:
427
+ st.markdown(f"**{title}** – {desc}")
428
+
429
+ elif menu == "Did You Know?":
430
+ st.subheader("❓ Fun Health Facts from Wikipedia")
431
+ st.info(get_did_you_know_fact())
432
+
433
+ elif menu == "Fitness Quiz":
434
+ st.subheader("🧠 Quick Fitness Quiz")
435
+ q, options, answer = generate_quiz()
436
+ user_answer = st.radio(q, options)
437
+ if st.button("Submit"):
438
+ if user_answer == answer:
439
+ st.success("Correct! ✅")
440
+ st.session_state.quiz_score += 10
441
+ st.success(f"You earned 10 points! Total score: {st.session_state.quiz_score}")
442
+ else:
443
+ st.error(f"Incorrect. The right answer is {answer}.")
444
+
445
+ elif menu == "BMI Calculator":
446
+ st.subheader("📊 BMI Calculator")
447
+
448
+ col1, col2 = st.columns(2)
449
+
450
+ with col1:
451
+ weight = st.number_input("Weight (kg)", min_value=0.0, max_value=300.0, value=70.0, step=0.1)
452
+
453
+ with col2:
454
+ unit = st.selectbox("Height unit", ["m", "cm", "ft"], index=0)
455
+
456
+ if unit == "m":
457
+ height = st.number_input("Height (m)", min_value=0.0, max_value=3.0, value=1.70, step=0.01)
458
+ elif unit == "cm":
459
+ height = st.number_input("Height (cm)", min_value=0.0, max_value=300.0, value=170.0, step=1.0)
460
+ else: # ft
461
+ height = st.number_input("Height (ft.in)",
462
+ min_value=0.0,
463
+ max_value=8.0,
464
+ value=5.6,
465
+ step=0.1,
466
+ help="Enter feet as whole number and inches as decimal (e.g., 5.6 for 5'6\")")
467
+
468
+ if st.button("Calculate BMI"):
469
+ bmi_value, bmi_category = calculate_bmi(weight, height, unit)
470
+
471
+ if bmi_value and bmi_category:
472
+ st.info(f"Your BMI: **{bmi_value}**")
473
+
474
+ if bmi_category == "Underweight":
475
+ st.warning(f"Category: **{bmi_category}**")
476
+ elif bmi_category == "Normal weight":
477
+ st.success(f"Category: **{bmi_category}**")
478
+ elif bmi_category == "Overweight":
479
+ st.warning(f"Category: **{bmi_category}**")
480
+ else:
481
+ st.error(f"Category: **{bmi_category}**")
482
+
483
+ st.write("BMI Categories:")
484
+ st.write("- Underweight: < 18.5")
485
+ st.write("- Normal weight: 18.5–24.9")
486
+ st.write("- Overweight: 25–29.9")
487
+ st.write("- Obese: ≥ 30")
488
+
489
+ elif menu == "AI Health Q&A":
490
+ st.subheader("🤖 Ask any health or fitness question")
491
+
492
+ if not AI_AVAILABLE:
493
+ st.error("AI features are not available. Please install required libraries: `pip install transformers torch`")
494
+ st.info("After installing, please restart the application.")
495
+ st.stop()
496
+
497
+ # Create tabs for different knowledge sources
498
+ tab1, tab2, tab3 = st.tabs(["General Health", "Nutrition", "Fitness"])
499
+
500
+ with tab1:
501
+ # General health context
502
+ health_context = """
503
+ Regular check-ups with healthcare providers are essential for preventive care.
504
+ Vaccination helps prevent infectious diseases by building immunity.
505
+ Mental health is as important as physical health for overall well-being.
506
+ Chronic stress can lead to various physical and mental health problems.
507
+ Sleep hygiene practices include consistent sleep schedule and limiting screen time before bed.
508
+ Proper handwashing is one of the most effective ways to prevent illness.
509
+ Smoking is the leading cause of preventable death worldwide.
510
+ Moderate alcohol consumption means up to 1 drink per day for women and 2 for men.
511
+ """
512
+
513
+ question1 = st.text_input("Ask a general health question", key="general_health")
514
+ if question1:
515
+ with st.spinner("Finding answer..."):
516
+ answer = answer_health_question(question1, health_context)
517
+ st.info(f"**Answer:** {answer}")
518
+ st.caption("Note: This AI provides general information and should not replace professional medical advice.")
519
+
520
+ with tab2:
521
+ # Nutrition context
522
+ nutrition_context = """
523
+ The five main food groups are fruits, vegetables, grains, protein foods, and dairy.
524
+ Proteins are essential for building and repairing tissues in the body.
525
+ Carbohydrates are the body's main source of energy.
526
+ Healthy fats support cell growth and protect organs.
527
+ Fiber aids digestion and helps maintain bowel health.
528
+ Vitamins and minerals are essential for various bodily functions.
529
+ Antioxidants help protect cells from damage caused by free radicals.
530
+ Turmeric contains curcumin which has anti-inflammatory properties.
531
+ Green tea is rich in antioxidants called catechins.
532
+ Processed foods often contain high levels of sodium, sugar, and unhealthy fats.
533
+ """
534
+
535
+ question2 = st.text_input("Ask a nutrition question", key="nutrition")
536
+ if question2:
537
+ with st.spinner("Finding answer..."):
538
+ answer = answer_health_question(question2, nutrition_context)
539
+ st.info(f"**Answer:** {answer}")
540
+ st.caption("Consult with a nutritionist for personalized dietary advice.")
541
+
542
+ with tab3:
543
+ # Fitness context
544
+ fitness_context = """
545
+ Cardiovascular exercise improves heart health and increases stamina.
546
+ Strength training helps build and maintain muscle mass.
547
+ Flexibility exercises help maintain joint mobility and prevent injuries.
548
+ Rest days are important for muscle recovery and growth.
549
+ Progressive overload is necessary for continued fitness improvements.
550
+ HIIT (High-Intensity Interval Training) involves short bursts of intense exercise.
551
+ Proper form during exercise helps prevent injuries.
552
+ Warming up before exercise prepares your body for physical activity.
553
+ Cooling down after exercise helps reduce muscle stiffness.
554
+ Functional fitness focuses on exercises that help with everyday activities.
555
+ """
556
+
557
+ question3 = st.text_input("Ask a fitness question", key="fitness")
558
+ if question3:
559
+ with st.spinner("Finding answer..."):
560
+ answer = answer_health_question(question3, fitness_context)
561
+ st.info(f"**Answer:** {answer}")
562
+ st.caption("Always consult with a fitness professional before starting a new exercise program.")
563
+
564
+ elif menu == "Knowledge Center":
565
+ st.subheader("📚 Health & Fitness Knowledge Center")
566
+ st.write("Explore a wealth of knowledge from various Wikimedia projects")
567
+
568
+ # Create tabs for different Wikimedia sources
569
+ wiki_tabs = st.tabs([
570
+ "Wikipedia", "Wiktionary", "Wikiquote",
571
+ "Wikibooks", "Wikimedia Commons", "Wikisource",
572
+ "Wikiversity", "Wikispecies", "Wikidata"
573
+ ])
574
+
575
+ query = st.text_input("Search across Wikimedia projects", placeholder="Enter a health or fitness topic...")
576
+
577
+ if query:
578
+ search_term = query.strip().replace(" ", "_")
579
+
580
+ # Wikipedia Tab
581
+ with wiki_tabs[0]:
582
+ st.subheader(f"📖 Wikipedia: {query}")
583
+ with st.spinner("Searching Wikipedia..."):
584
+ wiki_result = get_wikipedia_summary(search_term)
585
+ st.info(wiki_result)
586
+ st.caption("Source: Wikipedia, the free encyclopedia")
587
+
588
+ # Wiktionary Tab
589
+ with wiki_tabs[1]:
590
+ st.subheader(f"📕 Wiktionary: {query}")
591
+ with st.spinner("Searching Wiktionary..."):
592
+ wikt_result = get_wiktionary_definition(search_term)
593
+ st.info(wikt_result)
594
+ st.caption("Source: Wiktionary, the free dictionary")
595
+
596
+ # Wikiquote Tab
597
+ with wiki_tabs[2]:
598
+ st.subheader(f"💬 Wikiquote: {query}")
599
+ with st.spinner("Searching Wikiquote..."):
600
+ quote_result = get_wikiquote_quotes(search_term)
601
+ st.info(quote_result)
602
+ st.caption("Source: Wikiquote, the free quote compendium")
603
+
604
+ # Wikibooks Tab
605
+ with wiki_tabs[3]:
606
+ st.subheader(f"📚 Wikibooks: {query}")
607
+ with st.spinner("Searching Wikibooks..."):
608
+ books_result = get_wikibooks_content(search_term)
609
+ st.info(books_result)
610
+ st.caption("Source: Wikibooks, open books for an open world")
611
+
612
+ # Wikimedia Commons Tab
613
+ with wiki_tabs[4]:
614
+ st.subheader(f"🖼️ Wikimedia Commons: {query}")
615
+ with st.spinner("Searching Wikimedia Commons..."):
616
+ images = get_wikimedia_commons_images(search_term)
617
+ if images:
618
+ cols = st.columns(min(3, len(images)))
619
+ for i, img in enumerate(images):
620
+ with cols[i % 3]:
621
+ st.image(img["url"], caption=img["title"])
622
+ if img["description"]:
623
+ st.caption(img["description"][:100] + "..." if len(img["description"]) > 100 else img["description"])
624
+ else:
625
+ st.info("No images found for this topic on Wikimedia Commons.")
626
+ st.caption("Source: Wikimedia Commons, the free media repository")
627
+
628
+ # Wikisource Tab
629
+ with wiki_tabs[5]:
630
+ st.subheader(f"📜 Wikisource: {query}")
631
+ with st.spinner("Searching Wikisource..."):
632
+ source_results = get_wikisource_texts(search_term)
633
+ if source_results:
634
+ for result in source_results:
635
+ st.markdown(f"**{result['title']}**")
636
+ st.write(result["snippet"])
637
+ st.markdown("---")
638
+ else:
639
+ st.info("No relevant texts found on Wikisource.")
640
+ st.caption("Source: Wikisource, the free digital library")
641
+
642
+ # Wikiversity Tab
643
+ with wiki_tabs[6]:
644
+ st.subheader(f"🎓 Wikiversity: {query}")
645
+ with st.spinner("Searching Wikiversity..."):
646
+ university_result = get_wikiversity_resources(search_term)
647
+ st.info(university_result)
648
+ st.caption("Source: Wikiversity, a learning platform")
649
+
650
+ # Wikispecies Tab
651
+ with wiki_tabs[7]:
652
+ st.subheader(f"🦠 Wikispecies: {query}")
653
+ with st.spinner("Searching Wikispecies..."):
654
+ species_result = get_wikispecies_info(search_term)
655
+ st.info(species_result)
656
+ st.caption("Source: Wikispecies, free species directory")
657
+
658
+ # Wikidata Tab
659
+ with wiki_tabs[8]:
660
+ st.subheader(f"🗃️ Wikidata: {query}")
661
+ with st.spinner("Searching Wikidata..."):
662
+ data_result = get_wikidata_health_info(search_term)
663
+ if isinstance(data_result, dict):
664
+ st.markdown(f"**{data_result['label']}**")
665
+ st.write(data_result['description'])
666
+
667
+ if data_result['properties']:
668
+ st.subheader("Related properties:")
669
+ for prop, values in data_result['properties'].items():
670
+ st.write(f"**{prop}**: {', '.join(values)}")
671
+ else:
672
+ st.info(data_result)
673
+ st.caption("Source: Wikidata, the free knowledge base")
674
+
675
+ else:
676
+ st.info("Enter a health or fitness topic above to explore information from all Wikimedia projects")
677
+
678
+ # Show some example topics
679
+ st.markdown("### Example topics to search:")
680
+ example_cols = st.columns(3)
681
+ with example_cols[0]:
682
+ st.markdown("**Health topics**")
683
+ st.markdown("- Vitamin D")
684
+ st.markdown("- Diabetes")
685
+ st.markdown("- Mental health")
686
+ st.markdown("- Immune system")
687
+
688
+ with example_cols[1]:
689
+ st.markdown("**Fitness topics**")
690
+ st.markdown("- HIIT")
691
+ st.markdown("- Strength training")
692
+ st.markdown("- Flexibility")
693
+ st.markdown("- Cardiovascular exercise")
694
+
695
+ with example_cols[2]:
696
+ st.markdown("**Nutrition topics**")
697
+ st.markdown("- Protein")
698
+ st.markdown("- Carbohydrates")
699
+ st.markdown("- Antioxidants")
700
+ st.markdown("- Superfoods")
701
+
702
+ st.info("The Knowledge Center brings together health and fitness information from across all Wikimedia projects in one place.")
703
+
704
+ elif menu == "Progress Tracker":
705
+ st.subheader("📈 Personal Progress Tracker")
706
+
707
+ # Display current stats
708
+ col1, col2 = st.columns(2)
709
+ with col1:
710
+ st.metric("Workouts Completed", st.session_state.workout_completed)
711
+ with col2:
712
+ st.metric("Quiz Score", f"{st.session_state.quiz_score} points")
713
+
714
+ # Add workout completion
715
+ st.subheader("Log Your Activity")
716
+ with st.form("workout_form"):
717
+ workout_date = st.date_input("Date", datetime.now())
718
+ workout_type = st.selectbox("Workout Type",
719
+ ["Full Body", "Cardio", "Strength", "Flexibility", "Walking/Running", "Cycling", "Other"])
720
+ duration = st.number_input("Duration (minutes)", min_value=5, max_value=240, step=5)
721
+ intensity = st.slider("Intensity", 1, 10, 5)
722
+ notes = st.text_area("Notes (optional)")
723
+
724
+ submit = st.form_submit_button("Log Workout")
725
+
726
+ if submit:
727
+ st.session_state.workout_completed += 1
728
+ st.success(f"Workout logged! You've completed {st.session_state.workout_completed} workouts.")
729
+
730
+ # Display motivational message based on workout count
731
+ if st.session_state.workout_completed % 5 == 0:
732
+ st.balloons()
733
+ st.success(f"🎉 Congratulations on your {st.session_state.workout_completed}th workout!")
734
+
735
+ # Allow users to set goals
736
+ st.subheader("Set Health Goals")
737
+ goal = st.text_input("Enter your health goal")
738
+ target_date = st.date_input("Target date", datetime.now())
739
+
740
+ if st.button("Save Goal"):
741
+ st.success("Goal saved! We'll help you track your progress.")
742
+
743
+ # Display a simple progress chart (placeholder for now)
744
+ st.subheader("Workout History")
745
+
746
+ # Create chart data in the format Streamlit expects
747
+ # Create a DataFrame that Streamlit can plot
748
+ chart_data = pd.DataFrame({
749
+ 'Workouts': [
750
+ st.session_state.workout_completed,
751
+ max(0, st.session_state.workout_completed - 2),
752
+ max(0, st.session_state.workout_completed - 5),
753
+ max(0, st.session_state.workout_completed - 8)
754
+ ]},
755
+ index=['Week 1', 'Week 2', 'Week 3', 'Week 4']
756
+ )
757
+
758
+ st.bar_chart(chart_data)
src/hello.py ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import requests
3
+ import random
4
+
5
+ # -------------------------------
6
+ # Utils
7
+ # -------------------------------
8
+
9
+ @st.cache_data(ttl=3600) # Cache Wikipedia API calls for 1 hour
10
+ def get_wikipedia_summary(term):
11
+ try:
12
+ url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{term}"
13
+ response = requests.get(url, timeout=10)
14
+ if response.status_code == 200:
15
+ return response.json().get("extract", "No summary found.")
16
+ else:
17
+ return f"Error retrieving information: HTTP {response.status_code}"
18
+ except requests.RequestException as e:
19
+ st.error(f"Request error: {str(e)}")
20
+ return "Connection error. Please try again later."
21
+
22
+
23
+ def get_random_health_tip():
24
+ tips = [
25
+ "Drink at least 2 liters of water every day.",
26
+ "Do at least 30 minutes of physical activity daily.",
27
+ "Maintain a regular sleep schedule.",
28
+ "Include fruits and vegetables in every meal.",
29
+ "Take short breaks during long sitting hours.",
30
+ "Practice mindfulness meditation for 10 minutes daily.",
31
+ "Reduce sodium intake to help control blood pressure.",
32
+ "Limit screen time before bedtime for better sleep.",
33
+ "Choose whole grains over refined carbohydrates.",
34
+ "Incorporate strength training at least twice a week."
35
+ ]
36
+ return random.choice(tips)
37
+
38
+
39
+ def get_did_you_know_fact():
40
+ facts = [
41
+ "The human body has 206 bones.",
42
+ "Your heart beats about 100,000 times a day.",
43
+ "The skin is the body's largest organ.",
44
+ "The brain uses around 20% of the body’s oxygen.",
45
+ "Laughter is good for your heart and can reduce stress."
46
+ ]
47
+ return random.choice(facts)
48
+
49
+
50
+ def get_wikibooks_remedies():
51
+ # Placeholder text simulating Wikibooks data
52
+ return [
53
+ ("Turmeric Milk", "Used for colds and inflammation."),
54
+ ("Honey & Ginger", "Relieves sore throat and cough."),
55
+ ("Amla Juice", "Boosts immunity and rich in Vitamin C.")
56
+ ]
57
+
58
+
59
+ def get_workout_plan(workout_type="full_body"):
60
+ workouts = {
61
+ "full_body": [
62
+ "10 Jumping Jacks",
63
+ "10 Push-ups",
64
+ "15 Squats",
65
+ "20-second Plank",
66
+ "10 Lunges (each leg)",
67
+ "Repeat 3 times"
68
+ ],
69
+ "cardio": [
70
+ "30 seconds Jumping Jacks",
71
+ "30 seconds High Knees",
72
+ "30 seconds Butt Kicks",
73
+ "30 seconds Mountain Climbers",
74
+ "30 seconds rest",
75
+ "Repeat 4 times"
76
+ ],
77
+ "strength": [
78
+ "12 Push-ups",
79
+ "15 Squats with 5 second hold",
80
+ "10 Tricep Dips",
81
+ "10 Glute Bridges",
82
+ "8 Superman Holds",
83
+ "Repeat 3 times"
84
+ ],
85
+ "flexibility": [
86
+ "30 seconds Hamstring Stretch",
87
+ "30 seconds Quad Stretch (each leg)",
88
+ "30 seconds Child's Pose",
89
+ "30 seconds Cat-Cow Stretch",
90
+ "30 seconds Butterfly Stretch",
91
+ "Repeat 2 times"
92
+ ]
93
+ }
94
+ return workouts.get(workout_type, workouts["full_body"])
95
+
96
+
97
+ def generate_quiz():
98
+ questions = [
99
+ ("How many bones are there in the human body?", ["206", "201", "212", "195"], "206"),
100
+ ("What vitamin do we get from sunlight?", ["Vitamin A", "Vitamin B12", "Vitamin D", "Vitamin C"], "Vitamin D"),
101
+ ("Which organ uses the most oxygen?", ["Heart", "Brain", "Lungs", "Liver"], "Brain")
102
+ ]
103
+ return random.choice(questions)
104
+
105
+ def calculate_bmi(weight, height, unit="m"):
106
+ """Calculate BMI (Body Mass Index).
107
+
108
+ Args:
109
+ weight: Weight in kilograms
110
+ height: Height in meters, centimeters, or feet (with decimal for inches)
111
+ unit: Unit of height measurement ("m", "cm", or "ft")
112
+
113
+ Returns:
114
+ tuple: (bmi_value, bmi_category)
115
+ """
116
+ if weight <= 0 or height <= 0:
117
+ return None, None
118
+
119
+ # Convert height to meters for calculation
120
+ if unit == "cm":
121
+ height = height / 100.0
122
+ elif unit == "ft":
123
+ # Convert feet/inches to meters (1 foot = 0.3048 meters)
124
+ feet_whole = int(height)
125
+ inches = (height - feet_whole) * 10
126
+ height = feet_whole * 0.3048 + inches * 0.0254
127
+
128
+ bmi = weight / (height ** 2)
129
+
130
+ if bmi < 18.5:
131
+ category = "Underweight"
132
+ elif 18.5 <= bmi < 25:
133
+ category = "Normal weight"
134
+ elif 25 <= bmi < 30:
135
+ category = "Overweight"
136
+ else:
137
+ category = "Obese"
138
+
139
+ return round(bmi, 2), category
140
+
141
+ # -------------------------------
142
+ # UI
143
+ # -------------------------------
144
+
145
+ st.set_page_config(page_title="WikiFit", page_icon="💪")
146
+ st.title("💪 WikiFit – Health & Fitness from Wikimedia")
147
+
148
+ menu = st.sidebar.selectbox("Navigate", ["Daily Tip", "Health Search", "Workout Plans", "Home Remedies", "Did You Know?", "Fitness Quiz", "BMI Calculator"])
149
+
150
+ if menu == "Daily Tip":
151
+ st.subheader("📆 Daily Fitness/Nutrition Tip")
152
+ st.success(get_random_health_tip())
153
+
154
+ elif menu == "Health Search":
155
+ st.subheader("🔍 Search Health Info from Wikipedia")
156
+ query = st.text_input("Enter a health topic (e.g., Vitamin D, Yoga)")
157
+ if query:
158
+ result = get_wikipedia_summary(query.replace(" ", "_"))
159
+ st.info(result)
160
+
161
+ elif menu == "Workout Plans":
162
+ st.subheader("🏋️‍♀️ Basic Workout Plans from Wikibooks")
163
+ workout_type = st.selectbox("Choose workout type", ["full_body", "cardio", "strength", "flexibility"])
164
+ plan = get_workout_plan(workout_type)
165
+ for step in plan:
166
+ st.write(f"- {step}")
167
+
168
+ elif menu == "Home Remedies":
169
+ st.subheader("🌿 Traditional Remedies from Wikibooks")
170
+ remedies = get_wikibooks_remedies()
171
+ for title, desc in remedies:
172
+ st.markdown(f"**{title}** – {desc}")
173
+
174
+ elif menu == "Did You Know?":
175
+ st.subheader("❓ Fun Health Facts from Wikipedia")
176
+ st.info(get_did_you_know_fact())
177
+
178
+ elif menu == "Fitness Quiz":
179
+ st.subheader("🧠 Quick Fitness Quiz")
180
+ q, options, answer = generate_quiz()
181
+ user_answer = st.radio(q, options)
182
+ if st.button("Submit"):
183
+ if user_answer == answer:
184
+ st.success("Correct! ✅")
185
+ else:
186
+ st.error(f"Incorrect. The right answer is {answer}.")
187
+
188
+ elif menu == "BMI Calculator":
189
+ st.subheader("📊 BMI Calculator")
190
+
191
+ col1, col2 = st.columns(2)
192
+
193
+ with col1:
194
+ weight = st.number_input("Weight (kg)", min_value=0.0, max_value=300.0, value=70.0, step=0.1)
195
+
196
+ with col2:
197
+ unit = st.selectbox("Height unit", ["m", "cm", "ft"], index=0)
198
+
199
+ if unit == "m":
200
+ height = st.number_input("Height (m)", min_value=0.0, max_value=3.0, value=1.70, step=0.01)
201
+ elif unit == "cm":
202
+ height = st.number_input("Height (cm)", min_value=0.0, max_value=300.0, value=170.0, step=1.0)
203
+ else: # ft
204
+ height = st.number_input("Height (ft.in)",
205
+ min_value=0.0,
206
+ max_value=8.0,
207
+ value=5.6,
208
+ step=0.1,
209
+ help="Enter feet as whole number and inches as decimal (e.g., 5.6 for 5'6\")")
210
+
211
+ if st.button("Calculate BMI"):
212
+ bmi_value, bmi_category = calculate_bmi(weight, height, unit)
213
+
214
+ if bmi_value and bmi_category:
215
+ st.info(f"Your BMI: **{bmi_value}**")
216
+
217
+ # Color coding for BMI categories
218
+ if bmi_category == "Underweight":
219
+ st.warning(f"Category: **{bmi_category}**")
220
+ elif bmi_category == "Normal weight":
221
+ st.success(f"Category: **{bmi_category}**")
222
+ elif bmi_category == "Overweight":
223
+ st.warning(f"Category: **{bmi_category}**")
224
+ else:
225
+ st.error(f"Category: **{bmi_category}**")
226
+
227
+ st.write("BMI Categories:")
228
+ st.write("- Underweight: < 18.5")
229
+ st.write("- Normal weight: 18.5–24.9")
230
+ st.write("- Overweight: 25–29.9")
231
+ st.write("- Obese: ≥ 30")
src/requirements.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Core dependencies - required for both versions
2
+ numpy==1.24.3 # Fixed version to avoid compatibility issues
3
+ pandas==2.0.3 # For data manipulation and charts
4
+ streamlit==1.30.0 # Web app framework
5
+ requests==2.31.0 # For API calls to Wikimedia services
6
+
7
+ # AI feature dependencies (optional - required for full version)
8
+ transformers==4.36.2 # Hugging Face transformers for AI Q&A
9
+ torch==2.1.2 # PyTorch for transformer models
10
+
11
+ # Additional dependencies that might be useful (uncomment if needed)
12
+ # matplotlib==3.7.2 # For additional custom charts
13
+ # scikit-learn==1.3.0 # For potential future ML features
14
+ # plotly==5.15.0 # For interactive charts
src/wiki.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ WikiFit - Wiki API Helper Functions
3
+
4
+ This file serves as a backward-compatible adapter between the old direct API calls
5
+ and the new wikimedia module structure. It imports and re-exports all the relevant
6
+ functions from the wikimedia module.
7
+ """
8
+
9
+ from wikimedia import (
10
+ get_wikipedia_summary,
11
+ get_wiktionary_definition,
12
+ get_wikiquote_quotes,
13
+ get_wikibooks_content,
14
+ get_wikimedia_commons_images,
15
+ get_wikisource_texts,
16
+ get_wikiversity_resources,
17
+ get_wikispecies_info,
18
+ get_wikidata_health_info,
19
+ search_all_wikimedia
20
+ )
21
+
22
+ # Re-export all functions (for backward compatibility)
23
+ __all__ = [
24
+ 'get_wikipedia_summary',
25
+ 'get_wiktionary_definition',
26
+ 'get_wikiquote_quotes',
27
+ 'get_wikibooks_content',
28
+ 'get_wikimedia_commons_images',
29
+ 'get_wikisource_texts',
30
+ 'get_wikiversity_resources',
31
+ 'get_wikispecies_info',
32
+ 'get_wikidata_health_info',
33
+ 'search_all_wikimedia'
34
+ ]
src/wikifit_basic.py ADDED
@@ -0,0 +1,284 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import random
3
+ from datetime import datetime
4
+ import wikimedia # Import our Wikimedia module
5
+
6
+ # Setup page config
7
+ st.set_page_config(page_title="WikiFit Basic", page_icon="💪")
8
+ st.title("💪 WikiFit Basic – Health & Fitness App")
9
+
10
+ # -------------------------------
11
+ # Utility Functions
12
+ # -------------------------------
13
+
14
+ def get_wikipedia_summary(term):
15
+ """Get summary from Wikipedia API with error handling"""
16
+ try:
17
+ return wikimedia.get_wikipedia_summary(term)
18
+ except Exception as e:
19
+ st.error(f"Request error: {str(e)}")
20
+ return "Connection error. Please try again later."
21
+
22
+ def get_random_health_tip():
23
+ """Return a random health tip with seasonal awareness"""
24
+ # Get current month to provide seasonal tips
25
+ current_month = datetime.now().month
26
+
27
+ # Base tips that apply all year
28
+ base_tips = [
29
+ "Drink at least 2 liters of water every day.",
30
+ "Do at least 30 minutes of physical activity daily.",
31
+ "Maintain a regular sleep schedule.",
32
+ "Include fruits and vegetables in every meal.",
33
+ "Take short breaks during long sitting hours.",
34
+ "Practice mindfulness meditation for 10 minutes daily.",
35
+ "Reduce sodium intake to help control blood pressure.",
36
+ "Limit screen time before bedtime for better sleep.",
37
+ "Choose whole grains over refined carbohydrates.",
38
+ "Incorporate strength training at least twice a week."
39
+ ]
40
+
41
+ # Seasonal tips
42
+ seasonal_tips = {
43
+ # Winter (Dec-Feb)
44
+ "winter": [
45
+ "Increase vitamin D intake during winter months.",
46
+ "Stay hydrated even when it's cold.",
47
+ "Wash hands frequently to prevent seasonal colds and flu."
48
+ ],
49
+ # Spring (Mar-May)
50
+ "spring": [
51
+ "Consider seasonal allergy preparations before symptoms start.",
52
+ "Spring clean your diet - add fresh seasonal produce.",
53
+ "Gradually increase outdoor exercise as weather improves."
54
+ ],
55
+ # Summer (Jun-Aug)
56
+ "summer": [
57
+ "Apply sunscreen 30 minutes before sun exposure.",
58
+ "Stay extra hydrated during hot days.",
59
+ "Exercise during cooler parts of the day to avoid heat exhaustion."
60
+ ],
61
+ # Fall (Sep-Nov)
62
+ "fall": [
63
+ "Boost immune system as cold and flu season approaches.",
64
+ "Adjust exercise routines for cooling temperatures.",
65
+ "Incorporate seasonal produce like pumpkins and apples."
66
+ ]
67
+ }
68
+
69
+ # Determine current season
70
+ if current_month in [12, 1, 2]:
71
+ season = "winter"
72
+ elif current_month in [3, 4, 5]:
73
+ season = "spring"
74
+ elif current_month in [6, 7, 8]:
75
+ season = "summer"
76
+ else: # 9, 10, 11
77
+ season = "fall"
78
+
79
+ # Combine base tips with seasonal tips
80
+ all_tips = base_tips + seasonal_tips[season]
81
+ return random.choice(all_tips)
82
+
83
+ def get_workout_plan(workout_type="full_body"):
84
+ """Get workout plan based on workout type"""
85
+ workouts = {
86
+ "full_body": [
87
+ "10 Jumping Jacks",
88
+ "10 Push-ups",
89
+ "15 Squats",
90
+ "20-second Plank",
91
+ "10 Lunges (each leg)",
92
+ "Repeat 3 times"
93
+ ],
94
+ "cardio": [
95
+ "30 seconds Jumping Jacks",
96
+ "30 seconds High Knees",
97
+ "30 seconds Butt Kicks",
98
+ "30 seconds Mountain Climbers",
99
+ "30 seconds rest",
100
+ "Repeat 4 times"
101
+ ],
102
+ "strength": [
103
+ "12 Push-ups",
104
+ "15 Squats with 5 second hold",
105
+ "10 Tricep Dips",
106
+ "10 Glute Bridges",
107
+ "8 Superman Holds",
108
+ "Repeat 3 times"
109
+ ],
110
+ "flexibility": [
111
+ "30 seconds Hamstring Stretch",
112
+ "30 seconds Quad Stretch (each leg)",
113
+ "30 seconds Child's Pose",
114
+ "30 seconds Cat-Cow Stretch",
115
+ "30 seconds Butterfly Stretch",
116
+ "Repeat 2 times"
117
+ ]
118
+ }
119
+ return workouts.get(workout_type, workouts["full_body"])
120
+
121
+ def get_did_you_know_fact():
122
+ """Return a random health fact"""
123
+ facts = [
124
+ "The human body has 206 bones.",
125
+ "Your heart beats about 100,000 times a day.",
126
+ "The skin is the body's largest organ.",
127
+ "The brain uses around 20% of the body's oxygen.",
128
+ "Laughter is good for your heart and can reduce stress.",
129
+ "Adults have fewer bones than babies. Babies are born with 300 bones, but some fuse together.",
130
+ "The strongest muscle in your body is your masseter (jaw muscle)."
131
+ ]
132
+ return random.choice(facts)
133
+
134
+ def calculate_bmi(weight, height, unit="m"):
135
+ """Calculate BMI based on weight and height"""
136
+ if weight <= 0 or height <= 0:
137
+ return None, None
138
+
139
+ # Convert height to meters for calculation
140
+ if unit == "cm":
141
+ height = height / 100.0
142
+ elif unit == "ft":
143
+ feet_whole = int(height)
144
+ inches = (height - feet_whole) * 10
145
+ height = feet_whole * 0.3048 + inches * 0.0254
146
+
147
+ bmi = weight / (height ** 2)
148
+
149
+ if bmi < 18.5:
150
+ category = "Underweight"
151
+ elif 18.5 <= bmi < 25:
152
+ category = "Normal weight"
153
+ elif 25 <= bmi < 30:
154
+ category = "Overweight"
155
+ else:
156
+ category = "Obese"
157
+
158
+ return round(bmi, 2), category
159
+
160
+ # -------------------------------
161
+ # UI
162
+ # -------------------------------
163
+
164
+ # Initialize session state
165
+ if 'workout_completed' not in st.session_state:
166
+ st.session_state.workout_completed = 0
167
+ if 'quiz_score' not in st.session_state:
168
+ st.session_state.quiz_score = 0
169
+
170
+ # Get time of day for personalized welcome
171
+ current_hour = datetime.now().hour
172
+ if 5 <= current_hour < 12:
173
+ greeting = "Good morning"
174
+ elif 12 <= current_hour < 17:
175
+ greeting = "Good afternoon"
176
+ else:
177
+ greeting = "Good evening"
178
+
179
+ # Welcome message in the sidebar
180
+ st.sidebar.markdown(f"### {greeting}!")
181
+ st.sidebar.markdown("Welcome to WikiFit, your personal health assistant.")
182
+
183
+ # Display current date
184
+ st.sidebar.markdown(f"**Today**: {datetime.now().strftime('%B %d, %Y')}")
185
+
186
+ # Navigation sidebar
187
+ menu = st.sidebar.selectbox("Navigate", [
188
+ "Daily Tip",
189
+ "Health Search",
190
+ "Workout Plans",
191
+ "Home Remedies",
192
+ "Did You Know?",
193
+ "BMI Calculator"
194
+ ])
195
+
196
+ st.sidebar.info("This is the basic version of WikiFit that works without advanced dependencies.")
197
+ st.sidebar.markdown("To access AI features and the Knowledge Center, [install the required packages](https://github.com/your-username/wikifit#installation) and run `ai.py`.")
198
+
199
+ # Page content based on menu selection
200
+ if menu == "Daily Tip":
201
+ st.subheader("📆 Daily Fitness/Nutrition Tip")
202
+ st.success(get_random_health_tip())
203
+
204
+ elif menu == "Health Search":
205
+ st.subheader("🔍 Search Health Info from Wikipedia")
206
+ query = st.text_input("Enter a health topic (e.g., Vitamin D, Yoga)")
207
+ if query:
208
+ with st.spinner("Searching..."):
209
+ result = get_wikipedia_summary(query.replace(" ", "_"))
210
+ st.info(result)
211
+
212
+ elif menu == "Workout Plans":
213
+ st.subheader("🏋️‍♀️ Basic Workout Plans")
214
+ workout_type = st.selectbox("Choose workout type", ["full_body", "cardio", "strength", "flexibility"])
215
+ plan = get_workout_plan(workout_type)
216
+ for step in plan:
217
+ st.write(f"- {step}")
218
+
219
+ if st.button("Mark as Completed"):
220
+ st.session_state.workout_completed += 1
221
+ st.success(f"Great job! You've completed {st.session_state.workout_completed} workouts.")
222
+
223
+ elif menu == "Home Remedies":
224
+ st.subheader("🌿 Traditional Remedies")
225
+ remedies = [
226
+ ("Turmeric Milk", "Used for colds and inflammation."),
227
+ ("Honey & Ginger", "Relieves sore throat and cough."),
228
+ ("Amla Juice", "Boosts immunity and rich in Vitamin C."),
229
+ ("Mint Tea", "Aids digestion and relieves headaches.")
230
+ ]
231
+ for title, desc in remedies:
232
+ st.markdown(f"**{title}** – {desc}")
233
+
234
+ elif menu == "Did You Know?":
235
+ st.subheader("❓ Fun Health Facts")
236
+ st.info(get_did_you_know_fact())
237
+
238
+ elif menu == "BMI Calculator":
239
+ st.subheader("📊 BMI Calculator")
240
+
241
+ col1, col2 = st.columns(2)
242
+
243
+ with col1:
244
+ weight = st.number_input("Weight (kg)", min_value=0.0, max_value=300.0, value=70.0, step=0.1)
245
+
246
+ with col2:
247
+ unit = st.selectbox("Height unit", ["m", "cm", "ft"], index=0)
248
+
249
+ if unit == "m":
250
+ height = st.number_input("Height (m)", min_value=0.0, max_value=3.0, value=1.70, step=0.01)
251
+ elif unit == "cm":
252
+ height = st.number_input("Height (cm)", min_value=0.0, max_value=300.0, value=170.0, step=1.0)
253
+ else: # ft
254
+ height = st.number_input("Height (ft.in)",
255
+ min_value=0.0,
256
+ max_value=8.0,
257
+ value=5.6,
258
+ step=0.1,
259
+ help="Enter feet as whole number and inches as decimal (e.g., 5.6 for 5'6\")")
260
+
261
+ if st.button("Calculate BMI"):
262
+ bmi_value, bmi_category = calculate_bmi(weight, height, unit)
263
+
264
+ if bmi_value and bmi_category:
265
+ st.info(f"Your BMI: **{bmi_value}**")
266
+
267
+ if bmi_category == "Underweight":
268
+ st.warning(f"Category: **{bmi_category}**")
269
+ elif bmi_category == "Normal weight":
270
+ st.success(f"Category: **{bmi_category}**")
271
+ elif bmi_category == "Overweight":
272
+ st.warning(f"Category: **{bmi_category}**")
273
+ else:
274
+ st.error(f"Category: **{bmi_category}**")
275
+
276
+ st.write("BMI Categories:")
277
+ st.write("- Underweight: < 18.5")
278
+ st.write("- Normal weight: 18.5–24.9")
279
+ st.write("- Overweight: 25–29.9")
280
+ st.write("- Obese: ≥ 30")
281
+
282
+ # Footer
283
+ st.sidebar.markdown("---")
284
+ st.sidebar.markdown(f"© WikiFit {datetime.now().year}")
src/wikimedia.cpython-313.pyc ADDED
Binary file (16.2 kB). View file
 
src/wikimedia.py ADDED
@@ -0,0 +1,430 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ WikiFit - Wikimedia API Integration Module
3
+
4
+ This module provides functions to interact with various Wikimedia APIs
5
+ to retrieve health and fitness information.
6
+ """
7
+
8
+ import requests
9
+ import logging
10
+
11
+ # Setup logging
12
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
13
+
14
+ # Cache durations (in seconds)
15
+ CACHE_TTL = 3600 # 1 hour
16
+
17
+
18
+ def get_wikipedia_summary(term):
19
+ """
20
+ Get a summary of a topic from Wikipedia.
21
+
22
+ Args:
23
+ term: The search term/topic
24
+
25
+ Returns:
26
+ str: Summary text or error message
27
+ """
28
+ try:
29
+ url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{term}"
30
+ response = requests.get(url, timeout=10)
31
+ if response.status_code == 200:
32
+ data = response.json()
33
+ extract = data.get("extract", "")
34
+ if not extract:
35
+ # Check if we have an alternative like disambiguation
36
+ if data.get("type") == "disambiguation":
37
+ return f"'{term}' refers to multiple topics. Please try a more specific search term."
38
+ return "No summary found. This topic might not have an article on Wikipedia yet."
39
+ return extract
40
+ elif response.status_code == 404:
41
+ return f"The topic '{term}' was not found on Wikipedia. Please check spelling or try another term."
42
+ else:
43
+ logging.error(f"Wikipedia API error: {response.status_code} for term '{term}'")
44
+ return f"Error retrieving information: HTTP {response.status_code}"
45
+ except requests.RequestException as e:
46
+ logging.error(f"Wikipedia request error for '{term}': {str(e)}")
47
+ return "Connection error. Please check your internet connection and try again later."
48
+
49
+
50
+ def get_wiktionary_definition(term):
51
+ """Get word definitions from Wiktionary"""
52
+ try:
53
+ url = "https://en.wiktionary.org/w/api.php"
54
+ params = {
55
+ "action": "query",
56
+ "format": "json",
57
+ "titles": term,
58
+ "prop": "extracts",
59
+ "exsectionformat": "plain",
60
+ "exsentences": 5,
61
+ "explaintext": True
62
+ }
63
+ response = requests.get(url, params=params, timeout=10)
64
+
65
+ if response.status_code == 200:
66
+ data = response.json()
67
+ pages = data.get("query", {}).get("pages", {})
68
+
69
+ # Extract the first page content (there should only be one)
70
+ for page_id in pages:
71
+ if "extract" in pages[page_id]:
72
+ return pages[page_id]["extract"]
73
+
74
+ return "No definition found."
75
+ else:
76
+ return f"Error retrieving definition: HTTP {response.status_code}"
77
+ except requests.RequestException as e:
78
+ logging.error(f"Wiktionary request error: {str(e)}")
79
+ return "Connection error. Please try again later."
80
+
81
+
82
+ def get_wikiquote_quotes(term):
83
+ """Get quotes related to a topic from Wikiquote"""
84
+ try:
85
+ url = "https://en.wikiquote.org/w/api.php"
86
+ params = {
87
+ "action": "query",
88
+ "format": "json",
89
+ "titles": term,
90
+ "prop": "extracts",
91
+ "exsentences": 5,
92
+ "explaintext": True
93
+ }
94
+ response = requests.get(url, params=params, timeout=10)
95
+
96
+ if response.status_code == 200:
97
+ data = response.json()
98
+ pages = data.get("query", {}).get("pages", {})
99
+
100
+ # Extract the first page content (there should only be one)
101
+ for page_id in pages:
102
+ if int(page_id) > 0 and "extract" in pages[page_id]: # Skip missing pages
103
+ content = pages[page_id]["extract"].strip()
104
+ if content:
105
+ return content
106
+
107
+ return "No quotes found for this topic."
108
+ else:
109
+ return f"Error retrieving quotes: HTTP {response.status_code}"
110
+ except requests.RequestException as e:
111
+ logging.error(f"Wikiquote request error: {str(e)}")
112
+ return "Connection error. Please try again later."
113
+
114
+
115
+ def get_wikibooks_content(term):
116
+ """Get educational content from Wikibooks"""
117
+ try:
118
+ url = "https://en.wikibooks.org/w/api.php"
119
+ params = {
120
+ "action": "query",
121
+ "format": "json",
122
+ "titles": term,
123
+ "prop": "extracts",
124
+ "exsentences": 10,
125
+ "explaintext": True
126
+ }
127
+ response = requests.get(url, params=params, timeout=10)
128
+
129
+ if response.status_code == 200:
130
+ data = response.json()
131
+ pages = data.get("query", {}).get("pages", {})
132
+
133
+ # Extract the first page content
134
+ for page_id in pages:
135
+ if int(page_id) > 0 and "extract" in pages[page_id]:
136
+ return pages[page_id]["extract"]
137
+
138
+ return "No Wikibooks content found for this topic."
139
+ else:
140
+ return f"Error retrieving content: HTTP {response.status_code}"
141
+ except requests.RequestException as e:
142
+ logging.error(f"Wikibooks request error: {str(e)}")
143
+ return "Connection error. Please try again later."
144
+
145
+
146
+ def get_wikimedia_commons_images(term, limit=5):
147
+ """Get relevant images from Wikimedia Commons"""
148
+ try:
149
+ url = "https://commons.wikimedia.org/w/api.php"
150
+ params = {
151
+ "action": "query",
152
+ "format": "json",
153
+ "list": "search",
154
+ "srsearch": f"{term} haswbstatement:P180={term}", # Search for images with the term as subject
155
+ "srnamespace": 6, # File namespace
156
+ "srlimit": limit
157
+ }
158
+ response = requests.get(url, params=params, timeout=10)
159
+
160
+ if response.status_code == 200:
161
+ data = response.json()
162
+ search_results = data.get("query", {}).get("search", [])
163
+
164
+ image_titles = []
165
+ for result in search_results:
166
+ if "title" in result:
167
+ image_titles.append(result["title"])
168
+
169
+ # If we found images, get their URLs
170
+ image_data = []
171
+ if image_titles:
172
+ file_titles = "|".join(image_titles)
173
+ image_params = {
174
+ "action": "query",
175
+ "format": "json",
176
+ "titles": file_titles,
177
+ "prop": "imageinfo",
178
+ "iiprop": "url|extmetadata",
179
+ "iiurlwidth": 300 # Thumbnail width
180
+ }
181
+ img_response = requests.get(url, params=image_params, timeout=10)
182
+ if img_response.status_code == 200:
183
+ img_data = img_response.json()
184
+ pages = img_data.get("query", {}).get("pages", {})
185
+
186
+ for page_id in pages:
187
+ page = pages[page_id]
188
+ if "imageinfo" in page and page["imageinfo"]:
189
+ info = page["imageinfo"][0]
190
+ title = page.get("title", "").replace("File:", "")
191
+ thumb_url = info.get("thumburl", "")
192
+ description = info.get("extmetadata", {}).get("ImageDescription", {}).get("value", "")
193
+
194
+ # Clean HTML from description
195
+ description = description.replace("<p>", "").replace("</p>", "")
196
+
197
+ if thumb_url:
198
+ image_data.append({
199
+ "title": title,
200
+ "url": thumb_url,
201
+ "description": description
202
+ })
203
+
204
+ return image_data
205
+ else:
206
+ logging.error(f"Wikimedia Commons API error: {response.status_code} for term '{term}'")
207
+ return []
208
+ except requests.RequestException as e:
209
+ logging.error(f"Wikimedia Commons request error: {str(e)}")
210
+ return []
211
+
212
+
213
+ def get_wikisource_texts(term):
214
+ """Get health-related texts from Wikisource"""
215
+ try:
216
+ url = "https://en.wikisource.org/w/api.php"
217
+ params = {
218
+ "action": "query",
219
+ "format": "json",
220
+ "list": "search",
221
+ "srsearch": term,
222
+ "srlimit": 3
223
+ }
224
+ response = requests.get(url, params=params, timeout=10)
225
+
226
+ if response.status_code == 200:
227
+ data = response.json()
228
+ search_results = data.get("query", {}).get("search", [])
229
+
230
+ text_data = []
231
+ for result in search_results:
232
+ title = result.get("title", "")
233
+ snippet = result.get("snippet", "").replace("<span class=\"searchmatch\">", "").replace("</span>", "")
234
+ text_data.append({
235
+ "title": title,
236
+ "snippet": snippet
237
+ })
238
+
239
+ return text_data
240
+ else:
241
+ logging.error(f"Wikisource API error: {response.status_code} for term '{term}'")
242
+ return []
243
+ except requests.RequestException as e:
244
+ logging.error(f"Wikisource request error: {str(e)}")
245
+ return []
246
+
247
+
248
+ def get_wikiversity_resources(term):
249
+ """Get educational resources from Wikiversity"""
250
+ try:
251
+ url = "https://en.wikiversity.org/w/api.php"
252
+ params = {
253
+ "action": "query",
254
+ "format": "json",
255
+ "titles": term,
256
+ "prop": "extracts",
257
+ "exsentences": 5,
258
+ "explaintext": True
259
+ }
260
+ response = requests.get(url, params=params, timeout=10)
261
+
262
+ if response.status_code == 200:
263
+ data = response.json()
264
+ pages = data.get("query", {}).get("pages", {})
265
+
266
+ # Extract the first page content
267
+ for page_id in pages:
268
+ if int(page_id) > 0 and "extract" in pages[page_id]:
269
+ return pages[page_id]["extract"]
270
+
271
+ return "No Wikiversity resources found for this topic."
272
+ else:
273
+ return f"Error retrieving resources: HTTP {response.status_code}"
274
+ except requests.RequestException as e:
275
+ logging.error(f"Wikiversity request error: {str(e)}")
276
+ return "Connection error. Please try again later."
277
+
278
+
279
+ def get_wikispecies_info(species_name):
280
+ """Get species information from Wikispecies"""
281
+ try:
282
+ url = "https://species.wikimedia.org/w/api.php"
283
+ params = {
284
+ "action": "query",
285
+ "format": "json",
286
+ "titles": species_name,
287
+ "prop": "extracts",
288
+ "explaintext": True
289
+ }
290
+ response = requests.get(url, params=params, timeout=10)
291
+
292
+ if response.status_code == 200:
293
+ data = response.json()
294
+ pages = data.get("query", {}).get("pages", {})
295
+
296
+ # Extract the first page content
297
+ for page_id in pages:
298
+ if int(page_id) > 0 and "extract" in pages[page_id]:
299
+ return pages[page_id]["extract"]
300
+
301
+ return "No species information found."
302
+ else:
303
+ return f"Error retrieving species information: HTTP {response.status_code}"
304
+ except requests.RequestException as e:
305
+ logging.error(f"Wikispecies request error: {str(e)}")
306
+ return "Connection error. Please try again later."
307
+
308
+
309
+ def get_wikidata_health_info(term):
310
+ """Get structured health data from Wikidata"""
311
+ try:
312
+ # First, find the Wikidata ID for the term
313
+ url = "https://www.wikidata.org/w/api.php"
314
+ params = {
315
+ "action": "wbsearchentities",
316
+ "format": "json",
317
+ "search": term,
318
+ "language": "en"
319
+ }
320
+ response = requests.get(url, params=params, timeout=10)
321
+
322
+ if response.status_code == 200:
323
+ data = response.json()
324
+ search_results = data.get("search", [])
325
+
326
+ if not search_results:
327
+ return "No Wikidata information found for this term."
328
+
329
+ # Get the first result's ID
330
+ entity_id = search_results[0].get("id")
331
+
332
+ # Now get the entity data
333
+ entity_params = {
334
+ "action": "wbgetentities",
335
+ "format": "json",
336
+ "ids": entity_id,
337
+ "languages": "en"
338
+ }
339
+ entity_response = requests.get(url, params=entity_params, timeout=10)
340
+
341
+ if entity_response.status_code == 200:
342
+ entity_data = entity_response.json()
343
+ entities = entity_data.get("entities", {})
344
+
345
+ if entity_id in entities:
346
+ entity = entities[entity_id]
347
+
348
+ # Extract label and description
349
+ label = entity.get("labels", {}).get("en", {}).get("value", "No label")
350
+ description = entity.get("descriptions", {}).get("en", {}).get("value", "No description")
351
+
352
+ # Extract some claims/properties
353
+ claims = entity.get("claims", {})
354
+ properties = {}
355
+
356
+ # Common health-related properties
357
+ property_map = {
358
+ "P2175": "medical condition treated",
359
+ "P2176": "drug used for treatment",
360
+ "P780": "symptoms",
361
+ "P1050": "medical condition",
362
+ "P1995": "health specialty"
363
+ }
364
+
365
+ for prop_id, prop_name in property_map.items():
366
+ if prop_id in claims:
367
+ values = []
368
+ for claim in claims[prop_id]:
369
+ mainsnak = claim.get("mainsnak", {})
370
+ if mainsnak.get("datatype") == "wikibase-item" and "datavalue" in mainsnak:
371
+ value_id = mainsnak["datavalue"]["value"]["id"]
372
+ values.append(value_id)
373
+
374
+ if values:
375
+ properties[prop_name] = values
376
+
377
+ return {
378
+ "label": label,
379
+ "description": description,
380
+ "properties": properties
381
+ }
382
+
383
+ return "No detailed Wikidata information available."
384
+ else:
385
+ logging.error(f"Wikidata API error: {response.status_code} for term '{term}'")
386
+ return f"Error retrieving Wikidata: HTTP {response.status_code}"
387
+ except requests.RequestException as e:
388
+ logging.error(f"Wikidata request error: {str(e)}")
389
+ return "Connection error. Please try again later."
390
+
391
+
392
+ # Add a unified search function to search across all Wikimedia platforms
393
+ def search_all_wikimedia(term):
394
+ """
395
+ Search for a term across all Wikimedia platforms.
396
+
397
+ Args:
398
+ term: Search term
399
+
400
+ Returns:
401
+ dict: Results from all Wikimedia sources
402
+ """
403
+ # Normalize the term
404
+ search_term = term.strip().replace(" ", "_")
405
+
406
+ # Create a results dictionary
407
+ results = {
408
+ "wikipedia": None,
409
+ "wiktionary": None,
410
+ "wikiquote": None,
411
+ "wikibooks": None,
412
+ "commons": None,
413
+ "wikisource": None,
414
+ "wikiversity": None,
415
+ "wikispecies": None,
416
+ "wikidata": None
417
+ }
418
+
419
+ # Get results from each platform
420
+ results["wikipedia"] = get_wikipedia_summary(search_term)
421
+ results["wiktionary"] = get_wiktionary_definition(search_term)
422
+ results["wikiquote"] = get_wikiquote_quotes(search_term)
423
+ results["wikibooks"] = get_wikibooks_content(search_term)
424
+ results["commons"] = get_wikimedia_commons_images(search_term)
425
+ results["wikisource"] = get_wikisource_texts(search_term)
426
+ results["wikiversity"] = get_wikiversity_resources(search_term)
427
+ results["wikispecies"] = get_wikispecies_info(search_term)
428
+ results["wikidata"] = get_wikidata_health_info(search_term)
429
+
430
+ return results