Wall06 commited on
Commit
7353b8d
Β·
verified Β·
1 Parent(s): 3069e2e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +71 -190
app.py CHANGED
@@ -11,7 +11,6 @@ from sentinelhub import SHConfig
11
  from groq import Groq
12
  import google.generativeai as genai
13
  import tempfile
14
- from elevenlabs.client import ElevenLabs
15
 
16
  # -------------------- ENVIRONMENT VARIABLES --------------------
17
  HF_API_KEY = os.getenv("HF_API_KEY")
@@ -19,22 +18,14 @@ GROQ_API_KEY = os.getenv("GROQ_API_KEY")
19
  GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
20
  SENTINEL_CLIENT_ID = os.getenv("SENTINEL_CLIENT_ID")
21
  SENTINEL_CLIENT_SECRET = os.getenv("SENTINEL_CLIENT_SECRET")
22
- ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
23
 
24
- # -------------------- SENTINEL CONFIG --------------------
25
  config = SHConfig()
26
  if SENTINEL_CLIENT_ID and SENTINEL_CLIENT_SECRET:
27
  config.client_id = SENTINEL_CLIENT_ID
28
  config.client_secret = SENTINEL_CLIENT_SECRET
29
 
30
- # -------------------- ELEVENLABS SETUP --------------------
31
- el_client = None
32
- if ELEVENLABS_API_KEY:
33
- try:
34
- el_client = ElevenLabs(api_key=ELEVENLABS_API_KEY)
35
- except:
36
- pass
37
-
38
  # -------------------- AI FUNCTIONS --------------------
39
  def gemini_summary(text):
40
  try:
@@ -88,31 +79,50 @@ def smart_summary(text):
88
  errors.append(f"HF: {err}")
89
  return "⚠ SYSTEM FAILURE. DEBUG LOG:\n" + "\n".join(errors)
90
 
91
- # -------------------- AUDIO FUNCTION --------------------
92
  def generate_audio_report(text):
93
- """Safely generates audio. Returns None on failure instead of crashing."""
 
 
 
 
 
 
 
 
 
 
94
  if not text:
95
- return None
96
-
97
- # If client isn't ready (missing key), exit safely
98
- if not el_client:
99
- return None
100
 
 
 
 
 
 
 
101
  try:
102
- # Generate audio (limit length to save credits/speed up)
103
- audio_stream = el_client.generate(
104
- text=text[:500],
 
105
  voice="Brian",
106
  model="eleven_multilingual_v2"
107
  )
108
 
109
- # Save to a temporary file
110
  with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as f:
111
  for chunk in audio_stream:
112
  f.write(chunk)
113
  return f.name
114
- except:
115
- return None
 
 
 
 
 
 
 
116
 
117
  # -------------------- MATH & LOGIC --------------------
118
  def calculate_wqi(pH, do, nutrients):
@@ -152,28 +162,19 @@ def create_plots(wqi, hsi, erosion, turbidity):
152
  return fig
153
 
154
  def generate_graph_insights(wqi, hsi, erosion, turbidity):
155
- """Generates a text explanation for the graph"""
156
  text = "### πŸ“‰ Graph Analysis\n\n"
157
- # WQI (Blue)
158
- if wqi > 70: text += f"πŸ”΅ **Water Quality (Blue):** {wqi}/100. Excellent condition, safe for ecosystem.\n\n"
159
- elif wqi > 40: text += f"πŸ”΅ **Water Quality (Blue):** {wqi}/100. Moderate pollution detected.\n\n"
160
- else: text += f"πŸ”΅ **Water Quality (Blue):** {wqi}/100. **CRITICAL**. High pollution levels.\n\n"
161
- # HSI (Cyan)
162
- if hsi > 70: text += f"🟒 **Habitat (Cyan):** {hsi}/100. Great environment for fish and plants.\n\n"
163
- else: text += f"🟒 **Habitat (Cyan):** {hsi}/100. Poor conditions for biodiversity.\n\n"
164
- # Erosion (Red)
165
- if erosion > 50: text += f"πŸ”΄ **Erosion Risk (Red):** {erosion}/100. **HIGH RISK**. Banks are unstable.\n\n"
166
- else: text += f"πŸ”΄ **Erosion Risk (Red):** {erosion}/100. Stable river banks.\n\n"
167
- # Turbidity (Orange)
168
- if turbidity > 50: text += f"🟠 **Turbidity (Orange):** {turbidity}/100. Water is very cloudy/muddy.\n"
169
- else: text += f"🟠 **Turbidity (Orange):** {turbidity}/100. Water is clear.\n"
170
  return text
