ChakriYamasani commited on
Commit
832cd2c
·
verified ·
1 Parent(s): debd75a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +199 -191
app.py CHANGED
@@ -11,7 +11,7 @@ from helpers import (
11
  text_to_speech, speech_to_text, geocode_location,
12
  export_to_jsonl, export_to_csv, search_entries,
13
  register_user, authenticate_user, get_user_info, update_user_entry_count,
14
- translate_text, detect_language
15
  )
16
 
17
  # Set page config
@@ -29,66 +29,68 @@ if 'authenticated' not in st.session_state:
29
  st.session_state.authenticated = False
30
  if 'username' not in st.session_state:
31
  st.session_state.username = None
 
 
 
 
 
 
 
 
 
 
 
32
 
33
  # --- AUTHENTICATION PAGE ---
34
  if not st.session_state.authenticated:
35
- st.title("🌾 Welcome to the Farming Wisdom Archive")
36
- st.markdown("#### *Preserving Traditional Indian Farming Knowledge for Future Generations*")
37
  st.markdown("---")
38
-
39
  col1, col2 = st.columns([1, 1])
40
-
41
  with col1:
42
  st.image("https://images.pexels.com/photos/265216/pexels-photo-265216.jpeg",
43
  caption="Photo by Pixabay", use_container_width=True)
44
- st.markdown("""
45
- ### About This Platform
46
- This archive is a community-driven effort to document and share the rich, time-tested farming practices of India. By contributing, you help create a valuable open-source corpus for agricultural research and AI.
47
- """)
48
-
49
  with col2:
50
- tab1, tab2 = st.tabs(["**Login**", "**Register**"])
51
-
52
  with tab1:
53
- st.subheader("Login to Your Account")
54
  with st.form("login_form"):
55
- username = st.text_input("Username")
56
- password = st.text_input("Password", type="password")
57
- login_button = st.form_submit_button("Login", type="primary", use_container_width=True)
58
-
59
  if login_button:
60
  if username and password:
61
  if authenticate_user(username, password):
62
  st.session_state.authenticated = True
63
  st.session_state.username = username
64
- st.success("Login successful!")
65
  st.rerun()
66
  else:
67
- st.error("Invalid username or password")
68
  else:
69
- st.error("Please enter both username and password")
70
-
71
  with tab2:
72
- st.subheader("Join Our Community")
73
  with st.form("register_form"):
74
- full_name = st.text_input("Full Name")
75
- email = st.text_input("Email")
76
- reg_username = st.text_input("Choose Username")
77
- reg_password = st.text_input("Choose Password", type="password")
78
- confirm_password = st.text_input("Confirm Password", type="password")
79
- register_button = st.form_submit_button("Register", type="primary", use_container_width=True)
80
-
81
  if register_button:
82
  if full_name and email and reg_username and reg_password and confirm_password:
83
  if reg_password == confirm_password:
84
  if register_user(reg_username, email, reg_password, full_name):
85
- st.success("Registration successful! Please login.")
86
  else:
87
- st.error("Username or Email may already exist.")
88
  else:
89
- st.error("Passwords do not match")
90
  else:
91
- st.error("Please fill in all fields")
92
  st.stop()
93
 
94
  # --- MAIN APPLICATION (FOR AUTHENTICATED USERS) ---
@@ -97,131 +99,138 @@ user_info = get_user_info(st.session_state.username)
97
  # App header with user info
98
  col1, col2 = st.columns([3, 1])
99
  with col1:
100
- st.title("🌾 Farming Wisdom Archive")
101
  with col2:
102
  st.markdown(f"""
103
  <div style="text-align: right;">
104
- Welcome, <strong>{user_info.get('full_name', st.session_state.username)}</strong>!<br>
105
- <small>Entries Submitted: {user_info.get('entries_submitted', 0)}</small>
106
  </div>
107
  """, unsafe_allow_html=True)
108
- if st.button("Logout", use_container_width=True):
109
  st.session_state.authenticated = False
110
  st.session_state.username = None
111
  st.rerun()
112
 
113
  # --- NAVIGATION LOGIC ---
114
- st.sidebar.title("Navigation")
115
  def set_page(page_name):
116
  st.session_state.page_selection = page_name
117
 
118
- page_options = [
119
- "🏠 Home", "✍️ Submit Wisdom", "📖 Browse Knowledge",
120
- "🗺️ Knowledge Map", "🔍 Search", "🌐 Translation Hub",
121
- "📊 Export Data", "👤 Profile"
122
- ]
123
- page = st.sidebar.radio(
 
 
 
 
 
 
 
 
 
124
  "Go to",
125
  page_options,
126
  key="page_selection",
127
  label_visibility="collapsed"
128
  )
 
 
 
129
 
130
  # --- Home Page ---
131
- if page == "🏠 Home":
132
- st.header("🏠 Home Dashboard")
133
  st.markdown("---")
134
-
135
  with st.container(border=True):
136
- st.subheader("📊 Archive Statistics")
137
  total_entries = len(st.session_state.entries)
138
  languages = len(set(entry.get('language', 'Unknown') for entry in st.session_state.entries))
139
  categories = len(set(entry.get('category', 'Unknown') for entry in st.session_state.entries))
140
 
141
  stat_cols = st.columns(3)
142
- stat_cols[0].metric("Total Farming Entries", total_entries)
143
- stat_cols[1].metric("Languages Represented", languages)
144
- stat_cols[2].metric("Farming Categories", categories)
145
 
146
- st.markdown("### 🚀 Getting Started")
147
  gs_cols = st.columns(3)
148
  with gs_cols[0]:
149
  with st.container(border=True, height=180):
150
- st.markdown("#### ✍️ Share Knowledge")
151
- st.markdown("Contribute your traditional farming knowledge to the archive.")
152
- st.button("Share Now", on_click=set_page, args=("✍️ Submit Wisdom",), use_container_width=True)
153
  with gs_cols[1]:
154
  with st.container(border=True, height=180):
155
- st.markdown("#### 📖 Explore Entries")
156
- st.markdown("Explore wisdom shared by farmers from all across India.")
157
- st.button("Explore Now", on_click=set_page, args=("📖 Browse Knowledge",), use_container_width=True)
158
  with gs_cols[2]:
159
  with st.container(border=True, height=180):
