Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import os
|
2 |
-
from flask import Flask, render_template, request, jsonify
|
3 |
import requests
|
4 |
import pandas as pd
|
5 |
from datetime import datetime
|
@@ -8,18 +8,25 @@ import plotly.io as pio
|
|
8 |
import numpy as np
|
9 |
import dotenv
|
10 |
import json
|
|
|
|
|
|
|
11 |
|
12 |
dotenv.load_dotenv()
|
13 |
|
14 |
app = Flask(__name__)
|
15 |
|
|
|
|
|
|
|
|
|
16 |
def fetch_market_data(state=None, district=None, market=None, commodity=None):
|
17 |
"""Fetch data from the agricultural market API.
|
18 |
If the API fails or returns empty data, fallback to the CSV file.
|
19 |
Filters (state, district, market, commodity) are applied manually on CSV data.
|
20 |
"""
|
21 |
api_key = "579b464db66ec23bdd000001189bbb99e979428764bdbe8fdd44ebb7"
|
22 |
-
base_url = "
|
23 |
|
24 |
params = {
|
25 |
"api-key": api_key,
|
@@ -126,7 +133,7 @@ def get_ai_insights(market_data, state, district, market=None, commodity=None, l
|
|
126 |
}).round(2)
|
127 |
|
128 |
# Using environment variable for Gemini API key
|
129 |
-
api_key =
|
130 |
if not api_key:
|
131 |
print("Warning: Gemini API key not set")
|
132 |
return ""
|
@@ -239,7 +246,7 @@ def get_ai_insights(market_data, state, district, market=None, commodity=None, l
|
|
239 |
content = response_data['candidates'][0]['content']
|
240 |
if 'parts' in content and len(content['parts']) > 0:
|
241 |
insights = content['parts'][0]['text']
|
242 |
-
return format_ai_insights(insights)
|
243 |
print(f"API Response issue: {response.text[:100]}")
|
244 |
else:
|
245 |
print(f"Gemini API Error: {response.status_code} - {response.text[:100]}")
|
@@ -250,7 +257,67 @@ def get_ai_insights(market_data, state, district, market=None, commodity=None, l
|
|
250 |
print(f"Error generating insights: {str(e)}")
|
251 |
return ""
|
252 |
|
253 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
254 |
"""Format AI insights into structured HTML.
|
255 |
Returns an empty string if no valid insights are provided.
|
256 |
"""
|
@@ -301,10 +368,41 @@ def format_ai_insights(insights_data):
|
|
301 |
formatted_content += f'<li>{point}</li>'
|
302 |
formatted_content += '</ul></div>'
|
303 |
|
304 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
305 |
html = f"""
|
306 |
<div class="insights-header">
|
307 |
<h3>AI Market Insights</h3>
|
|
|
308 |
</div>
|
309 |
<div class="insight-section">
|
310 |
{formatted_content}
|
@@ -509,6 +607,14 @@ def get_commodities():
|
|
509 |
commodities = sorted(df['commodity'].dropna().unique())
|
510 |
return jsonify(commodities)
|
511 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
512 |
if __name__ == '__main__':
|
513 |
pio.templates.default = "plotly_white"
|
514 |
app.run(debug=True, host='0.0.0.0', port=7860)
|
|
|
1 |
import os
|
2 |
+
from flask import Flask, render_template, request, jsonify, send_file
|
3 |
import requests
|
4 |
import pandas as pd
|
5 |
from datetime import datetime
|
|
|
8 |
import numpy as np
|
9 |
import dotenv
|
10 |
import json
|
11 |
+
import gtts
|
12 |
+
import uuid
|
13 |
+
from pathlib import Path
|
14 |
|
15 |
dotenv.load_dotenv()
|
16 |
|
17 |
app = Flask(__name__)
|
18 |
|
19 |
+
# Create audio directory if it doesn't exist
|
20 |
+
AUDIO_DIR = Path("static/audio")
|
21 |
+
AUDIO_DIR.mkdir(parents=True, exist_ok=True)
|
22 |
+
|
23 |
def fetch_market_data(state=None, district=None, market=None, commodity=None):
|
24 |
"""Fetch data from the agricultural market API.
|
25 |
If the API fails or returns empty data, fallback to the CSV file.
|
26 |
Filters (state, district, market, commodity) are applied manually on CSV data.
|
27 |
"""
|
28 |
api_key = "579b464db66ec23bdd000001189bbb99e979428764bdbe8fdd44ebb7"
|
29 |
+
base_url = "https://api.data.gov.in/resource/9ef84268-d588-465a-a308-a864a43d007"
|
30 |
|
31 |
params = {
|
32 |
"api-key": api_key,
|
|
|
133 |
}).round(2)
|
134 |
|
135 |
# Using environment variable for Gemini API key
|
136 |
+
api_key = "AIzaSyBtXV2xJbrWVV57B5RWy_meKXOA59HFMeY"
|
137 |
if not api_key:
|
138 |
print("Warning: Gemini API key not set")
|
139 |
return ""
|
|
|
246 |
content = response_data['candidates'][0]['content']
|
247 |
if 'parts' in content and len(content['parts']) > 0:
|
248 |
insights = content['parts'][0]['text']
|
249 |
+
return format_ai_insights(insights, language)
|
250 |
print(f"API Response issue: {response.text[:100]}")
|
251 |
else:
|
252 |
print(f"Gemini API Error: {response.status_code} - {response.text[:100]}")
|
|
|
257 |
print(f"Error generating insights: {str(e)}")
|
258 |
return ""
|
259 |
|
260 |
+
def extract_text_from_insights(insights_html):
|
261 |
+
"""Extract pure text content from HTML insights for text-to-speech conversion."""
|
262 |
+
# Simple HTML tag removal - for production, consider using BeautifulSoup for better parsing
|
263 |
+
import re
|
264 |
+
text = re.sub(r'<.*?>', ' ', insights_html)
|
265 |
+
text = re.sub(r'\s+', ' ', text) # Remove extra whitespace
|
266 |
+
return text.strip()
|
267 |
+
|
268 |
+
def create_audio_from_text(text, language_code="en"):
|
269 |
+
"""Generate audio file from text using gTTS."""
|
270 |
+
if not text:
|
271 |
+
return None
|
272 |
+
|
273 |
+
# Map UI language selection to gTTS language codes
|
274 |
+
language_map = {
|
275 |
+
"English": "en",
|
276 |
+
"Hindi": "hi",
|
277 |
+
"Tamil": "ta",
|
278 |
+
"Telugu": "te",
|
279 |
+
"Marathi": "mr",
|
280 |
+
"Bengali": "bn",
|
281 |
+
"Gujarati": "gu",
|
282 |
+
"Kannada": "kn",
|
283 |
+
"Malayalam": "ml",
|
284 |
+
"Punjabi": "pa"
|
285 |
+
}
|
286 |
+
|
287 |
+
tts_lang = language_map.get(language_code, "en")
|
288 |
+
|
289 |
+
# Generate unique filename
|
290 |
+
filename = f"{uuid.uuid4()}.mp3"
|
291 |
+
filepath = AUDIO_DIR / filename
|
292 |
+
|
293 |
+
try:
|
294 |
+
tts = gtts.gTTS(text, lang=tts_lang, slow=False)
|
295 |
+
tts.save(str(filepath))
|
296 |
+
return f"/static/audio/{filename}"
|
297 |
+
except Exception as e:
|
298 |
+
print(f"Error creating audio: {str(e)}")
|
299 |
+
return None
|
300 |
+
|
301 |
+
def create_audio_local_fallback(text, language_code="en"):
|
302 |
+
"""Local fallback for TTS when network is unavailable."""
|
303 |
+
try:
|
304 |
+
# This requires pyttsx3 to be installed
|
305 |
+
import pyttsx3
|
306 |
+
engine = pyttsx3.init()
|
307 |
+
|
308 |
+
# Generate unique filename
|
309 |
+
filename = f"{uuid.uuid4()}.mp3"
|
310 |
+
filepath = AUDIO_DIR / filename
|
311 |
+
|
312 |
+
engine.save_to_file(text, str(filepath))
|
313 |
+
engine.runAndWait()
|
314 |
+
|
315 |
+
return f"/static/audio/{filename}"
|
316 |
+
except Exception as e:
|
317 |
+
print(f"Local TTS fallback failed: {str(e)}")
|
318 |
+
return None
|
319 |
+
|
320 |
+
def format_ai_insights(insights_data, language="English"):
|
321 |
"""Format AI insights into structured HTML.
|
322 |
Returns an empty string if no valid insights are provided.
|
323 |
"""
|
|
|
368 |
formatted_content += f'<li>{point}</li>'
|
369 |
formatted_content += '</ul></div>'
|
370 |
|
371 |
+
# Create the plain text version for audio generation
|
372 |
+
plain_text = f"Market Insights for {language}.\n\n"
|
373 |
+
for section, points in sections.items():
|
374 |
+
plain_text += f"{section}:\n"
|
375 |
+
for point in points:
|
376 |
+
# Clean up for speech
|
377 |
+
clean_point = point.replace("₹", " rupees ")
|
378 |
+
plain_text += f"• {clean_point}\n"
|
379 |
+
plain_text += "\n"
|
380 |
+
|
381 |
+
# Generate audio file
|
382 |
+
audio_path = create_audio_from_text(plain_text, language)
|
383 |
+
if audio_path is None:
|
384 |
+
audio_path = create_audio_local_fallback(plain_text)
|
385 |
+
|
386 |
+
# Add a wrapper for the insights with audio player
|
387 |
+
audio_player = ""
|
388 |
+
if audio_path:
|
389 |
+
audio_player = f"""
|
390 |
+
<div class="audio-player-container">
|
391 |
+
<h4>Listen to Insights</h4>
|
392 |
+
<audio id="insightsAudio" controls>
|
393 |
+
<source src="{audio_path}" type="audio/mpeg">
|
394 |
+
Your browser does not support the audio element.
|
395 |
+
</audio>
|
396 |
+
<button class="btn btn-sm btn-custom mt-2" id="playAudioBtn">
|
397 |
+
<i class="fa fa-play"></i> Play Audio
|
398 |
+
</button>
|
399 |
+
</div>
|
400 |
+
"""
|
401 |
+
|
402 |
html = f"""
|
403 |
<div class="insights-header">
|
404 |
<h3>AI Market Insights</h3>
|
405 |
+
{audio_player}
|
406 |
</div>
|
407 |
<div class="insight-section">
|
408 |
{formatted_content}
|
|
|
607 |
commodities = sorted(df['commodity'].dropna().unique())
|
608 |
return jsonify(commodities)
|
609 |
|
610 |
+
@app.route('/static/audio/<filename>')
|
611 |
+
def serve_audio(filename):
|
612 |
+
try:
|
613 |
+
return send_file(f"static/audio/{filename}", mimetype="audio/mpeg")
|
614 |
+
except Exception as e:
|
615 |
+
print(f"Error serving audio file: {str(e)}")
|
616 |
+
return "Audio file not found", 404
|
617 |
+
|
618 |
if __name__ == '__main__':
|
619 |
pio.templates.default = "plotly_white"
|
620 |
app.run(debug=True, host='0.0.0.0', port=7860)
|