AIencoder commited on
Commit
0e84231
·
verified ·
1 Parent(s): 5c19f16

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +230 -591
app.py CHANGED
@@ -2,12 +2,26 @@ import gradio as gr
2
  import requests
3
  import json
4
  import time
 
5
  from faster_whisper import WhisperModel
6
 
7
  OLLAMA_URL = "http://localhost:11434"
8
  MAX_RETRIES = 3
9
  TIMEOUT = 300
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  MODELS = {
12
  "⭐ Qwen2.5 Coder 7B (Best)": "qwen2.5-coder:7b",
13
  "🧠 DeepSeek Coder 6.7B (Logic)": "deepseek-coder:6.7b",
@@ -51,6 +65,25 @@ def init_whisper():
51
 
52
  init_whisper()
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  # ===== HELPER FUNCTIONS =====
55
 
56
  def check_ollama_health():
@@ -87,10 +120,8 @@ def validate_input(text, field_name="Input"):
87
  def transcribe_audio(audio):
88
  if audio is None:
89
  return ""
90
-
91
  if whisper_model is None:
92
  return "❌ Whisper not loaded. Voice input unavailable."
93
-
94
  try:
95
  segments, _ = whisper_model.transcribe(audio)
96
  text = " ".join([seg.text for seg in segments]).strip()
@@ -104,10 +135,17 @@ def transcribe_audio(audio):
104
 
105
  def call_ollama_with_retry(model_name, prompt, temperature=0.7, max_tokens=2048):
106
  if not check_ollama_health():
107
- return "❌ **Ollama is not running.**\n\nPlease wait for Ollama to start, or check the logs."
108
 
109
  model = MODELS.get(model_name, "qwen2.5-coder:3b")
110
 
 
 
 
 
 
 
 
111
  for attempt in range(MAX_RETRIES):
112
  try:
113
  r = requests.post(
@@ -116,10 +154,8 @@ def call_ollama_with_retry(model_name, prompt, temperature=0.7, max_tokens=2048)
116
  "model": model,
117
  "prompt": prompt,
118
  "stream": False,
119
- "options": {
120
- "temperature": temperature,
121
- "num_predict": max_tokens
122
- }
123
  },
124
  timeout=TIMEOUT
125
  )
@@ -127,18 +163,15 @@ def call_ollama_with_retry(model_name, prompt, temperature=0.7, max_tokens=2048)
127
  if r.status_code == 200:
128
  response = r.json().get("response", "")
129
  if not response.strip():
130
- return "⚠️ Model returned empty response. Try rephrasing your request."
131
  return response
132
-
133
  elif r.status_code == 404:
134
- return f"❌ **Model not found:** `{model}`\n\nThe model may still be downloading. Check logs or try a different model."
135
-
136
  elif r.status_code == 500:
137
- error_msg = r.text[:200] if r.text else "Unknown server error"
138
  if "out of memory" in error_msg.lower():
139
- return "❌ **Out of memory.**\n\nTry a smaller model like `Qwen2.5 Coder 1.5B (Fast)`."
140
  return f"❌ **Server error:** {error_msg}"
141
-
142
  else:
143
  return f"❌ **HTTP {r.status_code}:** {r.text[:100]}"
144
 
@@ -146,26 +179,22 @@ def call_ollama_with_retry(model_name, prompt, temperature=0.7, max_tokens=2048)
146
  if attempt < MAX_RETRIES - 1:
147
  time.sleep(2)
148
  continue
149
- return "❌ **Request timed out.**\n\nThe model is taking too long. Try:\n- A smaller model\n- Shorter input\n- Lower max tokens"
150
-
151
  except requests.exceptions.ConnectionError:
152
  if attempt < MAX_RETRIES - 1:
153
  time.sleep(2)
154
  continue
155
- return "❌ **Connection failed.**\n\nOllama may have crashed. Check the logs."
156
-
157
  except json.JSONDecodeError:
158
- return "❌ **Invalid response from Ollama.**\n\nThe model returned malformed data."
159
-
160
  except Exception as e:
161
- return f"❌ **Unexpected error:** {str(e)[:100]}"
162
 
163
- return "❌ **Max retries reached.** Please try again."
164
 
165
  def extract_code(text):
166
  if not text or "```" not in text:
167
  return text
168
-
169
  try:
170
  parts = text.split("```")
171
  if len(parts) >= 2:
@@ -173,11 +202,11 @@ def extract_code(text):
173
  if "\n" in code:
174
  code = code.split("\n", 1)[-1]
175
  return code.strip()
176
- except Exception:
177
  pass
178
  return text
179
 
180
- # ===== CORE FUNCTIONS =====
181
 
182
  def chat_stream(message, history, model_name, temperature, max_tokens):
183
  valid, error = validate_input(message, "Message")
@@ -186,11 +215,11 @@ def chat_stream(message, history, model_name, temperature, max_tokens):
186
  return
187
 
188
  if not check_ollama_health():
189
- yield history + [[message, "❌ **Ollama is not running.** Please wait for it to start."]]
190
  return
191
 
192
  model = MODELS.get(model_name, "qwen2.5-coder:3b")
193
- messages = [{"role": "system", "content": "You are an expert coding assistant. Provide clear, well-commented code. Always use markdown code blocks with language tags."}]
194
 
195
  for user_msg, assistant_msg in history:
196
  messages.append({"role": "user", "content": user_msg})
@@ -198,6 +227,12 @@ def chat_stream(message, history, model_name, temperature, max_tokens):
198
  messages.append({"role": "assistant", "content": assistant_msg})
199
 
200
  messages.append({"role": "user", "content": message})
 
 
 
 
 
 
201
 
202
  try:
203
  response = requests.post(
@@ -206,18 +241,19 @@ def chat_stream(message, history, model_name, temperature, max_tokens):
206
  "model": model,
207
  "messages": messages,
208
  "stream": True,
209
- "options": {"temperature": temperature, "num_predict": max_tokens}
 
210
  },
211
  stream=True,
212
  timeout=TIMEOUT
213
  )
214
 
215
  if response.status_code == 404:
216
- yield history + [[message, f"❌ **Model not found:** `{model}`\n\nTry a different model."]]
217
  return
218
 
219
  if response.status_code != 200:
220
- yield history + [[message, f"❌ **Error {response.status_code}:** {response.text[:100]}"]]
221
  return
222
 
223
  full = ""
@@ -226,7 +262,7 @@ def chat_stream(message, history, model_name, temperature, max_tokens):
226
  try:
227
  data = json.loads(line)
228
  if "error" in data:
229
- yield history + [[message, f"❌ **Model error:** {data['error']}"]]
230
  return
231
  if "message" in data:
232
  full += data["message"].get("content", "")
@@ -235,64 +271,95 @@ def chat_stream(message, history, model_name, temperature, max_tokens):
235
  continue
236
 
237
  if not full.strip():
238
- yield history + [[message, "⚠️ Model returned empty response. Try rephrasing."]]
239
 
240
  except requests.exceptions.Timeout:
241
- yield history + [[message, "❌ **Request timed out.** Try a smaller model or shorter input."]]
242
  except requests.exceptions.ConnectionError:
243
- yield history + [[message, "❌ **Connection lost.** Ollama may have crashed."]]
244
  except Exception as e:
245
- yield history + [[message, f"❌ **Error:** {str(e)[:100]}"]]
246
 
247
- def generate_code(prompt, language, model_name, temperature, max_tokens):
 
 
248
  valid, error = validate_input(prompt, "Description")
249
  if not valid:
250
- return error
 
251
 
252
- full_prompt = (
253
- f"Write {language} code for the following task:\n\n"
254
- f"{prompt}\n\n"
255
- "Requirements:\n"
256
- "- Clean, production-ready code\n"
257
- "- Add helpful comments\n"
258
- "- Handle edge cases\n"
259
- "- Output ONLY the code in a markdown code block"
260
- )
261
 