160
- st.markdown("#### 🗺️ Discover on Map")
161
- st.markdown("Find location-specific farming practices on our interactive map.")
162
- st.button("View Map", on_click=set_page, args=("🗺️ Knowledge Map",), use_container_width=True)
163
 
164
- # --- Submit Wisdom Page (CORRECTED) ---
165
- elif page == "✍️ Submit Wisdom":
166
- st.header("✍️ Submit New Farming Wisdom")
167
- st.markdown("Follow the steps below to contribute. Fields marked with `*` are required.")
168
 
169
  if 'form_data' not in st.session_state:
170
  st.session_state.form_data = {
171
- 'title': '', 'description': '', 'language': 'English', 'category': 'Other', # CORRECTED default value
172
  'location_name': '', 'manual_lat': 20.5937, 'manual_lon': 78.9629
173
  }
174
 
175
- # --- STEP 1: HELPER TOOLS (OUTSIDE THE FORM) ---
176
- st.subheader("Step 1: Use Helper Tools (Optional)")
177
  with st.container(border=True):
178
- st.markdown("**Pin a Location on the Map**")
179
- st.caption("Search for a location to automatically get its coordinates, which will update the map in the form below.")
180
  geocode_cols = st.columns([3, 1])
181
- geocode_input = geocode_cols[0].text_input("Search for a place (e.g., Hyderabad, Telangana)", label_visibility="collapsed")
182
- if geocode_cols[1].button("📍 Find Location", use_container_width=True):
183
  if geocode_input:
184
  coords = geocode_location(geocode_input)
185
  if coords:
186
  st.session_state.form_data['manual_lat'], st.session_state.form_data['manual_lon'] = coords
187
- st.success(f"Found and pinned: {geocode_input}")
188
  else:
189
- st.error(f"Could not find coordinates for '{geocode_input}'")
190
 
191
  st.markdown("---")
192
- st.markdown("**Record Description with Voice**")
193
- st.caption("Select a language and press record. The transcribed text will appear in the 'Description' field below.")
194
  speech_cols = st.columns([3, 1])
195
- speech_language = speech_cols[0].selectbox("Language for Speech Recognition", get_languages(), key="speech_lang")
196
- if speech_cols[1].button("🎤 Record Audio", use_container_width=True):
197
  with st.spinner("Listening..."):
198
- recorded_text = speech_to_text(speech_language)
199
  if recorded_text:
200
  st.session_state.form_data['description'] = recorded_text
201
- st.success(f"Text successfully recorded!")
202
  st.rerun()
203
  else:
204
- st.error("Could not record speech.")
205
 
206
  st.markdown("---")
207
 
208
- # --- STEP 2: MAIN SUBMISSION FORM ---
209
- st.subheader("Step 2: Complete and Submit the Form")
210
  with st.form("entry_form", clear_on_submit=True):
211
- with st.expander("**Part 1: Essential Information**", expanded=True):
212
- st.caption("This is the core of your submission. Describe the farming wisdom clearly.")
213
- title = st.text_input("Title*", value=st.session_state.form_data.get('title', ''), placeholder="e.g., Natural Pest Repellent using Neem Leaves")
214
- description = st.text_area("Description*", value=st.session_state.form_data.get('description', ''), height=250, placeholder="Describe the wisdom, practice, or story in detail...")
215
 
216
  col1, col2 = st.columns(2)
217
- # FIXED: The default value now correctly matches the list from get_categories() -> 'Other'
218
- category = col1.selectbox("Category*", get_categories(), index=get_categories().index(st.session_state.form_data.get('category', 'Other')))
219
- language = col2.selectbox("Language of this Entry*", get_languages(), index=get_languages().index(st.session_state.form_data.get('language', 'English')))
220
-
221
- with st.expander("**Part 2: Geographic Context**"):
222
- st.caption("Specify where this knowledge comes from. Use the helper tool above to search, or click the map to fine-tune.")
223
- location_name = st.text_input("Location Name (e.g., Village, District, State)", value=st.session_state.form_data.get('location_name', ''))
224
 
 
 
 
225
  map_center = [st.session_state.form_data['manual_lat'], st.session_state.form_data['manual_lon']]
226
  m = folium.Map(location=map_center, zoom_start=7)
227
  folium.Marker(map_center, popup="Your Selected Location", tooltip="Current Location").add_to(m)
@@ -233,21 +242,19 @@ elif page == "✍️ Submit Wisdom":
233
  st.rerun()
234
 
235
  loc_cols = st.columns(2)
236
- manual_lat = loc_cols[0].text_input("Latitude (Set by Map)", value=f"{st.session_state.form_data['manual_lat']:.6f}", disabled=True)
237
- manual_lon = loc_cols[1].text_input("Longitude (Set by Map)", value=f"{st.session_state.form_data['manual_lon']:.6f}", disabled=True)
238
 
239
- with st.expander("**Part 3: Supporting Media (Optional)**"):
240
- st.caption("Upload an image or a pre-recorded audio file that relates to this wisdom.")
241
- uploaded_image = st.file_uploader("Upload an Image", type=['jpg', 'jpeg', 'png'])
242
- uploaded_audio = st.file_uploader("Upload an Audio Recording", type=['mp3', 'wav', 'ogg'])
243
 
244
- # FIXED: This submit button must be indented inside the 'with st.form(...)' block
245
  st.markdown("---")
246
- submitted = st.form_submit_button("✅ Submit My Contribution", type="primary", use_container_width=True)
247
 
248
  if submitted:
249
  if title and description:
250
- # ... (submission logic remains the same) ...
251
  image_path, audio_path = None, None
252
  media_dir = "data_entries/media"
253
  os.makedirs(media_dir, exist_ok=True)
@@ -262,7 +269,7 @@ elif page == "✍️ Submit Wisdom":
262
 
