IqraFatima commited on
Commit
d5d7753
·
verified ·
1 Parent(s): fd0b808

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +109 -455
app.py CHANGED
@@ -1,199 +1,10 @@
1
-
2
-
3
- # # app.py v2
4
-
5
- # import os
6
- # import re
7
- # import fitz # PyMuPDF
8
- # import tempfile
9
- # from datetime import datetime
10
- # import base64
11
- # from gtts import gTTS
12
- # import streamlit as st
13
- # from transformers.pipelines import pipeline
14
- # from groq import Groq
15
-
16
- # # ✅ Hugging Face and GROQ secrets loaded via Hugging Face Spaces Secrets interface
17
-
18
- # # ⛳ Access secrets securely from environment variables
19
- # GROQ_API_KEY = os.getenv("GROQ_API_KEY")
20
- # HF_TOKEN = os.getenv("HF_TOKEN")
21
- # KAGGLE_USERNAME = os.getenv("KAGGLE_USERNAME")
22
- # KAGGLE_KEY = os.getenv("KAGGLE_KEY")
23
-
24
- # # ✅ Validate secrets
25
- # if not all([GROQ_API_KEY, HF_TOKEN, KAGGLE_USERNAME, KAGGLE_KEY]):
26
- # st.error("❌ One or more required API keys are missing from the environment.")
27
- # st.stop()
28
-
29
- # # ✅ Initialize Groq client
30
- # client = Groq(api_key=GROQ_API_KEY)
31
-
32
- # # ✅ Load phishing detection pipeline from Hugging Face
33
- # phishing_pipe = pipeline(
34
- # "text-classification",
35
- # model="ealvaradob/bert-finetuned-phishing",
36
- # token=HF_TOKEN
37
- # )
38
-
39
- # # ✅ Language and role options
40
- # language_choices = ["English", "Urdu", "French"]
41
- # role_choices = ["Admin", "Procurement", "Logistics"]
42
-
43
- # # ✅ Glossary terms
44
- # GLOSSARY = {
45
- # "phishing": "Phishing is a scam where attackers trick you into revealing personal information.",
46
- # "malware": "Malicious software designed to harm or exploit systems.",
47
- # "spam": "Unwanted or unsolicited messages.",
48
- # "tone": "The emotional character of the message."
49
- # }
50
-
51
- # # ✅ Translations (demo dictionary-based)
52
- # TRANSLATIONS = {
53
- # "Phishing": {"Urdu": "فشنگ", "French": "Hameçonnage"},
54
- # "Spam": {"Urdu": "سپیم", "French": "Courrier indésirable"},
55
- # "Malware": {"Urdu": "میلویئر", "French": "Logiciel malveillant"},
56
- # "Safe": {"Urdu": "محفوظ", "French": "Sûr"}
57
- # }
58
-
59
- # # =======================
60
- # # Streamlit UI
61
- # # =======================
62
- # st.set_page_config(page_title="ZeroPhish Gate", layout="wide")
63
- # st.title("🛡️ ZeroPhish Gate")
64
- # st.markdown("AI-powered phishing message detection and explanation.")
65
-
66
- # # Input fields
67
- # col1, col2 = st.columns([3, 1])
68
- # with col1:
69
- # text_input = st.text_area("✉️ Paste Suspicious Message", height=200)
70
- # uploaded_file = st.file_uploader("📄 Upload PDF/TXT (optional)", type=["pdf", "txt"])
71
-
72
- # with col2:
73
- # language = st.selectbox("🌐 Preferred Language", language_choices)
74
- # role = st.selectbox("🧑‍💼 Your Role", role_choices)
75
-
76
- # analyze_btn = st.button("🔍 Analyze with AI")
77
-
78
- # # =======================
79
- # # Function Definitions
80
- # # =======================
81
- # def extract_text_from_file(file):
82
- # if file is None:
83
- # return ""
84
- # ext = file.name.split(".")[-1].lower()
85
- # if ext == "pdf":
86
- # doc = fitz.open(stream=file.read(), filetype="pdf")
87
- # return "\n".join(page.get_text() for page in doc)
88
- # elif ext == "txt":
89
- # return file.read().decode("utf-8")
90
- # return ""
91
-
92
- # def analyze_with_huggingface(text):
93
- # try:
94
- # result = phishing_pipe(text)
95
- # label = result[0]['label']
96
- # confidence = round(result[0]['score'] * 100, 2)
97
- # threat_type = {
98
- # "PHISHING": "Phishing",
99
- # "SPAM": "Spam",
100
- # "MALWARE": "Malware",
101
- # "LEGITIMATE": "Safe"
102
- # }.get(label.upper(), "Unknown")
103
- # return label, confidence, threat_type
104
- # except Exception as e:
105
- # return "Error", 0, f"Error: {e}"
106
-
107
- # def semantic_analysis(text):
108
- # response = client.chat.completions.create(
109
- # model="llama3-8b-8192",
110
- # messages=[
111
- # {"role": "system", "content": "You are a cybersecurity assistant."},
112
- # {"role": "user", "content": f"Please explain this message in professional tone for a {role} in {language}. Do not end with questions.\n\nMessage:\n{text}"}
113
- # ]
114
- # )
115
- # return response.choices[0].message.content
116
-
117
- # def translate_label(threat_type):
118
- # return TRANSLATIONS.get(threat_type, {}).get(language, threat_type)
119
-
120
- # def text_to_speech(text):
121
- # tts = gTTS(text=text, lang='en')
122
- # with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as fp:
123
- # tts.save(fp.name)
124
- # return fp.name
125
-
126
- # def create_report(label, score, threat_type, explanation, text):
127
- # ts = datetime.now().strftime("%Y%m%d_%H%M%S")
128
- # filename = f"Zerophish_Report_{ts}.txt"
129
- # report = f"""
130
- # 🔍 AI Threat Detection Report
131
-
132
- # Input Message:
133
- # {text}
134
-
135
- # Prediction: {label}
136
- # Threat Type: {threat_type}
137
- # Confidence: {score}%
138
-
139
- # ---
140
-
141
- # 🧠 Explanation:
142
- # {explanation}
143
- # """
144
- # with open(filename, "w") as f:
145
- # f.write(report)
146
- # return filename
147
-
148
- # # =======================
149
- # # Run Analysis
150
- # # =======================
151
- # if analyze_btn:
152
- # combined_text = text_input
153
- # if uploaded_file:
154
- # extracted = extract_text_from_file(uploaded_file)
155
- # combined_text += "\n" + extracted
156
-
157
- # if not combined_text.strip():
158
- # st.warning("⚠️ Please enter some text or upload a file to analyze.")
159
- # else:
160
- # label, score, threat_type = analyze_with_huggingface(combined_text)
161
- # translated_threat = translate_label(threat_type)
162
-
163
- # st.subheader("🔍 AI Threat Detection Result")
164
- # st.markdown(f"**Prediction:** {label}")
165
- # st.markdown(f"**Threat Type:** {threat_type} ({translated_threat})")
166
- # st.markdown(f"**Confidence:** {score}%")
167
-
168
- # explanation = ""
169
- # if threat_type.lower() != "safe":
170
- # with st.expander("🧠 Semantic Reanalysis by LLaMA"):
171
- # explanation = semantic_analysis(combined_text)
172
- # st.write(explanation)
173
-
174
- # if st.button("🔊 Play Explanation as Audio"):
175
- # audio_path = text_to_speech(explanation)
176
- # with open(audio_path, "rb") as f:
177
- # st.audio(f.read(), format="audio/mp3")
178
-
179
- # with st.expander("📜 Glossary Help"):
180
- # for term, definition in GLOSSARY.items():
181
- # st.markdown(f"**{term.capitalize()}**: {definition}")
182
-
183
- # if explanation:
184
- # report_path = create_report(label, score, threat_type, explanation, combined_text)
185
- # with open(report_path, "rb") as f:
186
- # b64 = base64.b64encode(f.read()).decode()
187
- # href = f'<a href="data:file/txt;base64,{b64}" download="{report_path}">📄 Download Full Report</a>'
188
- # st.markdown(href, unsafe_allow_html=True)
189
-
190
- #app v3
191
  import os
