NexusInstruments commited on
Commit
4f6bb50
·
verified ·
1 Parent(s): 3a2d7a0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +157 -86
app.py CHANGED
@@ -1,73 +1,79 @@
1
  import os
2
  import json
 
3
  import tempfile
 
 
4
  import gradio as gr
5
  from huggingface_hub import InferenceClient
6
  from gtts import gTTS
7
 
 
 
 
 
 
8
  try:
9
  import PyPDF2
10
  except ImportError:
11
  PyPDF2 = None
12
 
13
 
14
- # =========================================
15
- # Configuration
16
- # =========================================
17
 
18
  MODEL_OPTIONS = {
19
- "Zephyr 7B (Serverless)": "HuggingFaceH4/zephyr-7b-beta",
20
- "Mixtral 8x7B (Serverless)": "mistralai/Mixtral-8x7B-Instruct-v0.1",
21
  }
22
 
23
  FALLBACK_MODEL = "HuggingFaceH4/zephyr-7b-beta"
24
 
 
 
 
 
 
 
25
  PERSONA_PRESETS = {
26
  "Balanced Assistant": "You are a helpful, intelligent AI assistant.",
27
-
28
  "Forensic Psychologist": """
29
  You are acting as a forensic psychologist.
30
  Provide structured, objective, evidence-based analysis.
31
  Do NOT diagnose real individuals.
32
  Separate facts, interpretations, and limitations.
33
  Maintain professional neutrality.
34
- This analysis is educational and not a clinical diagnosis.
35
  """
36
  }
37
 
38
  TASK_MODES = {
39
  "General Chat": "{user_input}",
40
-
41
  "Behavioral Analysis": """
42
- Conduct a behavioral analysis.
43
  1. Behavioral Indicators
44
  2. Emotional Tone
45
  3. Cognitive Patterns
46
- 4. Stress/Deception Markers
47
- 5. Risk-Relevant Observations
48
- 6. Alternative Explanations
49
- 7. Limitations
50
  Material:
51
  {user_input}
52
  """,
53
-
54
- "Explain Code (Natural Voice)": """
55
  Explain the following code clearly and conversationally,
56
- as if teaching a developer step-by-step in a calm, natural voice.
57
 
58
  Code:
59
  {user_input}
60
  """
61
  }
62
 
63
- MAX_CONTEXT_CHARS = 10000
64
- MAX_HISTORY_PAIRS = 6
65
- MAX_INPUT_CHARS = 3000
66
 
67
-
68
- # =========================================
69
- # Helpers
70
- # =========================================
71
 
72
  def get_client(model_id):
73
  token = os.environ.get("HF_TOKEN")
@@ -76,6 +82,39 @@ def get_client(model_id):
76
  return InferenceClient(model=model_id, token=token)
77
 
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  def extract_text(file):
80
  if not file:
81
  return ""
@@ -104,87 +143,112 @@ def text_to_speech(text):
104
  return temp_file.name
105
 
106
 
107
- def run_model(client, messages, temperature):
108
- response = client.chat_completion(
109
- messages=messages,
110
- max_tokens=700,
111
- temperature=temperature,
112
- top_p=0.95,
113
- stream=False,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  )
115
- return response.choices[0].message.content
116
 
 
 
117
 
118
- # =========================================
119
- # Core Logic
120
- # =========================================
121
 
122
- def generate_response(message, history, model_label, persona_label, task_mode, uploaded_file, voice_enabled):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
  if not message:
125
  return history, None
126
 
127
- try:
128
- message = message[:MAX_INPUT_CHARS]
129
- history = history[-MAX_HISTORY_PAIRS * 2:]
130
-
131
- model_id = MODEL_OPTIONS[model_label]
132
- system_prompt = PERSONA_PRESETS.get(persona_label, "")
133
- temperature = 0.4 if "Forensic" in persona_label else 0.7
134
 
135
- file_text = extract_text(uploaded_file)
136
- if file_text:
137
- file_text = file_text[:MAX_CONTEXT_CHARS]
138
- system_prompt += f"\n\nUse this document context when relevant:\n\n{file_text}"
139
 
140
- messages = [{"role": "system", "content": system_prompt}]
141
- messages.extend(history)
 
 
142
 
