AIencoder commited on
Commit
6d34b8c
·
verified ·
1 Parent(s): 9294d1f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +119 -425
app.py CHANGED
@@ -7,14 +7,15 @@ from typing import Dict, List, Tuple, Optional
7
  import os
8
  import json
9
  from functools import lru_cache
10
- import os
11
- os.environ["TOKENIZERS_PARALLELISM"] = "false" # Prevents tokenizer warnings
 
12
  # CPU-optimized configuration
13
  MODEL_NAME = "TinyLlama/TinyLlama-1.1B-Chat-v1.0"
14
  DEVICE = "cpu"
15
- DTYPE = torch.float32 # Using float32 for CPU stability (float16 not well supported on CPU)
16
 
17
- # File system emulation
18
  class FileSystem:
19
  def __init__(self):
20
  self.files = {
@@ -29,9 +30,6 @@ class FileSystem:
29
  def save_file(self, content: str) -> None:
30
  if self.current_file:
31
  self.files[self.current_file] = content
32
- self.history.append(("save", self.current_file, content[:100] + "..."))
33
- if len(self.history) > self.max_history:
34
- self.history.pop(0)
35
 
36
  def get_file(self, filename: str) -> str:
37
  return self.files.get(filename, "")
@@ -47,29 +45,24 @@ class FileSystem:
47
  if filename not in self.files:
48
  self.files[filename] = content
49
  self.current_file = filename
50
- self.history.append(("create", filename, content[:50] + "..."))
51
 
52
  def get_all_files(self) -> List[str]:
53
  return list(self.files.keys())
54
 
55
  def get_context(self) -> str:
56
- """Get context from all files for the AI model"""
57
  context = ""
58
  for filename, content in self.files.items():
59
  context += f"// File: {filename}\n{content}\n\n"
60
  return context
61
 
62
- # Initialize file system
63
  fs = FileSystem()
64
 
65
- # Cache the model to avoid reloading
66
  @lru_cache(maxsize=1)
67
  def load_model():
68
  print("Loading TinyLlama model for CPU... This may take a moment.")
69
  start_time = time.time()
70
-
71
  try:
72
- # For CPU, we don't use quantization that requires bitsandbytes
73
  tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
74
  model = AutoModelForCausalLM.from_pretrained(
75
  MODEL_NAME,
@@ -77,250 +70,119 @@ def load_model():
77
  device_map=DEVICE,
78
  low_cpu_mem_usage=True
79
  )
80
-
81
- # Create the pipeline
82
  pipe = pipeline(
83
  "text-generation",
84
  model=model,
85
  tokenizer=tokenizer,
86
- device=-1, # Force CPU
87
  max_new_tokens=256,
88
  temperature=0.2,
89
  top_p=0.95,
90
  do_sample=True
91
  )
92
-
93
- load_time = time.time() - start_time
94
- print(f"Model loaded successfully in {load_time:.2f} seconds!")
95
  return pipe
96
  except Exception as e:
97
  print(f"Error loading model: {str(e)}")
98
  return None
99
 
 
100
  def run_code(code: str) -> Tuple[str, str]:
101
- """Safely execute JavaScript code in a sandboxed environment"""
102
  start_time = time.time()
103
- output = ""
104
- error = ""
105
-
106
  try:
107
- # This is a placeholder - in a real implementation you'd use a proper JS sandbox
108
- # For demonstration, we'll just return a success message
109
  output = f"✓ Code executed successfully\nExecution time: {time.time() - start_time:.4f}s"
 
110
  except Exception as e:
111
- error = f"✗ Error: {str(e)}"
112
-
113
- return output, error
114
 
115
- def generate_completion(code: str, cursor_pos: int = 0) -> str:
116
- """Generate code completion based on current context"""
117
  model = load_model()
118
- if not model:
119
- return "Error: Failed to load AI model. Please try again later."
120
-
121
- # Get context from all files
122
- context = fs.get_context()
123
-
124
- # Create prompt for code completion
125
- prompt = f"""<|system|>
126
- You are an AI programming assistant, an expert at completing code in JavaScript.
127
- Complete the code below. Only return the completion, no explanations.
128
- Keep the same indentation style as the code above.
129
- </s>
130
- <|user|>
131
- Current code context:
132
- {context}
133
-
134
- Complete this code:
135
- {code}
136
- </s>
137
- <|assistant|>
138
- """
139
 
 
140
  try:
141
- # Generate completion
142
- result = model(
143
- prompt,
144
- pad_token_id=model.tokenizer.eos_token_id,
145
- num_return_sequences=1,
146
- return_full_text=False
147
- )
148
-
149
- # Extract and clean the completion
150
- completion = result[0]['generated_text'].strip()
151
-
152
- # Remove any parts that repeat the prompt
153
- if code.strip() in completion:
154
- completion = completion.replace(code.strip(), "")
155
-
156
- return completion
157
  except Exception as e:
158
- return f"Error generating completion: {str(e)}"
159
 
160
  def explain_code(code: str) -> str:
161
- """Generate explanation for the given code"""
162
  model = load_model()
163
- if not model:
164
- return "Error: Failed to load AI model. Please try again later."
165
-
166
- prompt = f"""<|system|>
167
- You are an AI programming assistant that explains code clearly and concisely.
168
- Provide a line-by-line explanation of what the code does.
169
- </s>
170
- <|user|>
171
- Explain this JavaScript code:
172
- {code}
173
- </s>
174
- <|assistant|>
175
- """
176
-
177
  try:
178
- result = model(
179
- prompt,
180
- pad_token_id=model.tokenizer.eos_token_id,
181
- max_new_tokens=512,
182
- num_return_sequences=1,
183
- return_full_text=False
184
- )
185
-
186
  return result[0]['generated_text'].strip()
187
  except Exception as e:
188
- return f"Error explaining code: {str(e)}"
189
 
190
  def refactor_code(code: str) -> str:
191
- """Suggest improvements to the given code"""
192
  model = load_model()
193
- if not model:
194
- return "Error: Failed to load AI model. Please try again later."
195
-
196
- prompt = f"""<|system|>
197
- You are an AI programming assistant that refactors code for better readability, performance, and maintainability.
198
- Provide a refactored version of the code with improvements.
199
- Explain the key changes in a comment at the top.
200
- </s>
201
- <|user|>
202
- Refactor this JavaScript code:
203
- {code}
204
- </s>
205
- <|assistant|>
206
- """
207
-
208
  try:
209
- result = model(
210
- prompt,
211
- pad_token_id=model.tokenizer.eos_token_id,
212
- max_new_tokens=512,
213
- num_return_sequences=1,
214
- return_full_text=False
215
- )
216
-
217
  return result[0]['generated_text'].strip()
218
  except Exception as e:
219
- return f"Error refactoring code: {str(e)}"
220
 
221
- def generate_code(prompt: str) -> str:
222
- """Generate code based on a natural language description"""
223
  model = load_model()
224
- if not model:
225
- return "Error: Failed to load AI model. Please try again later."
226
-
227
- prompt = f"""<|system|>
228
- You are an AI programming assistant that writes clean, efficient JavaScript code.
229
- Generate code based on the user's description. Include comments for complex parts.
230
- </s>
231
- <|user|>
232
- Write JavaScript code that: {prompt}
233
- </s>
234
- <|assistant|>
235
- """
236
-
237
  try:
238
- result = model(
239
- prompt,
240
- pad_token_id=model.tokenizer.eos_token_id,
241
- max_new_tokens=512,
242
- num_return_sequences=1,
243
- return_full_text=False
244
- )
245
-
246
  return result[0]['generated_text'].strip()
247
  except Exception as e:
248
- return f"Error generating code: {str(e)}"
249
-
250
- def process_voice_input(transcript: str) -> str:
251
- """Process voice input and convert to code or command"""
252
- # This would integrate with Web Speech API in the frontend
253
- # For now, just return the transcript as a placeholder
254
- return transcript
255
 
256
  def create_diff_view(original: str, modified: str) -> str:
257
- """Create a diff view between two code versions"""
258
- # Simple diff implementation for demonstration
259
  lines_original = original.split('\n')
260
  lines_modified = modified.split('\n')
261
-
262
  diff = []
263
- i, j = 0, 0
264
-
265
- while i < len(lines_original) and j < len(lines_modified):
266
- if lines_original[i] == lines_modified[j]:
267
- diff.append(f" {lines_original[i]}")
268
- i += 1
269
- j += 1
270
- else:
271
- if i < len(lines_original):
272
- diff.append(f"- {lines_original[i]}")
273
- i += 1
274
- if j < len(lines_modified):
275
- diff.append(f"+ {lines_modified[j]}")
276
- j += 1
277
-
278
- # Add remaining lines
279
- while i < len(lines_original):
280
- diff.append(f"- {lines_original[i]}")
281
- i += 1
282
-
283
- while j < len(lines_modified):
284
- diff.append(f"+ {lines_modified[j]}")
285
- j += 1
286
-
287
  return "\n".join(diff)
288
 
289
- # Gradio UI Components (updated for Gradio 6.5.1)
290
- with gr.Blocks(
291
- title="Axon Pro - Free AI IDE",
292
- theme=gr.themes.Default(
293
- font=[gr.themes.GoogleFont('JetBrains Mono'), 'monospace'],
294
- font_mono=[gr.themes.GoogleFont('JetBrains Mono'), 'monospace'],
295
- primary_hue="blue",
296
- neutral_hue="gray",
297
- radius=0
298
- ).set(
299
- button_primary_background_fill="*primary_500",
300
- button_primary_background_fill_hover="*primary_600",
301
- body_background_fill="*neutral_900",
302
- body_text_color="*neutral_50"
303
- ),
304
- css="""
305
- .editor-container { height: 50vh; }
306
- .terminal { height: 15vh; background-color: #1e1e1e; color: #d4d4d4; overflow: auto; }
307
- .diff-view { height: 40vh; overflow: auto; }
308
- .file-explorer { height: 50vh; background-color: #252526; overflow: auto; }
309
- .ai-chat { height: 40vh; overflow: auto; }
310
- .status-bar { background-color: #007acc; color: white; padding: 5px; text-align: center; }
311
- .btn { min-width: 100px; }
312
- .monaco-editor { height: 100% !important; }
313
- .theme-dark { --body-bg: #1e1e1e; --editor-bg: #1e1e1e; }
314
- .button-large { min-height: 40px !important; }
315
- .tab-nav { background-color: #252526 !important; }
316
- .tabitem { background-color: #1e1e1e !important; }
317
- .code-wrap { white-space: pre-wrap !important; word-break: break-word !important; }
318
- """
319
- ) as demo:
 
 
320
 
321
  gr.Markdown("# ⚡ Axon Pro — Free AI-Powered Code IDE")
322
 
323
- with gr.Tabs():
 
324
  with gr.Tab("Editor", id="editor-tab"):
325
  with gr.Row(equal_height=True):
326
  # File Explorer
@@ -334,13 +196,9 @@ with gr.Blocks(
334
  container=False
335
  )
336
  with gr.Row():
337
- new_file_btn = gr.Button("➕ New File", variant="secondary", elem_classes="button-large")
338
- save_btn = gr.Button("💾 Save", variant="secondary", elem_classes="button-large")
339
- new_file_name = gr.Textbox(
340
- placeholder="filename.js",
341
- label="New File Name",
342
- container=False
343
- )
344
 
345
  # Main Editor Area
346
  with gr.Column(scale=4):
@@ -354,65 +212,43 @@ with gr.Blocks(
354
  )
355
 
356
  with gr.Row():
357
- run_btn = gr.Button("▶ Run (Ctrl+R)", variant="primary", elem_classes="button-large")
358
- complete_btn = gr.Button("✨ Complete (Ctrl+Enter)", variant="secondary", elem_classes="button-large")
359
- explain_btn = gr.Button("📝 Explain (Ctrl+Shift+E)", variant="secondary", elem_classes="button-large")
360
- refactor_btn = gr.Button("🔧 Refactor", variant="secondary", elem_classes="button-large")
361
- generate_btn = gr.Button("⚡ Generate", variant="secondary", elem_classes="button-large")
362
- voice_btn = gr.Button("🎤 Voice", variant="secondary", elem_classes="button-large")
363
-
364
  with gr.Tabs():
365
  with gr.Tab("Terminal", id="terminal-tab"):
366
  terminal = gr.Textbox(
367
- value="$ _ (Ctrl+R to run)",
368
  lines=5,
369
  interactive=False,
370
  elem_classes="terminal"
371
  )
372
- clear_btn = gr.Button("CLEAR", variant="secondary", elem_classes="button-large")
373
 
374
  with gr.Tab("AI Chat", id="chat-tab"):
375
- chat_history = gr.Chatbot(
376
- label="Axon AI",
377
- elem_classes="ai-chat",
378
- height="100%",
379
- bubble_full_width=False,
380
- avatar_images=(None, "https://api.iconify.design/teenyicons:ai-solid.svg")
381
- )
382
  with gr.Row():
383
- chat_input = gr.Textbox(
384
- placeholder="Ask about your code...",
385
- label="Message Axon AI",
386
- container=False,
387
- scale=7
388
- )
389
- send_btn = gr.Button("Send", variant="primary", elem_classes="button-large", scale=1)
390
 
391
  with gr.Tab("Diff View", id="diff-tab"):
392
- diff_view = gr.Code(
393
- value="",
394
- label="AI Changes",
395
- language="diff",
396
- elem_classes="diff-view code-wrap",
397
- interactive=False
398
- )
399
  with gr.Row():
400
- apply_btn = gr.Button("Apply Changes", variant="primary", elem_classes="button-large")
401
- discard_btn = gr.Button("Discard Changes", variant="secondary", elem_classes="button-large")
402
 
403
- status_bar = gr.Markdown(
404
- f"**AXON PRO v1.0** | {len(fs.get_all_files())} files | {sum(len(content.split('\\n')) for content in fs.files.values())} lines | JavaScript | Axon Pro v1.0 | AI Ready",
405
- elem_classes="status-bar"
406
- )
407
 
408
- # Hidden state for tracking
409
  current_file_state = gr.State(fs.current_file)
410
  diff_original_state = gr.State("")
411
  diff_modified_state = gr.State("")
412
  diff_mode_state = gr.State(False)
413
 
414
- # Event handlers
415
- def update_file_content(content, current_file):
416
  fs.save_file(content)
417
  return fs.get_current_file_content()
418
 
@@ -426,218 +262,76 @@ with gr.Blocks(
426
  return gr.update(choices=fs.get_all_files(), value=name), fs.get_current_file_content()
427
  return gr.update(choices=fs.get_all_files()), fs.get_current_file_content()
428
 
429
- def save_file(content, current_file):
430
- fs.save_file(content)
431
- return content
432
-
433
  def run_code_wrapper(content):
434
- output, error = run_code(content)
435
- return output if not error else error
436
 
437
  def complete_code_wrapper(content):
438
- completion = generate_completion(content)
439
- return content + completion
440
 
441
  def explain_code_wrapper(content):
442
  explanation = explain_code(content)
443
  fs.save_file(content)
444
- diff_original = content
445
- diff_modified = f"// EXPLANATION:\n// {explanation.replace('\\n', '\\n// ')}\n\n{content}"
446
-
447
- # Switch to diff view
448
- diff = create_diff_view(diff_original, diff_modified)
449
- return diff, diff_original, diff_modified, True
450
 
451
  def refactor_code_wrapper(content):
452
  refactored = refactor_code(content)
453
  fs.save_file(content)
454
- diff_original = content
455
- diff_modified = refactored
456
-
457
- # Switch to diff view
458
- diff = create_diff_view(diff_original, diff_modified)
459
- return diff, diff_original, diff_modified, True
460
-
461
  def generate_code_wrapper(prompt, history):
462
- if not prompt.strip():
463
- return diff_view.value, diff_original_state.value, diff_modified_state.value, diff_mode_state.value, history
464
-
465
  generated = generate_code(prompt)
466
- # Switch to diff view with the generated code
467
- diff_original = ""
468
- diff_modified = generated
469
-
470
- # Switch to diff view
471
- diff = create_diff_view(diff_original, diff_modified)
472
- return diff, diff_original, diff_modified, True, history + [[prompt, "Generated code is ready for review in Diff View"]]
473
-
474
- def apply_diff(diff_original, diff_modified, in_diff_mode):
475
- if in_diff_mode:
476
- fs.save_file(diff_modified)
477
- return fs.get_current_file_content(), False
478
- return gr.update(), in_diff_mode
479
-
480
- def discard_diff():
481
- return fs.get_current_file_content(), False
482
-
483
- def clear_terminal():
484
- return "$ _ (Ctrl+R to run)"
485
-
486
- def handle_chat(message, history):
487
- if not message.strip():
488
- return "", history
489
-
490
- # For demo, just echo the message with a placeholder response
491
- response = f"AI: This is a demo response. In a full implementation, I'd analyze your code context and provide helpful suggestions."
492
- new_history = history + [[message, response]]
493
- return "", new_history
494
-
495
- def switch_to_diff_tab():
496
- return gr.Tabs(selected="diff-tab")
497
-
498
- def switch_to_editor_tab():
499
- return gr.Tabs(selected="editor-tab")
500
-
501
- # Bind events
502
- editor.change(update_file_content, [editor, current_file_state], editor)
503
  file_list.change(load_file, file_list, [editor, current_file_state])
504
  new_file_btn.click(create_new_file, new_file_name, [file_list, editor])
505
- save_btn.click(save_file, [editor, current_file_state], editor)
506
 
507
  run_btn.click(run_code_wrapper, editor, terminal)
508
  complete_btn.click(complete_code_wrapper, editor, editor)
 
509
 
 
510
  explain_btn.click(
511
- explain_code_wrapper,
512
- editor,
513
  [diff_view, diff_original_state, diff_modified_state, diff_mode_state]
514
  ).then(
515
- switch_to_diff_tab, None, demo.tabs
516
  )
517
 
518
  refactor_btn.click(
519
- refactor_code_wrapper,
520
- editor,
521
  [diff_view, diff_original_state, diff_modified_state, diff_mode_state]
522
  ).then(
523
- switch_to_diff_tab, None, demo.tabs
524
- )
525
-
526
- generate_btn.click(
527
- lambda: gr.update(visible=True),
528
- outputs=chat_input
529
  )
530
 
531
  chat_input.submit(
532
- handle_chat,
533
- [chat_input, chat_history],
534
- [chat_input, chat_history]
535
- ).then(
536
- generate_code_wrapper,
537
- [chat_input, chat_history],
538
- [diff_view, diff_original_state, diff_modified_state, diff_mode_state, chat_history]
539
  ).then(
540
- switch_to_diff_tab, None, demo.tabs
541
- )
542
-
543
- send_btn.click(
544
- handle_chat,
545
- [chat_input, chat_history],
546
- [chat_input, chat_history]
547
- ).then(
548
- generate_code_wrapper,
549
- [chat_input, chat_history],
550
- [diff_view, diff_original_state, diff_modified_state, diff_mode_state, chat_history]
551
- ).then(
552
- switch_to_diff_tab, None, demo.tabs
553
  )
554
 
555
  apply_btn.click(
556
- apply_diff,
557
- [diff_original_state, diff_modified_state, diff_mode_state],
558
- [editor, diff_mode_state]
559
  ).then(
560
- switch_to_editor_tab, None, demo.tabs
561
  )
562
 
563
  discard_btn.click(
564
- discard_diff,
565
- outputs=[editor, diff_mode_state]
566
  ).then(
567
- switch_to_editor_tab, None, demo.tabs
568
- )
569
-
570
- clear_btn.click(
571
- clear_terminal,
572
- outputs=terminal
573
- )
574
-
575
- # Add keyboard shortcuts using Gradio's new event system
576
- demo.load(
577
- None,
578
- None,
579
- None,
580
- _js="""
581
- () => {
582
- document.addEventListener('keydown', function(e) {
583
- // Ctrl+R: Run code
584
- if (e.ctrlKey && e.key === 'r') {
585
- e.preventDefault();
586
- const runBtn = document.querySelector('button:contains("Run")');
587
- if (runBtn) runBtn.click();
588
- }
589
-
590
- // Ctrl+Enter: Complete code
591
- if (e.ctrlKey && e.key === 'Enter') {
592
- e.preventDefault();
593
- const completeBtn = document.querySelector('button:contains("Complete")');
594
- if (completeBtn) completeBtn.click();
595
- }
596
-
597
- // Ctrl+Shift+E: Explain code
598
- if (e.ctrlKey && e.shiftKey && e.key === 'E') {
599
- e.preventDefault();
600
- const explainBtn = document.querySelector('button:contains("Explain")');
601
- if (explainBtn) explainBtn.click();
602
- }
603
-
604
- // Ctrl+B: Toggle file explorer
605
- if (e.ctrlKey && e.key === 'b') {
606
- e.preventDefault();
607
- // Implementation would toggle sidebar
608
- }
609
-
610
- // Ctrl+J: Toggle terminal
611
- if (e.ctrlKey && e.key === 'j') {
612
- e.preventDefault();
613
- // Implementation would toggle terminal
614
- }
615
-
616
- // Ctrl+L: Toggle AI chat
617
- if (e.ctrlKey && e.key === 'l') {
618
- e.preventDefault();
619
- // Implementation would toggle chat panel
620
- }
621
-
622
- // Ctrl+N: New file
623
- if (e.ctrlKey && e.key === 'n') {
624
- e.preventDefault();
625
- document.querySelector('input[placeholder="filename.js"]').focus();
626
- }
627
- });
628
- }
629
- """
630
  )
631
 
632
  if __name__ == "__main__":
633
- print("Starting Axon Pro IDE...")
634
- print(f"Running on CPU with {torch.__version__}")
635
- print(f"Model: {MODEL_NAME}")
636
- demo.launch(
637
- server_name="0.0.0.0",
638
- server_port=int(os.getenv("PORT", 7860)),
639
- debug=True,
640
- show_api=False,
641
- favicon_path="https://api.iconify.design/teenyicons:ai-solid.svg",
642
- root_path=os.getenv("ROOT_PATH", "")
643
- )
 
7
  import os
8
  import json
9
  from functools import lru_cache
10
+
11
+ os.environ["TOKENIZERS_PARALLELISM"] = "false"
12
+
13
  # CPU-optimized configuration
14
  MODEL_NAME = "TinyLlama/TinyLlama-1.1B-Chat-v1.0"
15
  DEVICE = "cpu"
16
+ DTYPE = torch.float32
17
 
18
+ # --- File System Class (Same as before) ---
19
  class FileSystem:
20
  def __init__(self):
21
  self.files = {
 
30
  def save_file(self, content: str) -> None:
31
  if self.current_file:
32
  self.files[self.current_file] = content
 
 
 
33
 
34
  def get_file(self, filename: str) -> str:
35
  return self.files.get(filename, "")
 
45
  if filename not in self.files:
46
  self.files[filename] = content
47
  self.current_file = filename
 
48
 
49
  def get_all_files(self) -> List[str]:
50
  return list(self.files.keys())
51
 
52
  def get_context(self) -> str:
 
53
  context = ""
54
  for filename, content in self.files.items():
55
  context += f"// File: {filename}\n{content}\n\n"
56
  return context
57
 
 
58
  fs = FileSystem()
59
 
60
+ # --- Model Loading ---
61
  @lru_cache(maxsize=1)
62
  def load_model():
63
  print("Loading TinyLlama model for CPU... This may take a moment.")
64
  start_time = time.time()
 
65
  try:
 
66
  tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
67
  model = AutoModelForCausalLM.from_pretrained(
68
  MODEL_NAME,
 
70
  device_map=DEVICE,
71
  low_cpu_mem_usage=True
72
  )
 
 
73
  pipe = pipeline(
74
  "text-generation",
75
  model=model,
76
  tokenizer=tokenizer,
 
77
  max_new_tokens=256,
78
  temperature=0.2,
79
  top_p=0.95,
80
  do_sample=True
81
  )
82
+ print(f"Model loaded successfully in {time.time() - start_time:.2f} seconds!")
 
 
83
  return pipe
84
  except Exception as e:
85
  print(f"Error loading model: {str(e)}")
86
  return None
87
 
88
+ # --- Logic Functions ---
89
  def run_code(code: str) -> Tuple[str, str]:
 
90
  start_time = time.time()
 
 
 
91
  try:
 
 
92
  output = f"✓ Code executed successfully\nExecution time: {time.time() - start_time:.4f}s"
93
+ return output, ""
94
  except Exception as e:
95
+ return "", f"✗ Error: {str(e)}"
 
 
96
 
97
+ def generate_completion(code: str) -> str:
 
98
  model = load_model()
99
+ if not model: return "Error: Model failed to load."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
+ prompt = f"<|system|>You are a JS expert. Complete the code. No explanations.</s><|user|>\n{code}\n</s><|assistant|>"
102
  try:
103
+ result = model(prompt, num_return_sequences=1, return_full_text=False)
104
+ return result[0]['generated_text'].strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  except Exception as e:
106
+ return f"/* Error: {str(e)} */"
107
 
108
  def explain_code(code: str) -> str:
 
109
  model = load_model()
110
+ if not model: return "Error loading model."
111
+ prompt = f"<|system|>Explain this code concisely.</s><|user|>\n{code}\n</s><|assistant|>"
 
 
 
 
 
 
 
 
 
 
 
 
112
  try:
113
+ result = model(prompt, max_new_tokens=512)
 
 
 
 
 
 
 
114
  return result[0]['generated_text'].strip()
115
  except Exception as e:
116
+ return str(e)
117
 
118
  def refactor_code(code: str) -> str:
 
119
  model = load_model()
120
+ if not model: return "Error loading model."
121
+ prompt = f"<|system|>Refactor this JS code for best practices.</s><|user|>\n{code}\n</s><|assistant|>"
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  try:
123
+ result = model(prompt, max_new_tokens=512)
 
 
 
 
 
 
 
124
  return result[0]['generated_text'].strip()
125
  except Exception as e:
126
+ return str(e)
127
 
128
+ def generate_code(prompt_text: str) -> str:
 
129
  model = load_model()
130
+ if not model: return "Error loading model."
131
+ prompt = f"<|system|>Write JavaScript code for: {prompt_text}</s><|assistant|>"
 
 
 
 
 
 
 
 
 
 
 
132
  try:
133
+ result = model(prompt, max_new_tokens=512)
 
 
 
 
 
 
 
134
  return result[0]['generated_text'].strip()
135
  except Exception as e:
136
+ return str(e)
 
 
 
 
 
 
137
 
138
  def create_diff_view(original: str, modified: str) -> str:
 
 
139
  lines_original = original.split('\n')
140
  lines_modified = modified.split('\n')
 
141
  diff = []
142
+ # Very basic diff visualizer
143
+ import difflib
144
+ for line in difflib.unified_diff(lines_original, lines_modified, lineterm=""):
145
+ diff.append(line)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  return "\n".join(diff)
147
 
148
+ # --- Gradio UI ---
149
+ # 1. FIXED THEME DEFINITION
150
+ theme = gr.themes.Default(
151
+ font=[gr.themes.GoogleFont('JetBrains Mono'), 'monospace'],
152
+ font_mono=[gr.themes.GoogleFont('JetBrains Mono'), 'monospace'],
153
+ primary_hue="blue",
154
+ neutral_hue="gray",
155
+ # radius=0 <-- REMOVED THIS CAUSE OF ERROR
156
+ ).set(
157
+ button_primary_background_fill="*primary_500",
158
+ button_primary_background_fill_hover="*primary_600",
159
+ body_background_fill="*neutral_900",
160
+ body_text_color="*neutral_50",
161
+ radius_size="none" # <-- Added this to achieve square corners
162
+ )
163
+
164
+ css = """
165
+ .editor-container { height: 50vh; }
166
+ .terminal { height: 15vh; background-color: #1e1e1e; color: #d4d4d4; overflow: auto; }
167
+ .diff-view { height: 40vh; overflow: auto; }
168
+ .file-explorer { height: 50vh; background-color: #252526; overflow: auto; }
169
+ .ai-chat { height: 40vh; overflow: auto; }
170
+ .status-bar { background-color: #007acc; color: white; padding: 5px; text-align: center; }
171
+ .btn { min-width: 100px; }
172
+ .monaco-editor { height: 100% !important; }
173
+ .theme-dark { --body-bg: #1e1e1e; --editor-bg: #1e1e1e; }
174
+ .button-large { min-height: 40px !important; }
175
+ .tab-nav { background-color: #252526 !important; }
176
+ .tabitem { background-color: #1e1e1e !important; }
177
+ .code-wrap { white-space: pre-wrap !important; word-break: break-word !important; }
178
+ """
179
+
180
+ with gr.Blocks(title="Axon Pro - Free AI IDE", theme=theme, css=css) as demo:
181
 
182
  gr.Markdown("# ⚡ Axon Pro — Free AI-Powered Code IDE")
183
 
184
+ # 2. FIXED TABS VARIABLE ASSIGNMENT
185
+ with gr.Tabs() as main_tabs:
186
  with gr.Tab("Editor", id="editor-tab"):
187
  with gr.Row(equal_height=True):
188
  # File Explorer
 
196
  container=False
197
  )
198
  with gr.Row():
199
+ new_file_btn = gr.Button("➕ New", variant="secondary")
200
+ save_btn = gr.Button("💾 Save", variant="secondary")
201
+ new_file_name = gr.Textbox(placeholder="filename.js", label="New File Name", container=False)
 
 
 
 
202
 
203
  # Main Editor Area
204
  with gr.Column(scale=4):
 
212
  )
213
 
214
  with gr.Row():
215
+ run_btn = gr.Button("▶ Run", variant="primary")
216
+ complete_btn = gr.Button("✨ Complete", variant="secondary")
217
+ explain_btn = gr.Button("📝 Explain", variant="secondary")
218
+ refactor_btn = gr.Button("🔧 Refactor", variant="secondary")
219
+
 
 
220
  with gr.Tabs():
221
  with gr.Tab("Terminal", id="terminal-tab"):
222
  terminal = gr.Textbox(
223
+ value="$ _",
224
  lines=5,
225
  interactive=False,
226
  elem_classes="terminal"
227
  )
228
+ clear_btn = gr.Button("CLEAR TERMINAL", variant="secondary", size="sm")
229
 
230
  with gr.Tab("AI Chat", id="chat-tab"):
231
+ chat_history = gr.Chatbot(label="Axon AI", height=300)
 
 
 
 
 
 
232
  with gr.Row():
233
+ chat_input = gr.Textbox(placeholder="Ask to generate code...", scale=7, container=False)
234
+ send_btn = gr.Button("Generate", variant="primary", scale=1)
 
 
 
 
 
235
 
236
  with gr.Tab("Diff View", id="diff-tab"):
237
+ diff_view = gr.Code(label="AI Changes", language="diff", elem_classes="diff-view code-wrap", interactive=False)
 
 
 
 
 
 
238
  with gr.Row():
239
+ apply_btn = gr.Button("Apply Changes", variant="primary")
240
+ discard_btn = gr.Button("Discard Changes", variant="secondary")
241
 
242
+ status_bar = gr.Markdown(f"**AXON PRO v1.0** | CPU Mode | TinyLlama-1.1B", elem_classes="status-bar")
 
 
 
243
 
244
+ # State
245
  current_file_state = gr.State(fs.current_file)
246
  diff_original_state = gr.State("")
247
  diff_modified_state = gr.State("")
248
  diff_mode_state = gr.State(False)
249
 
250
+ # Wrappers
251
+ def update_file_content(content):
252
  fs.save_file(content)
253
  return fs.get_current_file_content()
254
 
 
262
  return gr.update(choices=fs.get_all_files(), value=name), fs.get_current_file_content()
263
  return gr.update(choices=fs.get_all_files()), fs.get_current_file_content()
264
 
 
 
 
 
265
  def run_code_wrapper(content):
266
+ out, err = run_code(content)
267
+ return out if not err else err
268
 
269
  def complete_code_wrapper(content):
270
+ comp = generate_completion(content)
271
+ return content + comp
272
 
273
  def explain_code_wrapper(content):
274
  explanation = explain_code(content)
275
  fs.save_file(content)
276
+ diff_orig = content
277
+ diff_mod = f"/* EXPLANATION:\n{explanation}\n*/\n\n{content}"
278
+ diff = create_diff_view(diff_orig, diff_mod)
279
+ return diff, diff_orig, diff_mod, True
 
 
280
 
281
  def refactor_code_wrapper(content):
282
  refactored = refactor_code(content)
283
  fs.save_file(content)
284
+ diff = create_diff_view(content, refactored)
285
+ return diff, content, refactored, True
286
+
 
 
 
 
287
  def generate_code_wrapper(prompt, history):
 
 
 
288
  generated = generate_code(prompt)
289
+ diff = create_diff_view("", generated)
290
+ new_hist = history + [[prompt, "Generated code available in Diff View"]]
291
+ return diff, "", generated, True, new_hist, ""
292
+
293
+ # Event Wiring
294
+ editor.change(update_file_content, editor, None)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  file_list.change(load_file, file_list, [editor, current_file_state])
296
  new_file_btn.click(create_new_file, new_file_name, [file_list, editor])
 
297
 
298
  run_btn.click(run_code_wrapper, editor, terminal)
299
  complete_btn.click(complete_code_wrapper, editor, editor)
300
+ clear_btn.click(lambda: "$ _", None, terminal)
301
 
302
+ # 3. FIXED TAB SWITCHING (Using main_tabs variable)
303
  explain_btn.click(
304
+ explain_code_wrapper, editor,
 
305
  [diff_view, diff_original_state, diff_modified_state, diff_mode_state]
306
  ).then(
307
+ lambda: gr.Tabs(selected="diff-tab"), None, main_tabs
308
  )
309
 
310
  refactor_btn.click(
311
+ refactor_code_wrapper, editor,
 
312
  [diff_view, diff_original_state, diff_modified_state, diff_mode_state]
313
  ).then(
314
+ lambda: gr.Tabs(selected="diff-tab"), None, main_tabs
 
 
 
 
 
315
  )
316
 
317
  chat_input.submit(
318
+ generate_code_wrapper, [chat_input, chat_history],
319
+ [diff_view, diff_original_state, diff_modified_state, diff_mode_state, chat_history, chat_input]
 
 
 
 
 
320
  ).then(
321
+ lambda: gr.Tabs(selected="diff-tab"), None, main_tabs
 
 
 
 
 
 
 
 
 
 
 
 
322
  )
323
 
324
  apply_btn.click(
325
+ lambda mod: (mod, False), diff_modified_state, [editor, diff_mode_state]
 
 
326
  ).then(
327
+ lambda: gr.Tabs(selected="editor-tab"), None, main_tabs
328
  )
329
 
330
  discard_btn.click(
331
+ lambda: (gr.update(), False), None, [editor, diff_mode_state]
 
332
  ).then(
333
+ lambda: gr.Tabs(selected="editor-tab"), None, main_tabs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  )
335
 
336
  if __name__ == "__main__":
337
+ demo.launch(server_name="0.0.0.0", server_port=7860)