192
  import re
193
  import fitz # PyMuPDF
194
  import tempfile
195
  import base64
196
  from datetime import datetime
 
197
  from gtts import gTTS
198
  import streamlit as st
199
  from transformers import pipeline
@@ -242,9 +53,11 @@ TRANSLATIONS = {
242
  "Safe": {"Urdu": "محفوظ", "French": "Sûr"}
243
  }
244
 
245
- # ✅ In-memory history
246
  if "history" not in st.session_state:
247
  st.session_state.history = []
 
 
248
 
249
  # =======================
250
  # Streamlit UI
@@ -255,13 +68,38 @@ st.markdown("""
255
  <style>
256
  .report-container {
257
  border: 1px solid #ddd;
258
- padding: 1rem;
259
- border-radius: 10px;
260
- background-color: #f9f9f9;
 
 
261
  }
262
  .highlight {
263
  font-weight: bold;
264
  color: #d9534f;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  }
266
  </style>
267
  """, unsafe_allow_html=True)
@@ -326,11 +164,45 @@ def semantic_analysis(text):
326
  def translate_label(threat_type):
327
  return TRANSLATIONS.get(threat_type, {}).get(language, threat_type)
328
 
329
- def text_to_speech(text):
330
- tts = gTTS(text=text, lang='en')
331
- with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as fp:
332
- tts.save(fp.name)
333
- return fp.name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
 