262
- result = call_ollama_with_retry(model_name, full_prompt, temperature, max_tokens)
263
- if result.startswith("❌") or result.startswith("⚠️"):
264
- return result
265
- return extract_code(result)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
 
267
  def explain_code(code, model_name, detail_level, max_tokens):
268
  valid, error = validate_input(code, "Code")
269
  if not valid:
270
  return error
271
 
272
- detail_prompts = {
273
- "Brief": "Give a brief 2-3 sentence explanation of what this code does.",
274
- "Normal": "Explain what this code does, including the main logic and any important details.",
275
- "Detailed": "Give a detailed explanation including: purpose, how it works step-by-step, time/space complexity, and potential improvements."
276
  }
277
 
278
- prompt = detail_prompts.get(detail_level, detail_prompts["Normal"]) + "\n\nCode:\n" + code
279
- return call_ollama_with_retry(model_name, prompt, 0.5, max_tokens)
280
 
281
  def fix_code(code, error_msg, model_name, max_tokens):
282
  valid, error = validate_input(code, "Code")
283
  if not valid:
284
  return error
285
 
286
- error_text = error_msg if error_msg and error_msg.strip() else "Code is not working as expected"
287
- prompt = (
288
- "Fix the following code and explain what was wrong.\n\n"
289
- "Code:\n" + code + "\n\n"
290
- "Error/Problem: " + error_text + "\n\n"
291
- "Provide:\n"
292
- "1. The fixed code in a markdown code block\n"
293
- "2. Brief explanation of what was wrong\n"
294
- "3. Any suggestions to prevent similar issues"
295
- )
296
  return call_ollama_with_retry(model_name, prompt, 0.3, max_tokens)
297
 
298
  def review_code(code, model_name, max_tokens):
@@ -300,126 +367,45 @@ def review_code(code, model_name, max_tokens):
300
  if not valid:
301
  return error
302
 
303
- prompt = (
304
- "Review this code and provide feedback on:\n\n"
305
- "1. **Code Quality** - Is it clean, readable, well-structured?\n"
306
- "2. **Bugs/Issues** - Any potential bugs or problems?\n"
307
- "3. **Performance** - Any performance concerns?\n"
308
- "4. **Security** - Any security issues?\n"
309
- "5. **Suggestions** - How could it be improved?\n\n"
310
- "Code:\n" + code
311
- )
312
  return call_ollama_with_retry(model_name, prompt, 0.4, max_tokens)
313
 
314
  def convert_code(code, source_lang, target_lang, model_name, max_tokens):
315
  valid, error = validate_input(code, "Code")
316
  if not valid:
317
  return error
318
-
319
  if source_lang == target_lang:
320
- return "⚠️ Source and target languages are the same."
321
-
322
- prompt = (
323
- f"Convert this {source_lang} code to {target_lang}.\n\n"
324
- "Requirements:\n"
325
- f"- Write idiomatic {target_lang} code\n"
326
- "- Preserve the functionality exactly\n"
327
- "- Add comments explaining any language-specific differences\n"
328
- "- Output ONLY the converted code in a markdown code block\n\n"
329
- f"{source_lang} Code:\n" + code
330
- )
331
 
 
332
  result = call_ollama_with_retry(model_name, prompt, 0.3, max_tokens)
333
- if result.startswith("❌") or result.startswith("⚠️"):
334
- return result
335
- return extract_code(result)
336
 
337
  def generate_tests(code, language, framework, model_name, max_tokens):
338
  valid, error = validate_input(code, "Code")
339
  if not valid:
340
  return error
341
 
342
- frameworks = {
343
- "Python": "pytest",
344
- "JavaScript": "Jest",
345
- "TypeScript": "Jest",
346
- "Java": "JUnit",
347
- "C#": "NUnit",
348
- "Go": "testing package",
349
- "Rust": "built-in test framework",
350
- "Ruby": "RSpec",
351
- "PHP": "PHPUnit",
352
- }
353
-
354
- fw = framework if framework and framework.strip() else frameworks.get(language, "appropriate testing framework")
355
-
356
- prompt = (
357
- f"Generate comprehensive unit tests for this {language} code using {fw}.\n\n"
358
- "Requirements:\n"
359
- "- Test all functions/methods\n"
360
- "- Include edge cases\n"
361
- "- Include both positive and negative tests\n"
362
- "- Add descriptive test names\n"
363
- "- Output ONLY the test code in a markdown code block\n\n"
364
- "Code to test:\n" + code
365
- )
366
-
367
  result = call_ollama_with_retry(model_name, prompt, 0.3, max_tokens)
368
- if result.startswith("❌") or result.startswith("⚠️"):
369
- return result
370
- return extract_code(result)
371
 
372
  def document_code(code, language, style, model_name, max_tokens):
373
  valid, error = validate_input(code, "Code")
374
  if not valid:
375
  return error
376
 
377
- styles = {
378
- "Docstrings": "Add comprehensive docstrings to all functions, classes, and methods",
379
- "Comments": "Add inline comments explaining the logic",
380
- "Both": "Add both docstrings and inline comments",
381
- "README": "Generate a README.md documenting this code"
382
- }
383
-
384
- prompt = (
385
- f"Document this {language} code.\n\n"
386
- f"Task: {styles.get(style, styles['Both'])}\n\n"
387
- "Requirements:\n"
388
- "- Be clear and concise\n"
389
- "- Explain parameters, return values, and exceptions\n"
390
- "- Include usage examples where helpful\n"
391
- "- Output the fully documented code in a markdown code block\n\n"
392
- "Code:\n" + code
393
- )
394
-
395
  result = call_ollama_with_retry(model_name, prompt, 0.4, max_tokens)
396
- if style == "README" or result.startswith("❌") or result.startswith("⚠️"):
397
- return result
398
- return extract_code(result)
399
 
400
  def optimize_code(code, language, focus, model_name, max_tokens):
401
  valid, error = validate_input(code, "Code")
402
  if not valid:
403
  return error
404
 
405
- focus_prompts = {
406
- "Performance": "Optimize for speed and efficiency. Reduce time complexity where possible.",
407
- "Readability": "Refactor for better readability and maintainability. Follow best practices.",
408
- "Memory": "Optimize memory usage. Reduce allocations and improve data structures.",
409
- "All": "Optimize for performance, readability, and memory usage."
410
- }
411
-
412
- prompt = (
413
- f"Optimize this {language} code.\n\n"
414
- f"Focus: {focus_prompts.get(focus, focus_prompts['All'])}\n\n"
415
- "Requirements:\n"
416
- "- Explain what you changed and why\n"
417
- "- Preserve the original functionality\n"
418
- "- Show before/after complexity if relevant\n"
419
- "- Output the optimized code in a markdown code block\n\n"
420
- "Code:\n" + code
421
- )
422
-
423
  return call_ollama_with_retry(model_name, prompt, 0.3, max_tokens)
424
 
425
  def build_regex(description, model_name, max_tokens):
@@ -427,16 +413,7 @@ def build_regex(description, model_name, max_tokens):
427
  if not valid:
428
  return error
429
 
430
- prompt = (
431
- "Create a regex pattern for the following requirement:\n\n"
432
- f"{description}\n\n"
433
- "Provide:\n"
434
- "1. The regex pattern\n"
435
- "2. Explanation of each part\n"
436
- "3. Example matches and non-matches\n"
437
- "4. Code example in Python showing usage"
438
- )
439
-
440
  return call_ollama_with_retry(model_name, prompt, 0.3, max_tokens)
441
 
442
  def build_api(description, framework, model_name, max_tokens):
@@ -444,558 +421,220 @@ def build_api(description, framework, model_name, max_tokens):
444
  if not valid:
445
  return error
446
 