143
- formatted_input = TASK_MODES[task_mode].format(user_input=message)
144
- messages.append({"role": "user", "content": formatted_input})
145
 
146
- try:
147
- client = get_client(model_id)
148
- answer = run_model(client, messages, temperature)
149
- except Exception:
150
- fallback_client = get_client(FALLBACK_MODEL)
151
- answer = "⚠️ Fallback model used.\n\n" + run_model(fallback_client, messages, temperature)
152
 
153
- history.append({"role": "user", "content": message})
154
- history.append({"role": "assistant", "content": answer})
155
 
156
- audio_file = None
157
- if voice_enabled:
158
- audio_file = text_to_speech(answer)
159
 
160
- return history, audio_file
161
 
162
- except Exception as e:
163
- history.append({"role": "assistant", "content": f"⚠️ ERROR:\n\n{str(e)}"})
164
- return history, None
165
 
 
166
 
167
- # =========================================
168
- # Utilities
169
- # =========================================
170
 
171
  def clear_chat():
172
  return [], None
173
 
174
- def export_chat(history):
175
- file_path = "conversation.json"
176
- with open(file_path, "w") as f:
177
- json.dump(history, f, indent=2)
178
- return file_path
179
 
180
-
181
- # =========================================
182
  # UI
183
- # =========================================
184
 
185
  with gr.Blocks(theme=gr.themes.Soft(), title="Omniscient IRIS") as demo:
186
 
187
- gr.Markdown("## Omniscient IRIS — Voice Enabled")
188
 
189
  with gr.Row():
190
 
@@ -192,7 +256,7 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Omniscient IRIS") as demo:
192
 
193
  chatbot = gr.Chatbot(height=500, type="messages")
194
  msg = gr.Textbox(
195
- placeholder="Enter material for analysis or ask a question...",
196
  show_label=False
197
  )
198
 
@@ -221,26 +285,33 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Omniscient IRIS") as demo:
221
  label="Mode"
222
  )
223
 
224
- voice_toggle = gr.Checkbox(label="Enable Voice Output", value=True)
 
 
 
225
 
226
  file_upload = gr.File(
227
- label="Upload Document (txt, pdf, md)",
228
  file_types=[".txt", ".pdf", ".md"]
229
  )
230
 
231
- export_btn = gr.Button("Export Conversation")
232
 
233
  state = gr.State([])
234
 
235
  send_btn.click(
236
  generate_response,
237
- inputs=[msg, state, model_selector, persona_selector, task_selector, file_upload, voice_toggle],
 
 
238
  outputs=[chatbot, audio_output],
239
  )
240
 
241
  msg.submit(
242
  generate_response,
243
- inputs=[msg, state, model_selector, persona_selector, task_selector, file_upload, voice_toggle],
 
 
244
  outputs=[chatbot, audio_output],
245
  )
246
 
@@ -249,10 +320,10 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Omniscient IRIS") as demo:
249
  outputs=[chatbot, audio_output],
250
  ).then(lambda: [], outputs=state)
251
 
252
- export_btn.click(
253
- export_chat,
254
  inputs=chatbot,
255
- outputs=gr.File(label="Download JSON")
256
  )
257
 
258
  if __name__ == "__main__":
 
1
  import os
2
  import json
3
+ import time
4
  import tempfile
5
+ from datetime import datetime
6
+
7
  import gradio as gr
8
  from huggingface_hub import InferenceClient
9
  from gtts import gTTS
10
 
11
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
12
+ from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
13
+ from reportlab.lib import colors
14
+ from reportlab.lib.units import inch
15
+
16
  try:
17
  import PyPDF2
18
  except ImportError:
19
  PyPDF2 = None
20
 
21
 
22
+ # =========================================================
23
+ # CONFIGURATION
24
+ # =========================================================
25
 
26
  MODEL_OPTIONS = {
27
+ "Zephyr 7B (Stable)": "HuggingFaceH4/zephyr-7b-beta",
28
+ "Mixtral 8x7B": "mistralai/Mixtral-8x7B-Instruct-v0.1",
29
  }
30
 
31
  FALLBACK_MODEL = "HuggingFaceH4/zephyr-7b-beta"
32
 