335
  def render_history():
336
  with st.expander("🕓 View Analysis History"):
@@ -347,7 +219,9 @@ def render_history():
347
  # =======================
348
  if clear_btn:
349
  st.session_state.history.clear()
350
- st.success("✅ History cleared!")
 
 
351
 
352
  if analyze_btn:
353
  combined_text = text_input
@@ -370,14 +244,43 @@ if analyze_btn:
370
 
371
  summary = ""
372
  if threat_type.lower() != "safe":
373
- with st.expander("🧠 Semantic Reanalysis by LLaMA"):
374
- summary = semantic_analysis(combined_text)
 
375
  st.write(summary)
376
 
377
- if st.button("🔊 Play Explanation as Audio"):
378
- audio_path = text_to_speech(summary)
379
- with open(audio_path, "rb") as f:
380
- st.audio(f.read(), format="audio/mp3")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
 
382
  # Save history
383
  st.session_state.history.append({
@@ -392,252 +295,3 @@ if analyze_btn:
392
  st.markdown(f"**{term.capitalize()}**: {definition}")
393
 
394
  render_history()
395
-
396
- #App v 3
397
- # app.py
398
-
399
- # # app.py
400
-
401
- # import os
402
- # import re
403
- # import fitz # PyMuPDF
404
- # import tempfile
405
- # import base64
406
- # from datetime import datetime
407
- # from gtts import gTTS
408
- # import streamlit as st
409
- # from transformers.pipelines import pipeline
410
- # from groq import Groq
411
-
412
- # # ✅ Hugging Face and GROQ secrets loaded via Hugging Face Spaces Secrets interface
413
-
414
- # # ⛳ Access secrets securely from environment variables
415
- # GROQ_API_KEY = os.getenv("GROQ_API_KEY")
416
- # HF_TOKEN = os.getenv("HF_TOKEN")
417
- # KAGGLE_USERNAME = os.getenv("KAGGLE_USERNAME")
418
- # KAGGLE_KEY = os.getenv("KAGGLE_KEY")
419
-
420
- # # ✅ Validate secrets
421
- # if not all([GROQ_API_KEY, HF_TOKEN, KAGGLE_USERNAME, KAGGLE_KEY]):
422
- # st.error("❌ One or more required API keys are missing from the environment.")
423
- # st.stop()
424
-
425
- # # ✅ Initialize Groq client
426
- # client = Groq(api_key=GROQ_API_KEY)
427
-
428
- # # ✅ Load phishing detection pipeline from Hugging Face
429
- # phishing_pipe = pipeline(
430
- # "text-classification",
431
- # model="ealvaradob/bert-finetuned-phishing",
432
- # token=HF_TOKEN
433
- # )
434
-
435
- # # ✅ Language and role options
436
- # language_choices = ["English", "Urdu", "French"]
437
- # role_choices = ["Admin", "Procurement", "Logistics"]
438
-
439
- # # ✅ Glossary terms
440
- # GLOSSARY = {
441
- # "phishing": "Phishing is a scam where attackers trick you into revealing personal information.",
442
- # "malware": "Malicious software designed to harm or exploit systems.",
443
- # "spam": "Unwanted or unsolicited messages.",
444
- # "tone": "The emotional character of the message."
445
- # }
446
-
447
- # # ✅ Translations (demo dictionary-based)
448
- # TRANSLATIONS = {
449
- # "Phishing": {"Urdu": "فشنگ", "French": "Hameçonnage"},
450
- # "Spam": {"Urdu": "سپیم", "French": "Courrier indésirable"},
451
- # "Malware": {"Urdu": "میلویئر", "French": "Logiciel malveillant"},
452
- # "Safe": {"Urdu": "محفوظ", "French": "Sûr"}
453
- # }
454
-
455
- # # ✅ In-memory history
456
- # if "history" not in st.session_state:
457
- # st.session_state.history = []
458
-
459
- # # =======================
460
- # # Streamlit UI
461
- # # =======================
462
- # st.set_page_config(page_title="ZeroPhish Gate", layout="wide")
463
-
464
- # st.markdown("""
465
- # <style>
466
- # .report-container {
467
- # border: 1px solid #ddd;
468
- # padding: 1rem;
469
- # border-radius: 10px;
470
- # background-color: #f9f9f9;
471
- # }
472
- # .highlight {
473
- # font-weight: bold;
474
- # color: #d9534f;
475
- # }
476
- # </style>
477
- # """, unsafe_allow_html=True)
478
-
479
- # st.title("🛡️ ZeroPhish Gate")
480
- # st.markdown("AI-powered phishing message detection and explanation.")
481
-
482
- # # Input fields
483
- # col1, col2 = st.columns([3, 1])
484
- # with col1:
485
- # text_input = st.text_area("✉️ Paste Suspicious Message", height=200)
486
- # uploaded_file = st.file_uploader("📄 Upload PDF/TXT (optional)", type=["pdf", "txt"])
487
-
488
- # with col2:
489
- # language = st.selectbox("🌐 Preferred Language", language_choices)
490
- # role = st.selectbox("🧑‍💼 Your Role", role_choices)
491
-
492
- # analyze_btn = st.button("🔍 Analyze with AI")
493
- # clear_btn = st.button("🗑️ Clear History")
494
-
495
- # # =======================
496
- # # Function Definitions
497
- # # =======================
498
- # def extract_text_from_file(file):
499
- # if file is None:
500
- # return ""
501
- # ext = file.name.split(".")[-1].lower()
502
- # if ext == "pdf":
503
- # doc = fitz.open(stream=file.read(), filetype="pdf")
504
- # return "\n".join(page.get_text() for page in doc)
505
- # elif ext == "txt":
506
- # return file.read().decode("utf-8")
507
- # return ""
508
-
509
- # def analyze_with_huggingface(text):
510
- # try:
511
- # result = phishing_pipe(text)
512
- # label = result[0]['label']
513
- # confidence = round(result[0]['score'] * 100, 2)
514
- # threat_type = {
515
- # "PHISHING": "Phishing",
516
- # "SPAM": "Spam",
517
- # "MALWARE": "Malware",
518
- # "LEGITIMATE": "Safe"
519
- # }.get(label.upper(), "Unknown")
520
- # return label, confidence, threat_type
521
- # except Exception as e:
522
- # return "Error", 0, f"Error: {e}"
523
-
524
- # def semantic_analysis(text):
525
- # response = client.chat.completions.create(
526
- # model="llama3-8b-8192",
527
- # messages=[
528
- # {"role": "system", "content": "You are a cybersecurity assistant."},
529
- # {"role": "user", "content": f"Explain this suspicious message for a {role} in {language} without ending in questions:\n{text}"}
530
- # ]
531
- # )
532
- # raw = response.choices[0].message.content
533
- # clean = re.sub(r"Is there anything else you'd like.*", "", raw, flags=re.I).strip()
534
- # return clean
535
-
536
- # def translate_label(threat_type):
537
- # return TRANSLATIONS.get(threat_type, {}).get(language, threat_type)
538
-
539
- # def text_to_speech(text):
540
- # try:
541
- # tts = gTTS(text=text, lang='en')
542
- # with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as fp:
543
- # tts.save(fp.name)
544
- # audio_path = fp.name
545
- # audio_file = open(audio_path, "rb")
546
- # audio_bytes = audio_file.read()
547
- # st.audio(audio_bytes, format="audio/mp3")
548
- # audio_file.close()
549
- # os.remove(audio_path)
550
- # except Exception as e:
551
- # st.error(f"❌ Audio playback error: {e}")
552
-
553
- # def create_report(label, score, threat_type, explanation, text):
554
- # ts = datetime.now().strftime("%Y%m%d_%H%M%S")
555
- # filename = f"Zerophish_Report_{ts}.txt"
556
- # report = f"""
557
- # 🔍 AI Threat Detection Report
558
-
559
- # Input Message:
560
- # {text}
561
-
562
- # Prediction: {label}
563
- # Threat Type: {threat_type}
564
- # Confidence: {score}%
565
-
566
- # ---
567
-
568
- # 🧠 Explanation:
569
- # {explanation}
570
- # """
571
- # with open(filename, "w") as f:
572
- # f.write(report)
573
- # return filename
574
-
575
- # def render_history():
576
- # with st.expander("🕓 View Analysis History", expanded=True):
577
- # for i, record in enumerate(reversed(st.session_state.history)):
578
- # with st.container():
579
- # st.markdown(f"**🔢 Entry #{len(st.session_state.history) - i}**")
580
- # st.markdown(f"**📝 Input:** {record['input'][:100]}...")
581
- # st.markdown(f"**🔐 Type:** {record['threat']} | **📊 Confidence:** {record['score']}%")
582
- # st.markdown(f"**📖 Summary:** {record['summary'][:200]}...")
583
- # st.markdown("---")
584
-
585
- # # =======================
586
- # # Run Analysis
587
- # # =======================
588
- # if clear_btn:
589
- # st.session_state.history.clear()
590
- # st.success("✅ History cleared!")
591
-
592
- # if analyze_btn:
593
- # combined_text = text_input
594
- # if uploaded_file:
595
- # extracted = extract_text_from_file(uploaded_file)
596
- # combined_text += "\n" + extracted
597
-
598
- # if not combined_text.strip():
599
- # st.warning("⚠️ Please enter some text or upload a file to analyze.")
600
- # else:
601
- # label, score, threat_type = analyze_with_huggingface(combined_text)
602
- # translated_threat = translate_label(threat_type)
603
-
604
- # st.subheader("🔍 AI Threat Detection Result")
605
- # st.markdown(f"<div class='report-container'>"
606
- # f"<p><span class='highlight'>Prediction:</span> {label}</p>"
607
- # f"<p><span class='highlight'>Threat Type:</span> {threat_type} ({translated_threat})</p>"
608
- # f"<p><span class='highlight'>Confidence:</span> {score}%</p>"
609
- # f"</div>", unsafe_allow_html=True)
610
-
611
- # summary = ""
612
- # if threat_type.lower() != "safe":
613
- # with st.expander("🧠 Semantic Reanalysis by LLaMA"):
614
- # summary = semantic_analysis(combined_text)
615
- # st.write(summary)
616
-
617
- # if st.button("🔊 Play Explanation as Audio"):
618
- # text_to_speech(summary)
619
-
620
- # if st.button("📤 Send Report to IT"):
621
- # st.success("📨 Report sent to IT successfully.")
622
-
623
- # # Save history
624
- # st.session_state.history.append({
625
- # "input": combined_text,
626
- # "threat": threat_type,
627
- # "score": score,
628
- # "summary": summary
629
- # })
630
-
631
- # # Generate and offer download link
632
- # if summary:
633
- # report_path = create_report(label, score, threat_type, summary, combined_text)
634
- # with open(report_path, "rb") as f:
635
- # b64 = base64.b64encode(f.read()).decode()
636
- # href = f'<a href="data:file/txt;base64,{b64}" download="{report_path}">📄 Download Full Report</a>'
637
- # st.markdown(href, unsafe_allow_html=True)
638
-
639
- # with st.expander("📜 Glossary Help"):
640
- # for term, definition in GLOSSARY.items():
641
- # st.markdown(f"**{term.capitalize()}**: {definition}")
642
-
643
- # render_history()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
  import re
3
  import fitz # PyMuPDF
4
  import tempfile
5
  import base64
6
  from datetime import datetime
7
+ from io import BytesIO
8
  from gtts import gTTS
9
  import streamlit as st
10
  from transformers import pipeline
 
53
  "Safe": {"Urdu": "محفوظ", "French": "Sûr"}
54
  }
55
 
56
+ # ✅ In-memory history and audio state
57
  if "history" not in st.session_state:
58
  st.session_state.history = []
59
+ if "current_audio" not in st.session_state:
60
+ st.session_state.current_audio = None
61
 
62
  # =======================
63
  # Streamlit UI
 
68
  <style>
69
  .report-container {
70
  border: 1px solid #ddd;
71
+ padding: 1.5rem;
72
+ border-radius: 15px;
73
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
74
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
75
+ margin: 1rem 0;
76
  }
77
  .highlight {
78
  font-weight: bold;
79
  color: #d9534f;
80
+ background-color: #fff3cd;
81
+ padding: 2px 6px;
82
+ border-radius: 4px;
83
+ }
84
+ .audio-section {
85
+ background-color: #e8f4f8;
86
+ padding: 1rem;
87
+ border-radius: 10px;
88
+ border-left: 4px solid #17a2b8;
89
+ margin: 1rem 0;
90
+ }
91
+ .success-audio {
92
+ color: #155724;
93
+ background-color: #d4edda;
94
+ border: 1px solid #c3e6cb;
95
+ padding: 0.75rem;
96
+ border-radius: 0.375rem;
97
+ margin: 0.5rem 0;
98
+ }
99
+ .stAudio > div {
100
+ background-color: #f8f9fa;
101
+ border-radius: 10px;
102
+ padding: 0.5rem;
103
  }
104
  </style>
105
  """, unsafe_allow_html=True)
 
164
  def translate_label(threat_type):
165
  return TRANSLATIONS.get(threat_type, {}).get(language, threat_type)
166
 
167
+ def text_to_speech(text, language_code='en'):
168
+ """Convert text to speech and return audio bytes"""
169
+ try:
170
+ # Map languages to gTTS language codes
171
+ lang_map = {
172
+ "English": "en",
173
+ "Urdu": "ur",
174
+ "French": "fr"
175
+ }
176
+ lang_code = lang_map.get(language_code, "en")
177
+
178
+ # Limit text length for better performance
179
+ if len(text) > 1000:
180
+ text = text[:1000] + "... (truncated for audio)"
181
+
182
+ # Create TTS object
183
+ tts = gTTS(text=text, lang=lang_code, slow=False)
184
+
185
+ # Use BytesIO to handle audio in memory
186
+ audio_buffer = BytesIO()
187
+ tts.write_to_fp(audio_buffer)
188
+ audio_buffer.seek(0)
189
+
190
+ return audio_buffer.getvalue()
191
+
192
+ except Exception as e:
193
+ st.error(f"❌ Audio generation failed: {str(e)}")
194
+ # Try with English as fallback
195
+ if lang_code != 'en':
196
+ try:
197
+ st.info("🔄 Trying with English language...")
198
+ tts = gTTS(text=text, lang='en', slow=False)
199
+ audio_buffer = BytesIO()
200
+ tts.write_to_fp(audio_buffer)
201
+ audio_buffer.seek(0)
202
+ return audio_buffer.getvalue()
203
+ except:
204
+ pass
205
+ return None
206
 
207
  def render_history():
208
  with st.expander("🕓 View Analysis History"):
 
219
  # =======================
220
  if clear_btn:
221
  st.session_state.history.clear()
222
+ if 'current_audio' in st.session_state:
223
+ st.session_state.current_audio = None
224
+ st.success("✅ History and audio cleared!")
225
 
226
  if analyze_btn:
227
  combined_text = text_input
 
244
 
245
  summary = ""
246
  if threat_type.lower() != "safe":
247
+ with st.expander("🧠 Semantic Reanalysis by LLaMA", expanded=True):
248
+ with st.spinner("🤖 Generating AI explanation..."):
249
+ summary = semantic_analysis(combined_text)
250
  st.write(summary)
251
 
252
+ # Enhanced Audio section
253
+ st.markdown("---")
254
+ st.markdown("### 🎧 Audio Explanation")
255
+
256
+ # Create audio content upfront to avoid regeneration
257
+ if 'current_audio' not in st.session_state:
258
+ st.session_state.current_audio = None
259
+
260
+ col_audio1, col_audio2, col_audio3 = st.columns([1, 1, 2])
261
+
262
+ with col_audio1:
263
+ if st.button("🎵 Generate Audio", key="gen_audio_btn", type="primary"):
264
+ with st.spinner("🎵 Creating audio..."):
265
+ st.session_state.current_audio = text_to_speech(summary, language)
266
+ if st.session_state.current_audio:
267
+ st.success("✅ Audio ready!")
268
+ else:
269
+ st.error("❌ Audio generation failed")
270
+
271
+ with col_audio2:
272
+ if st.button("🔄 Refresh Audio", key="refresh_audio_btn"):
273
+ st.session_state.current_audio = None
274
+ st.info("🔄 Audio cleared. Click Generate Audio again.")
275
+
276
+ # Display audio player if audio is available
277
+ if st.session_state.current_audio:
278
+ st.markdown('<div class="audio-section">', unsafe_allow_html=True)
279
+ st.markdown("**🔊 Click play button below:**")
280
+ st.audio(st.session_state.current_audio, format="audio/mp3")
281
+ st.markdown("</div>", unsafe_allow_html=True)
282
+ else:
283
+ st.info("🎵 Click 'Generate Audio' to hear the AI explanation")
284
 
285
  # Save history
286
  st.session_state.history.append({
 
295
  st.markdown(f"**{term.capitalize()}**: {definition}")
296
 
297
  render_history()