447
- prompt = (
448
- f"Create a REST API endpoint using {framework}.\n\n"
449
- f"Requirements:\n{description}\n\n"
450
- "Include:\n"
451
- "- Route definition with proper HTTP methods\n"
452
- "- Request validation\n"
453
- "- Error handling\n"
454
- "- Response formatting\n"
455
- "- Brief documentation comments\n"
456
- "- Output the code in a markdown code block"
457
- )
458
-
459
  result = call_ollama_with_retry(model_name, prompt, 0.3, max_tokens)
460
- if result.startswith("❌") or result.startswith("⚠️"):
461
- return result
462
- return extract_code(result)
463
 
464
- # ===== PREMIUM CSS =====
465
 
466
  css = """
467
- /* ===== GLOBAL ===== */
468
  :root {
469
  --primary: #6366f1;
470
- --primary-dark: #4f46e5;
471
  --secondary: #8b5cf6;
472
- --accent: #06b6d4;
473
  --bg-dark: #0f172a;
474
  --bg-card: #1e293b;
475
- --bg-hover: #334155;
476
- --text-primary: #f1f5f9;
477
- --text-secondary: #94a3b8;
478
  --border: #334155;
479
- --success: #10b981;
480
- --warning: #f59e0b;
481
- --error: #ef4444;
482
  --gradient: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #06b6d4 100%);
483
  }
484
-
485
- .gradio-container {
486
- max-width: 1500px !important;
487
- margin: auto !important;
488
- background: var(--bg-dark) !important;
489
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif !important;
490
- }
491
-
492
- /* ===== HEADER ===== */
493
  .header-section {
494
  background: var(--gradient);
495
  border-radius: 20px;
496
  padding: 32px 40px;
497
  margin-bottom: 24px;
498
- position: relative;
499
- overflow: hidden;
500
  box-shadow: 0 20px 40px rgba(99, 102, 241, 0.3);
501
  }
502
-
503
- .header-section::before {
504
- content: '';
505
- position: absolute;
506
- top: -50%;
507
- right: -50%;
508
- width: 100%;
509
- height: 200%;
510
- background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 60%);
511
- animation: pulse 4s ease-in-out infinite;
512
- }
513
-
514
- @keyframes pulse {
515
- 0%, 100% { transform: scale(1); opacity: 0.5; }
516
- 50% { transform: scale(1.1); opacity: 0.8; }
517
- }
518
-
519
- .header-content {
520
- position: relative;
521
- z-index: 1;
522
- display: flex;
523
- justify-content: space-between;
524
- align-items: center;
525
- flex-wrap: wrap;
526
- gap: 20px;
527
- }
528
-
529
- .header-title {
530
- color: white;
531
- margin: 0;
532
- font-size: 2.8rem;
533
- font-weight: 800;
534
- letter-spacing: -0.02em;
535
- text-shadow: 0 2px 10px rgba(0,0,0,0.2);
536
- }
537
-
538
- .header-subtitle {
539
- color: rgba(255,255,255,0.9);
540
- margin: 8px 0 0 0;
541
- font-size: 1.1rem;
542
- font-weight: 400;
543
- }
544
-
545
- .header-badges {
546
- display: flex;
547
- gap: 10px;
548
- flex-wrap: wrap;
549
- }
550
-
551
  .badge {
552
  background: rgba(255,255,255,0.2);
553
- backdrop-filter: blur(10px);
554
  padding: 8px 16px;
555
  border-radius: 50px;
556
  font-size: 0.85rem;
557
- font-weight: 500;
558
  color: white;
559
- border: 1px solid rgba(255,255,255,0.2);
560
- }
561
-
562
- /* ===== STATUS BAR ===== */
563
- .status-bar {
564
- background: var(--bg-card);
565
- border: 1px solid var(--border);
566
- border-radius: 16px;
567
- padding: 16px 24px;
568
- margin-bottom: 20px;
569
- }
570
-
571
- /* ===== SETTINGS PANEL ===== */
572
- .settings-panel {
573
- background: var(--bg-card);
574
- border: 1px solid var(--border);
575
- border-radius: 16px;
576
- padding: 20px 24px;
577
- margin-bottom: 20px;
578
  }
579
-
580
- /* ===== MODEL INFO ===== */
581
- .model-info-box {
582
- background: linear-gradient(135deg, rgba(99, 102, 241, 0.1) 0%, rgba(139, 92, 246, 0.1) 100%);
583
- border: 1px solid rgba(99, 102, 241, 0.3);
584
- border-radius: 12px;
585
- padding: 12px 18px;
586
- font-size: 0.9rem;
587
- color: var(--text-secondary);
588
- margin-top: 12px;
589
- margin-bottom: 20px;
590
- }
591
-
592
- /* ===== TABS ===== */
593
- .tab-nav {
594
- background: var(--bg-card) !important;
595
- border: 1px solid var(--border) !important;
596
- border-radius: 16px !important;
597
- padding: 8px !important;
598
- gap: 6px !important;
599
- margin-bottom: 20px !important;
600
- flex-wrap: wrap !important;
601
- }
602
-
603
- .tab-nav button {
604
- background: transparent !important;
605
- border: none !important;
606
- border-radius: 12px !important;
607
- padding: 12px 20px !important;
608
- font-weight: 600 !important;
609
- font-size: 0.9rem !important;
610
- color: var(--text-secondary) !important;
611
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
612
- }
613
-
614
- .tab-nav button:hover {
615
- background: var(--bg-hover) !important;
616
- color: var(--text-primary) !important;
617
- }
618
-
619
  .tab-nav button.selected {
620
  background: var(--gradient) !important;
621
  color: white !important;
622
- box-shadow: 0 4px 15px rgba(99, 102, 241, 0.4) !important;
623
  }
624
-
625
- /* ===== CHATBOT ===== */
626
- .chatbot-container {
627
- background: var(--bg-card) !important;
628
- border: 1px solid var(--border) !important;
629
- border-radius: 16px !important;
630
- }
631
-
632
- /* ===== INPUTS ===== */
633
- textarea, input[type="text"] {
634
- background: var(--bg-card) !important;
635
- border: 1px solid var(--border) !important;
636
- border-radius: 12px !important;
637
- color: var(--text-primary) !important;
638
- padding: 14px 18px !important;
639
- font-size: 0.95rem !important;
640
- transition: all 0.2s ease !important;
641
- }
642
-
643
- textarea:focus, input[type="text"]:focus {
644
- border-color: var(--primary) !important;
645
- box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2) !important;
646
- outline: none !important;
647
- }
648
-
649
- /* ===== CODE BLOCKS ===== */
650
- .code-wrap {
651
- border-radius: 16px !important;
652
- overflow: hidden !important;
653
- border: 1px solid var(--border) !important;
654
- }
655
-
656
- /* ===== BUTTONS ===== */
657
- .primary-btn, button.primary {
658
  background: var(--gradient) !important;
659
  border: none !important;
660
- border-radius: 12px !important;
661
- padding: 14px 28px !important;
662
- font-weight: 600 !important;
663
- font-size: 0.95rem !important;
664
- color: white !important;
665
- cursor: pointer !important;
666
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
667
- box-shadow: 0 4px 15px rgba(99, 102, 241, 0.3) !important;
668
- }
669
-
670
- .primary-btn:hover, button.primary:hover {
671
- transform: translateY(-2px) !important;
672
- box-shadow: 0 8px 25px rgba(99, 102, 241, 0.4) !important;
673
- }
674
-
675
- .secondary-btn {
676
- background: var(--bg-hover) !important;
677
- border: 1px solid var(--border) !important;
678
- border-radius: 12px !important;
679
- padding: 12px 20px !important;
680
- font-weight: 500 !important;
681
- color: var(--text-secondary) !important;
682
- transition: all 0.2s ease !important;
683
  }
684
-
685
- .secondary-btn:hover {
686
- background: var(--bg-card) !important;
687
- border-color: var(--primary) !important;
688
- color: var(--text-primary) !important;
689
- }
690
-
691
- /* ===== MARKDOWN OUTPUT ===== */
692
- .markdown-output {
693
- background: var(--bg-card);
694
- border: 1px solid var(--border);
695
- border-radius: 16px;
696
- padding: 24px;
697
- color: var(--text-primary);
698
- line-height: 1.7;
699
- }
700
-
701
- /* ===== DIVIDER ===== */
702
- .divider {
703
- height: 1px;
704
- background: var(--border);
705
- margin: 24px 0;
706
- }
707
-
708
- /* ===== TOOL SECTION ===== */
709
- .tool-section {
710
- background: var(--bg-card);
711
- border: 1px solid var(--border);
712
- border-radius: 16px;
713
- padding: 24px;
714
- margin-bottom: 20px;
715
- }
716
-
717
- .tool-title {
718
- color: var(--text-primary);
719
- font-size: 1.2rem;
720
- font-weight: 600;
721
- margin-bottom: 16px;
722
- }
723
-
724
- /* ===== FOOTER ===== */
725
- .footer {
726
- text-align: center;
727
- padding: 24px;
728
- color: var(--text-secondary);
729
- font-size: 0.85rem;
730
- border-top: 1px solid var(--border);
731
- margin-top: 32px;
732
- }
733
-
734
- /* ===== SCROLLBAR ===== */
735
- ::-webkit-scrollbar {
736
- width: 8px;
737
- height: 8px;
738
- }
739
-
740
- ::-webkit-scrollbar-track {
741
- background: var(--bg-dark);
742
- }
743
-
744
- ::-webkit-scrollbar-thumb {
745
- background: var(--border);
746
- border-radius: 4px;
747
- }
748
-
749
- ::-webkit-scrollbar-thumb:hover {
750
- background: var(--text-secondary);
751
- }
752
-
753
- /* ===== HIDE DEFAULT FOOTER ===== */
754
  footer { display: none !important; }
755
-
756
- /* ===== RESPONSIVE ===== */
757
- @media (max-width: 768px) {
758
- .header-title { font-size: 2rem; }
759
- .header-content { flex-direction: column; text-align: center; }
760
- .header-badges { justify-content: center; }
761
- .tab-nav button { padding: 10px 14px !important; font-size: 0.8rem !important; }
762
- }
763
  """