33
+ MAX_CONTEXT_CHARS = 10000
34
+ MAX_HISTORY_PAIRS = 6
35
+ MAX_INPUT_CHARS = 3000
36
+ CHAT_LOG_FILE = "chat_master_log.json"
37
+
38
+
39
  PERSONA_PRESETS = {
40
  "Balanced Assistant": "You are a helpful, intelligent AI assistant.",
 
41
  "Forensic Psychologist": """
42
  You are acting as a forensic psychologist.
43
  Provide structured, objective, evidence-based analysis.
44
  Do NOT diagnose real individuals.
45
  Separate facts, interpretations, and limitations.
46
  Maintain professional neutrality.
 
47
  """
48
  }
49
 
50
  TASK_MODES = {
51
  "General Chat": "{user_input}",
 
52
  "Behavioral Analysis": """
53
+ Conduct a behavioral analysis:
54
  1. Behavioral Indicators
55
  2. Emotional Tone
56
  3. Cognitive Patterns
57
+ 4. Risk Observations
58
+ 5. Alternative Explanations
59
+ 6. Limitations
60
+
61
  Material:
62
  {user_input}
63
  """,
64
+ "Explain Code": """
 
65
  Explain the following code clearly and conversationally,
66
+ as if teaching a developer step-by-step.
67
 
68
  Code:
69
  {user_input}
70
  """
71
  }
72
 
 
 
 
73
 
74
+ # =========================================================
75
+ # INFERENCE LAYER
76
+ # =========================================================
 
77
 
78
  def get_client(model_id):
79
  token = os.environ.get("HF_TOKEN")
 
82
  return InferenceClient(model=model_id, token=token)
83
 
84
 
85
+ def run_with_retry(client, messages, temperature, retries=3, delay=2):
86
+ for attempt in range(retries):
87
+ try:
88
+ response = client.chat_completion(
89
+ messages=messages,
90
+ max_tokens=700,
91
+ temperature=temperature,
92
+ top_p=0.95,
93
+ stream=False,
94
+ )
95
+ return response.choices[0].message.content
96
+ except Exception as e:
97
+ if attempt < retries - 1:
98
+ time.sleep(delay)
99
+ else:
100
+ raise e
101
+
102
+
103
+ def generate_ai_response(model_id, messages, temperature):
104
+ try:
105
+ client = get_client(model_id)
106
+ return run_with_retry(client, messages, temperature)
107
+ except Exception:
108
+ fallback_client = get_client(FALLBACK_MODEL)
109
+ return "⚠️ Fallback model used.\n\n" + run_with_retry(
110
+ fallback_client, messages, temperature
111
+ )
112
+
113
+
114
+ # =========================================================
115
+ # UTILITIES
116
+ # =========================================================
117
+
118
  def extract_text(file):
119
  if not file:
120
  return ""
 
143
  return temp_file.name
144
 
145
 
146
+ def append_to_master_log(user_msg, assistant_msg):
147
+ entry = {
148
+ "timestamp": datetime.utcnow().isoformat(),
149
+ "user": user_msg,
150
+ "assistant": assistant_msg
151
+ }
152
+
153
+ if os.path.exists(CHAT_LOG_FILE):
154
+ with open(CHAT_LOG_FILE, "r") as f:
155
+ data = json.load(f)
156
+ else:
157
+ data = []
158
+
159
+ data.append(entry)
160
+
161
+ with open(CHAT_LOG_FILE, "w") as f:
162
+ json.dump(data, f, indent=2)
163
+
164
+
165
+ def export_pdf(history):
166
+ file_path = f"transcript_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}.pdf"
167
+ doc = SimpleDocTemplate(file_path)
168
+ elements = []
169
+
170
+ styles = getSampleStyleSheet()
171
+ user_style = ParagraphStyle(
172
+ "UserStyle",
173
+ parent=styles["Normal"],
174
+ textColor=colors.blue,
175
+ spaceAfter=6
176
+ )
177
+
178
+ assistant_style = ParagraphStyle(
179
+ "AssistantStyle",
180
+ parent=styles["Normal"],
181
+ textColor=colors.darkgreen,
182
+ spaceAfter=12
183
  )
 
184
 