263
  entry = {
264
  'id': len(st.session_state.entries) + 1, 'title': title, 'description': description,
265
- 'language': language, 'category': category, 'location_name': location_name,
266
  'latitude': st.session_state.form_data['manual_lat'],
267
  'longitude': st.session_state.form_data['manual_lon'],
268
  'image_path': image_path, 'audio_path': audio_path,
@@ -274,35 +281,36 @@ elif page == "✍️ Submit Wisdom":
274
  if save_entry(entry):
275
  st.session_state.entries.append(entry)
276
  update_user_entry_count(st.session_state.username)
277
- st.success("Farming wisdom submitted successfully! Thank you.")
278
  st.session_state.pop('form_data', None)
279
  else:
280
- st.error("Failed to save entry. Please try again.")
281
  else:
282
- st.error("Please fill in the required fields: Title and Description.")
283
 
284
  # --- Browse Knowledge Page ---
285
- elif page == "📖 Browse Knowledge":
286
- st.header("📖 Browse Farming Knowledge")
287
- st.markdown("Explore wisdom shared by the community. Use the filters to narrow your search.")
288
 
289
  with st.container(border=True):
290
  col1, col2, col3 = st.columns(3)
291
  with col1:
292
- filter_language = st.selectbox("Filter by Language", ["All"] + get_languages())
293
  with col2:
294
- filter_category = st.selectbox("Filter by Category", ["All"] + get_categories())
295
  with col3:
296
- sort_by = st.selectbox("Sort by", ["Newest First", "Oldest First", "Title A-Z"])
297
 
298
  filtered_entries = st.session_state.entries.copy()
299
- if filter_language != "All": filtered_entries = [e for e in filtered_entries if e.get('language') == filter_language]
300
- if filter_category != "All": filtered_entries = [e for e in filtered_entries if e.get('category') == filter_category]
301
- if sort_by == "Newest First": filtered_entries.sort(key=lambda x: x.get('timestamp', ''), reverse=True)
302
- elif sort_by == "Oldest First": filtered_entries.sort(key=lambda x: x.get('timestamp', ''))
303
- elif sort_by == "Title A-Z": filtered_entries.sort(key=lambda x: x.get('title', '').lower())
 
304
 
305
- st.markdown(f"**Showing {len(filtered_entries)} of {len(st.session_state.entries)} entries**")
306
  st.markdown("---")
307
 
308
  for entry in filtered_entries:
@@ -310,31 +318,31 @@ elif page == "📖 Browse Knowledge":
310
  st.subheader(f"📖 {entry.get('title', 'Untitled')}")
311
 
312
  meta_cols = st.columns(4)
313
- meta_cols[0].markdown(f"**Category:** {entry.get('category', 'N/A')}")
314
- meta_cols[1].markdown(f"**Language:** {entry.get('language', 'N/A')}")
315
- meta_cols[2].markdown(f"**Location:** {entry.get('location_name', 'N/A')}")
316
- meta_cols[3].markdown(f"**Submitted:** {entry.get('timestamp', 'N/A')[:10]}")
317
 
318
- with st.expander("View Details and Media"):
319
  col1, col2 = st.columns([2, 1])
320
  with col1:
321
- st.markdown(f"**Description:**")
322
  st.write(entry.get('description', 'No description'))
323
- if st.button(f"🔊 Listen to Description", key=f"tts_{entry.get('id')}"):
324
  text_to_speech(entry.get('description', ''), entry.get('language'))
325
 
326
  with col2:
327
  if entry.get('image_path') and os.path.exists(entry['image_path']):
328
- st.image(Image.open(entry['image_path']), caption="Attached Image", use_container_width=True)
329
  if entry.get('audio_path') and os.path.exists(entry['audio_path']):
330
  st.audio(entry['audio_path'])
331
  if entry.get('latitude') and entry.get('longitude'):
332
- st.markdown(f"**Coords:** `{entry['latitude']:.4f}, {entry['longitude']:.4f}`")
333
 
334
  # --- Knowledge Map Page ---
335
- elif page == "🗺️ Knowledge Map":
336
- st.header("🗺️ Farming Wisdom Map")
337
- st.markdown("Explore traditional farming knowledge geographically. Click on a marker to see details.")
338
 
339
  geo_entries = [e for e in st.session_state.entries if e.get('latitude') and e.get('longitude')]
340
 
@@ -343,8 +351,8 @@ elif page == "🗺️ Knowledge Map":
343
  for entry in geo_entries:
344
  popup_html = f"""
345
  <b>{entry.get('title', 'Untitled')}</b><br>
346
- <b>Category:</b> {entry.get('category', 'N/A')}<br>
347
- <b>Language:</b> {entry.get('language', 'N/A')}
348
  """
349
  folium.Marker(
350
  [entry['latitude'], entry['longitude']],
@@ -352,132 +360,132 @@ elif page == "🗺️ Knowledge Map":
352
  tooltip=entry.get('title', 'Untitled')
353
  ).add_to(m)
354
  st_folium(m, width=1200, height=600, returned_objects=[])
355
- st.info(f"Showing {len(geo_entries)} entries with location data on the map.")
356
  else:
357
- st.warning("No entries with location data found. Submit entries with coordinates to see them on the map!")
358
 
359
  # --- Search Page ---
360
- elif page == "🔍 Search":
361
- st.header("🔍 Search Knowledge")
362
- st.markdown("Use the search bar and filters to find specific farming techniques and wisdom.")
363
 
364
  with st.container(border=True):
365
- search_query = st.text_input("Search for farming practices...", label_visibility="collapsed", placeholder="🔎 Search for farming practices...")
366
- with st.expander("Advanced Filters"):
367
  col1, col2 = st.columns(2)
368
- search_language = col1.selectbox("Language", ["All"] + get_languages(), key="search_lang")
369
- search_category = col2.selectbox("Category", ["All"] + get_categories(), key="search_cat")
370
- has_media = col1.checkbox("Has Media (Image/Audio)")
371
- has_location = col2.checkbox("Has Location Data")
372
 
373
  if search_query:
374
  results = search_entries(
375
  st.session_state.entries, search_query,
376
- language=search_language if search_language != "All" else None,
377
- category=search_category if search_category != "All" else None,
378
  has_media=has_media, has_location=has_location
379
  )
380
- st.markdown(f"--- \n ### Found {len(results)} results for '{search_query}'")
381
  for entry in results:
382
  with st.container(border=True):
383
  st.subheader(f"📖 {entry.get('title', 'Untitled')}")
384
- st.markdown(f"**Category:** {entry.get('category', 'N/A')} | **Language:** {entry.get('language', 'N/A')} | **Location:** {entry.get('location_name', 'N/A')}")
385
  st.write(entry.get('description', 'No description'))
386
 
387
  # --- Translation Hub Page ---
388
- elif page == "🌐 Translation Hub":
389
- st.header("🌐 Translation Hub")
390
- st.markdown("Translate farming knowledge between different Indian languages.")
391
 
392
  with st.container(border=True):
393
  col1, col2 = st.columns(2)
394
  with col1:
395
- st.subheader("Original Text")
396
- source_language = st.selectbox("Source Language", ["Auto-detect"] + get_languages())
397
- source_text = st.text_area("Text to translate", height=200, placeholder="Enter text here...")
398
 
399
  with col2:
400
- st.subheader("Translated Text")
401
- target_language = st.selectbox("Translate to", get_languages())
402
- if st.button("🌐 Translate", type="primary", use_container_width=True) and source_text:
403
  with st.spinner("Translating..."):
404
  source_lang_code = source_language if source_language != "Auto-detect" else "auto"
405
  translated_text = translate_text(source_text, target_language, source_lang_code)
406
- st.text_area("Translation", value=translated_text, height=200, key="translated_output")
407
  else:
408
- st.text_area("Translation", value="", height=200)
409
 
410
  # --- Export Data Page ---
411
- elif page == "📊 Export Data":
412
- st.header("📊 Export Data")
413
- st.markdown("Export collected farming wisdom for research and analysis.")
414
 
415
  with st.container(border=True):
416
- st.subheader("Export Configuration")
417
  col1, col2 = st.columns(2)
418
- export_format = col1.selectbox("Select Format", ["CSV", "JSONL"])
419
- export_language = col2.selectbox("Filter by Language", ["All"] + get_languages(), key="export_lang")
420
- export_category = col1.selectbox("Filter by Category", ["All"] + get_categories(), key="export_cat")
421
 
422
- if st.button("Generate Export File", type="primary", use_container_width=True):
423
  filtered_entries = st.session_state.entries.copy()
424
- if export_language != "All": filtered_entries = [e for e in filtered_entries if e.get('language') == export_language]
425
- if export_category != "All": filtered_entries = [e for e in filtered_entries if e.get('category') == export_category]
426
 
427
  if not filtered_entries:
428
- st.warning("No entries match the selected filters.")
429
  else:
430
  timestamp = datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%d')
431
  if export_format == "CSV":
432
  export_data = export_to_csv(filtered_entries, True, True)
433
  st.download_button(
434
- label="📥 Download CSV", data=export_data,
435
  file_name=f"farming_wisdom_{timestamp}.csv", mime="text/csv", use_container_width=True
436
  )
437
  else: # JSONL
438
  export_data = export_to_jsonl(filtered_entries, True, True)
439
  st.download_button(
440
- label="📥 Download JSONL", data=export_data,
441
  file_name=f"farming_wisdom_{timestamp}.jsonl", mime="application/jsonl", use_container_width=True
442
  )
443
- st.success(f"Export file ready for {len(filtered_entries)} entries.")
444
 
445
  # --- Profile Page ---
446
- elif page == "👤 Profile":
447
- st.header(f"👤 User Profile: {user_info.get('full_name', st.session_state.username)}")
448
  st.markdown("---")
449
 
450
- tab1, tab2, tab3 = st.tabs(["**ℹ️ My Info**", "**📜 My Contributions**", "**⚙️ Settings**"])
451
 
452
  with tab1:
453
  with st.container(border=True):
454
- st.subheader("Profile Information")
455
  info_cols = st.columns(2)
456
- info_cols[0].markdown(f"**Full Name:**\n\n`{user_info.get('full_name', 'Not provided')}`")
457
- info_cols[0].markdown(f"**Username:**\n\n`{st.session_state.username}`")
458
- info_cols[1].markdown(f"**Email:**\n\n`{user_info.get('email', 'Not provided')}`")
459
- info_cols[1].markdown(f"**Member Since:**\n\n`{user_info.get('registration_date', 'Unknown')[:10]}`")
460
- st.metric("Total Entries Submitted", user_info.get('entries_submitted', 0))
461
 
462
  with tab2:
463
  with st.container(border=True):
464
- st.subheader("My Recent Contributions")
465
  my_entries = [e for e in st.session_state.entries if e.get('contributor') == st.session_state.username]
466
  if my_entries:
467
- st.write(f"You have contributed **{len(my_entries)}** farming knowledge entries. Here are the latest 5:")
468
  for entry in reversed(my_entries[-5:]):
469
  st.markdown(f"- **{entry.get('title', 'Untitled')}** (*{entry.get('category', 'N/A')}*)")
470
  else:
471
- st.info("You haven't submitted any entries yet. Go to the 'Submit Wisdom' page to share your knowledge!")
472
 
473
  with tab3:
474
  with st.container(border=True):
475
- st.subheader("Account Preferences")
476
- st.selectbox("Preferred Language (for display)", get_languages(), index=1)
477
- st.checkbox("Enable email notifications for new entries", value=False)
478
- if st.button("Update Profile", use_container_width=True):
479
- st.success("Profile settings updated successfully! (Note: Feature is illustrative)")
480
 
481
  # --- Footer ---
482
  st.sidebar.markdown("---")
483
- st.sidebar.info("🌾 **Farming Wisdom Archive v1.1**")
 
11
  text_to_speech, speech_to_text, geocode_location,
12
  export_to_jsonl, export_to_csv, search_entries,
13
  register_user, authenticate_user, get_user_info, update_user_entry_count,
14
+ translate_text, detect_language, get_ui_text
15
  )