764
 
765
- # ===== UI (Gradio 6.0 Compatible) =====
766
 
767
  with gr.Blocks(title="Axon v6") as demo:
768
 
769
- # Header
770
  gr.HTML("""
771
  <div class="header-section">
772
- <div class="header-content">
773
- <div>
774
- <h1 class="header-title">🔥 Axon v6</h1>
775
- <p class="header-subtitle">AI-Powered Coding Assistant</p>
776
- </div>
777
- <div class="header-badges">
778
- <span class="badge">🤖 10 Models</span>
779
- <span class="badge">🛠️ 9 Tools</span>
780
- <span class="badge">🔒 100% Local</span>
781
- <span class="badge">⚡ No Rate Limits</span>
782
- </div>
783
  </div>
784
  </div>
785
  """)
786
 
787
- # Status
788
- with gr.Row():
789
- status = gr.Markdown(value=get_status, every=5)
790
 
791
- # Settings Panel
792
  with gr.Row():
793
- model_dropdown = gr.Dropdown(
794
- choices=list(MODELS.keys()),
795
- value="Qwen2.5 Coder 3B",
796
- label="🤖 Model",
797
- scale=3
798
- )
799
  temperature = gr.Slider(0, 1, value=0.7, step=0.1, label="🌡️ Creativity", scale=2)
800
  max_tokens = gr.Slider(256, 8192, value=2048, step=256, label="📏 Max Tokens", scale=2)
801
 
802
- model_info_display = gr.Markdown(value="🚀 Fast & capableRecommended")
803
- model_dropdown.change(get_model_info, model_dropdown, model_info_display)
804
 
805
  with gr.Tabs():
806
 
807
- # ===== CHAT =====
808
  with gr.TabItem("💬 Chat"):
809
  chatbot = gr.Chatbot(height=500)
810
  with gr.Row():
811
- msg = gr.Textbox(
812
- placeholder="Ask anything about coding... Press Enter to send",
813
- show_label=False, scale=8, lines=1
814
- )
815
  send = gr.Button("Send ➤", variant="primary", scale=1)
816
  with gr.Row():
817
- audio_input = gr.Audio(sources=["microphone"], type="filepath", label="🎤 Voice", scale=2)
818
- transcribe_btn = gr.Button("🎤 Transcribe", scale=1)
819
  clear = gr.Button("🗑️ Clear", scale=1)
820
- with gr.Accordion("💡 Quick Prompts", open=False):
821
- gr.Examples([
822
- "Write a Python function to find all prime numbers up to n",
823
- "Explain async/await vs promises in JavaScript",
824
- "How do I implement a binary search tree?",
825
- "Write a REST API with authentication in FastAPI"
826
- ], inputs=msg)
827
 
828
- # ===== GENERATE =====
829
  with gr.TabItem("⚡ Generate"):
830
  with gr.Row():
831
  with gr.Column(scale=1):
832
- gen_prompt = gr.Textbox(
833
- label="📝 Describe what you want to build",
834
- placeholder="e.g., A function that validates email addresses with regex",
835
- lines=5
836
- )
837
  with gr.Row():
838
- gen_lang = gr.Dropdown(LANGUAGES, value="Python", label="🔤 Language", scale=2)
839
  gen_temp = gr.Slider(0, 1, value=0.3, step=0.1, label="🌡️", scale=1)
840
- gen_btn = gr.Button("⚡ Generate Code", variant="primary", size="lg")
841
  with gr.Column(scale=2):
842
- gen_output = gr.Code(label="Generated Code", language="python", lines=22)
843
 
844
- # ===== EXPLAIN =====
845
  with gr.TabItem("🔍 Explain"):
846
  with gr.Row():
847
  with gr.Column(scale=1):
848
- explain_input = gr.Code(label="📋 Paste your code", lines=14)
849
- explain_detail = gr.Radio(
850
- ["Brief", "Normal", "Detailed"],
851
- value="Normal", label="📊 Detail Level"
852
- )
853
- explain_btn = gr.Button("🔍 Explain Code", variant="primary", size="lg")
854
  with gr.Column(scale=1):
855
- explain_output = gr.Markdown(label="Explanation")
856
 
857
- # ===== DEBUG =====
858
  with gr.TabItem("🔧 Debug"):
859
  with gr.Row():
860
  with gr.Column(scale=1):
861
- fix_input = gr.Code(label="🐛 Paste buggy code", lines=12)
862
- fix_error = gr.Textbox(
863
- label=" Error message (optional)",
864
- placeholder="Paste error or describe the issue",
865
- lines=3
866
- )
867
- fix_btn = gr.Button("🔧 Fix Code", variant="primary", size="lg")
868
  with gr.Column(scale=1):
869
- fix_output = gr.Markdown(label="Solution")
870
 
871
- # ===== REVIEW =====
872
  with gr.TabItem("📋 Review"):
873
  with gr.Row():
874
  with gr.Column(scale=1):
875
- review_input = gr.Code(label="📋 Code to review", lines=16)
876
- review_btn = gr.Button("📋 Review Code", variant="primary", size="lg")
877
  with gr.Column(scale=1):
878
- review_output = gr.Markdown(label="Code Review")
879
 
880
- # ===== CONVERT =====
881
  with gr.TabItem("🔄 Convert"):
882
  with gr.Row():
883
  with gr.Column(scale=1):
884
- convert_input = gr.Code(label="📥 Source Code", lines=14)
885
  with gr.Row():