171
 
172
  # -------------------- PDF ENGINE --------------------
173
  def generate_pdf(wqi, hsi, erosion, turbidity, summary_text):
174
  pdf = FPDF()
175
  pdf.add_page()
176
- # QR CODE
177
  qr = qrcode.QRCode(box_size=3)
178
  qr.add_data("FlumenIntel Report Verified")
179
  qr.make(fit=True)
@@ -181,35 +182,14 @@ def generate_pdf(wqi, hsi, erosion, turbidity, summary_text):
181
  with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp:
182
  img.save(tmp.name)
183
  pdf.image(tmp.name, x=165, y=10, w=30)
184
- # HEADER
185
  pdf.set_y(15)
186
  pdf.set_font("Arial", "B", 24)
187
  pdf.set_text_color(0, 97, 255)
188
  pdf.cell(0, 10, "FlumenIntel", ln=True, align='L')
189
- pdf.set_font("Arial", "I", 12)
190
- pdf.set_text_color(100, 100, 100)
191
- pdf.cell(0, 10, "River Health Assessment", ln=True, align='L')
192
  pdf.ln(10)
193
- # METRICS TABLE
194
- pdf.set_font("Arial", "B", 14)
195
- pdf.set_text_color(0, 0, 0)
196
- pdf.cell(0, 10, "1. Key Environmental Metrics", ln=True)
197
  pdf.set_font("Arial", "", 12)
198
- pdf.cell(50, 10, f"Water Quality (WQI):", border=1)
199
- pdf.cell(50, 10, f"{wqi}/100", border=1, ln=1)
200
- pdf.cell(50, 10, f"Habitat Score (HSI):", border=1)
201
- pdf.cell(50, 10, f"{hsi}/100", border=1, ln=1)
202
- pdf.cell(50, 10, f"Erosion Risk:", border=1)
203
- pdf.cell(50, 10, f"{erosion}/100", border=1, ln=1)
204
- pdf.cell(50, 10, f"Turbidity:", border=1)
205
- pdf.cell(50, 10, f"{turbidity}/100", border=1, ln=1)
206
- pdf.ln(10)
207
- # SUMMARY
208
- pdf.set_font("Arial", "B", 14)
209
- pdf.cell(0, 10, "2. Scientist's Analysis", ln=True)
210
- pdf.set_font("Arial", "", 11)
211
- clean_summary = summary_text.encode('latin-1', 'replace').decode('latin-1')
212
- pdf.multi_cell(0, 6, clean_summary)
213
  try:
214
  return pdf.output(dest='S').encode('latin-1')
215
  except:
@@ -227,25 +207,12 @@ def process_data(flow_rate, water_temp, sediment, construction, pH, do, nutrient
227
 
228
  prompt = f"""
229
  ROLE: Senior Environmental Scientist.
230
- TASK: Write a formal "River Health Assessment Report".
231
- DATA:
232
- - WQI: {wqi} (Potability: {potability})
233
- - HSI: {hsi}
234
- - Erosion: {erosion}
235
- - Turbidity: {turbidity}
236
-
237
- REQUIREMENTS:
238
- - Tone: Professional, Objective, Scientific.
239
- - No Markdown symbols (like ** or ##). Use plain text formatting.
240
- - Structure:
241
- 1. EXECUTIVE SUMMARY: High-level status.
242
- 2. BIOLOGICAL IMPACT: Effect on local aquatic life.
243
- 3. MITIGATION PLAN: 3 specific, actionable steps.
244
- 4. FORECAST: Predicted outcome if untreated.
245
  """
246
 
247
  summary = smart_summary(prompt)
248
-
249
  fig = create_plots(wqi, hsi, erosion, turbidity)
250
  graph_text = generate_graph_insights(wqi, hsi, erosion, turbidity)
251
  pdf_bytes = generate_pdf(wqi, hsi, erosion, turbidity, summary)
@@ -259,110 +226,43 @@ def process_data(flow_rate, water_temp, sediment, construction, pH, do, nutrient
259
  return status_text, fig, graph_text, summary, pdf_path
260
 
261
  except Exception as e:
262
- import traceback
263
- return str(e), None, "", "", None, ""
264
 
265
- # Wrapper to handle outputs mapping correctly
266
  def run_app(flow, temp, sediment, construction, ph, do, nutrients, sat_img):
267
- status, fig, graph_txt, summary, pdf = process_data(flow, temp, sediment, construction, ph, do, nutrients, sat_img)
268
- return status, fig, graph_txt, summary, pdf
269
 
270
- # -------------------- UI DESIGN & CSS --------------------
271
  custom_css = """
272
  @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap');
273
- /* Global Font */
274
  * { font-family: 'Poppins', sans-serif !important; }
275
- /* Title Box */
276
- #title-box {
277
- text-align: center;
278
- background: linear-gradient(135deg, #0061ff 0%, #60efff 100%);
279
- padding: 25px;
280
- border-radius: 12px;
281
- box-shadow: 0 4px 20px rgba(0, 97, 255, 0.3);
282
- color: white;
283
- margin-bottom: 25px;
284
- }
285
- /* Input Cards */
286
- .group-container {
287
- background-color: #1f2937;
288
- border: 1px solid #374151;
289
- border-radius: 10px;
290
- padding: 15px;
291
- margin-bottom: 15px;
292
- box-shadow: 0 2px 5px rgba(0,0,0,0.2);
293
- }
294
- .group-container h3 {
295
- color: #60efff !important;
296
- font-weight: 600;
297
- }
298
- /* Analyze Button */
299
- #analyze-btn {
300
- background: linear-gradient(90deg, #0061ff 0%, #60efff 100%);
301
- border: none;
302
- color: white;
303
- font-weight: 600;
304
- font-size: 1.1rem;
305
- border-radius: 8px;
306
- transition: transform 0.2s;
307
- }
308
- #analyze-btn:hover {
309
- transform: scale(1.02);
310
- box-shadow: 0 0 15px rgba(96, 239, 255, 0.5);
311
- }
312
- /* About Me Profile Styling */
313
- .about-container {
314
- background: #111827;
315
- border: 1px solid #374151;
316
- border-radius: 15px;
317
- padding: 30px;
318
- margin-top: 10px;
319
- color: #e5e7eb;
320
- }
321
- .about-header {
322
- font-size: 1.8rem;
323
- font-weight: 600;
324
- color: #60efff;
325
- margin-bottom: 10px;
326
- border-bottom: 2px solid #0061ff;
327
- padding-bottom: 5px;
328
- display: inline-block;
329
- }
330
- .about-text {
331
- font-size: 1.1rem;
332
- line-height: 1.8;
333
- margin-top: 15px;
334
- }
335
  """
336
 
337
- with gr.Blocks(title="FlumenIntel") as demo:
338
- gr.HTML(f"<style>{custom_css}</style>")
339
  with gr.Column(elem_id="title-box"):
340
- gr.Markdown("<h1>FlumenIntel 🌊</h1><h3>Advanced River Health Analytics</h3>")
341
 
342
- # -------------------- TABS SYSTEM --------------------
343
  with gr.Tabs():
344
-
345
- # --- TAB 1: THE APP ---
346
  with gr.TabItem("πŸš€ Dashboard"):
347
  with gr.Row():
348
  # LEFT INPUTS
349
  with gr.Column(scale=1):
350
- with gr.Group(elem_classes="group-container"):
351
- gr.Markdown("### 1. Hydrological Data")
352
- flow = gr.Number(label="Flow Rate (mΒ³/s)", value=45)
353
- temp = gr.Number(label="Temperature (Β°C)", value=18)
354
- sediment = gr.Slider(0, 10, label="Sediment Level", value=2)
355
- construction = gr.Slider(0, 10, label="Construction Activity", value=0)
356
 
357
- with gr.Group(elem_classes="group-container"):
358
- gr.Markdown("### 2. Chemical Data")
359
- ph = gr.Number(label="pH Level", value=7.2)
360
- do = gr.Number(label="Dissolved Oxygen (mg/L)", value=9.5)
361
- nutrients = gr.Slider(0, 10, label="Nutrient Load", value=1)
362
 
363
- with gr.Group(elem_classes="group-container"):
364
- gr.Markdown("### 3. Visual Analysis")
365
- sat_img = gr.Image(label="Satellite Image", type="pil")
366
 
367
  analyze_btn = gr.Button("GENERATE REPORT", elem_id="analyze-btn")
368
 
@@ -373,16 +273,12 @@ with gr.Blocks(title="FlumenIntel") as demo:
373
  with gr.Tabs():
374
  with gr.TabItem("πŸ“Š Visual Analytics"):
375
  plot_output = gr.Plot(label="Metric Visualization")
376
- # NEW: Graph Explanation Text
377
- graph_summary_box = gr.Markdown("### Graph Insights will appear here...")
378
 
379
  with gr.TabItem("πŸ“„ Official Report"):
380
- ai_summary = gr.Textbox(
381
- label="Scientist's Assessment",
382
- lines=20,
383
- interactive=False
384
- )
385
- # --- AUDIO BUTTON ADDED HERE ---
386
  with gr.Row():
387
  audio_btn = gr.Button("πŸ”Š Listen to Report (ElevenLabs)")
388
  audio_out = gr.Audio(label="Player", type="filepath")
@@ -392,28 +288,13 @@ with gr.Blocks(title="FlumenIntel") as demo:
392
  inputs=ai_summary,
393
  outputs=audio_out
394
  )
395
- # -------------------------------
396
-
397
  with gr.TabItem("πŸ“₯ Export"):
398
- gr.Markdown("### Download Verified PDF")
399
  pdf_output = gr.File(label="FlumenIntel Report.pdf")
400
 
401
  # --- TAB 2: ABOUT ME ---
402
  with gr.TabItem("πŸ‘€ About Me"):
403
- with gr.Column(elem_classes="about-container"):
404
- gr.HTML("""
405
- <div class="about-header">Abdullah</div>
406
- <div style="color: #9ca3af; font-size: 1rem; margin-bottom: 20px;">Computer Engineering Undergraduate | AI & Hardware Enthusiast</div>
407
-
408
- <div class="about-text">
409
- I am a computer engineering undergraduate with a strong foundation in software development, AI, and hardware systems.
410
- I have hands-on experience building practical projects, ranging from applications that enhance user experiences to embedded systems and circuit design.
411
- My work reflects a commitment to innovation, problem-solving, and applying technology to real-world challenges.
412
- <br><br>
413
- I am actively developing expertise in AI, web development, and software engineering, with a focus on creating scalable and impactful solutions.
414
- I thrive in dynamic environments, value continuous learning, and aim to combine technical proficiency with strategic thinking to contribute to cutting-edge projects and technology-driven initiatives.
415
- </div>
416
- """)
417
 
418
  # Events
419
  analyze_btn.click(
 
11
  from groq import Groq
12
  import google.generativeai as genai
13
  import tempfile
 
14
 
15
  # -------------------- ENVIRONMENT VARIABLES --------------------
16
  HF_API_KEY = os.getenv("HF_API_KEY")
 
18
  GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
19
  SENTINEL_CLIENT_ID = os.getenv("SENTINEL_CLIENT_ID")
20
  SENTINEL_CLIENT_SECRET = os.getenv("SENTINEL_CLIENT_SECRET")
21
+ # We fetch ELEVENLABS_KEY inside the function now to ensure it loads
22
 
23
+ # -------------------- CLIENT SETUP --------------------
24
  config = SHConfig()
25
  if SENTINEL_CLIENT_ID and SENTINEL_CLIENT_SECRET:
26
  config.client_id = SENTINEL_CLIENT_ID
27
  config.client_secret = SENTINEL_CLIENT_SECRET
28
 
 
 
 
 
 
 
 
 
29
  # -------------------- AI FUNCTIONS --------------------
30
  def gemini_summary(text):
31
  try:
 
79
  errors.append(f"HF: {err}")
80
  return "⚠ SYSTEM FAILURE. DEBUG LOG:\n" + "\n".join(errors)
81
 
82
+ # -------------------- AUDIO FUNCTION (ROBUST VERSION) --------------------
83
  def generate_audio_report(text):
84
+ """
85
+ Connects to ElevenLabs *inside* the function to avoid startup errors.
86
+ Shows a RED ERROR popup if something fails.
87
+ """
88
+ # 1. Check for Library
89
+ try:
90
+ from elevenlabs.client import ElevenLabs
91
+ except ImportError:
92
+ raise gr.Error("❌ Library Missing! Add 'elevenlabs' to requirements.txt")
93
+
94
+ # 2. Check for Text
95
  if not text:
96
+ raise gr.Error("❌ No text! Generate the report first.")
 
 
 
 
97
 
98
+ # 3. Check for Key
99
+ api_key = os.getenv("ELEVENLABS_API_KEY")
100
+ if not api_key:
101
+ raise gr.Error("❌ API Key Missing! Check Settings > Secrets.")
102
+
103
+ # 4. Try to Generate
104
  try:
105
+ client = ElevenLabs(api_key=api_key)
106
+
107
+ audio_stream = client.generate(
108
+ text=text[:400], # Limit to 400 chars to be safe/fast
109
  voice="Brian",
110
  model="eleven_multilingual_v2"
111
  )
112
 
 
113
  with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as f:
114
  for chunk in audio_stream:
115
  f.write(chunk)
116
  return f.name
117
+
118
+ except Exception as e:
119
+ error_msg = str(e)
120
+ if "401" in error_msg:
121
+ raise gr.Error("❌ 401 Unauthorized: The API Key is wrong. Check for spaces!")
122
+ elif "quota" in error_msg.lower():
123
+ raise gr.Error("❌ Quota Exceeded: You ran out of free credits.")
124
+ else:
125
+ raise gr.Error(f"❌ ElevenLabs Error: {error_msg}")
126
 
127
  # -------------------- MATH & LOGIC --------------------
128
  def calculate_wqi(pH, do, nutrients):
 
162
  return fig
163
 
164
  def generate_graph_insights(wqi, hsi, erosion, turbidity):
 
165
  text = "### πŸ“‰ Graph Analysis\n\n"
166
+ if wqi > 70: text += f"πŸ”΅ **Water Quality:** {wqi}/100. Excellent condition.\n\n"
167
+ elif wqi > 40: text += f"πŸ”΅ **Water Quality:** {wqi}/100. Moderate pollution.\n\n"
168
+ else: text += f"πŸ”΅ **Water Quality:** {wqi}/100. **CRITICAL**.\n\n"
169
+
170
+ if hsi > 70: text += f"🟒 **Habitat:** {hsi}/100. Good biodiversity.\n\n"
171
+ else: text += f"🟒 **Habitat:** {hsi}/100. Poor conditions.\n\n"
 
 
 
 
 
 
 
172
  return text
173
 
174
  # -------------------- PDF ENGINE --------------------
175
  def generate_pdf(wqi, hsi, erosion, turbidity, summary_text):
176
  pdf = FPDF()
177
  pdf.add_page()
 
178
  qr = qrcode.QRCode(box_size=3)
179
  qr.add_data("FlumenIntel Report Verified")
180
  qr.make(fit=True)
 
182
  with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp:
183
  img.save(tmp.name)
184
  pdf.image(tmp.name, x=165, y=10, w=30)
 
185
  pdf.set_y(15)
186
  pdf.set_font("Arial", "B", 24)
187
  pdf.set_text_color(0, 97, 255)
188
  pdf.cell(0, 10, "FlumenIntel", ln=True, align='L')
 
 
 
189
  pdf.ln(10)
 
 
 
 
190
  pdf.set_font("Arial", "", 12)
191
+ pdf.set_text_color(0, 0, 0)
192
+ pdf.multi_cell(0, 6, summary_text.encode('latin-1', 'replace').decode('latin-1'))
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  try:
194
  return pdf.output(dest='S').encode('latin-1')
195
  except:
 
207
 
208
  prompt = f"""
209
  ROLE: Senior Environmental Scientist.
210
+ TASK: Write a formal River Health Report.
211
+ DATA: WQI: {wqi}, HSI: {hsi}, Erosion: {erosion}, Turbidity: {turbidity}.
212
+ REQUIREMENTS: Professional tone. 3 paragraphs max.
 
 
 
 
 
 
 
 
 
 
 
 
213
  """
214
 
215
  summary = smart_summary(prompt)
 
216
  fig = create_plots(wqi, hsi, erosion, turbidity)
217
  graph_text = generate_graph_insights(wqi, hsi, erosion, turbidity)
218
  pdf_bytes = generate_pdf(wqi, hsi, erosion, turbidity, summary)
 
226
  return status_text, fig, graph_text, summary, pdf_path
227
 
228
  except Exception as e:
229
+ return str(e), None, "", "", None
 
230
 
231
+ # Wrapper
232
  def run_app(flow, temp, sediment, construction, ph, do, nutrients, sat_img):
233
+ return process_data(flow, temp, sediment, construction, ph, do, nutrients, sat_img)
 
234
 
235
+ # -------------------- UI DESIGN --------------------
236
  custom_css = """
237
  @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap');
 
238
  * { font-family: 'Poppins', sans-serif !important; }
239
+ #title-box { background: linear-gradient(135deg, #0061ff 0%, #60efff 100%); color: white; padding: 20px; border-radius: 12px; text-align: center;}
240
+ #analyze-btn { background: linear-gradient(90deg, #0061ff 0%, #60efff 100%); color: white; border: none; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  """
242
 
243
+ with gr.Blocks(title="FlumenIntel", css=custom_css) as demo:
 
244
  with gr.Column(elem_id="title-box"):
245
+ gr.Markdown("# FlumenIntel 🌊\n### Advanced River Health Analytics")
246
 
 
247
  with gr.Tabs():
248
+ # --- TAB 1: DASHBOARD ---
 
249
  with gr.TabItem("πŸš€ Dashboard"):
250
  with gr.Row():
251
  # LEFT INPUTS
252
  with gr.Column(scale=1):
253
+ gr.Markdown("### 1. Hydrological Data")
254
+ flow = gr.Number(label="Flow Rate", value=45)
255
+ temp = gr.Number(label="Temperature", value=18)
256
+ sediment = gr.Slider(0, 10, label="Sediment", value=2)
257
+ construction = gr.Slider(0, 10, label="Construction", value=0)
 
258
 
259
+ gr.Markdown("### 2. Chemical Data")
260
+ ph = gr.Number(label="pH Level", value=7.2)
261
+ do = gr.Number(label="Dissolved Oxygen", value=9.5)
262
+ nutrients = gr.Slider(0, 10, label="Nutrient Load", value=1)
 
263
 
264
+ gr.Markdown("### 3. Visual Analysis")
265
+ sat_img = gr.Image(label="Satellite Image", type="pil")
 
266
 
267
  analyze_btn = gr.Button("GENERATE REPORT", elem_id="analyze-btn")
268
 
 
273
  with gr.Tabs():
274
  with gr.TabItem("πŸ“Š Visual Analytics"):
275
  plot_output = gr.Plot(label="Metric Visualization")
276
+ graph_summary_box = gr.Markdown("### Insights...")
 
277
 
278
  with gr.TabItem("πŸ“„ Official Report"):
279
+ ai_summary = gr.Textbox(label="Scientist's Assessment", lines=15, interactive=False)
280
+
281
+ # --- AUDIO BUTTON ---
 
 
 
282
  with gr.Row():
283
  audio_btn = gr.Button("πŸ”Š Listen to Report (ElevenLabs)")
284
  audio_out = gr.Audio(label="Player", type="filepath")
 
288
  inputs=ai_summary,
289
  outputs=audio_out
290
  )
291
+
 
292
  with gr.TabItem("πŸ“₯ Export"):
 
293
  pdf_output = gr.File(label="FlumenIntel Report.pdf")
294
 
295
  # --- TAB 2: ABOUT ME ---
296
  with gr.TabItem("πŸ‘€ About Me"):
297
+ gr.Markdown("## Abdullah\nComputer Engineering Undergraduate | AI & Hardware Enthusiast")
 
 
 
 
 
 
 
 
 
 
 
 
 
298
 
299
  # Events
300
  analyze_btn.click(