16
 
17
  # Set page config
 
29
  st.session_state.authenticated = False
30
  if 'username' not in st.session_state:
31
  st.session_state.username = None
32
+ # NEW: Initialize language selection
33
+ if 'language' not in st.session_state:
34
+ st.session_state.language = "English"
35
+
36
+ # --- LANGUAGE SELECTOR WIDGET ---
37
+ # This needs to be defined early so the lang variable is available globally
38
+ lang = st.sidebar.selectbox(
39
+ label="Language / भाषा",
40
+ options=["English", "Hindi"],
41
+ key='language'
42
+ )
43
 
44
  # --- AUTHENTICATION PAGE ---
45
  if not st.session_state.authenticated:
46
+ st.title(get_ui_text("app_title", lang))
47
+ st.markdown(f"#### *{get_ui_text('app_tagline', lang)}*")
48
  st.markdown("---")
 
49
  col1, col2 = st.columns([1, 1])
 
50
  with col1:
51
  st.image("https://images.pexels.com/photos/265216/pexels-photo-265216.jpeg",
52
  caption="Photo by Pixabay", use_container_width=True)
53
+ st.markdown(f"### {get_ui_text('about_platform_header', lang)}")
54
+ st.markdown(get_ui_text('about_platform_text', lang))
 
 
 