886
- convert_from = gr.Dropdown(LANGUAGES, value="Python", label="From", scale=1)
887
- convert_to = gr.Dropdown(LANGUAGES, value="JavaScript", label="To", scale=1)
888
- convert_btn = gr.Button("🔄 Convert Code", variant="primary", size="lg")
889
  with gr.Column(scale=1):
890
- convert_output = gr.Code(label="📤 Converted Code", lines=14)
891
 
892
- # ===== TEST =====
893
  with gr.TabItem("🧪 Test"):
894
  with gr.Row():
895
  with gr.Column(scale=1):
896
- test_input = gr.Code(label="📋 Code to test", lines=14)
897
  with gr.Row():
898
- test_lang = gr.Dropdown(LANGUAGES[:12], value="Python", label="Language", scale=2)
899
- test_framework = gr.Textbox(label="Framework", placeholder="e.g., pytest", scale=2)
900
- test_btn = gr.Button("🧪 Generate Tests", variant="primary", size="lg")
901
  with gr.Column(scale=1):
902
- test_output = gr.Code(label="Generated Tests", lines=14)
903
 
904
- # ===== DOCUMENT =====
905
  with gr.TabItem("📝 Document"):
906
  with gr.Row():
907
  with gr.Column(scale=1):
908
- doc_input = gr.Code(label="📋 Code to document", lines=14)
909
  with gr.Row():
910
- doc_lang = gr.Dropdown(LANGUAGES, value="Python", label="Language", scale=2)
911
- doc_style = gr.Dropdown(
912
- ["Docstrings", "Comments", "Both", "README"],
913
- value="Both", label="Style", scale=2
914
- )
915
- doc_btn = gr.Button("📝 Document", variant="primary", size="lg")
916
  with gr.Column(scale=1):
917
- doc_output = gr.Code(label="Documented Code", lines=14)
918
 
919
- # ===== OPTIMIZE =====
920
  with gr.TabItem("🚀 Optimize"):
921
  with gr.Row():
922
  with gr.Column(scale=1):
923
- opt_input = gr.Code(label="📋 Code to optimize", lines=14)
924
  with gr.Row():
925
- opt_lang = gr.Dropdown(LANGUAGES, value="Python", label="Language", scale=2)
926
- opt_focus = gr.Dropdown(
927
- ["All", "Performance", "Readability", "Memory"],
928
- value="All", label="Focus", scale=2
929
- )
930
- opt_btn = gr.Button("🚀 Optimize", variant="primary", size="lg")
931
  with gr.Column(scale=1):
932
- opt_output = gr.Markdown(label="Optimized Code")
933
 
934
- # ===== TOOLS =====
935
  with gr.TabItem("🛠️ Tools"):
936
-
937
- # Regex Builder
938
  gr.Markdown("### 🎯 Regex Builder")
939
  with gr.Row():
940
- with gr.Column(scale=1):
941
- regex_desc = gr.Textbox(
942
- label="Describe the pattern",
943
- placeholder="e.g., Match email addresses, validate phone numbers...",
944
- lines=3
945
- )
946
  regex_btn = gr.Button("🎯 Build Regex", variant="primary")
947
- with gr.Column(scale=1):
948
- regex_output = gr.Markdown(label="Regex Pattern")
949
 
950
- gr.Markdown("---")
951
-
952
- # API Builder
953
- gr.Markdown("### 🔗 API Builder")
954
  with gr.Row():
955
- with gr.Column(scale=1):
956
- api_desc = gr.Textbox(
957
- label="Describe the endpoint",
958
- placeholder="e.g., POST endpoint for user registration...",
959
- lines=3
960
- )
961
- api_framework = gr.Dropdown(
962
- ["FastAPI (Python)", "Express (Node.js)", "Gin (Go)", "Spring Boot (Java)", "Flask (Python)", "Django REST (Python)"],
963
- value="FastAPI (Python)", label="Framework"
964
- )
965
  api_btn = gr.Button("🔗 Build API", variant="primary")
966
- with gr.Column(scale=1):
967
- api_output = gr.Code(label="API Code", lines=14)
968
 
969
- # Footer
970
- gr.HTML("""
971
- <div class="footer">
972
- <p>🔒 Running 100% locally via Ollama • Your code never leaves your machine</p>
973
- <p style="margin-top: 8px; opacity: 0.7;">Axon v6 • Built with ❤️</p>
974
- </div>
975
- """)
976
 
977
- # ===== EVENT HANDLERS =====
978
-
979
  def respond(message, history, model, temp, tokens):
980
  history = history or []
981
- for updated_history in chat_stream(message, history, model, temp, tokens):
982
- yield updated_history, ""
983
 
984
  msg.submit(respond, [msg, chatbot, model_dropdown, temperature, max_tokens], [chatbot, msg])
985
  send.click(respond, [msg, chatbot, model_dropdown, temperature, max_tokens], [chatbot, msg])
986
  clear.click(lambda: [], None, chatbot)
987
- transcribe_btn.click(transcribe_audio, audio_input, msg)
 
 
 
988
 
989
- gen_btn.click(generate_code, [gen_prompt, gen_lang, model_dropdown, gen_temp, max_tokens], gen_output)
990
  explain_btn.click(explain_code, [explain_input, model_dropdown, explain_detail, max_tokens], explain_output)
991
  fix_btn.click(fix_code, [fix_input, fix_error, model_dropdown, max_tokens], fix_output)
992
  review_btn.click(review_code, [review_input, model_dropdown, max_tokens], review_output)
993
  convert_btn.click(convert_code, [convert_input, convert_from, convert_to, model_dropdown, max_tokens], convert_output)
994
- test_btn.click(generate_tests, [test_input, test_lang, test_framework, model_dropdown, max_tokens], test_output)
995
  doc_btn.click(document_code, [doc_input, doc_lang, doc_style, model_dropdown, max_tokens], doc_output)
996
  opt_btn.click(optimize_code, [opt_input, opt_lang, opt_focus, model_dropdown, max_tokens], opt_output)
997
  regex_btn.click(build_regex, [regex_desc, model_dropdown, max_tokens], regex_output)
998
- api_btn.click(build_api, [api_desc, api_framework, model_dropdown, max_tokens], api_output)
 
 
 
999
 
1000
- # Launch with CSS (Gradio 6.0 way)
1001
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
2
  import requests
3
  import json
4
  import time
5
+ import os
6
  from faster_whisper import WhisperModel
7
 
8
  OLLAMA_URL = "http://localhost:11434"
9
  MAX_RETRIES = 3
10
  TIMEOUT = 300
11
 
