Kai Izumoto commited on
Commit
44859d3
·
verified ·
1 Parent(s): bdda78d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +74 -18
app.py CHANGED
@@ -28,6 +28,7 @@ PYTHON_MODEL = "Nxcode-CQ-7B-orpo"
28
  OTHER_MODEL = "Qwen/Qwen2.5-Coder-32B-Instruct"
29
  FALLBACK_MODELS = [
30
  "Qwen/Qwen2.5-Coder-32B-Instruct",
 
31
  "OpenCodeInterpreter-DS-33B"
32
  ]
33
 
@@ -167,6 +168,8 @@ def call_model(client: InferenceClient, system: str, user: str, is_python: bool,
167
  primary_model = PYTHON_MODEL if is_python else OTHER_MODEL
168
  models_to_try = [primary_model] + FALLBACK_MODELS
169
 
 
 
170
  messages = [{"role": "system", "content": system}, {"role": "user", "content": user}]
171
 
172
  last_exception = None
@@ -232,33 +235,66 @@ def validate_files_dict(files: Dict[str, str]) -> bool:
232
  def parse_meta(text: str) -> Optional[Dict[str, Any]]:
233
  """Parses model output to extract code files, trying structured JSON first, then falling back to heuristics."""
234
  # Strict JSON/META block parsing
235
- for pattern in [r"```json\s*(.*?)```", r"```meta\s*(.*?)```"]:
236
  match = re.search(pattern, text, re.DOTALL | re.IGNORECASE)
237
  if match:
238
  try:
239
  content = match.group(1).strip()
240
  parsed = json.loads(content)
241
  if "files" in parsed and validate_files_dict(parsed["files"]):
 
242
  return parsed
243
- except (json.JSONDecodeError, TypeError):
 
244
  continue
245
 
246
  # Fallback to heuristic parsing of code blocks
247
  files = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  code_blocks = re.findall(r"```(?:\w+)?\s*([\s\S]*?)```", text, re.DOTALL)
 
249
  if not code_blocks:
 
250
  return None
251
 
252
- # Try to find filenames from comments or preceding lines
253
- # This is a simplified heuristic; more advanced logic could be added
254
- potential_filenames = re.findall(r'#\s*File:\s*([\w/._-]+)', text)
255
  for i, block in enumerate(code_blocks):
256
- filename = potential_filenames[i] if i < len(potential_filenames) else f"file_{i+1}.py"
257
- files[filename] = block.strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
 
259
- if validate_files_dict(files):
 
260
  return {"files": files, "changelog": "Extracted files via heuristic parsing."}
261
-
 
262
  return None
263
 
264
  # ---------- Enhanced evaluators ----------
@@ -468,11 +504,16 @@ Return the perfected code in META format."""
468
  response = call_model(self.client, system, prompt, self.is_python, **self.settings)
469
 
470
  if "<<ERROR" in response:
 
471
  return {"success": False, "warning": "Model error - keeping previous code"}
472
 
473
  meta = parse_meta(response)
474
  if not meta or not meta.get("files"):
475
- return {"success": False, "warning": "Parse failed - keeping previous code"}
 
 
 
 
476
 
477
  files = meta["files"]
478
  write_files(workdir, files)
@@ -508,17 +549,22 @@ Return the perfected code in META format."""
508
  if self.stop_flag.exists():
509
  try:
510
  self.stop_flag.unlink()
511
- except OSError: pass
512
- yield self.format_output("Stopped by user", iteration, max_iterations)
 
 
513
  break
514
 
515
- yield self.format_output(f"Iteration {iteration}/{max_iterations} running...", iteration, max_iterations)
516
 
517
  result = self.perform_iteration(iteration)
518
 
519
  if not result.get("success"):
520
- logging.warning(result.get("warning", "Unknown iteration error"))
521
- time.sleep(1) # Pause before retrying or ending
 
 
 
522
  iteration += 1
523
  continue
524
 
@@ -539,6 +585,10 @@ Return the perfected code in META format."""
539
  self.best_zip = result.get("zip")
540
  self.best_review = result.get("review", "")
541
  self.best_readme = result.get("readme", "")
 
 
 
 
542
 
543
  if result.get("workdir") and result.get("workdir") != self.best_workspace:
544
  self.cleanup_workdir(Path(result["workdir"]))
@@ -669,9 +719,15 @@ def create_ui():
669
 
670
  def set_stop(controller_state_val):
671
  if controller_state_val and (stop_path_str := controller_state_val.get("stop_flag_path")):
672
- Path(stop_path_str).touch()
673
- return "Stop signal sent..."
674
- return "Could not stop: no active process found."
 
 
 
 
 
 
675
 
676
  outputs = [
677
  run_log, model_display, progress_display, metrics_html, eval_json,
 
28
  OTHER_MODEL = "Qwen/Qwen2.5-Coder-32B-Instruct"
29
  FALLBACK_MODELS = [
30
  "Qwen/Qwen2.5-Coder-32B-Instruct",
31
+ "Nxcode-CQ-7B-orpo",
32
  "OpenCodeInterpreter-DS-33B"
33
  ]
34
 
 
168
  primary_model = PYTHON_MODEL if is_python else OTHER_MODEL
169
  models_to_try = [primary_model] + FALLBACK_MODELS
170
 
171
+ logging.info(f"Calling model for {'Python' if is_python else 'Other'} project. Primary: {primary_model}")
172
+
173
  messages = [{"role": "system", "content": system}, {"role": "user", "content": user}]
174
 
175
  last_exception = None
 
235
  def parse_meta(text: str) -> Optional[Dict[str, Any]]:
236
  """Parses model output to extract code files, trying structured JSON first, then falling back to heuristics."""
237
  # Strict JSON/META block parsing
238
+ for pattern in [r"```json\s*(.*?)```", r"```meta\s*(.*?)```", r"```META\s*(.*?)```"]:
239
  match = re.search(pattern, text, re.DOTALL | re.IGNORECASE)
240
  if match:
241
  try:
242
  content = match.group(1).strip()
243
  parsed = json.loads(content)
244
  if "files" in parsed and validate_files_dict(parsed["files"]):
245
+ logging.info(f"Successfully parsed META JSON with {len(parsed['files'])} files")
246
  return parsed
247
+ except (json.JSONDecodeError, TypeError) as e:
248
+ logging.warning(f"JSON parse failed: {e}")
249
  continue
250
 
251
  # Fallback to heuristic parsing of code blocks
252
  files = {}
253
+
254
+ # Try to find filename markers before code blocks
255
+ # Patterns like: # File: main.py or ## main.py or **main.py**
256
+ filename_patterns = [
257
+ r'#\s*[Ff]ile:\s*([\w/._-]+\.[\w]+)',
258
+ r'##\s*([\w/._-]+\.[\w]+)',
259
+ r'\*\*\s*([\w/._-]+\.[\w]+)\s*\*\*'
260
+ ]
261
+
262
+ all_filenames = []
263
+ for pattern in filename_patterns:
264
+ all_filenames.extend(re.findall(pattern, text))
265
+
266
  code_blocks = re.findall(r"```(?:\w+)?\s*([\s\S]*?)```", text, re.DOTALL)
267
+
268
  if not code_blocks:
269
+ logging.warning("No code blocks found in model response")
270
  return None
271
 
272
+ # Match filenames with code blocks
 
 
273
  for i, block in enumerate(code_blocks):
274
+ block_content = block.strip()
275
+ if not block_content:
276
+ continue
277
+
278
+ if i < len(all_filenames):
279
+ filename = all_filenames[i]
280
+ else:
281
+ # Guess filename based on content
282
+ if "def test_" in block_content or "import pytest" in block_content:
283
+ filename = f"test_main.py"
284
+ elif "requirements" in text.lower() and i == 0:
285
+ filename = "requirements.txt"
286
+ elif "# README" in block_content or "## " in block_content[:100]:
287
+ filename = "README.md"
288
+ else:
289
+ filename = f"main.py" if i == 0 else f"file_{i}.py"
290
+
291
+ files[filename] = block_content
292
 
293
+ if validate_files_dict(files) and files:
294
+ logging.info(f"Heuristic parsing extracted {len(files)} files: {list(files.keys())}")
295
  return {"files": files, "changelog": "Extracted files via heuristic parsing."}
296
+
297
+ logging.error("Failed to extract any valid files from model response")
298
  return None
299
 
300
  # ---------- Enhanced evaluators ----------
 
504
  response = call_model(self.client, system, prompt, self.is_python, **self.settings)
505
 
506
  if "<<ERROR" in response:
507
+ logging.error(f"Model returned error: {response[:200]}")
508
  return {"success": False, "warning": "Model error - keeping previous code"}
509
 
510
  meta = parse_meta(response)
511
  if not meta or not meta.get("files"):
512
+ logging.error(f"Parse failed. Response preview: {response[:500]}")
513
+ # Save failed response for debugging
514
+ with open(f"/tmp/failed_response_{iteration}.txt", "w") as f:
515
+ f.write(response)
516
+ return {"success": False, "warning": f"Parse failed - see /tmp/failed_response_{iteration}.txt"}
517
 
518
  files = meta["files"]
519
  write_files(workdir, files)
 
549
  if self.stop_flag.exists():
550
  try:
551
  self.stop_flag.unlink()
552
+ logging.info("Stop flag detected - stopping generation")
553
+ except OSError:
554
+ pass
555
+ yield self.format_output("⛔ Stopped by user", iteration, max_iterations)
556
  break
557
 
558
+ yield self.format_output(f"🔄 Iteration {iteration}/{max_iterations} running...", iteration, max_iterations)
559
 
560
  result = self.perform_iteration(iteration)
561
 
562
  if not result.get("success"):
563
+ warning_msg = result.get("warning", "Unknown iteration error")
564
+ logging.warning(f"Iteration {iteration} failed: {warning_msg}")
565
+ # CRITICAL: Still yield output so UI updates and shows the previous best code
566
+ yield self.format_output(f"⚠️ Iteration {iteration} failed: {warning_msg}", iteration, max_iterations)
567
+ time.sleep(2) # Give more time before retry
568
  iteration += 1
569
  continue
570
 
 
585
  self.best_zip = result.get("zip")
586
  self.best_review = result.get("review", "")
587
  self.best_readme = result.get("readme", "")
588
+ logging.info(f"New best score: {score}/100")
589
+ else:
590
+ # Even if score didn't improve, still update current_files for next iteration
591
+ logging.info(f"Score {score}/100 - keeping best: {self.best_score}/100")
592
 
593
  if result.get("workdir") and result.get("workdir") != self.best_workspace:
594
  self.cleanup_workdir(Path(result["workdir"]))
 
719
 
720
  def set_stop(controller_state_val):
721
  if controller_state_val and (stop_path_str := controller_state_val.get("stop_flag_path")):
722
+ stop_path = Path(stop_path_str)
723
+ try:
724
+ stop_path.touch()
725
+ logging.info(f"Stop flag created at {stop_path}")
726
+ return "⛔ Stop signal sent! Will stop after current iteration completes..."
727
+ except Exception as e:
728
+ logging.error(f"Failed to create stop flag: {e}")
729
+ return f"❌ Failed to stop: {e}"
730
+ return "❌ Could not stop: No active process found. Start generation first."
731
 
732
  outputs = [
733
  run_log, model_display, progress_display, metrics_html, eval_json,