55
  with col2:
56
+ tab1, tab2 = st.tabs([f"**{get_ui_text('login_tab', lang)}**", f"**{get_ui_text('register_tab', lang)}**"])
 
57
  with tab1:
58
+ st.subheader(get_ui_text('login_subheader', lang))
59
  with st.form("login_form"):
60
+ username = st.text_input(get_ui_text('username_label', lang))
61
+ password = st.text_input(get_ui_text('password_label', lang), type="password")
62
+ login_button = st.form_submit_button(get_ui_text('login_button', lang), type="primary", use_container_width=True)
 
63
  if login_button:
64
  if username and password:
65
  if authenticate_user(username, password):
66
  st.session_state.authenticated = True
67
  st.session_state.username = username
68
+ st.success(get_ui_text('login_success', lang))
69
  st.rerun()
70
  else:
71
+ st.error(get_ui_text('invalid_credentials', lang))
72
  else:
73
+ st.error(get_ui_text('enter_credentials', lang))
 
74
  with tab2:
75
+ st.subheader(get_ui_text('register_subheader', lang))
76
  with st.form("register_form"):
77
+ full_name = st.text_input(get_ui_text('full_name_label', lang))
78
+ email = st.text_input(get_ui_text('email_label', lang))
79
+ reg_username = st.text_input(get_ui_text('choose_username_label', lang))
80
+ reg_password = st.text_input(get_ui_text('choose_password_label', lang), type="password")
81
+ confirm_password = st.text_input(get_ui_text('confirm_password_label', lang), type="password")
82
+ register_button = st.form_submit_button(get_ui_text('register_button', lang), type="primary", use_container_width=True)
 
83
  if register_button:
84
  if full_name and email and reg_username and reg_password and confirm_password:
85
  if reg_password == confirm_password:
86
  if register_user(reg_username, email, reg_password, full_name):
87
+ st.success(get_ui_text('registration_success', lang))
88
  else:
89
+ st.error(get_ui_text('registration_failed', lang))
90
  else:
91
+ st.error(get_ui_text('passwords_no_match', lang))
92
  else:
93
+ st.error(get_ui_text('fill_all_fields', lang))
94
  st.stop()
95
 
96
  # --- MAIN APPLICATION (FOR AUTHENTICATED USERS) ---
 
99
  # App header with user info
100
  col1, col2 = st.columns([3, 1])
101
  with col1:
102
+ st.title(get_ui_text("app_title", lang))
103
  with col2:
104
  st.markdown(f"""
105
  <div style="text-align: right;">
106
+ {get_ui_text('welcome_message', lang)}, <strong>{user_info.get('full_name', st.session_state.username)}</strong>!<br>
107
+ <small>{get_ui_text('entries_submitted', lang)}: {user_info.get('entries_submitted', 0)}</small>
108
  </div>
109
  """, unsafe_allow_html=True)
110
+ if st.button(get_ui_text('logout_button', lang), use_container_width=True):
111
  st.session_state.authenticated = False
112
  st.session_state.username = None
113
  st.rerun()
114
 
115
  # --- NAVIGATION LOGIC ---
116
+ st.sidebar.title(get_ui_text('navigation_header', lang))
117
  def set_page(page_name):
118
  st.session_state.page_selection = page_name
119
 
120
+ # Map keys to translated page names
121
+ page_keys = {
122
+ "home": get_ui_text("home_page", lang),
123
+ "submit": get_ui_text("submit_page", lang),
124
+ "browse": get_ui_text("browse_page", lang),
125
+ "map": get_ui_text("map_page", lang),
126
+ "search": get_ui_text("search_page", lang),
127
+ "translate": get_ui_text("translate_page", lang),
128
+ "export": get_ui_text("export_page", lang),
129
+ "profile": get_ui_text("profile_page", lang),
130
+ }
131
+ page_options = list(page_keys.values())
132
+
133
+ # Get the key of the selected page to use in the if/elif block
134
+ selected_page_name = st.sidebar.radio(
135
  "Go to",
136
  page_options,
137
  key="page_selection",
138
  label_visibility="collapsed"
139
  )
140
+ # Find the key corresponding to the selected page name
141
+ page_key = [key for key, value in page_keys.items() if value == selected_page_name][0]
142
+
143
 
144
  # --- Home Page ---
145
+ if page_key == "home":
146
+ st.header(get_ui_text("home_header", lang))
147
  st.markdown("---")
 
148
  with st.container(border=True):
149
+ st.subheader(get_ui_text("stats_header", lang))
150
  total_entries = len(st.session_state.entries)
151
  languages = len(set(entry.get('language', 'Unknown') for entry in st.session_state.entries))
152
  categories = len(set(entry.get('category', 'Unknown') for entry in st.session_state.entries))
153
 
154
  stat_cols = st.columns(3)
155
+ stat_cols[0].metric(get_ui_text("total_entries_metric", lang), total_entries)
156
+ stat_cols[1].metric(get_ui_text("languages_metric", lang), languages)
157
+ stat_cols[2].metric(get_ui_text("categories_metric", lang), categories)
158
 
159
+ st.markdown(f"### {get_ui_text('getting_started_header', lang)}")
160
  gs_cols = st.columns(3)
161
  with gs_cols[0]:
162
  with st.container(border=True, height=180):
163
+ st.markdown(f"#### {get_ui_text('share_knowledge_card_header', lang)}")
164
+ st.markdown(get_ui_text('share_knowledge_card_text', lang))
165
+ st.button(get_ui_text('share_now_button', lang), on_click=set_page, args=(page_keys["submit"],), use_container_width=True)
166
  with gs_cols[1]:
167
  with st.container(border=True, height=180):
168
+ st.markdown(f"#### {get_ui_text('explore_entries_card_header', lang)}")
169
+ st.markdown(get_ui_text('explore_entries_card_text', lang))
170
+ st.button(get_ui_text('explore_now_button', lang), on_click=set_page, args=(page_keys["browse"],), use_container_width=True)
171
  with gs_cols[2]:
172
  with st.container(border=True, height=180):