12
+ # ===== PERFORMANCE SETTINGS =====
13
+ OLLAMA_OPTIONS = {
14
+ "num_ctx": 4096, # Context window (lower = faster, 4096 is good balance)
15
+ "num_batch": 512, # Batch size for prompt processing
16
+ "num_thread": 4, # CPU threads (adjust based on your CPU)
17
+ "repeat_penalty": 1.1, # Prevent repetition
18
+ "top_k": 40, # Top-K sampling (lower = faster)
19
+ "top_p": 0.9, # Nucleus sampling
20
+ }
21
+
22
+ # Keep model loaded for 10 minutes (faster subsequent requests)
23
+ KEEP_ALIVE = "10m"
24
+
25
  MODELS = {
26
  "⭐ Qwen2.5 Coder 7B (Best)": "qwen2.5-coder:7b",
27
  "🧠 DeepSeek Coder 6.7B (Logic)": "deepseek-coder:6.7b",
 
65
 
66
  init_whisper()
67
 
68
+ # ===== PRELOAD DEFAULT MODEL =====
69
+ def preload_model():
70
+ """Preload default model for faster first request"""
71
+ try:
72
+ print("🔥 Preloading default model...")
73
+ requests.post(
74
+ f"{OLLAMA_URL}/api/generate",
75
+ json={
76
+ "model": "qwen2.5-coder:3b",
77
+ "prompt": "Hi",
78
+ "keep_alive": KEEP_ALIVE,
79
+ "options": {"num_predict": 1}
80
+ },
81
+ timeout=60
82
+ )
83
+ print("✅ Model preloaded!")
84
+ except Exception as e:
85
+ print(f"⚠️ Preload failed: {e}")
86
+
87
  # ===== HELPER FUNCTIONS =====
88
 
89
  def check_ollama_health():
 
120
  def transcribe_audio(audio):
121
  if audio is None:
122
  return ""
 
123
  if whisper_model is None:
124
  return "❌ Whisper not loaded. Voice input unavailable."
 
125
  try:
126
  segments, _ = whisper_model.transcribe(audio)
127
  text = " ".join([seg.text for seg in segments]).strip()
 
135
 
136
  def call_ollama_with_retry(model_name, prompt, temperature=0.7, max_tokens=2048):
137
  if not check_ollama_health():
138
+ return "❌ **Ollama is not running.**\n\nPlease wait for Ollama to start."
139
 
140
  model = MODELS.get(model_name, "qwen2.5-coder:3b")
141
 
142
+ # Merge performance options with request options
143
+ options = {
144
+ **OLLAMA_OPTIONS,
145
+ "temperature": temperature,
146
+ "num_predict": max_tokens
147
+ }
148
+
149
  for attempt in range(MAX_RETRIES):
150
  try:
151
  r = requests.post(
 
154
  "model": model,
155
  "prompt": prompt,
156
  "stream": False,
157
+ "keep_alive": KEEP_ALIVE,
158
+ "options": options
 
 
159
  },
160
  timeout=TIMEOUT
161
  )
 
163
  if r.status_code == 200:
164
  response = r.json().get("response", "")
165
  if not response.strip():
166
+ return "⚠️ Model returned empty response. Try rephrasing."
167
  return response
 
168
  elif r.status_code == 404:
169
+ return f"❌ **Model not found:** `{model}`"
 
170
  elif r.status_code == 500:
171
+ error_msg = r.text[:200] if r.text else "Unknown error"
172
  if "out of memory" in error_msg.lower():
173
+ return "❌ **Out of memory.** Try a smaller model."
174
  return f"❌ **Server error:** {error_msg}"
 
175
  else:
176
  return f"❌ **HTTP {r.status_code}:** {r.text[:100]}"
177
 
 
179
  if attempt < MAX_RETRIES - 1:
180
  time.sleep(2)
181
  continue
182
+ return "❌ **Timeout.** Try smaller model or shorter input."
 
183
  except requests.exceptions.ConnectionError:
184
  if attempt < MAX_RETRIES - 1:
185
  time.sleep(2)
186
  continue
187
+ return "❌ **Connection failed.** Ollama may have crashed."
 
188
  except json.JSONDecodeError:
189
+ return "❌ **Invalid response from Ollama.**"
 
190
  except Exception as e:
191
+ return f"❌ **Error:** {str(e)[:100]}"
192
 
193
+ return "❌ **Max retries reached.**"
194
 
195
  def extract_code(text):
196
  if not text or "```" not in text:
197
  return text
 
198
  try:
199
  parts = text.split("```")
200
  if len(parts) >= 2:
 
202
  if "\n" in code:
203
  code = code.split("\n", 1)[-1]
204
  return code.strip()
205
+ except:
206
  pass
207
  return text
208
 
209
+ # ===== STREAMING FUNCTIONS (FASTER FEEDBACK) =====
210
 
211
  def chat_stream(message, history, model_name, temperature, max_tokens):
212
  valid, error = validate_input(message, "Message")
 
215
  return
216
 
217
  if not check_ollama_health():
218
+ yield history + [[message, "❌ **Ollama not running.**"]]
219
  return
220
 
221
  model = MODELS.get(model_name, "qwen2.5-coder:3b")
222
+ messages = [{"role": "system", "content": "Expert coding assistant. Use markdown code blocks."}]
223
 
224
  for user_msg, assistant_msg in history:
225
  messages.append({"role": "user", "content": user_msg})
 
227
  messages.append({"role": "assistant", "content": assistant_msg})
228
 
229
  messages.append({"role": "user", "content": message})
230
+
231
+ options = {
232
+ **OLLAMA_OPTIONS,
233
+ "temperature": temperature,
234
+ "num_predict": max_tokens
235
+ }
236
 
237
  try:
238
  response = requests.post(
 
241
  "model": model,
242
  "messages": messages,
243
  "stream": True,
244
+ "keep_alive": KEEP_ALIVE,
245
+ "options": options
246
  },
247
  stream=True,
248
  timeout=TIMEOUT
249
  )
250
 
251
  if response.status_code == 404:
252
+ yield history + [[message, f"❌ **Model not found:** `{model}`"]]
253
  return
254
 
255
  if response.status_code != 200:
256
+ yield history + [[message, f"❌ **Error {response.status_code}**"]]
257
  return
258
 
259
  full = ""
 
262
  try:
263
  data = json.loads(line)
264
  if "error" in data:
265
+ yield history + [[message, f"❌ **Error:** {data['error']}"]]
266
  return
267
  if "message" in data:
268
  full += data["message"].get("content", "")
 
271
  continue
272
 
273
  if not full.strip():
274
+ yield history + [[message, "⚠️ Empty response. Try rephrasing."]]
275
 
276
  except requests.exceptions.Timeout:
277
+ yield history + [[message, "❌ **Timeout.** Try smaller model."]]
278
  except requests.exceptions.ConnectionError:
279
+ yield history + [[message, "❌ **Connection lost.**"]]
280
  except Exception as e:
281
+ yield history + [[message, f"❌ **Error:** {str(e)[:50]}"]]
282
 
283
+ # ===== STREAMING CODE GENERATION (NEW!) =====
284
+
285
+ def generate_code_stream(prompt, language, model_name, temperature, max_tokens):
286
  valid, error = validate_input(prompt, "Description")
287
  if not valid:
288
+ yield error
289
+ return
290
 
291
+ if not check_ollama_health():
292
+ yield " **Ollama not running.**"
293
+ return
294
+
295
+ model = MODELS.get(model_name, "qwen2.5-coder:3b")
 
 
 
 
296
 
297
+ # Shorter, optimized prompt
298
+ full_prompt = f"Write clean {language} code with comments for:\n{prompt}\n\nCode only:"
299
+
300
+ options = {
301
+ **OLLAMA_OPTIONS,
302
+ "temperature": temperature,
303
+ "num_predict": max_tokens
304
+ }
305
+
306
+ try:
307
+ response = requests.post(
308
+ f"{OLLAMA_URL}/api/generate",
309
+ json={
310
+ "model": model,
311
+ "prompt": full_prompt,
312
+ "stream": True,
313
+ "keep_alive": KEEP_ALIVE,
314
+ "options": options
315
+ },
316
+ stream=True,
317
+ timeout=TIMEOUT
318
+ )
319
+
320
+ if response.status_code != 200:
321
+ yield f"❌ **Error {response.status_code}**"
322
+ return
323
+
324
+ full = ""
325
+ for line in response.iter_lines():
326
+ if line:
327
+ try:
328
+ data = json.loads(line)
329
+ if "response" in data:
330
+ full += data["response"]
331
+ # Extract code as we stream
332
+ yield extract_code(full)
333
+ except:
334
+ continue
335
+
336
+ except requests.exceptions.Timeout:
337
+ yield "❌ **Timeout.**"
338
+ except Exception as e:
339
+ yield f"❌ **Error:** {str(e)[:50]}"
340
+
341
+ # ===== OPTIMIZED CORE FUNCTIONS (SHORTER PROMPTS) =====
342
 
343
  def explain_code(code, model_name, detail_level, max_tokens):
344
  valid, error = validate_input(code, "Code")
345
  if not valid:
346
  return error
347
 
