Vedika commited on
Commit
9b19acf
·
verified ·
1 Parent(s): 3aa6701

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +462 -325
app.py CHANGED
@@ -1,3 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
  import sys
3
  import json
@@ -9,7 +21,10 @@ import tempfile
9
  import threading
10
  import traceback
11
  import requests
12
- from typing import Dict, Any, List, Optional, Generator
 
 
 
13
 
14
  from flask import (
15
  Flask,
@@ -19,517 +34,639 @@ from flask import (
19
  render_template_string,
20
  send_file,
21
  jsonify,
22
- make_response
 
23
  )
 
24
  import edge_tts
25
 
26
  # =========================================================================================
27
- # SECTION 1: ADVANCED LOGGING CONFIGURATION
28
  # =========================================================================================
29
- # सिस्टम की हर गतिविधि को ट्रैक करने के लिए कस्टम लॉगर।
30
- class CustomFormatter(logging.Formatter):
31
- """लॉगिंग आउटपुट को सुंदर और स्पष्ट बनाने के लिए कस्टम फॉर्मेटर।"""
32
- grey = "\x1b[38;20m"
33
- yellow = "\x1b[33;20m"
34
- red = "\x1b[31;20m"
35
- bold_red = "\x1b[31;1m"
36
- green = "\x1b[32;20m"
37
- reset = "\x1b[0m"
38
- format_str = "%(asctime)s - ARJUN-CORE - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)"
 
 
 
 
 
39
 
40
  FORMATS = {
41
- logging.DEBUG: grey + format_str + reset,
42
- logging.INFO: green + format_str + reset,
43
- logging.WARNING: yellow + format_str + reset,
44
- logging.ERROR: red + format_str + reset,
45
- logging.CRITICAL: bold_red + format_str + reset
46
  }
47
 
48
- def format(self, record):
49
- log_fmt = self.FORMATS.get(record.levelno)
50
- formatter = logging.Formatter(log_fmt, datefmt='%Y-%m-%d %H:%M:%S')
51
  return formatter.format(record)
52
 
53
- logger = logging.getLogger("ArjunBackend")
54
- logger.setLevel(logging.DEBUG)
55
- ch = logging.StreamHandler()
56
- ch.setFormatter(CustomFormatter())
57
- logger.addHandler(ch)
 
 
 
 
 
 
 
 
 
58
 
59
  # =========================================================================================
60
- # SECTION 2: CUSTOM EXCEPTIONS
61
  # =========================================================================================
62
- # त्रुटियों को बारीकी से पकड़ने के लिए कस्टम एक्सेप्शन क्लासेस।
63
- class ArjunBaseException(Exception):
64
- """अर्जुन सिस्टम के लिए बेस एक्सेप्शन क्लास।"""
65
- def __init__(self, message: str, status_code: int = 500):
66
  super().__init__(message)
67
  self.message = message
68
  self.status_code = status_code
 
69
 
70
- class ConfigurationError(ArjunBaseException):
71
- """जब पर्यावरण चर (Environment Variables) गायब हों।"""
72
  pass
73
 
74
- class LLMAPIConnectionError(ArjunBaseException):
75
- """जब भाषा मॉडल API से संपर्क टूट जाए।"""
76
  pass
77
 
78
- class TTSGenerationError(ArjunBaseException):
79
- """जब प्रभात न्यूरल आवाज़ जनरेट करने में विफल हो।"""
80
  pass
81
 
82
  # =========================================================================================
83
- # SECTION 3: SYSTEM CONFIGURATION MANAGER
84
  # =========================================================================================
85
- class ConfigManager:
 
 
 
 
 
 
 
 
 
86
  """
87
- यह क्लास सिस्टम की सभी सेटिंग्स और सीक्रेट्स (Secrets) को मैनेज करती है।
88
- यह सुनिश्चित करती है कि कोई भी डेटा हार्डकोडेड (Hardcoded) न हो।
89
  """
90
- def __init__(self):
91
- logger.info("Initializing Configuration Manager...")
92
- self.api_key = os.environ.get("YOUR_VEDIKA_API_KEY")
93
- self.base_url = os.environ.get("BASE_URL")
94
- self.model_id = os.environ.get("MODEL_ID")
 
 
 
 
 
95
 
96
- self.invoke_url = self._format_base_url(self.base_url)
97
- self.validate_config()
 
 
 
 
98
 
99
- def _format_base_url(self, url: Optional[str]) -> str:
100
- """API URL को सही प्रारूप में बदलता है।"""
101
- if not url:
102
  return ""
103
- url = url.strip()
104
- if not url.endswith("/chat/completions"):
105
- return f"{url.rstrip('/')}/chat/completions"
106
- return url
107
-
108
- def validate_config(self):
109
- """जाँच करता है कि सभी ज़रूरी सीक्रेट्स मौजूद हैं या नहीं।"""
110
- missing = []
111
- if not self.api_key: missing.append("YOUR_VEDIKA_API_KEY")
112
- if not self.base_url: missing.append("BASE_URL")
113
- if not self.model_id: missing.append("MODEL_ID")
114
 
115
- if missing:
116
- error_msg = f"Critical Configuration Missing: {', '.join(missing)}"
117
- logger.error(error_msg)
118
- # हम सर्वर क्रैश नहीं करेंगे, बल्कि रिक्वेस्ट आने पर एरर देंगे।
119
- else:
120
- logger.info("All system configurations validated successfully.")
 
 
 
 
 
 
121
 
122
- # ग्लोबल कॉन्फिग ऑब्जेक्ट
123
- config = ConfigManager()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
125
  # =========================================================================================
126
- # SECTION 4: TEMPORARY FILE MANAGER (GARBAGE COLLECTION)
127
  # =========================================================================================
128
- class TempFileManager:
 
129
  """
130
- यह क्लास सुनिश्चित करती है कि जनरेट की गई ऑडियो (MP3) फाइल्स
131
- सिस्टम की मेमोरी भरें। यह उन्हें सुरक्षित रूप से डिलीट करती है।
132
  """
133
  def __init__(self):
134
- self.temp_dir = tempfile.gettempdir()
135
- self.active_files = set()
136
- logger.info(f"Temporary File Manager initialized at {self.temp_dir}")
137
-
138
- def create_temp_audio_path(self) -> str:
139
- """एक यूनीक सुरक्षित फाइल पाथ जनरेट करता है।"""
140
- unique_id = uuid.uuid4().hex
141
- file_path = os.path.join(self.temp_dir, f"arjun_tts_{unique_id}.mp3")
142
- self.active_files.add(file_path)
143
- return file_path
144
-
145
- def schedule_cleanup(self, file_path: str, delay_seconds: int = 60):
146
- """कुछ समय बाद फाइल को डिलीट करने के लिए बैकग्राउंड थ्रेड चलाता है।"""
147
- def _cleanup():
148
- time.sleep(delay_seconds)
149
  try:
150
- if os.path.exists(file_path):
151
- os.remove(file_path)
152
- logger.debug(f"Garbage Collection: Deleted {file_path}")
153
- if file_path in self.active_files:
154
- self.active_files.remove(file_path)
155
  except Exception as e:
156
- logger.error(f"Cleanup failed for {file_path}: {str(e)}")
157
 
158
- cleanup_thread = threading.Thread(target=_cleanup, daemon=True)
159
- cleanup_thread.start()
160
 
161
- file_manager = TempFileManager()
162
 
163
  # =========================================================================================
164
- # SECTION 5: ADVANCED TTS ENGINE (PRABHAT NEURAL HANDLER)
165
  # =========================================================================================
166
- class TTSEngine:
 
167
  """
168
- टेक्स्ट-टू-स्पीच (TTS) को हैंडल करने के लिए विशेष क्लास।
169
- यह Flask के सिंक्रोनस थ्रेड्स और Asyncio के बीच के टकराव को दूर करती है।
170
  """
171
  def __init__(self):
172
- # प्रभात न्यूरल (India Male) की सेटिंग्स
173
- # Pitch: -2% (प्राकृतिक भारीपन), Rate: +0% (सामान्य गति)
174
- self.voice = "en-IN-PrabhatNeural"
175
- self.pitch = "-2%"
176
- self.rate = "+0%"
177
- logger.info(f"TTS Engine initialized with Voice: {self.voice}")
178
-
179
- def generate_audio_sync(self, text: str, output_path: str) -> bool:
180
- """
181
- यह फंक्शन asyncio लूप को एक सुरक्षित आइसोलेटेड (Isolated) तरीके से चलाता है
182
- ताकि Flask सर्वर कभी हैंग न हो। यह यूज़र की सबसे बड़ी समस्या का समाधान है।
183
- """
184
- # टेक्स्ट की सफाई (Markdown हटाना)
185
- clean_text = self._clean_text_for_speech(text)
186
- if not clean_text:
187
- logger.warning("TTS Engine received empty text after cleaning.")
188
  return False
189
 
190
- logger.info(f"Starting TTS Generation for text length: {len(clean_text)}")
 
191
 
192
- # Async फंक्शन जो असल में edge-tts को कॉल करेगा
193
- async def _async_generate():
 
194
  try:
195
- communicate = edge_tts.Communicate(
196
- text=clean_text,
197
- voice=self.voice,
198
- pitch=self.pitch,
199
- rate=self.rate
200
  )
201
- await communicate.save(output_path)
202
  return True
203
  except Exception as e:
204
- logger.error(f"Edge-TTS Core Error: {str(e)}")
205
- traceback.print_exc()
206
  return False
207
 
208
- # नया इवेंट लूप बनाकर चलाना (Thread-safe)
209
- loop = asyncio.new_event_loop()
210
- asyncio.set_event_loop(loop)
211
  try:
212
- success = loop.run_until_complete(_async_generate())
213
  return success
214
- except Exception as e:
215
- logger.error(f"Event Loop Error during TTS: {str(e)}")
216
  return False
217
  finally:
218
- loop.close()
219
 
220
- def _clean_text_for_speech(self, text: str) -> str:
221
- """AI के आउटपुट से अनचाहे चिह्न हटाता है ताकि आवाज़ फटे।"""
222
  import re
223
- # Markdown इमेज��ज हटाना
 
224
  text = re.sub(r'!\[.*?\]\(.*?\)', '', text)
225
- # Markdown लिंक्स हटाना
226
  text = re.sub(r'\[.*?\]\(.*?\)', '', text)
227
- # <think> टैग्स हटाना
228
  text = re.sub(r'<think>.*?</think>', '', text, flags=re.DOTALL)
229
- # बोल्ड/इटैलिक चिह्न हटाना
230
- text = text.replace('*', '').replace('_', '').replace('`', '')
231
  return text.strip()
232
 
233
- tts_engine = TTSEngine()
234
 
235
  # =========================================================================================
236
- # SECTION 6: LLM API STREAMING HANDLER
237
  # =========================================================================================
238
- class LLMAPIHandler:
 
239
  """
240
- यह क्लास यूज़र के मैसेज और फाइल्स को प्रोसेस करके
241
- भाषा मॉडल (LLM) को भेजती है और स्ट्रीमिंग रिस्पॉन्स को वापस लाती है।
242
  """
243
- def __init__(self, cfg: ConfigManager):
244
- self.cfg = cfg
245
-
246
- def construct_messages(self, user_msg: str, attachments: List[Dict], sys_prompt: str, history: List[Dict]) -> List[Dict]:
247
- """पेलोड (Payload) का निर्माण करता है।"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  messages = []
249
 
250
- # 1. System Prompt
251
  if sys_prompt and sys_prompt.strip():
252
  messages.append({"role": "system", "content": sys_prompt.strip()})
253
 
254
- # 2. History (पुराने मैसेज)
255
- for h_msg in history:
256
- role = h_msg.get("role", "user")
257
- content = h_msg.get("content", "")
258
- if content:
259
- messages.append({"role": role, "content": content})
260
-
261
- # 3. Current User Message & Attachments
262
- content_payload = []
263
- if user_msg and user_msg.strip():
264
- content_payload.append({"type": "text", "text": user_message.strip()})
265
-
266
- for att in attachments:
267
- att_type = att.get("type")
268
- b64_data = att.get("data")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
 
270
- if not att_type or not b64_data:
271
- continue
272
 
273
- if att_type == "image":
274
- content_payload.append({
275
- "type": "image_url",
276
- "image_url": {"url": f"data:image/jpeg;base64,{b64_data}"}
277
- })
278
- elif att_type in ["audio", "file", "video"]:
279
- # वीडियो को भी ऑडियो/फाइल की तरह ट्रीट किया जाएगा अगर मॉडल सपोर्ट करता है
280
- content_payload.append({
281
- "type": "input_audio",
282
- "input_audio": {"data": b64_data, "format": "wav"}
283
- })
284
-
285
- # Fallback if empty
286
- if not content_payload:
287
- content_payload.append({"type": "text", "text": "Hello"})
288
-
289
- messages.append({"role": "user", "content": content_payload})
290
  return messages
291
 
292
- def stream_response(self, payload: Dict[str, Any]) -> Generator[str, None, None]:
293
- """API से डेटा स्ट्रीम करता है और सुरक्षित रूप से यील्ड (Yield) करता है।"""
 
 
 
294
  headers = {
295
  "Authorization": f"Bearer {self.cfg.api_key}",
296
  "Accept": "text/event-stream",
297
  "Content-Type": "application/json"
298
  }
299
 
300
- logger.info(f"Initiating streaming request to {self.cfg.invoke_url}...")
301
 
302
  try:
303
  with requests.post(
304
  self.cfg.invoke_url,
305
  headers=headers,
306
- json=payload,
307
  stream=True,
308
- timeout=120 # 2 minute timeout for safety
309
  ) as response:
310
 
311
- # Check for HTTP errors
312
  if response.status_code != 200:
313
- error_text = response.text
314
- logger.error(f"API HTTP Error {response.status_code}: {error_text}")
315
- yield f"data: {json.dumps({'choices': [{'delta': {'content': f'**API Error:** {response.status_code}'}}]})}\n\n"
 
316
  yield "data: [DONE]\n\n"
317
  return
318
 
319
- for line in response.iter_lines():
320
- if line:
321
- decoded_line = line.decode("utf-8")
322
- if decoded_line.startswith("data: "):
323
- yield decoded_line + "\n\n"
 
324
 
325
  except requests.exceptions.Timeout:
326
- logger.error("API Request Timed Out.")
327
- yield f"data: {json.dumps({'choices': [{'delta': {'content': '**Error:** Request timed out.'}}]})}\n\n"
 
 
328
  except requests.exceptions.RequestException as e:
329
- logger.error(f"API Network Error: {str(e)}")
330
- yield f"data: {json.dumps({'choices': [{'delta': {'content': '**Error:** Network connection failed.'}}]})}\n\n"
 
 
331
  except Exception as e:
332
- logger.error(f"Unknown Streaming Error: {str(e)}")
333
  traceback.print_exc()
334
- yield f"data: {json.dumps({'choices': [{'delta': {'content': '**Error:** Internal server error during stream.'}}]})}\n\n"
 
335
 
336
- llm_handler = LLMAPIHandler(config)
337
 
338
  # =========================================================================================
339
- # SECTION 7: FLASK APPLICATION SETUP
340
  # =========================================================================================
 
341
  app = Flask(__name__)
 
342
 
343
- # Request Logging Middleware
344
  @app.before_request
345
- def log_request_info():
346
- """हर रिक्वेस्ट की जानकारी लॉग करता है।"""
347
- logger.debug(f"Incoming Request: {request.method} {request.path}")
 
348
 
349
  @app.after_request
350
- def add_cors_headers(response):
351
- """CORS और सिक्योरिटी हेडर्स जोड़ता है।"""
352
  response.headers["Access-Control-Allow-Origin"] = "*"
353
  response.headers["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS"
354
  response.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization"
 
 
 
 
 
 
 
355
  return response
356
 
357
- # =========================================================================================
358
- # SECTION 8: API ROUTES & ENDPOINTS
359
- # =========================================================================================
360
-
361
  @app.route('/', methods=['GET'])
362
- def serve_frontend():
363
- """मुख्य HTML फाइल (index.html) सर्व करता है।"""
364
- logger.info("Serving index.html to client.")
365
  try:
366
- # सुनिश्चित करें कि index.html उसी डायरेक्टरी में है
367
- file_path = os.path.join(os.path.dirname(__file__), 'index.html')
368
- with open(file_path, 'r', encoding='utf-8') as f:
369
- html_content = f.read()
370
- return render_template_string(html_content)
371
  except FileNotFoundError:
372
- logger.error("index.html file not found on server.")
373
- return make_response("<h1>Error: index.html missing!</h1><p>Please place index.html in the same directory as app.py</p>", 404)
 
 
 
374
  except Exception as e:
375
- logger.error(f"Error reading index.html: {str(e)}")
376
- return make_response(f"<h1>Internal Error</h1><p>{str(e)}</p>", 500)
377
 
 
 
 
378
  @app.route('/api/chat', methods=['POST', 'OPTIONS'])
379
- def chat_endpoint():
380
- """LLM चैट प्रोसेसिंग के लिए मुख्य एंडपॉइंट।"""
 
 
 
381
  if request.method == 'OPTIONS':
382
  return Response(status=200)
383
 
384
- # 1. Validate Config
 
 
385
  if not config.api_key or not config.invoke_url or not config.model_id:
386
- logger.critical("Chat request denied. Missing Configuration Secrets.")
387
- return jsonify({"error": "Server is improperly configured. Check Secrets."}), 500
388
 
389
- # 2. Parse Request
390
  try:
391
- data = request.get_json() or {}
392
  except Exception as e:
393
- logger.error(f"Invalid JSON payload: {str(e)}")
394
- return jsonify({"error": "Invalid JSON format."}), 400
395
 
396
- user_message = data.get("message", "")
397
- attachments = data.get("attachments", [])
398
- system_prompt = data.get("system_prompt", "")
399
- history = data.get("history", [])
400
- max_tokens = data.get("max_tokens", 4096)
401
- temperature = data.get("temperature", 0.7)
402
 
403
- logger.info(f"Received chat request. Msg length: {len(user_message)}, Attachments: {len(attachments)}")
404
 
405
- # 3. Construct Payload
406
  try:
407
- messages = llm_handler.construct_messages(user_message, attachments, system_prompt, history)
408
  except Exception as e:
409
- logger.error(f"Payload construction failed: {str(e)}")
410
- return jsonify({"error": "Failed to construct message payload."}), 500
 
411
 
412
- api_payload = {
413
  "model": config.model_id,
414
- "messages": messages,
415
  "max_tokens": int(max_tokens),
416
  "temperature": float(temperature),
417
- "top_p": 0.70,
418
  "stream": True
419
  }
420
 
421
- # 4. Stream Response
422
  return Response(
423
- stream_with_context(llm_handler.stream_response(api_payload)),
424
  mimetype='text/event-stream'
425
  )
426
 
427
-
 
 
428
  @app.route('/api/tts', methods=['POST', 'OPTIONS'])
429
- def tts_endpoint():
430
  """
431
- टेक्स्ट-टू-स्पीच (Prabhat Neural) जनरेशन एंडपॉइंट।
432
- यह ऑडियो फाइल बनाता है, उसे सर्व करता है, और फिर डिलीट करने का शेड्यूल बनाता है।
 
433
  """
434
  if request.method == 'OPTIONS':
435
  return Response(status=200)
436
 
437
  try:
438
  data = request.get_json() or {}
439
- text = data.get("text", "").strip()
 
440
  except Exception as e:
441
- logger.error(f"Invalid JSON in TTS request: {str(e)}")
442
- return jsonify({"error": "Invalid JSON payload"}), 400
443
 
444
- if not text:
445
- logger.warning("TTS Request received empty text.")
446
- return jsonify({"error": "No text provided"}), 400
447
 
448
- logger.info(f"Processing TTS request. Text length: {len(text)}")
449
 
450
- # एक सुरक्षित टेम्पररी फाइल पाथ प्राप्त करें
451
- output_audio_path = file_manager.create_temp_audio_path()
452
 
453
- # सिंक्रोनस थ्रेड के अंदर एसिंक्रोनस TTS को सुरक्षित रूप से चलाएं
454
- success = tts_engine.generate_audio_sync(text, output_audio_path)
455
 
456
- if not success or not os.path.exists(output_audio_path):
457
- logger.error("TTS Audio file was not created successfully.")
458
- return jsonify({"error": "TTS Engine failed to generate audio."}), 500
459
 
460
- logger.info(f"TTS Audio generated successfully at: {output_audio_path}")
461
 
462
- # फाइल को क्लाइंट को भेजने के बाद 60 सेकंड में डिलीट करने का शेड्यूल
463
- file_manager.schedule_cleanup(output_audio_path, delay_seconds=60)
464
 
465
  try:
466
- # फाइल को बाइट्स के रूप में भेजें (Streaming)
467
  return send_file(
468
- output_audio_path,
469
  mimetype="audio/mpeg",
470
  as_attachment=False,
471
- download_name="arjun_voice.mp3"
472
  )
473
  except Exception as e:
474
- logger.error(f"Failed to send TTS file: {str(e)}")
475
- return jsonify({"error": "Failed to transmit audio file."}), 500
476
-
477
 
 
 
 
478
  @app.route('/health', methods=['GET'])
479
- def health_check():
480
- """सर्वर की स्थिति जाँचने के लिए एंडपॉइंट।"""
481
- status = {
482
- "status": "healthy",
483
- "arjun_core": "online",
484
- "tts_engine": "initialized",
485
- "timestamp": time.time()
 
 
 
 
 
 
 
 
486
  }
487
- return jsonify(status), 200
 
488
 
489
  # =========================================================================================
490
- # SECTION 9: ERROR HANDLERS
491
  # =========================================================================================
492
  @app.errorhandler(404)
493
- def not_found(error):
494
- logger.warning(f"404 Not Found: {request.path}")
495
- return jsonify({"error": "Resource not found"}), 404
 
 
 
 
 
496
 
497
  @app.errorhandler(500)
498
- def internal_error(error):
499
- logger.error(f"500 Internal Server Error: {request.path}")
500
- return jsonify({"error": "Internal Server Error"}), 500
 
501
 
502
  # =========================================================================================
503
- # MAIN EXECUTION BLOCK
504
  # =========================================================================================
505
- def print_startup_banner():
506
- """सर्वर शुरू होने पर एक सुंदर बैनर प्रिंट करता है।"""
507
- banner = """
508
- ========================================================
509
- █████╗ █████��╗ ██╗██╗ ██╗███╗ ██╗
510
- ██╔══██╗██╔══██╗ ██║██║ ██║████╗ ██║
511
- ███████║██████╔╝ ██║██║ ██║██╔██╗ ██║
512
- ██╔══██║██╔══██╗██ ██║██║ ██║██║╚██╗██║
513
- ██║ ██║██║ ██║╚█████╔╝╚██████╔╝██║ ╚████║
514
- ╚═╝ ╚═╝╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═╝ ╚═══╝
515
- ADVANCED EDITION (V2.0)
516
- ========================================================
517
- System : Arjun Intelligence Core
518
- TTS Mode : Microsoft Edge (Prabhat Neural)
519
- Status : Online and Listening...
520
- ========================================================
521
  """
522
- print("\x1b[32;20m" + banner + "\x1b[0m")
 
523
 
524
  if __name__ == '__main__':
525
- # बैनर दिखाएं
526
- print_startup_banner()
527
 
528
- # पोर्ट सेट करें
529
- port = int(os.environ.get("PORT", 7860))
530
 
531
- logger.info(f"Starting Arjun Backend Server on port {port}...")
532
 
533
- # प्रोडक्शन डिप्लॉयमेंट के लिए, Waitress या Gunicorn का इस्तेमाल बेहतर है,
534
- # लेकिन स्थानीय/डेवलपमेंट के लिए Flask का रन सर्वर (Threaded) पर्याप्त है।
535
- app.run(host='0.0.0.0', port=port, threaded=True)
 
1
+ """
2
+ =========================================================================================
3
+ ARJUN 2.O - ENTERPRISE BACKEND ARCHITECTURE
4
+ =========================================================================================
5
+ Author: Abhay Kumar
6
+ Architecture: Microservices Pattern within Monolith
7
+ Compatibility: Docker, Hugging Face Spaces, AWS, GCP
8
+ Description: Highly robust, scalable, and fail-safe Flask backend serving LLM capabilities,
9
+ advanced multimodal payload formatting, Edge-TTS synthesis, and system diagnostics.
10
+ =========================================================================================
11
+ """
12
+
13
  import os
14
  import sys
15
  import json
 
21
  import threading
22
  import traceback
23
  import requests
24
+ import dataclasses
25
+ from datetime import datetime
26
+ from functools import wraps
27
+ from typing import Dict, Any, List, Optional, Generator, Union, Callable
28
 
29
  from flask import (
30
  Flask,
 
34
  render_template_string,
35
  send_file,
36
  jsonify,
37
+ make_response,
38
+ g
39
  )
40
+
41
  import edge_tts
42
 
43
  # =========================================================================================
44
+ # MODULE 1: ENTERPRISE LOGGING & TELEMETRY
45
  # =========================================================================================
46
+
47
+ class EnterpriseFormatter(logging.Formatter):
48
+ """
49
+ Advanced logging formatter providing color-coded, heavily structured console output
50
+ to track complex asynchronous events and HTTP requests effectively.
51
+ """
52
+ CYAN = "\x1b[36;20m"
53
+ GREY = "\x1b[38;20m"
54
+ YELLOW = "\x1b[33;20m"
55
+ RED = "\x1b[31;20m"
56
+ BOLD_RED = "\x1b[31;1m"
57
+ GREEN = "\x1b[32;20m"
58
+ RESET = "\x1b[0m"
59
+
60
+ FORMAT_TEMPLATE = "%(asctime)s | %(levelname)-8s | [ARJUN-CORE] | %(module)s:%(lineno)d | %(message)s"
61
 
62
  FORMATS = {
63
+ logging.DEBUG: CYAN + FORMAT_TEMPLATE + RESET,
64
+ logging.INFO: GREEN + FORMAT_TEMPLATE + RESET,
65
+ logging.WARNING: YELLOW + FORMAT_TEMPLATE + RESET,
66
+ logging.ERROR: RED + FORMAT_TEMPLATE + RESET,
67
+ logging.CRITICAL: BOLD_RED + FORMAT_TEMPLATE + RESET
68
  }
69
 
70
+ def format(self, record: logging.LogRecord) -> str:
71
+ log_fmt = self.FORMATS.get(record.levelno, self.FORMAT_TEMPLATE)
72
+ formatter = logging.Formatter(log_fmt, datefmt='%Y-%m-%d %H:%M:%S.%f')
73
  return formatter.format(record)
74
 
75
+ def setup_enterprise_logger() -> logging.Logger:
76
+ """Initializes the global telemetry and logging system."""
77
+ logger = logging.getLogger("ArjunEnterprise")
78
+ logger.setLevel(logging.DEBUG)
79
+
80
+ # Prevent duplicate handlers if module is reloaded
81
+ if not logger.handlers:
82
+ console_handler = logging.StreamHandler()
83
+ console_handler.setFormatter(EnterpriseFormatter())
84
+ logger.addHandler(console_handler)
85
+
86
+ return logger
87
+
88
+ logger = setup_enterprise_logger()
89
 
90
  # =========================================================================================
91
+ # MODULE 2: EXCEPTION HIERARCHY
92
  # =========================================================================================
93
+
94
+ class ArjunSystemException(Exception):
95
+ """Base exception for all Arjun Core related faults."""
96
+ def __init__(self, message: str, status_code: int = 500, payload: dict = None):
97
  super().__init__(message)
98
  self.message = message
99
  self.status_code = status_code
100
+ self.payload = payload or {}
101
 
102
+ class EnvironmentConfigurationFault(ArjunSystemException):
103
+ """Raised when critical deployment secrets are missing."""
104
  pass
105
 
106
+ class UpstreamGatewayTimeout(ArjunSystemException):
107
+ """Raised when the Hugging Face / LLM provider takes too long to respond."""
108
  pass
109
 
110
+ class PayloadFormattingError(ArjunSystemException):
111
+ """Raised when the incoming JSON cannot be transformed into API-compliant schema."""
112
  pass
113
 
114
  # =========================================================================================
115
+ # MODULE 3: DEPLOYMENT SECRETS & CONFIGURATION MANAGER
116
  # =========================================================================================
117
+
118
+ @dataclasses.dataclass
119
+ class SystemState:
120
+ boot_time: float = time.time()
121
+ total_requests_served: int = 0
122
+ total_errors_caught: int = 0
123
+
124
+ state = SystemState()
125
+
126
+ class ConfigurationManager:
127
  """
128
+ Singleton pattern configuration manager. Secures runtime variables and ensures
129
+ zero hardcoded credentials exist within the executable code.
130
  """
131
+ _instance = None
132
+
133
+ def __new__(cls):
134
+ if cls._instance is None:
135
+ cls._instance = super(ConfigurationManager, cls).__new__(cls)
136
+ cls._instance._initialize()
137
+ return cls._instance
138
+
139
+ def _initialize(self):
140
+ logger.info("Bootstrapping Configuration Manager...")
141
 
142
+ self.api_key = os.environ.get("YOUR_VEDIKA_API_KEY", "")
143
+ self.base_url = os.environ.get("BASE_URL", "")
144
+ self.model_id = os.environ.get("MODEL_ID", "")
145
+
146
+ self.invoke_url = self._build_secure_endpoint(self.base_url)
147
+ self.verify_integrity()
148
 
149
+ def _build_secure_endpoint(self, base: str) -> str:
150
+ """Constructs the exact completion endpoint avoiding double slashes."""
151
+ if not base:
152
  return ""
153
+ base = base.strip()
154
+ if not base.endswith("/chat/completions"):
155
+ return f"{base.rstrip('/')}/chat/completions"
156
+ return base
157
+
158
+ def verify_integrity(self) -> bool:
159
+ """Audits the environment. Will not crash, but logs critical warnings."""
160
+ missing_vars = []
161
+ if not self.api_key: missing_vars.append("YOUR_VEDIKA_API_KEY")
162
+ if not self.base_url: missing_vars.append("BASE_URL")
163
+ if not self.model_id: missing_vars.append("MODEL_ID")
164
 
165
+ if missing_vars:
166
+ logger.critical(f"ENVIRONMENT AUDIT FAILED. Missing Secrets: {', '.join(missing_vars)}")
167
+ return False
168
+
169
+ logger.info(f"Environment Audit Passed. Target Model: {self.model_id}")
170
+ return True
171
+
172
+ config = ConfigurationManager()
173
+
174
+ # =========================================================================================
175
+ # MODULE 4: CIRCUIT BREAKER & RETRY MECHANISMS
176
+ # =========================================================================================
177
 
178
+ def with_retry(max_retries: int = 3, backoff_factor: float = 1.5):
179
+ """
180
+ Enterprise decorator: Automatically retries failing network requests.
181
+ Prevents the backend from failing immediately due to micro-outages.
182
+ """
183
+ def decorator(func: Callable):
184
+ @wraps(func)
185
+ def wrapper(*args, **kwargs):
186
+ retries = 0
187
+ while retries < max_retries:
188
+ try:
189
+ return func(*args, **kwargs)
190
+ except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as e:
191
+ retries += 1
192
+ logger.warning(f"Network fault detected ({str(e)}). Retry {retries}/{max_retries} executing...")
193
+ time.sleep(backoff_factor * retries)
194
+ logger.error("Maximum retries exhausted. Circuit Breaker triggered.")
195
+ raise UpstreamGatewayTimeout("Upstream AI Matrix is currently unreachable.", 504)
196
+ return wrapper
197
+ return decorator
198
 
199
  # =========================================================================================
200
+ # MODULE 5: TEMPORARY ASSET & GARBAGE COLLECTION SYSTEM
201
  # =========================================================================================
202
+
203
+ class AssetGarbageCollector:
204
  """
205
+ Manages temporary files (like synthesized audio) to ensure Docker instances
206
+ and Hugging Face spaces do not run out of ephemeral storage over time.
207
  """
208
  def __init__(self):
209
+ self.storage_directory = tempfile.gettempdir()
210
+ self.registry = set()
211
+ logger.info(f"Garbage Collector initialized at virtual mount: {self.storage_directory}")
212
+
213
+ def allocate_file(self, prefix: str = "arjun_asset_", extension: str = ".tmp") -> str:
214
+ """Allocates a cryptographically unique file path."""
215
+ file_id = uuid.uuid4().hex
216
+ secure_path = os.path.join(self.storage_directory, f"{prefix}{file_id}{extension}")
217
+ self.registry.add(secure_path)
218
+ return secure_path
219
+
220
+ def schedule_demolition(self, target_path: str, lifespan_seconds: int = 120):
221
+ """Asynchronously wipes files from disk after they are served to the client."""
222
+ def _demolish():
223
+ time.sleep(lifespan_seconds)
224
  try:
225
+ if os.path.exists(target_path):
226
+ os.remove(target_path)
227
+ logger.debug(f"[GC] Securely wiped temporary asset: {target_path}")
228
+ if target_path in self.registry:
229
+ self.registry.remove(target_path)
230
  except Exception as e:
231
+ logger.error(f"[GC] Failed to wipe asset {target_path}: {str(e)}")
232
 
233
+ demolition_thread = threading.Thread(target=_demolish, daemon=True)
234
+ demolition_thread.start()
235
 
236
+ gc_system = AssetGarbageCollector()
237
 
238
  # =========================================================================================
239
+ # MODULE 6: NEURAL ACOUSTIC ENGINE (EDGE TTS WRAPPER)
240
  # =========================================================================================
241
+
242
+ class NeuralAcousticEngine:
243
  """
244
+ Bridges Flask's synchronous architecture with Edge-TTS asynchronous nature.
245
+ Utilizes isolated event loops to prevent thread blocking and server hangs.
246
  """
247
  def __init__(self):
248
+ # Default Voice: Christopher for English, but dynamically handled usually
249
+ self.default_voice = "en-US-ChristopherNeural"
250
+ self.default_pitch = "+0%"
251
+ self.default_rate = "+0%"
252
+ logger.info("Neural Acoustic Engine (Edge-TTS) armed and ready.")
253
+
254
+ def synthesize_speech(self, text: str, output_path: str, lang_code: str = 'en') -> bool:
255
+ """Executes the synthesis in an isolated asyncio loop."""
256
+ sanitized_text = self._sanitize_text(text)
257
+ if not sanitized_text:
258
+ logger.warning("TTS aborted: Text was empty post-sanitization.")
 
 
 
 
 
259
  return False
260
 
261
+ # Dynamic voice selection based on detected or requested language
262
+ target_voice = "hi-IN-MadhurNeural" if lang_code == 'hi' else self.default_voice
263
 
264
+ logger.info(f"Initiating acoustic synthesis. Length: {len(sanitized_text)} chars. Voice: {target_voice}")
265
+
266
+ async def _async_compile():
267
  try:
268
+ communicator = edge_tts.Communicate(
269
+ text=sanitized_text,
270
+ voice=target_voice,
271
+ pitch=self.default_pitch,
272
+ rate=self.default_rate
273
  )
274
+ await communicator.save(output_path)
275
  return True
276
  except Exception as e:
277
+ logger.error(f"TTS Compilation Failure: {str(e)}")
 
278
  return False
279
 
280
+ # Isolated Event Loop Execution
281
+ isolated_loop = asyncio.new_event_loop()
282
+ asyncio.set_event_loop(isolated_loop)
283
  try:
284
+ success = isolated_loop.run_until_complete(_async_compile())
285
  return success
286
+ except Exception as err:
287
+ logger.error(f"Event Loop Integrity Failure during TTS: {str(err)}")
288
  return False
289
  finally:
290
+ isolated_loop.close()
291
 
292
+ def _sanitize_text(self, raw_text: str) -> str:
293
+ """Strips markdown, code blocks, and reasoning tags before passing to audio generator."""
294
  import re
295
+ text = re.sub(r'```.*?
296
+ ```', ' Code block omitted for audio. ', raw_text, flags=re.DOTALL)
297
  text = re.sub(r'!\[.*?\]\(.*?\)', '', text)
 
298
  text = re.sub(r'\[.*?\]\(.*?\)', '', text)
 
299
  text = re.sub(r'<think>.*?</think>', '', text, flags=re.DOTALL)
300
+ text = text.replace('*', '').replace('_', '').replace('`', '').replace('#', '')
 
301
  return text.strip()
302
 
303
+ acoustic_engine = NeuralAcousticEngine()
304
 
305
  # =========================================================================================
306
+ # MODULE 7: LLM PAYLOAD ARCHITECT & STREAM MANAGER
307
  # =========================================================================================
308
+
309
+ class LLMGateway:
310
  """
311
+ The core logic hub for interacting with upstream Hugging Face Inference endpoints.
312
+ Responsible for intelligent payload morphing based on attachment presence.
313
  """
314
+ def __init__(self, config_ref: ConfigurationManager):
315
+ self.cfg = config_ref
316
+
317
+ def format_history(self, history: List[Dict]) -> List[Dict]:
318
+ """Ensures the history strictly matches OpenAI/HF specs (user/assistant)."""
319
+ formatted = []
320
+ for msg in history:
321
+ # Map frontend 'bot' to standard 'assistant'
322
+ role = "assistant" if msg.get("role") == "bot" else "user"
323
+ content = str(msg.get("content", ""))
324
+ if content.strip():
325
+ formatted.append({"role": role, "content": content})
326
+ return formatted
327
+
328
+ def build_payload(self, user_msg: str, attachments: List[Dict], sys_prompt: str, history: List[Dict]) -> List[Dict]:
329
+ """
330
+ CRITICAL LOGIC: Morphs the payload based on context.
331
+ If no attachments exist, 'content' MUST be a string to avoid 400 Bad Requests on standard text models.
332
+ If attachments exist, 'content' becomes a multimodal List[Dict].
333
+ """
334
  messages = []
335
 
336
+ # 1. System Directive
337
  if sys_prompt and sys_prompt.strip():
338
  messages.append({"role": "system", "content": sys_prompt.strip()})
339
 
340
+ # 2. Historical Context
341
+ messages.extend(self.format_history(history))
342
+
343
+ # 3. Current Turn Analysis
344
+ if not attachments:
345
+ # STANDARD TEXT MODE (Prevents API crashes)
346
+ safe_text = user_msg.strip() if user_msg.strip() else "Hello."
347
+ messages.append({"role": "user", "content": safe_text})
348
+ logger.debug("Payload formulated as STRICT TEXT (No attachments).")
349
+ else:
350
+ # MULTIMODAL MODE (Vision / Audio capable endpoints)
351
+ content_array = []
352
+ if user_msg.strip():
353
+ content_array.append({"type": "text", "text": user_message.strip()})
354
+
355
+ for att in attachments:
356
+ att_type = att.get("type")
357
+ b64_data = att.get("data")
358
+
359
+ if not b64_data: continue
360
+
361
+ if att_type == "image":
362
+ content_array.append({
363
+ "type": "image_url",
364
+ "image_url": {"url": f"data:image/jpeg;base64,{b64_data}"}
365
+ })
366
+ elif att_type in ["audio", "file", "document", "video"]:
367
+ # Depending on backend capability, we append it.
368
+ # Note: Many endpoints ignore audio, but we construct it properly anyway.
369
+ content_array.append({
370
+ "type": "input_audio",
371
+ "input_audio": {"data": b64_data, "format": "wav"}
372
+ })
373
 
374
+ if not content_array:
375
+ content_array.append({"type": "text", "text": "Hello."})
376
 
377
+ messages.append({"role": "user", "content": content_array})
378
+ logger.debug(f"Payload formulated as MULTIMODAL. Items: {len(content_array)}")
379
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
380
  return messages
381
 
382
+ def execute_stream(self, api_payload: Dict[str, Any]) -> Generator[str, None, None]:
383
+ """
384
+ Opens a persistent connection to the Upstream LLM, reads the stream chunk by chunk,
385
+ and yields it directly back to the Flask client.
386
+ """
387
  headers = {
388
  "Authorization": f"Bearer {self.cfg.api_key}",
389
  "Accept": "text/event-stream",
390
  "Content-Type": "application/json"
391
  }
392
 
393
+ logger.info(f"Opening Streaming Vector to: {self.cfg.invoke_url}")
394
 
395
  try:
396
  with requests.post(
397
  self.cfg.invoke_url,
398
  headers=headers,
399
+ json=api_payload,
400
  stream=True,
401
+ timeout=180 # Extended timeout for massive reasoning models
402
  ) as response:
403
 
 
404
  if response.status_code != 200:
405
+ err_txt = response.text
406
+ logger.error(f"Upstream API Failure [{response.status_code}]: {err_txt}")
407
+ error_json = json.dumps({"choices": [{"delta": {"content": f"\n\n**CRITICAL UPSTREAM ERROR {response.status_code}:**\nThe AI Provider rejected the payload. Ensure your model supports the requested features.\n\n`{err_txt[:200]}`"}}]})
408
+ yield f"data: {error_json}\n\n"
409
  yield "data: [DONE]\n\n"
410
  return
411
 
412
+ # Successfully connected. Begin data relay.
413
+ for raw_bytes in response.iter_lines():
414
+ if raw_bytes:
415
+ decoded_string = raw_bytes.decode("utf-8")
416
+ if decoded_string.startswith("data: "):
417
+ yield decoded_string + "\n\n"
418
 
419
  except requests.exceptions.Timeout:
420
+ logger.error("Upstream Gateway Timeout.")
421
+ yield f"data: {json.dumps({'choices': [{'delta': {'content': '**System Alert:** Connection to the AI matrix timed out.'}}]})}\n\n"
422
+ yield "data: [DONE]\n\n"
423
+
424
  except requests.exceptions.RequestException as e:
425
+ logger.error(f"Upstream Network Disconnect: {str(e)}")
426
+ yield f"data: {json.dumps({'choices': [{'delta': {'content': '**System Alert:** Network disconnect detected.'}}]})}\n\n"
427
+ yield "data: [DONE]\n\n"
428
+
429
  except Exception as e:
430
+ logger.error(f"Stream Interpreter Crash: {str(e)}")
431
  traceback.print_exc()
432
+ yield f"data: {json.dumps({'choices': [{'delta': {'content': '**System Alert:** Internal processing failure during stream.'}}]})}\n\n"
433
+ yield "data: [DONE]\n\n"
434
 
435
+ llm_gateway = LLMGateway(config)
436
 
437
  # =========================================================================================
438
+ # MODULE 8: FLASK APPLICATION & ROUTING ARCHITECTURE
439
  # =========================================================================================
440
+
441
  app = Flask(__name__)
442
+ app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024 # 50 MB Max upload size limitation
443
 
 
444
  @app.before_request
445
+ def intercept_request():
446
+ """Middleware: Analytics and Security Checks"""
447
+ g.start_time = time.time()
448
+ logger.debug(f"Intercepted Request: {request.method} {request.path}")
449
 
450
  @app.after_request
451
+ def inject_security_headers(response):
452
+ """Middleware: Injects Cross-Origin Resource Sharing and Security Headers"""
453
  response.headers["Access-Control-Allow-Origin"] = "*"
454
  response.headers["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS"
455
  response.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization"
456
+ response.headers["X-Powered-By"] = "Arjun Intelligence Core"
457
+ response.headers["X-Frame-Options"] = "SAMEORIGIN"
458
+
459
+ if hasattr(g, 'start_time'):
460
+ latency = (time.time() - g.start_time) * 1000
461
+ logger.debug(f"Request resolved in {latency:.2f}ms")
462
+
463
  return response
464
 
465
+ # -----------------------------------------------------------------------------------------
466
+ # ENDPOINT: FRONTEND SERVING
467
+ # -----------------------------------------------------------------------------------------
 
468
  @app.route('/', methods=['GET'])
469
+ def render_interface():
470
+ """Serves the primary monolithic HTML application."""
471
+ logger.info("Serving Application Interface.")
472
  try:
473
+ base_dir = os.path.dirname(os.path.abspath(__file__))
474
+ html_path = os.path.join(base_dir, 'index.html')
475
+ with open(html_path, 'r', encoding='utf-8') as file:
476
+ return render_template_string(file.read())
 
477
  except FileNotFoundError:
478
+ logger.critical("Primary UI file 'index.html' is missing from the directory.")
479
+ return make_response(
480
+ "<h1>Fatal Error 404</h1><p>The core UI file 'index.html' could not be located on the server disk.</p>",
481
+ 404
482
+ )
483
  except Exception as e:
484
+ logger.error(f"Template Rendering Failure: {str(e)}")
485
+ return make_response(f"<h1>Server Fault 500</h1><p>{str(e)}</p>", 500)
486
 
487
+ # -----------------------------------------------------------------------------------------
488
+ # ENDPOINT: LLM CHAT PROCESSING
489
+ # -----------------------------------------------------------------------------------------
490
  @app.route('/api/chat', methods=['POST', 'OPTIONS'])
491
+ def process_chat_transaction():
492
+ """
493
+ Main Gateway Endpoint. Receives JSON from frontend, builds appropriate payload,
494
+ and proxies the streaming response back to the client.
495
+ """
496
  if request.method == 'OPTIONS':
497
  return Response(status=200)
498
 
499
+ state.total_requests_served += 1
500
+
501
+ # Configuration Guard
502
  if not config.api_key or not config.invoke_url or not config.model_id:
503
+ logger.critical("Transaction blocked. System configuration invalid.")
504
+ return jsonify({"error": "Backend misconfigured. API Keys missing."}), 500
505
 
506
+ # JSON Parsing Guard
507
  try:
508
+ payload_data = request.get_json() or {}
509
  except Exception as e:
510
+ logger.error(f"Malformed JSON intercepted: {str(e)}")
511
+ return jsonify({"error": "Payload must be strictly valid JSON."}), 400
512
 
513
+ user_text = payload_data.get("message", "")
514
+ attachments = payload_data.get("attachments", [])
515
+ system_prompt = payload_data.get("system_prompt", "")
516
+ history = payload_data.get("history", [])
517
+ max_tokens = payload_data.get("max_tokens", 4096)
518
+ temperature = payload_data.get("temperature", 0.75)
519
 
520
+ logger.info(f"Processing transaction. History Length: {len(history)} | Attachments: {len(attachments)}")
521
 
522
+ # Construct the highly-optimized payload
523
  try:
524
+ mapped_messages = llm_gateway.build_payload(user_text, attachments, system_prompt, history)
525
  except Exception as e:
526
+ logger.error(f"Payload Compilation Error: {str(e)}")
527
+ traceback.print_exc()
528
+ return jsonify({"error": "Internal Error formatting LLM payload."}), 500
529
 
530
+ api_dispatch_json = {
531
  "model": config.model_id,
532
+ "messages": mapped_messages,
533
  "max_tokens": int(max_tokens),
534
  "temperature": float(temperature),
535
+ "top_p": 0.85, # Slightly broadened for better code generation
536
  "stream": True
537
  }
538
 
539
+ # Execute stream relay
540
  return Response(
541
+ stream_with_context(llm_gateway.execute_stream(api_dispatch_json)),
542
  mimetype='text/event-stream'
543
  )
544
 
545
+ # -----------------------------------------------------------------------------------------
546
+ # ENDPOINT: NATIVE TTS FALLBACK (EDGE-TTS)
547
+ # -----------------------------------------------------------------------------------------
548
  @app.route('/api/tts', methods=['POST', 'OPTIONS'])
549
+ def synthesize_audio():
550
  """
551
+ Fallback TTS Endpoint.
552
+ Though frontend uses Gradio primarily, this remains as an internal fallback
553
+ and microservice utility. Converts text to speech locally.
554
  """
555
  if request.method == 'OPTIONS':
556
  return Response(status=200)
557
 
558
  try:
559
  data = request.get_json() or {}
560
+ text_content = data.get("text", "").strip()
561
+ lang_mode = data.get("lang", "en") # 'en' or 'hi'
562
  except Exception as e:
563
+ logger.error(f"Malformed JSON in TTS request: {str(e)}")
564
+ return jsonify({"error": "Invalid payload format"}), 400
565
 
566
+ if not text_content:
567
+ return jsonify({"error": "Empty text payload provided."}), 400
 
568
 
569
+ logger.info(f"TTS requested for {len(text_content)} characters. Lang: {lang_mode}")
570
 
571
+ output_path = gc_system.allocate_file(prefix="arjun_tts_", extension=".mp3")
 
572
 
573
+ # Synchronously await asynchronous compilation
574
+ success = acoustic_engine.synthesize_speech(text_content, output_path, lang_code=lang_mode)
575
 
576
+ if not success or not os.path.exists(output_path):
577
+ logger.error("Acoustic engine failed to finalize the asset.")
578
+ return jsonify({"error": "Acoustic generation failed."}), 500
579
 
580
+ logger.info(f"Acoustic asset finalized: {output_path}")
581
 
582
+ # Fire-and-forget destruction timer
583
+ gc_system.schedule_demolition(output_path, lifespan_seconds=90)
584
 
585
  try:
 
586
  return send_file(
587
+ output_path,
588
  mimetype="audio/mpeg",
589
  as_attachment=False,
590
+ download_name="arjun_transmission.mp3"
591
  )
592
  except Exception as e:
593
+ logger.error(f"Transmission failure of acoustic asset: {str(e)}")
594
+ return jsonify({"error": "Failed to transmit binary audio data."}), 500
 
595
 
596
+ # -----------------------------------------------------------------------------------------
597
+ # ENDPOINT: SYSTEM DIAGNOSTICS & HEALTH
598
+ # -----------------------------------------------------------------------------------------
599
  @app.route('/health', methods=['GET'])
600
+ def system_health_check():
601
+ """Detailed health check endpoint for Load Balancers and Docker health checks."""
602
+ uptime_seconds = time.time() - state.boot_time
603
+
604
+ health_report = {
605
+ "status": "OPERATIONAL",
606
+ "system_name": "Arjun Core Version 2.0",
607
+ "author": "Abhay Kumar",
608
+ "diagnostics": {
609
+ "uptime_seconds": round(uptime_seconds, 2),
610
+ "requests_processed": state.total_requests_served,
611
+ "temporary_assets_tracked": len(gc_system.registry),
612
+ "configuration_status": "Valid" if config.verify_integrity() else "Compromised"
613
+ },
614
+ "timestamp_utc": datetime.utcnow().isoformat()
615
  }
616
+ return jsonify(health_report), 200
617
+
618
 
619
  # =========================================================================================
620
+ # MODULE 9: GLOBAL ERROR HANDLERS
621
  # =========================================================================================
622
  @app.errorhandler(404)
623
+ def handle_404(error):
624
+ state.total_errors_caught += 1
625
+ logger.warning(f"Unmatched Route Requested: {request.path}")
626
+ return jsonify({"error": "Endpoint not found within the Arjun routing matrix."}), 404
627
+
628
+ @app.errorhandler(405)
629
+ def handle_405(error):
630
+ return jsonify({"error": "Method Not Allowed."}), 405
631
 
632
  @app.errorhandler(500)
633
+ def handle_500(error):
634
+ state.total_errors_caught += 1
635
+ logger.error(f"Unhandled Server Exception Triggered on {request.path}")
636
+ return jsonify({"error": "Internal Server Failure. Check logs."}), 500
637
 
638
  # =========================================================================================
639
+ # MODULE 10: EXECUTION BOOTSTRAP
640
  # =========================================================================================
641
+ def display_terminal_splash():
642
+ """Prints an impressive ASCII art splash screen to the standard output upon boot."""
643
+ splash_text = """
644
+ =======================================================================
645
+ █████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗ ██████╗
646
+ ██╔══██╗██╔══██╗ ██║██║ ██║████╗ ██║ ╚════██╗ ██╔═══██╗
647
+ ███████║██████╔╝ ██║██║ ██║██╔██╗ ██║ █████╔╝ ██║ ██║
648
+ ██╔══██║██╔══██╗██ ██║██║ ██║██║╚██╗██║ ██╔═══╝ ██║ ██║
649
+ ██║ ██║██║ ██║╚█████╔╝╚██████╔╝██║ ╚████║ ███████╗ ╚██████╔╝
650
+ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═╝ ╚═══╝ ╚══════╝ ╚═════╝
651
+ =======================================================================
652
+ Architecture : Enterprise AI Matrix
653
+ Author : Abhay Kumar
654
+ Version : 2.0 (Production Stable)
655
+ Protocols : Edge-TTS, Dynamic Context Mapping, Secure Streams
656
+ =======================================================================
657
  """
658
+ # Print securely
659
+ print("\x1b[36;1m" + splash_text + "\x1b[0m", flush=True)
660
 
661
  if __name__ == '__main__':
662
+ # Initialize terminal visuals
663
+ display_terminal_splash()
664
 
665
+ # Retrieve port bindings (Default 7860 for Hugging Face Spaces compatibility)
666
+ target_port = int(os.environ.get("PORT", 7860))
667
 
668
+ logger.info(f"Ignition sequence initiated. Binding server to 0.0.0.0:{target_port}")
669
 
670
+ # Using Flask's threaded server.
671
+ # For hardcore production on AWS/GCP, wrap this with Gunicorn: gunicorn -w 4 -k gevent app:app
672
+ app.run(host='0.0.0.0', port=target_port, threaded=True, debug=False)