173
+ st.markdown(f"#### {get_ui_text('discover_map_card_header', lang)}")
174
+ st.markdown(get_ui_text('discover_map_card_text', lang))
175
+ st.button(get_ui_text('view_map_button', lang), on_click=set_page, args=(page_keys["map"],), use_container_width=True)
176
 
177
+ # --- Submit Wisdom Page ---
178
+ elif page_key == "submit":
179
+ st.header(get_ui_text("submit_header", lang))
180
+ st.markdown(get_ui_text("submit_tagline", lang))
181
 
182
  if 'form_data' not in st.session_state:
183
  st.session_state.form_data = {
184
+ 'title': '', 'description': '', 'language': 'English', 'category': 'Other',
185
  'location_name': '', 'manual_lat': 20.5937, 'manual_lon': 78.9629
186
  }
187
 
188
+ st.subheader(get_ui_text("step1_header", lang))
 
189
  with st.container(border=True):
190
+ st.markdown(get_ui_text("pin_location_header", lang))
191
+ st.caption(get_ui_text("pin_location_caption", lang))
192
  geocode_cols = st.columns([3, 1])
193
+ geocode_input = geocode_cols[0].text_input("search_location", label_visibility="collapsed", placeholder=get_ui_text("find_location_placeholder", lang))
194
+ if geocode_cols[1].button(get_ui_text("find_location_button", lang), use_container_width=True):
195
  if geocode_input:
196
  coords = geocode_location(geocode_input)
197
  if coords:
198
  st.session_state.form_data['manual_lat'], st.session_state.form_data['manual_lon'] = coords
199
+ st.success(get_ui_text("location_found_success", lang).format(location=geocode_input))
200
  else:
201
+ st.error(get_ui_text("location_not_found_error", lang).format(location=geocode_input))
202
 
203
  st.markdown("---")
204
+ st.markdown(get_ui_text("record_voice_header", lang))
205
+ st.caption(get_ui_text("record_voice_caption", lang))
206
  speech_cols = st.columns([3, 1])
207
+ speech_language_for_stt = speech_cols[0].selectbox("Language for Speech Recognition", get_languages(), key="speech_lang")
208
+ if speech_cols[1].button(get_ui_text("record_audio_button", lang), use_container_width=True):
209
  with st.spinner("Listening..."):
210
+ recorded_text = speech_to_text(speech_language_for_stt)
211
  if recorded_text:
212
  st.session_state.form_data['description'] = recorded_text
213
+ st.success(get_ui_text("speech_recorded_success", lang))
214
  st.rerun()
215
  else:
216
+ st.error(get_ui_text("speech_record_error", lang))
217
 
218
  st.markdown("---")
219
 
220
+ st.subheader(get_ui_text("step2_header", lang))
 
221
  with st.form("entry_form", clear_on_submit=True):
222
+ with st.expander(get_ui_text("part1_header", lang), expanded=True):
223
+ st.caption(get_ui_text("part1_caption", lang))
224
+ title = st.text_input(get_ui_text("title_label", lang), value=st.session_state.form_data.get('title', ''), placeholder=get_ui_text("title_placeholder", lang))
225
+ description = st.text_area(get_ui_text("description_label", lang), value=st.session_state.form_data.get('description', ''), height=250, placeholder=get_ui_text("description_placeholder", lang))
226
 
227
  col1, col2 = st.columns(2)
228
+ category = col1.selectbox(get_ui_text("category_label", lang), get_categories(), index=get_categories().index(st.session_state.form_data.get('category', 'Other')))
229
+ language_of_entry = col2.selectbox(get_ui_text("language_entry_label", lang), get_languages(), index=get_languages().index(st.session_state.form_data.get('language', 'English')))
 
 
 
 
 
230
 
231
+ with st.expander(get_ui_text("part2_header", lang)):
232
+ st.caption(get_ui_text("part2_caption", lang))
233
+ location_name = st.text_input(get_ui_text("location_name_label", lang), value=st.session_state.form_data.get('location_name', ''))
234
  map_center = [st.session_state.form_data['manual_lat'], st.session_state.form_data['manual_lon']]
235
  m = folium.Map(location=map_center, zoom_start=7)
236
  folium.Marker(map_center, popup="Your Selected Location", tooltip="Current Location").add_to(m)
 
242
  st.rerun()
243
 
244
  loc_cols = st.columns(2)
245
+ manual_lat = loc_cols[0].text_input(get_ui_text("latitude_label", lang), value=f"{st.session_state.form_data['manual_lat']:.6f}", disabled=True)
246
+ manual_lon = loc_cols[1].text_input(get_ui_text("longitude_label", lang), value=f"{st.session_state.form_data['manual_lon']:.6f}", disabled=True)
247
 
248
+ with st.expander(get_ui_text("part3_header", lang)):
249
+ st.caption(get_ui_text("part3_caption", lang))
250
+ uploaded_image = st.file_uploader(get_ui_text("image_upload_label", lang), type=['jpg', 'jpeg', 'png'])
251
+ uploaded_audio = st.file_uploader(get_ui_text("audio_upload_label", lang), type=['mp3', 'wav', 'ogg'])
252
 
 
253
  st.markdown("---")
254
+ submitted = st.form_submit_button(get_ui_text("submit_contribution_button", lang), type="primary", use_container_width=True)
255
 
256
  if submitted:
257
  if title and description:
 
258
  image_path, audio_path = None, None
259
  media_dir = "data_entries/media"
260
  os.makedirs(media_dir, exist_ok=True)
 
269
 