348
+ prompts = {
349
+ "Brief": f"Explain briefly (2-3 sentences):\n{code}",
350
+ "Normal": f"Explain this code:\n{code}",
351
+ "Detailed": f"Detailed explanation (purpose, logic, complexity, improvements):\n{code}"
352
  }
353
 
354
+ return call_ollama_with_retry(model_name, prompts.get(detail_level, prompts["Normal"]), 0.5, max_tokens)
 
355
 
356
  def fix_code(code, error_msg, model_name, max_tokens):
357
  valid, error = validate_input(code, "Code")
358
  if not valid:
359
  return error
360
 
361
+ err = error_msg.strip() if error_msg else "Not working"
362
+ prompt = f"Fix this code. Error: {err}\n\n{code}\n\nFixed code and explanation:"
 
 
 
 
 
 
 
 
363
  return call_ollama_with_retry(model_name, prompt, 0.3, max_tokens)
364
 
365
  def review_code(code, model_name, max_tokens):
 
367
  if not valid:
368
  return error
369
 
370
+ prompt = f"Review for bugs, performance, security, and improvements:\n{code}"
 
 
 
 
 
 
 
 
371
  return call_ollama_with_retry(model_name, prompt, 0.4, max_tokens)
372
 
373
  def convert_code(code, source_lang, target_lang, model_name, max_tokens):
374
  valid, error = validate_input(code, "Code")
375
  if not valid:
376
  return error
 
377
  if source_lang == target_lang:
378
+ return "⚠️ Same language selected."
 
 
 
 
 
 
 
 
 
 
379
 
380
+ prompt = f"Convert {source_lang} to {target_lang}. Output only code:\n{code}"
381
  result = call_ollama_with_retry(model_name, prompt, 0.3, max_tokens)
382
+ return result if result.startswith("❌") or result.startswith("⚠️") else extract_code(result)
 
 
383
 
384
  def generate_tests(code, language, framework, model_name, max_tokens):
385
  valid, error = validate_input(code, "Code")
386
  if not valid:
387
  return error
388
 
389
+ fw = framework.strip() if framework else "pytest" if language == "Python" else "Jest"
390
+ prompt = f"Generate {fw} tests for this {language} code. Output only test code:\n{code}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
  result = call_ollama_with_retry(model_name, prompt, 0.3, max_tokens)
392
+ return result if result.startswith("❌") or result.startswith("⚠️") else extract_code(result)
 
 
393
 
394
  def document_code(code, language, style, model_name, max_tokens):
395
  valid, error = validate_input(code, "Code")
396
  if not valid:
397
  return error
398
 
399
+ prompt = f"Add {style.lower()} to this {language} code:\n{code}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
  result = call_ollama_with_retry(model_name, prompt, 0.4, max_tokens)
401
+ return result if style == "README" or result.startswith("❌") else extract_code(result)
 
 
402
 
403
  def optimize_code(code, language, focus, model_name, max_tokens):
404
  valid, error = validate_input(code, "Code")
405
  if not valid:
406
  return error
407
 
408
+ prompt = f"Optimize for {focus.lower()}. Explain changes:\n{code}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
409
  return call_ollama_with_retry(model_name, prompt, 0.3, max_tokens)
410
 
411
  def build_regex(description, model_name, max_tokens):
 
413
  if not valid:
414
  return error
415
 
416
+ prompt = f"Create regex for: {description}\n\nPattern, explanation, examples, Python code:"
 
 
 
 
 
 
 
 
 
417
  return call_ollama_with_retry(model_name, prompt, 0.3, max_tokens)
418
 
419
  def build_api(description, framework, model_name, max_tokens):
 
421
  if not valid:
422
  return error
423
 
424
+ prompt = f"Create {framework} REST endpoint:\n{description}\n\nCode with validation and error handling:"
 
 
 
 
 
 
 
 
 
 
 
425
  result = call_ollama_with_retry(model_name, prompt, 0.3, max_tokens)
426
+ return result if result.startswith("❌") else extract_code(result)
 
 
427
 
428
+ # ===== CSS =====
429
 
430
  css = """
 
431
  :root {
432
  --primary: #6366f1;
 
433
  --secondary: #8b5cf6;
 
434
  --bg-dark: #0f172a;
435
  --bg-card: #1e293b;
 
 
 
436
  --border: #334155;
437
+ --text-primary: #f1f5f9;
 
 
438
  --gradient: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #06b6d4 100%);
439
  }
440
+ .gradio-container { max-width: 1500px !important; margin: auto !important; }
 
 
 
 
 
 
 
 
441
  .header-section {
442
  background: var(--gradient);
443
  border-radius: 20px;
444
  padding: 32px 40px;
445
  margin-bottom: 24px;
 
 
446
  box-shadow: 0 20px 40px rgba(99, 102, 241, 0.3);
447
  }
448
+ .header-title { color: white; margin: 0; font-size: 2.5rem; font-weight: 800; }
449
+ .header-subtitle { color: rgba(255,255,255,0.9); margin: 8px 0 0 0; }
450
+ .header-badges { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 16px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
451
  .badge {
452
  background: rgba(255,255,255,0.2);
 
453
  padding: 8px 16px;
454
  border-radius: 50px;
455
  font-size: 0.85rem;
 
456
  color: white;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
457
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
  .tab-nav button.selected {
459
  background: var(--gradient) !important;
460
  color: white !important;
 
461
  }
462
+ button.primary {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463
  background: var(--gradient) !important;
464
  border: none !important;
465
+ border-radius: 10px !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
466
  }
467
+ .footer { text-align: center; padding: 24px; color: #94a3b8; font-size: 0.85rem; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
  footer { display: none !important; }
 
 
 
 
 
 
 
 
469
  """
470
 
471
+ # ===== UI =====
472
 
473
  with gr.Blocks(title="Axon v6") as demo:
474
 
 
475
  gr.HTML("""
476
  <div class="header-section">
477
+ <h1 class="header-title">🔥 Axon v6</h1>
478
+ <p class="header-subtitle">AI-Powered Coding Assistant • Optimized for Speed</p>
479
+ <div class="header-badges">
480
+ <span class="badge">🤖 7 Models</span>
481
+ <span class="badge">🛠️ 9 Tools</span>
482
+ <span class="badge">⚡ Optimized</span>
483
+ <span class="badge">🔒 100% Local</span>
 
 
 
 
484
  </div>
485
  </div>
486
  """)
487
 
488
+ status = gr.Markdown(value=get_status, every=5)
 
 
489
 
 
490
  with gr.Row():
491
+ model_dropdown = gr.Dropdown(choices=list(MODELS.keys()), value="Qwen2.5 Coder 3B (Fast)", label="🤖 Model", scale=3)
 
 
 
 
 
492
  temperature = gr.Slider(0, 1, value=0.7, step=0.1, label="🌡️ Creativity", scale=2)
493
  max_tokens = gr.Slider(256, 8192, value=2048, step=256, label="📏 Max Tokens", scale=2)
494
 
495
+ model_info = gr.Markdown(value="⚖️ Balanced ~2GBGreat all-rounder")
496
+ model_dropdown.change(get_model_info, model_dropdown, model_info)
497
 
498
  with gr.Tabs():
499
 
 
500
  with gr.TabItem("💬 Chat"):
501
  chatbot = gr.Chatbot(height=500)
502
  with gr.Row():
503
+ msg = gr.Textbox(placeholder="Ask anything...", show_label=False, scale=8)
 
 
 
504
  send = gr.Button("Send ➤", variant="primary", scale=1)
505
  with gr.Row():
506
+ audio = gr.Audio(sources=["microphone"], type="filepath", label="🎤", scale=2)
507
+ transcribe = gr.Button("🎤 Transcribe", scale=1)
508
  clear = gr.Button("🗑️ Clear", scale=1)