185
+ elements.append(Paragraph("Omniscient IRIS Transcript", styles["Heading1"]))
186
+ elements.append(Spacer(1, 0.3 * inch))
187
 
188
+ for msg in history:
189
+ role = msg["role"]
190
+ content = msg["content"].replace("\n", "<br/>")
191
 
192
+ if role == "user":
193
+ elements.append(Paragraph(f"<b>User:</b> {content}", user_style))
194
+ elif role == "assistant":
195
+ elements.append(Paragraph(f"<b>Assistant:</b> {content}", assistant_style))
196
+
197
+ doc.build(elements)
198
+ return file_path
199
+
200
+
201
+ # =========================================================
202
+ # CORE CHAT LOGIC
203
+ # =========================================================
204
+
205
+ def generate_response(message, history, model_label, persona_label,
206
+ task_mode, uploaded_file, voice_enabled):
207
 
208
  if not message:
209
  return history, None
210
 
211
+ message = message[:MAX_INPUT_CHARS]
212
+ history = history[-MAX_HISTORY_PAIRS * 2:]
 
 
 
 
 
213
 
214
+ model_id = MODEL_OPTIONS[model_label]
215
+ system_prompt = PERSONA_PRESETS[persona_label]
216
+ temperature = 0.4 if "Forensic" in persona_label else 0.7
 
217
 
218
+ file_text = extract_text(uploaded_file)
219
+ if file_text:
220
+ file_text = file_text[:MAX_CONTEXT_CHARS]
221
+ system_prompt += f"\n\nDocument Context:\n{file_text}"
222
 
223
+ messages = [{"role": "system", "content": system_prompt}]
224
+ messages.extend(history)
225
 
226
+ formatted_input = TASK_MODES[task_mode].format(user_input=message)
227
+ messages.append({"role": "user", "content": formatted_input})
 
 
 
 
228
 
229
+ answer = generate_ai_response(model_id, messages, temperature)
 
230
 
231
+ history.append({"role": "user", "content": message})
232
+ history.append({"role": "assistant", "content": answer})
 
233
 
234
+ append_to_master_log(message, answer)
235
 
236
+ audio_file = text_to_speech(answer) if voice_enabled else None
 
 
237
 
238
+ return history, audio_file
239
 
 
 
 
240
 
241
  def clear_chat():
242
  return [], None
243
 
 
 
 
 
 
244
 
245
+ # =========================================================
 
246
  # UI
247
+ # =========================================================
248
 
249
  with gr.Blocks(theme=gr.themes.Soft(), title="Omniscient IRIS") as demo:
250
 
251
+ gr.Markdown("## Omniscient IRIS — Resilient Voice Enabled Assistant")
252
 
253
  with gr.Row():
254
 
 
256
 
257
  chatbot = gr.Chatbot(height=500, type="messages")
258
  msg = gr.Textbox(
259
+ placeholder="Enter material for analysis...",
260
  show_label=False
261
  )
262
 
 
285
  label="Mode"
286
  )
287
 
288
+ voice_toggle = gr.Checkbox(
289
+ label="Enable Voice Output",
290
+ value=True
291
+ )
292
 
293
  file_upload = gr.File(
294
+ label="Upload Document",
295
  file_types=[".txt", ".pdf", ".md"]
296
  )
297
 
298
+ pdf_btn = gr.Button("Download PDF Transcript")
299
 
300
  state = gr.State([])
301
 
302
  send_btn.click(
303
  generate_response,
304
+ inputs=[msg, state, model_selector,
305
+ persona_selector, task_selector,
306
+ file_upload, voice_toggle],
307
  outputs=[chatbot, audio_output],
308
  )
309
 
310
  msg.submit(
311
  generate_response,
312
+ inputs=[msg, state, model_selector,
313
+ persona_selector, task_selector,
314
+ file_upload, voice_toggle],
315
  outputs=[chatbot, audio_output],
316
  )
317
 
 
320
  outputs=[chatbot, audio_output],
321
  ).then(lambda: [], outputs=state)
322
 
323
+ pdf_btn.click(
324
+ export_pdf,
325
  inputs=chatbot,
326
+ outputs=gr.File(label="Download PDF")
327
  )
328
 
329
  if __name__ == "__main__":