270
  entry = {
271
  'id': len(st.session_state.entries) + 1, 'title': title, 'description': description,
272
+ 'language': language_of_entry, 'category': category, 'location_name': location_name,
273
  'latitude': st.session_state.form_data['manual_lat'],
274
  'longitude': st.session_state.form_data['manual_lon'],
275
  'image_path': image_path, 'audio_path': audio_path,
 
281
  if save_entry(entry):
282
  st.session_state.entries.append(entry)
283
  update_user_entry_count(st.session_state.username)
284
+ st.success(get_ui_text("submit_success", lang))
285
  st.session_state.pop('form_data', None)
286
  else:
287
+ st.error(get_ui_text("submit_failed", lang))
288
  else:
289
+ st.error(get_ui_text("submit_validation_error", lang))
290
 
291
  # --- Browse Knowledge Page ---
292
+ elif page_key == "browse":
293
+ st.header(get_ui_text("browse_header", lang))
294
+ st.markdown(get_ui_text("browse_tagline", lang))
295
 
296
  with st.container(border=True):
297
  col1, col2, col3 = st.columns(3)
298
  with col1:
299
+ filter_language = st.selectbox(get_ui_text("filter_lang_label", lang), [get_ui_text("all_option", lang)] + get_languages())
300
  with col2:
301
+ filter_category = st.selectbox(get_ui_text("filter_cat_label", lang), [get_ui_text("all_option", lang)] + get_categories())
302
  with col3:
303
+ sort_by = st.selectbox(get_ui_text("sort_by_label", lang), [get_ui_text("newest_first_option", lang), get_ui_text("oldest_first_option", lang), get_ui_text("title_az_option", lang)])
304
 
305
  filtered_entries = st.session_state.entries.copy()
306
+ if filter_language != get_ui_text("all_option", lang): filtered_entries = [e for e in filtered_entries if e.get('language') == filter_language]
307
+ if filter_category != get_ui_text("all_option", lang): filtered_entries = [e for e in filtered_entries if e.get('category') == filter_category]
308
+
309
+ if sort_by == get_ui_text("newest_first_option", lang): filtered_entries.sort(key=lambda x: x.get('timestamp', ''), reverse=True)
310
+ elif sort_by == get_ui_text("oldest_first_option", lang): filtered_entries.sort(key=lambda x: x.get('timestamp', ''))
311
+ elif sort_by == get_ui_text("title_az_option", lang): filtered_entries.sort(key=lambda x: x.get('title', '').lower())
312
 
313
+ st.markdown(get_ui_text("showing_entries", lang).format(count=len(filtered_entries), total=len(st.session_state.entries)))
314
  st.markdown("---")
315
 
316
  for entry in filtered_entries:
 
318
  st.subheader(f"📖 {entry.get('title', 'Untitled')}")
319
 
320
  meta_cols = st.columns(4)
321
+ meta_cols[0].markdown(get_ui_text("category_display", lang).format(category=entry.get('category', 'N/A')))
322
+ meta_cols[1].markdown(get_ui_text("language_display", lang).format(language=entry.get('language', 'N/A')))
323
+ meta_cols[2].markdown(get_ui_text("location_display", lang).format(location=entry.get('location_name', 'N/A')))
324
+ meta_cols[3].markdown(get_ui_text("submitted_display", lang).format(date=entry.get('timestamp', 'N/A')[:10]))
325
 
326
+ with st.expander(get_ui_text("view_details_expander", lang)):
327
  col1, col2 = st.columns([2, 1])
328
  with col1:
329
+ st.markdown(get_ui_text("description_display", lang))
330
  st.write(entry.get('description', 'No description'))
331
+ if st.button(get_ui_text("listen_button", lang), key=f"tts_{entry.get('id')}"):
332
  text_to_speech(entry.get('description', ''), entry.get('language'))
333
 
334
  with col2:
335
  if entry.get('image_path') and os.path.exists(entry['image_path']):
336
+ st.image(Image.open(entry['image_path']), caption=get_ui_text("image_caption", lang), use_container_width=True)
337
  if entry.get('audio_path') and os.path.exists(entry['audio_path']):
338
  st.audio(entry['audio_path'])
339
  if entry.get('latitude') and entry.get('longitude'):
340
+ st.markdown(get_ui_text("coords_display", lang).format(lat=f"{entry['latitude']:.4f}", lon=f"{entry['longitude']:.4f}"))
341
 
342
  # --- Knowledge Map Page ---
343
+ elif page_key == "map":
344
+ st.header(get_ui_text("map_header", lang))
345
+ st.markdown(get_ui_text("map_tagline", lang))
346
 
347
  geo_entries = [e for e in st.session_state.entries if e.get('latitude') and e.get('longitude')]
348
 
 
351
  for entry in geo_entries:
352
  popup_html = f"""
353
  <b>{entry.get('title', 'Untitled')}</b><br>
354
+ <b>{get_ui_text("map_popup_category", lang)}</b> {entry.get('category', 'N/A')}<br>
355
+ <b>{get_ui_text("map_popup_language", lang)}</b> {entry.get('language', 'N/A')}
356
  """
357
  folium.Marker(
358
  [entry['latitude'], entry['longitude']],
 
360
  tooltip=entry.get('title', 'Untitled')
361
  ).add_to(m)
362
  st_folium(m, width=1200, height=600, returned_objects=[])
363
+ st.info(get_ui_text("map_info", lang).format(count=len(geo_entries)))
364
  else:
365
+ st.warning(get_ui_text("map_warning", lang))
366
 
367
  # --- Search Page ---
368
+ elif page_key == "search":
369
+ st.header(get_ui_text("search_header", lang))
370
+ st.markdown(get_ui_text("search_tagline", lang))
371
 
372
  with st.container(border=True):
373
+ search_query = st.text_input("search", label_visibility="collapsed", placeholder=get_ui_text("search_placeholder", lang))
374
+ with st.expander(get_ui_text("advanced_filters_expander", lang)):
375
  col1, col2 = st.columns(2)
376
+ search_language = col1.selectbox(get_ui_text("filter_lang_label", lang), [get_ui_text("all_option", lang)] + get_languages(), key="search_lang")
377
+ search_category = col2.selectbox(get_ui_text("filter_cat_label", lang), [get_ui_text("all_option", lang)] + get_categories(), key="search_cat")
378
+ has_media = col1.checkbox(get_ui_text("has_media_checkbox", lang))
379
+ has_location = col2.checkbox(get_ui_text("has_location_checkbox", lang))
380
 
381
  if search_query:
382
  results = search_entries(
383
  st.session_state.entries, search_query,
384
+ language=search_language,
385
+ category=search_category,
386
  has_media=has_media, has_location=has_location
387
  )
388
+ st.markdown(get_ui_text("search_results_header", lang).format(count=len(results), query=search_query))
389
  for entry in results:
390
  with st.container(border=True):
391
  st.subheader(f"📖 {entry.get('title', 'Untitled')}")
392
+ st.markdown(f"**{get_ui_text('map_popup_category', lang)}** {entry.get('category', 'N/A')} | **{get_ui_text('map_popup_language', lang)}** {entry.get('language', 'N/A')} | **{get_ui_text('location_display', lang).format(location=entry.get('location_name', 'N/A'))}**")
393
  st.write(entry.get('description', 'No description'))
394
 
395
  # --- Translation Hub Page ---
396
+ elif page_key == "translate":
397
+ st.header(get_ui_text("translation_hub_header", lang))
398
+ st.markdown(get_ui_text("translation_hub_tagline", lang))
399
 
400
  with st.container(border=True):
401
  col1, col2 = st.columns(2)
402
  with col1:
403
+ st.subheader(get_ui_text("original_text_header", lang))
404
+ source_language = st.selectbox(get_ui_text("source_language_label", lang), ["Auto-detect"] + get_languages())
405
+ source_text = st.text_area(get_ui_text("text_to_translate_label", lang), height=200, placeholder=get_ui_text("text_to_translate_placeholder", lang), label_visibility="collapsed")
406
 
407
  with col2:
408
+ st.subheader(get_ui_text("translated_text_header", lang))
409
+ target_language = st.selectbox(get_ui_text("target_language_label", lang), get_languages())
410
+ if st.button(get_ui_text("translate_button", lang), type="primary", use_container_width=True) and source_text:
411
  with st.spinner("Translating..."):
412
  source_lang_code = source_language if source_language != "Auto-detect" else "auto"
413
  translated_text = translate_text(source_text, target_language, source_lang_code)
414
+ st.text_area(get_ui_text("translation_output_label", lang), value=translated_text, height=200, key="translated_output", label_visibility="collapsed")
415
  else:
416
+ st.text_area(get_ui_text("translation_output_label", lang), value="", height=200, label_visibility="collapsed")
417
 
418
  # --- Export Data Page ---
419
+ elif page_key == "export":
420
+ st.header(get_ui_text("export_header", lang))
421
+ st.markdown(get_ui_text("export_tagline", lang))
422
 
423
  with st.container(border=True):
424
+ st.subheader(get_ui_text("export_config_header", lang))
425
  col1, col2 = st.columns(2)
426
+ export_format = col1.selectbox(get_ui_text("format_label", lang), ["CSV", "JSONL"])
427
+ export_language = col2.selectbox(get_ui_text("filter_lang_label", lang), [get_ui_text("all_option", lang)] + get_languages(), key="export_lang")
428
+ export_category = col1.selectbox(get_ui_text("filter_cat_label", lang), [get_ui_text("all_option", lang)] + get_categories(), key="export_cat")
429
 
430
+ if st.button(get_ui_text("generate_export_button", lang), type="primary", use_container_width=True):
431
  filtered_entries = st.session_state.entries.copy()
432
+ if export_language != get_ui_text("all_option", lang): filtered_entries = [e for e in filtered_entries if e.get('language') == export_language]
433
+ if export_category != get_ui_text("all_option", lang): filtered_entries = [e for e in filtered_entries if e.get('category') == export_category]
434
 
435
  if not filtered_entries:
436
+ st.warning(get_ui_text("export_no_match_warning", lang))
437
  else:
438
  timestamp = datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%d')
439
  if export_format == "CSV":
440
  export_data = export_to_csv(filtered_entries, True, True)
441
  st.download_button(
442
+ label=get_ui_text("export_download_csv_button", lang), data=export_data,
443
  file_name=f"farming_wisdom_{timestamp}.csv", mime="text/csv", use_container_width=True
444
  )
445
  else: # JSONL
446
  export_data = export_to_jsonl(filtered_entries, True, True)
447
  st.download_button(
448
+ label=get_ui_text("export_download_jsonl_button", lang), data=export_data,
449
  file_name=f"farming_wisdom_{timestamp}.jsonl", mime="application/jsonl", use_container_width=True
450
  )
451
+ st.success(get_ui_text("export_ready_success", lang).format(count=len(filtered_entries)))
452
 
453
  # --- Profile Page ---
454
+ elif page_key == "profile":
455
+ st.header(get_ui_text("profile_header", lang).format(name=user_info.get('full_name', st.session_state.username)))
456
  st.markdown("---")
457
 
458
+ tab1, tab2, tab3 = st.tabs([f"**{get_ui_text('my_info_tab', lang)}**", f"**{get_ui_text('my_contributions_tab', lang)}**", f"**{get_ui_text('settings_tab', lang)}**"])
459
 
460
  with tab1:
461
  with st.container(border=True):
462
+ st.subheader(get_ui_text("profile_info_header", lang))
463
  info_cols = st.columns(2)
464
+ info_cols[0].markdown(get_ui_text("full_name_display", lang).format(name=user_info.get('full_name', 'Not provided')))
465
+ info_cols[0].markdown(get_ui_text("username_display", lang).format(username=st.session_state.username))
466
+ info_cols[1].markdown(get_ui_text("email_display", lang).format(email=user_info.get('email', 'Not provided')))
467
+ info_cols[1].markdown(get_ui_text("member_since_display", lang).format(date=user_info.get('registration_date', 'Unknown')[:10]))
468
+ st.metric(get_ui_text("total_entries_metric_profile", lang), user_info.get('entries_submitted', 0))
469
 
470
  with tab2:
471
  with st.container(border=True):
472
+ st.subheader(get_ui_text("my_recent_contributions_header", lang))
473
  my_entries = [e for e in st.session_state.entries if e.get('contributor') == st.session_state.username]
474
  if my_entries:
475
+ st.write(get_ui_text("contributions_count_message", lang).format(count=len(my_entries)))
476
  for entry in reversed(my_entries[-5:]):
477
  st.markdown(f"- **{entry.get('title', 'Untitled')}** (*{entry.get('category', 'N/A')}*)")
478
  else:
479
+ st.info(get_ui_text("no_contributions_message", lang))
480
 
481
  with tab3:
482
  with st.container(border=True):
483
+ st.subheader(get_ui_text("account_prefs_header", lang))
484
+ st.selectbox(get_ui_text("preferred_language_label", lang), get_languages(), index=1)
485
+ st.checkbox(get_ui_text("email_notifications_checkbox", lang), value=False)
486
+ if st.button(get_ui_text("update_profile_button", lang), use_container_width=True):
487
+ st.success(get_ui_text("profile_update_success", lang))
488
 
489
  # --- Footer ---
490
  st.sidebar.markdown("---")
491
+ st.sidebar.info(get_ui_text("app_version_footer", lang))