509
+ with gr.Accordion("💡 Examples", open=False):
510
+ gr.Examples(["Write a Python quicksort", "Explain async/await in JS"], inputs=msg)
 
 
 
 
 
511
 
 
512
  with gr.TabItem("⚡ Generate"):
513
  with gr.Row():
514
  with gr.Column(scale=1):
515
+ gen_prompt = gr.Textbox(label="📝 Describe what to build", lines=4)
 
 
 
 
516
  with gr.Row():
517
+ gen_lang = gr.Dropdown(LANGUAGES, value="Python", label="Language", scale=2)
518
  gen_temp = gr.Slider(0, 1, value=0.3, step=0.1, label="🌡️", scale=1)
519
+ gen_btn = gr.Button("⚡ Generate (Streaming)", variant="primary")
520
  with gr.Column(scale=2):
521
+ gen_output = gr.Code(label="Code", language="python", lines=18)
522
 
 
523
  with gr.TabItem("🔍 Explain"):
524
  with gr.Row():
525
  with gr.Column(scale=1):
526
+ explain_input = gr.Code(label="📋 Code", lines=12)
527
+ explain_detail = gr.Radio(["Brief", "Normal", "Detailed"], value="Normal", label="Detail")
528
+ explain_btn = gr.Button("🔍 Explain", variant="primary")
 
 
 
529
  with gr.Column(scale=1):
530
+ explain_output = gr.Markdown()
531
 
 
532
  with gr.TabItem("🔧 Debug"):
533
  with gr.Row():
534
  with gr.Column(scale=1):
535
+ fix_input = gr.Code(label="🐛 Code", lines=10)
536
+ fix_error = gr.Textbox(label="❌ Error", lines=2)
537
+ fix_btn = gr.Button("🔧 Fix", variant="primary")
 
 
 
 
538
  with gr.Column(scale=1):
539
+ fix_output = gr.Markdown()
540
 
 
541
  with gr.TabItem("📋 Review"):
542
  with gr.Row():
543
  with gr.Column(scale=1):
544
+ review_input = gr.Code(label="📋 Code", lines=14)
545
+ review_btn = gr.Button("📋 Review", variant="primary")
546
  with gr.Column(scale=1):
547
+ review_output = gr.Markdown()
548
 
 
549
  with gr.TabItem("🔄 Convert"):
550
  with gr.Row():
551
  with gr.Column(scale=1):
552
+ convert_input = gr.Code(label="📥 Source", lines=12)
553
  with gr.Row():
554
+ convert_from = gr.Dropdown(LANGUAGES, value="Python", label="From")
555
+ convert_to = gr.Dropdown(LANGUAGES, value="JavaScript", label="To")
556
+ convert_btn = gr.Button("🔄 Convert", variant="primary")
557
  with gr.Column(scale=1):
558
+ convert_output = gr.Code(label="📤 Result", lines=12)
559
 
 
560
  with gr.TabItem("🧪 Test"):
561
  with gr.Row():
562
  with gr.Column(scale=1):
563
+ test_input = gr.Code(label="📋 Code", lines=12)
564
  with gr.Row():
565
+ test_lang = gr.Dropdown(LANGUAGES[:12], value="Python", label="Language")
566
+ test_fw = gr.Textbox(label="Framework", placeholder="pytest")
567
+ test_btn = gr.Button("🧪 Generate Tests", variant="primary")
568
  with gr.Column(scale=1):
569
+ test_output = gr.Code(label="Tests", lines=12)
570
 
 
571
  with gr.TabItem("📝 Document"):
572
  with gr.Row():
573
  with gr.Column(scale=1):
574
+ doc_input = gr.Code(label="📋 Code", lines=12)
575
  with gr.Row():
576
+ doc_lang = gr.Dropdown(LANGUAGES, value="Python", label="Language")
577
+ doc_style = gr.Dropdown(["Docstrings", "Comments", "Both", "README"], value="Both", label="Style")
578
+ doc_btn = gr.Button("📝 Document", variant="primary")
 
 
 
579
  with gr.Column(scale=1):
580
+ doc_output = gr.Code(label="Documented", lines=12)
581
 
 
582
  with gr.TabItem("🚀 Optimize"):
583
  with gr.Row():
584
  with gr.Column(scale=1):
585
+ opt_input = gr.Code(label="📋 Code", lines=12)
586
  with gr.Row():
587
+ opt_lang = gr.Dropdown(LANGUAGES, value="Python", label="Language")
588
+ opt_focus = gr.Dropdown(["All", "Performance", "Readability", "Memory"], value="All", label="Focus")
589
+ opt_btn = gr.Button("🚀 Optimize", variant="primary")
 
 
 
590
  with gr.Column(scale=1):
591
+ opt_output = gr.Markdown()
592
 
 
593
  with gr.TabItem("🛠️ Tools"):
 
 
594
  gr.Markdown("### 🎯 Regex Builder")
595
  with gr.Row():
596
+ with gr.Column():
597
+ regex_desc = gr.Textbox(label="Describe pattern", lines=2)
 
 
 
 
598
  regex_btn = gr.Button("🎯 Build Regex", variant="primary")
599
+ with gr.Column():
600
+ regex_output = gr.Markdown()
601
 
602
+ gr.Markdown("---\n### 🔗 API Builder")
 
 
 
603
  with gr.Row():
604
+ with gr.Column():
605
+ api_desc = gr.Textbox(label="Describe endpoint", lines=2)
606
+ api_fw = gr.Dropdown(["FastAPI", "Express", "Flask", "Gin"], value="FastAPI", label="Framework")
 
 
 
 
 
 
 
607
  api_btn = gr.Button("🔗 Build API", variant="primary")
608
+ with gr.Column():
609
+ api_output = gr.Code(label="API Code", lines=12)
610
 
611
+ gr.HTML('<div class="footer">🔒 100% Local • ⚡ Optimized for Speed • Built with ❤️</div>')
 
 
 
 
 
 
612
 
613
+ # Events
 
614
  def respond(message, history, model, temp, tokens):
615
  history = history or []
616
+ for updated in chat_stream(message, history, model, temp, tokens):
617
+ yield updated, ""
618
 
619
  msg.submit(respond, [msg, chatbot, model_dropdown, temperature, max_tokens], [chatbot, msg])
620
  send.click(respond, [msg, chatbot, model_dropdown, temperature, max_tokens], [chatbot, msg])
621
  clear.click(lambda: [], None, chatbot)
622
+ transcribe.click(transcribe_audio, audio, msg)
623
+
624
+ # Streaming generate!
625
+ gen_btn.click(generate_code_stream, [gen_prompt, gen_lang, model_dropdown, gen_temp, max_tokens], gen_output)
626
 
 
627
  explain_btn.click(explain_code, [explain_input, model_dropdown, explain_detail, max_tokens], explain_output)
628
  fix_btn.click(fix_code, [fix_input, fix_error, model_dropdown, max_tokens], fix_output)
629
  review_btn.click(review_code, [review_input, model_dropdown, max_tokens], review_output)
630
  convert_btn.click(convert_code, [convert_input, convert_from, convert_to, model_dropdown, max_tokens], convert_output)
631
+ test_btn.click(generate_tests, [test_input, test_lang, test_fw, model_dropdown, max_tokens], test_output)
632
  doc_btn.click(document_code, [doc_input, doc_lang, doc_style, model_dropdown, max_tokens], doc_output)
633
  opt_btn.click(optimize_code, [opt_input, opt_lang, opt_focus, model_dropdown, max_tokens], opt_output)
634
  regex_btn.click(build_regex, [regex_desc, model_dropdown, max_tokens], regex_output)
635
+ api_btn.click(build_api, [api_desc, api_fw, model_dropdown, max_tokens], api_output)
636
+
637
+ # Preload model on startup
638
+ preload_model()
639
 
 
640
  demo.launch(server_name="0.0.0.0", server_port=7860)