suprimedev commited on
Commit
bbb0217
·
verified ·
1 Parent(s): ee6d51d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +224 -210
app.py CHANGED
@@ -14,66 +14,127 @@ import traceback
14
  import json
15
  from typing import List, Tuple, Optional, Dict
16
  import requests
17
- import time # Added for cleanup
18
-
19
- # =================================================================
20
- # 1. Configuration and Setup
21
- # =================================================================
22
-
23
- # Use OpenRouter API (OpenAI-compatible)
24
- OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
25
- TALKGPT_API_KEY = os.getenv("TALKGPT_API_KEY", OPENROUTER_API_KEY) # Use OpenRouter key as fallback for TalkGPT
26
- TALKGPT_UPLOAD_URL = "https://talkgpt.ir/api/LUMA/upload.php"
27
-
28
- client = openai.OpenAI(
29
- api_key=OPENROUTER_API_KEY,
30
- base_url="https://openrouter.ai/api/v1"
31
- )
32
-
33
- MODEL_NAME = "x-ai/grok-4-fast"
34
-
35
- # Define a persistent directory for output files that need cleanup
36
- PERSISTENT_OUTPUT_DIR = os.path.join(tempfile.gettempdir(), "ai_processor_outputs")
37
- os.makedirs(PERSISTENT_OUTPUT_DIR, exist_ok=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
- # =================================================================
40
- # 3. Automatic Cleanup Function
41
- # =================================================================
42
 
43
- def cleanup_old_files(directory: str, max_age_seconds: int = 86400):
44
- """Removes files and directories older than max_age_seconds."""
45
- now = time.time()
46
- count = 0
47
-
48
- if not os.path.exists(directory):
49
- return 0
50
 
51
- print(f"Starting cleanup in {directory} for items older than {max_age_seconds/3600:.1f} hours.")
52
-
53
- for item in os.listdir(directory):
54
- item_path = os.path.join(directory, item)
55
- try:
56
- # Get modification time
57
- mtime = os.path.getmtime(item_path)
58
- if now - mtime > max_age_seconds:
59
- if os.path.isfile(item_path):
60
- os.unlink(item_path)
61
- count += 1
62
- elif os.path.isdir(item_path):
63
- shutil.rmtree(item_path)
64
- count += 1
65
- except Exception as e:
66
- # print(f"Error during cleanup of {item_path}: {e}")
67
- pass
68
 
69
- print(f"Cleanup finished. Removed {count} old items.")
70
- return count
71
-
72
- # Clean up on startup
73
- cleanup_old_files(tempfile.gettempdir())
74
- cleanup_old_files(PERSISTENT_OUTPUT_DIR)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
- # Clean up any existing temp files on startup to save space (original logic kept)
77
  try:
78
  tempdir = tempfile.gettempdir()
79
  for item in os.listdir(tempdir):
@@ -96,79 +157,18 @@ try:
96
  except:
97
  pass
98
 
99
- # =================================================================
100
- # 2. TalkGPT Upload Function
101
- # =================================================================
102
-
103
- def upload_to_talkgpt(file_path: str) -> Optional[str]:
104
- """Uploads a file to TalkGPT API and returns the public URL."""
105
- if not TALKGPT_API_KEY:
106
- print("TALKGPT_API_KEY is not set. Skipping upload.")
107
- return None
108
-
109
- if not os.path.exists(file_path):
110
- print(f"Error: File not found for upload: {file_path}")
111
- return None
112
-
113
- print(f"Attempting to upload file to TalkGPT: {os.path.basename(file_path)}")
114
-
115
- try:
116
- # Prepare multipart/form-data
117
- files = {
118
- 'file': (os.path.basename(file_path), open(file_path, 'rb'))
119
- }
120
-
121
- # Prepare headers and data
122
- headers = {
123
- "X-API-KEY": TALKGPT_API_KEY
124
- }
125
- data = {
126
- "api_key": TALKGPT_API_KEY
127
- }
128
-
129
- response = requests.post(
130
- TALKGPT_UPLOAD_URL,
131
- files=files,
132
- data=data,
133
- headers=headers,
134
- timeout=60
135
- )
136
-
137
- response.raise_for_status()
138
-
139
- # Parse JSON response
140
- decoded = response.json()
141
-
142
- if decoded.get("success"):
143
- file_url = decoded.get("file_url")
144
- print(f"✅ Upload successful. URL: {file_url}")
145
- return file_url
146
- else:
147
- message = decoded.get("message", "Unknown error during API response parsing")
148
- print(f"❌ Upload failed. Message: {message}")
149
- return None
150
-
151
- except requests.exceptions.RequestException as e:
152
- print(f"❌ Network/Request Error during upload: {e}")
153
- return None
154
- except json.JSONDecodeError:
155
- print(f"❌ Failed to decode JSON response: {response.text}")
156
- return None
157
- except Exception as e:
158
- print(f"❌ Unexpected error during upload: {e}")
159
- return None
160
- finally:
161
- # Ensure file handle is closed
162
- if 'file' in files:
163
- files['file'][1].close()
164
 
165
- # =================================================================
166
- # ErrorAnalyzer and Utility functions (No change needed)
167
- # =================================================================
168
 
169
  class ErrorAnalyzer:
170
  """Analyze errors and suggest fixes"""
171
- # ... (Keep the original ErrorAnalyzer class) ...
172
  @staticmethod
173
  def analyze_error(error_message: str, code: str) -> Dict:
174
  """Analyze error and return fix strategy"""
@@ -267,7 +267,7 @@ def detect_required_packages(code):
267
  pre_installed = {
268
  'gradio', 'openai', 'pillow', 'rembg', 'numpy', 'opencv-python', 'scikit-learn',
269
  'tensorflow', 'torch', 'lxml', 'requests', 'matplotlib', 'seaborn', 'onnxruntime',
270
- 'proglog', 'openpyxl', 'moviepy', 'pandas' # Added pandas to pre-installed list for common usage
271
  }
272
 
273
  # Import patterns
@@ -457,6 +457,7 @@ def download_file_from_url(url: str, temp_dir: str) -> Optional[str]:
457
  f.write(chunk)
458
 
459
  print(f"Downloaded {url} to {local_path}")
 
460
  return local_path
461
  except Exception as e:
462
  print(f"Failed to download {url}: {e}")
@@ -485,7 +486,6 @@ def generate_code_with_openrouter(instruction, file_paths, previous_errors=None,
485
  alternative_approaches += "\n- Implement fallback solutions"
486
  alternative_approaches += "\n- Generate mock data if files are problematic"
487
 
488
- # NOTE: Instructing the model to save output to PERSISTENT_OUTPUT_DIR
489
  prompt_template = textwrap.dedent("""
490
  You are a Python expert. Instruction: "{instruction}"
491
  Input files: {file_paths_str} (use file_paths[0] for first file, iterate for multiple; if empty, generate based on instruction alone).
@@ -496,12 +496,11 @@ Write a complete Python script that:
496
  1. Import all necessary libraries at the top.
497
  2. Add "# pip install package_name" comments after imports for all needed libraries.
498
  3. Define file_paths = {file_paths_list}
499
- 4. Define the output directory as PERSISTENT_OUTPUT_DIR = "{persistent_dir}"
500
- 5. Add comprehensive error handling with try-except blocks
501
- 6. Create output directory if needed using os.makedirs(PERSISTENT_OUTPUT_DIR, exist_ok=True)
502
- 7. Save output to the PERSISTENT_OUTPUT_DIR
503
- 8. Print "OUTPUT_FILE_PATH: /full/path/to/output" at the end using os.path.abspath()
504
- 9. If file operations fail, try alternative approaches
505
 
506
  Important rules:
507
  - For pandas Excel operations, always add: # pip install openpyxl
@@ -515,8 +514,6 @@ Important rules:
515
  Example with error handling:
516
  import os
517
  import tempfile
518
- # Define the persistent output directory
519
- PERSISTENT_OUTPUT_DIR = "{persistent_dir}"
520
  try:
521
  import pandas as pd
522
  # pip install pandas openpyxl
@@ -527,8 +524,9 @@ except ImportError:
527
  file_paths = {file_paths_list}
528
 
529
  try:
530
- os.makedirs(PERSISTENT_OUTPUT_DIR, exist_ok=True)
531
- output_path = os.path.join(PERSISTENT_OUTPUT_DIR, 'output.xlsx')
 
532
 
533
  # Your main logic here with error handling
534
 
@@ -553,19 +551,18 @@ Output ONLY Python code, no markdown.
553
  file_paths_str=file_paths_str,
554
  file_paths_list=file_paths_list,
555
  error_context=error_context,
556
- alternative_approaches=alternative_approaches,
557
- persistent_dir=PERSISTENT_OUTPUT_DIR
558
  )
559
 
560
  try:
561
  response = client.chat.completions.create(
562
  model=MODEL_NAME,
563
  messages=[
564
- {"role": "system", "content": "Output only clean executable Python code with comprehensive error handling. Ensure the output path is always inside PERSISTENT_OUTPUT_DIR."},
565
  {"role": "user", "content": prompt}
566
  ],
567
  max_tokens=4000,
568
- temperature=0.1 if attempt == 1 else 0.3
569
  )
570
 
571
  generated_code = response.choices[0].message.content.strip()
@@ -600,9 +597,8 @@ def execute_code_with_retry(code: str, max_attempts: int = 3) -> Tuple[bool, str
600
  install_packages_if_needed(required_packages)
601
 
602
  # Step 2: Wrap code
603
- # Note: We do not wrap the code in a generic try-except here because the model is instructed
604
- # to include its own comprehensive try-except blocks, and we need the subprocess RC for failure analysis.
605
- wrapped_code = code
606
 
607
  # Step 3: Compile check
608
  print("Compiling code...")
@@ -623,15 +619,15 @@ def execute_code_with_retry(code: str, max_attempts: int = 3) -> Tuple[bool, str
623
  tf.write(wrapped_code)
624
  tf_path = tf.name
625
  print(f"Temp file: {tf_path}")
 
626
 
627
  # Step 5: Execute
628
  print(f"Executing...")
629
- # Use a short timeout for the execution itself
630
  result = subprocess.run(
631
  [sys.executable, tf_path],
632
  capture_output=True,
633
  text=True,
634
- timeout=90 # Increased timeout slightly for heavy processing
635
  )
636
  stdout, stderr = result.stdout, result.stderr
637
  rc = result.returncode
@@ -644,15 +640,13 @@ def execute_code_with_retry(code: str, max_attempts: int = 3) -> Tuple[bool, str
644
  pass
645
 
646
  if rc != 0:
647
- # If RC is non-zero, it means the internal script failed, likely due to an unhandled exception
648
- # or an explicit sys.exit(1) in the generated code's catch block.
649
- error_msg = f"Execution failed (RC {rc}):\nStderr: {stderr}\nStdout: {stdout}"
650
  print(error_msg)
651
 
652
  # Check if we should retry
653
  if attempt < max_attempts:
654
- # Analyze error for next attempt (use stderr for analysis)
655
- error_analysis = ErrorAnalyzer.analyze_error(stderr or stdout, code)
656
 
657
  # Try to fix by installing missing packages
658
  if error_analysis['packages']:
@@ -660,7 +654,7 @@ def execute_code_with_retry(code: str, max_attempts: int = 3) -> Tuple[bool, str
660
  for pkg in error_analysis['packages']:
661
  install_package(pkg)
662
 
663
- return False, stderr or stdout, None
664
  else:
665
  return False, error_msg, None
666
 
@@ -670,11 +664,11 @@ def execute_code_with_retry(code: str, max_attempts: int = 3) -> Tuple[bool, str
670
 
671
  if output_path_match:
672
  output_path = output_path_match.group(1).strip()
673
- # Ensure the path is within the allowed persistent directory
674
- if os.path.exists(output_path) and os.path.abspath(output_path).startswith(os.path.abspath(PERSISTENT_OUTPUT_DIR)):
675
  return True, stdout, output_path
676
  else:
677
- error_msg = f"Output path not found or outside persistent directory: {output_path}"
678
  if attempt < max_attempts:
679
  print(error_msg)
680
  return False, error_msg, None
@@ -689,7 +683,7 @@ def execute_code_with_retry(code: str, max_attempts: int = 3) -> Tuple[bool, str
689
  return False, "No output generated", None
690
 
691
  except subprocess.TimeoutExpired:
692
- error_msg = "Timeout: Code execution took too long (Max 90 seconds)"
693
  if attempt < max_attempts:
694
  print(error_msg)
695
  return False, error_msg, None
@@ -705,18 +699,13 @@ def execute_code_with_retry(code: str, max_attempts: int = 3) -> Tuple[bool, str
705
 
706
  return False, "Max attempts reached", None
707
 
708
- def process_request(instruction, files, urls_input):
709
- """Main processing function with self-correction, supporting URLs and TalkGPT upload."""
710
-
711
- # 1. Cleanup before starting (to save space during heavy usage)
712
- cleanup_old_files(PERSISTENT_OUTPUT_DIR)
713
-
714
  try:
715
  if not instruction.strip():
716
- return "لطفاً دستور را وارد کنید. (فایل‌ها و لینک‌ها اختیاری هستند)", None
717
 
718
  file_paths = []
719
- temp_dirs_to_clean = []
720
 
721
  # Handle uploaded files
722
  if files:
@@ -725,7 +714,7 @@ def process_request(instruction, files, urls_input):
725
  # Handle URLs: download to temp dir
726
  if urls_input and urls_input.strip():
727
  temp_dir_for_downloads = tempfile.mkdtemp(prefix='url_downloads_')
728
- temp_dirs_to_clean.append(temp_dir_for_downloads)
729
  urls = [url.strip() for url in urls_input.split(',') if url.strip()]
730
  downloaded_paths = []
731
  for url in urls:
@@ -737,9 +726,7 @@ def process_request(instruction, files, urls_input):
737
 
738
  # Track errors for learning
739
  previous_errors = []
740
-
741
- final_file_path = None
742
- final_output_text = ""
743
 
744
  # Main retry loop
745
  for attempt in range(1, 4): # 3 attempts
@@ -748,6 +735,7 @@ def process_request(instruction, files, urls_input):
748
  print(f"{'='*50}")
749
 
750
  # Generate code
 
751
  generated_code = generate_code_with_openrouter(
752
  instruction,
753
  file_paths,
@@ -756,18 +744,35 @@ def process_request(instruction, files, urls_input):
756
  )
757
 
758
  if len(generated_code) < 20:
759
- final_output_text = f"کد ضعیف تولید شد: {generated_code}"
760
- break
 
 
761
 
762
  # Try to execute
763
- success, output, file_path = execute_code_with_retry(generated_code, max_attempts=1) # Only one execution attempt per LLM generation
764
 
765
  if success:
766
- final_output_text = f"✅ Success on attempt {attempt}!\n\n"
767
- final_output_text += f"Generated Code:\n```python\n{generated_code}\n```\n\n"
768
- final_output_text += f"Output:\n{output}"
769
- final_file_path = file_path
770
- break # Exit retry loop on success
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
771
  else:
772
  # Analyze error
773
  print(f"\n❌ Attempt {attempt} failed")
@@ -787,52 +792,61 @@ def process_request(instruction, files, urls_input):
787
  error_report += f"- Details: {err['original_error'][:200]}...\n"
788
 
789
  error_report += f"\n\nLast generated code:\n```python\n{generated_code}\n```"
790
- final_output_text = error_report
791
- break
792
 
793
- # 2. Handle final output file (if one was produced)
794
- uploaded_url = None
795
- output_file_for_gr = None
796
-
797
- if final_file_path and os.path.exists(final_file_path):
798
- # Attempt TalkGPT upload
799
- uploaded_url = upload_to_talkgpt(final_file_path)
800
-
801
- if uploaded_url:
802
- final_output_text += f"\n\n--- آپلود فایل ---"
803
- final_output_text += f"\n✅ فایل خروجی با موفقیت در TalkGPT آپلود شد."
804
- final_output_text += f"\n🔗 لینک مستقیم فایل: {uploaded_url}"
805
- # Return the local file path to Gradio for download link
806
- output_file_for_gr = final_file_path
807
- else:
808
- final_output_text += f"\n\n--- آپلود فایل ---"
809
- final_output_text += f"\n⚠️ آپلود در TalkGPT ناموفق بود. فایل محلی ارائه می‌شود."
810
- output_file_for_gr = final_file_path
811
-
812
- # 3. Cleanup downloaded files
813
- for d in temp_dirs_to_clean:
814
- if os.path.exists(d):
815
- shutil.rmtree(d, ignore_errors=True)
816
-
817
- return final_output_text, output_file_for_gr
818
 
819
  except Exception as e:
820
  error_msg = f"General error: {type(e).__name__}: {e}\nFull traceback: {traceback.format_exc()}"
821
  print(error_msg)
822
- return error_msg, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
823
 
824
  # Gradio Interface
825
- # 1. Set concurrency limit in gr.Blocks
826
- with gr.Blocks(title="AI File Processor - Self Correcting", concurrency_limit=5) as demo:
827
  gr.Markdown("""
828
- # 🤖 AI File Processor - Self Correcting Edition
829
 
830
  این سیستم می‌تواند:
831
  - کد Python تولید کند
832
  - خطاها را تشخیص و تحلیل کند
833
  - به طور خودکار مشکلات را برطرف کند
834
  - تا 3 بار با رویکردهای مختلف تلاش کند
835
- - **فایل‌های خروجی را به صورت خودکار در TalkGPT آپلود کرده و لینک آن را ارائه دهد.**
 
 
836
 
837
  **مثال دستورات:**
838
  - "یک فایل اکسل با 1000 نام و شماره تلفن ایرانی بساز"
@@ -861,8 +875,8 @@ with gr.Blocks(title="AI File Processor - Self Correcting", concurrency_limit=5)
861
  btn = gr.Button("🚀 اجرا", variant="primary")
862
 
863
  with gr.Row():
864
- output = gr.Textbox(label="نتیجه (شامل کد، خروجی و لینک آپلود)", lines=15)
865
- file_out = gr.File(label="فایل خروجی (فایل محلی برای دانلود)", interactive=False) # Set interactive=False as the main link is in the text output
866
 
867
  # Examples
868
  gr.Examples(
@@ -878,4 +892,4 @@ with gr.Blocks(title="AI File Processor - Self Correcting", concurrency_limit=5)
878
  btn.click(fn=process_request, inputs=[instruction, files, urls], outputs=[output, file_out])
879
 
880
  if __name__ == "__main__":
881
- demo.launch(share=True)
 
14
  import json
15
  from typing import List, Tuple, Optional, Dict
16
  import requests
17
+ import threading
18
+ import time
19
+ from datetime import datetime, timedelta
20
+ import queue
21
+ import concurrent.futures
22
+ from functools import wraps
23
+ import atexit
24
+
25
+ # Configuration for TalkGPT upload
26
+ TALKGPT_API_URL = "https://talkgpt.ir/api/LUMA/upload.php"
27
+ TALKGPT_API_KEY = os.getenv("TALKGPT_API_KEY", "YOUR_STRONG_SECRET_API_KEY_12345")
28
+
29
+ # Clean up old files every hour
30
+ CLEANUP_INTERVAL = 3600 # 1 hour
31
+ FILE_MAX_AGE = 86400 # 24 hours
32
+
33
+ # Track created files
34
+ created_files = queue.Queue()
35
+ created_files_lock = threading.Lock()
36
+
37
+ # Executor for concurrent processing
38
+ executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)
39
+
40
+ def cleanup_old_files():
41
+ """Clean up files older than 24 hours"""
42
+ while True:
43
+ try:
44
+ current_time = time.time()
45
+ temp_dir = tempfile.gettempdir()
46
+
47
+ # Clean temp directory
48
+ for item in os.listdir(temp_dir):
49
+ item_path = os.path.join(temp_dir, item)
50
+ try:
51
+ if os.path.isfile(item_path):
52
+ if current_time - os.path.getmtime(item_path) > FILE_MAX_AGE:
53
+ os.unlink(item_path)
54
+ print(f"Deleted old file: {item_path}")
55
+ elif os.path.isdir(item_path) and item.startswith(('tmp', 'url_downloads_')):
56
+ if current_time - os.path.getmtime(item_path) > FILE_MAX_AGE:
57
+ shutil.rmtree(item_path)
58
+ print(f"Deleted old directory: {item_path}")
59
+ except Exception as e:
60
+ print(f"Error cleaning {item_path}: {e}")
61
+
62
+ # Clean tracked files
63
+ cleaned_files = []
64
+ with created_files_lock:
65
+ while not created_files.empty():
66
+ file_info = created_files.get()
67
+ if current_time - file_info['time'] > FILE_MAX_AGE:
68
+ try:
69
+ if os.path.exists(file_info['path']):
70
+ if os.path.isfile(file_info['path']):
71
+ os.unlink(file_info['path'])
72
+ elif os.path.isdir(file_info['path']):
73
+ shutil.rmtree(file_info['path'])
74
+ print(f"Deleted tracked file: {file_info['path']}")
75
+ except Exception as e:
76
+ print(f"Error deleting tracked file {file_info['path']}: {e}")
77
+ else:
78
+ cleaned_files.append(file_info)
79
+
80
+ # Put back files that are not old enough
81
+ for file_info in cleaned_files:
82
+ created_files.put(file_info)
83
+
84
+ except Exception as e:
85
+ print(f"Cleanup error: {e}")
86
+
87
+ time.sleep(CLEANUP_INTERVAL)
88
 
89
+ # Start cleanup thread
90
+ cleanup_thread = threading.Thread(target=cleanup_old_files, daemon=True)
91
+ cleanup_thread.start()
92
 
93
+ def track_file(file_path):
94
+ """Track a created file for cleanup"""
95
+ with created_files_lock:
96
+ created_files.put({
97
+ 'path': file_path,
98
+ 'time': time.time()
99
+ })
100
 
101
+ def upload_to_talkgpt(file_path):
102
+ """Upload file to TalkGPT and return the URL"""
103
+ try:
104
+ if not os.path.exists(file_path):
105
+ return None, "File not found"
106
+
107
+ with open(file_path, 'rb') as f:
108
+ files = {'file': (os.path.basename(file_path), f)}
109
+ data = {'api_key': TALKGPT_API_KEY}
110
+ headers = {'X-API-KEY': TALKGPT_API_KEY}
 
 
 
 
 
 
 
111
 
112
+ response = requests.post(
113
+ TALKGPT_API_URL,
114
+ files=files,
115
+ data=data,
116
+ headers=headers,
117
+ timeout=300 # 5 minutes timeout for large files
118
+ )
119
+
120
+ if response.status_code == 200:
121
+ result = response.json()
122
+ if result.get('success'):
123
+ file_url = result.get('file_url')
124
+ expiry = result.get('expiry_timestamp', time.time() + 86400)
125
+ expiry_date = datetime.fromtimestamp(expiry).strftime('%Y-%m-%d %H:%M:%S')
126
+ return file_url, f"Expires: {expiry_date}"
127
+ else:
128
+ return None, result.get('message', 'Upload failed')
129
+ else:
130
+ return None, f"HTTP {response.status_code}: {response.text}"
131
+
132
+ except requests.exceptions.Timeout:
133
+ return None, "Upload timeout - file may be too large"
134
+ except Exception as e:
135
+ return None, f"Upload error: {str(e)}"
136
 
137
+ # Clean up any existing temp files on startup
138
  try:
139
  tempdir = tempfile.gettempdir()
140
  for item in os.listdir(tempdir):
 
157
  except:
158
  pass
159
 
160
+ # Use OpenRouter API (OpenAI-compatible)
161
+ OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
162
+ client = openai.OpenAI(
163
+ api_key=OPENROUTER_API_KEY,
164
+ base_url="https://openrouter.ai/api/v1"
165
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
 
167
+ MODEL_NAME = "x-ai/grok-4-fast"
 
 
168
 
169
  class ErrorAnalyzer:
170
  """Analyze errors and suggest fixes"""
171
+
172
  @staticmethod
173
  def analyze_error(error_message: str, code: str) -> Dict:
174
  """Analyze error and return fix strategy"""
 
267
  pre_installed = {
268
  'gradio', 'openai', 'pillow', 'rembg', 'numpy', 'opencv-python', 'scikit-learn',
269
  'tensorflow', 'torch', 'lxml', 'requests', 'matplotlib', 'seaborn', 'onnxruntime',
270
+ 'proglog', 'openpyxl', 'moviepy'
271
  }
272
 
273
  # Import patterns
 
457
  f.write(chunk)
458
 
459
  print(f"Downloaded {url} to {local_path}")
460
+ track_file(local_path)
461
  return local_path
462
  except Exception as e:
463
  print(f"Failed to download {url}: {e}")
 
486
  alternative_approaches += "\n- Implement fallback solutions"
487
  alternative_approaches += "\n- Generate mock data if files are problematic"
488
 
 
489
  prompt_template = textwrap.dedent("""
490
  You are a Python expert. Instruction: "{instruction}"
491
  Input files: {file_paths_str} (use file_paths[0] for first file, iterate for multiple; if empty, generate based on instruction alone).
 
496
  1. Import all necessary libraries at the top.
497
  2. Add "# pip install package_name" comments after imports for all needed libraries.
498
  3. Define file_paths = {file_paths_list}
499
+ 4. Add comprehensive error handling with try-except blocks
500
+ 5. Create output directory if needed using os.makedirs(exist_ok=True)
501
+ 6. Save output to a temp directory using tempfile.mkdtemp()
502
+ 7. Print "OUTPUT_FILE_PATH: /full/path/to/output" at the end using os.path.abspath()
503
+ 8. If file operations fail, try alternative approaches
 
504
 
505
  Important rules:
506
  - For pandas Excel operations, always add: # pip install openpyxl
 
514
  Example with error handling:
515
  import os
516
  import tempfile
 
 
517
  try:
518
  import pandas as pd
519
  # pip install pandas openpyxl
 
524
  file_paths = {file_paths_list}
525
 
526
  try:
527
+ temp_dir = tempfile.mkdtemp()
528
+ os.makedirs(temp_dir, exist_ok=True)
529
+ output_path = os.path.join(temp_dir, 'output.xlsx')
530
 
531
  # Your main logic here with error handling
532
 
 
551
  file_paths_str=file_paths_str,
552
  file_paths_list=file_paths_list,
553
  error_context=error_context,
554
+ alternative_approaches=alternative_approaches
 
555
  )
556
 
557
  try:
558
  response = client.chat.completions.create(
559
  model=MODEL_NAME,
560
  messages=[
561
+ {"role": "system", "content": "Output only clean executable Python code with comprehensive error handling."},
562
  {"role": "user", "content": prompt}
563
  ],
564
  max_tokens=4000,
565
+ temperature=0.1 if attempt == 1 else 0.3 # Increase creativity on retries
566
  )
567
 
568
  generated_code = response.choices[0].message.content.strip()
 
597
  install_packages_if_needed(required_packages)
598
 
599
  # Step 2: Wrap code
600
+ indented = indent_code(code)
601
+ wrapped_code = f"try:\n{indented}\nexcept Exception as e:\n print(f'ERROR: {{e}}')\n import traceback; traceback.print_exc()\n import sys; sys.exit(1)"
 
602
 
603
  # Step 3: Compile check
604
  print("Compiling code...")
 
619
  tf.write(wrapped_code)
620
  tf_path = tf.name
621
  print(f"Temp file: {tf_path}")
622
+ track_file(tf_path)
623
 
624
  # Step 5: Execute
625
  print(f"Executing...")
 
626
  result = subprocess.run(
627
  [sys.executable, tf_path],
628
  capture_output=True,
629
  text=True,
630
+ timeout=60
631
  )
632
  stdout, stderr = result.stdout, result.stderr
633
  rc = result.returncode
 
640
  pass
641
 
642
  if rc != 0:
643
+ error_msg = f"Execution failed (RC {rc}):\nStderr: {stderr}"
 
 
644
  print(error_msg)
645
 
646
  # Check if we should retry
647
  if attempt < max_attempts:
648
+ # Analyze error for next attempt
649
+ error_analysis = ErrorAnalyzer.analyze_error(stderr, code)
650
 
651
  # Try to fix by installing missing packages
652
  if error_analysis['packages']:
 
654
  for pkg in error_analysis['packages']:
655
  install_package(pkg)
656
 
657
+ return False, stderr, None
658
  else:
659
  return False, error_msg, None
660
 
 
664
 
665
  if output_path_match:
666
  output_path = output_path_match.group(1).strip()
667
+ if os.path.exists(output_path):
668
+ track_file(output_path)
669
  return True, stdout, output_path
670
  else:
671
+ error_msg = f"Output path not found: {output_path}"
672
  if attempt < max_attempts:
673
  print(error_msg)
674
  return False, error_msg, None
 
683
  return False, "No output generated", None
684
 
685
  except subprocess.TimeoutExpired:
686
+ error_msg = "Timeout: Code execution took too long"
687
  if attempt < max_attempts:
688
  print(error_msg)
689
  return False, error_msg, None
 
699
 
700
  return False, "Max attempts reached", None
701
 
702
+ def process_request_sync(instruction, files, urls_input):
703
+ """Synchronous processing function"""
 
 
 
 
704
  try:
705
  if not instruction.strip():
706
+ return "لطفاً دستور را وارد کنید. (فایل‌ها و لینک‌ها اختیاری هستند)", None, None
707
 
708
  file_paths = []
 
709
 
710
  # Handle uploaded files
711
  if files:
 
714
  # Handle URLs: download to temp dir
715
  if urls_input and urls_input.strip():
716
  temp_dir_for_downloads = tempfile.mkdtemp(prefix='url_downloads_')
717
+ track_file(temp_dir_for_downloads)
718
  urls = [url.strip() for url in urls_input.split(',') if url.strip()]
719
  downloaded_paths = []
720
  for url in urls:
 
726
 
727
  # Track errors for learning
728
  previous_errors = []
729
+ generated_codes = []
 
 
730
 
731
  # Main retry loop
732
  for attempt in range(1, 4): # 3 attempts
 
735
  print(f"{'='*50}")
736
 
737
  # Generate code
738
+ print("Generating code...")
739
  generated_code = generate_code_with_openrouter(
740
  instruction,
741
  file_paths,
 
744
  )
745
 
746
  if len(generated_code) < 20:
747
+ return f"کد ضعیف تولید شد: {generated_code}", None, None
748
+
749
+ generated_codes.append(generated_code)
750
+ print(f"Generated code preview: {generated_code[:200]}...")
751
 
752
  # Try to execute
753
+ success, output, file_path = execute_code_with_retry(generated_code, max_attempts=2)
754
 
755
  if success:
756
+ # Success! Upload to TalkGPT if file was generated
757
+ talkgpt_url = None
758
+ talkgpt_message = ""
759
+ if file_path and os.path.exists(file_path):
760
+ print("Uploading to TalkGPT...")
761
+ talkgpt_url, talkgpt_message = upload_to_talkgpt(file_path)
762
+ if talkgpt_url:
763
+ result_text = f"✅ Success on attempt {attempt}!\n\n"
764
+ result_text += f"📁 TalkGPT URL: {talkgpt_url}\n"
765
+ result_text += f"📅 {talkgpt_message}\n\n"
766
+ else:
767
+ result_text = f"✅ Success on attempt {attempt}!\n\n"
768
+ result_text += f"⚠️ Upload to TalkGPT failed: {talkgpt_message}\n\n"
769
+ else:
770
+ result_text = f"✅ Success on attempt {attempt}!\n\n"
771
+
772
+ result_text += f"Generated Code:\n```python\n{generated_code}\n```\n\n"
773
+ result_text += f"Output:\n{output}"
774
+
775
+ return result_text, file_path, talkgpt_url
776
  else:
777
  # Analyze error
778
  print(f"\n❌ Attempt {attempt} failed")
 
792
  error_report += f"- Details: {err['original_error'][:200]}...\n"
793
 
794
  error_report += f"\n\nLast generated code:\n```python\n{generated_code}\n```"
795
+ return error_report, None, None
 
796
 
797
+ return "Unexpected end of retry loop", None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
798
 
799
  except Exception as e:
800
  error_msg = f"General error: {type(e).__name__}: {e}\nFull traceback: {traceback.format_exc()}"
801
  print(error_msg)
802
+ return error_msg, None, None
803
+
804
+ def process_request(instruction, files, urls_input):
805
+ """Process request with concurrent execution support"""
806
+ future = executor.submit(process_request_sync, instruction, files, urls_input)
807
+ result_text, file_path, talkgpt_url = future.result()
808
+
809
+ # Return results, including TalkGPT URL if available
810
+ if talkgpt_url:
811
+ # Append TalkGPT URL to result text if not already included
812
+ if talkgpt_url not in result_text:
813
+ result_text += f"\n\n📁 Direct Link: {talkgpt_url}"
814
+
815
+ return result_text, file_path
816
+
817
+ # Cleanup on exit
818
+ def cleanup_on_exit():
819
+ """Clean up when the app exits"""
820
+ print("Cleaning up...")
821
+ executor.shutdown(wait=True)
822
+ # Final cleanup of tracked files
823
+ with created_files_lock:
824
+ while not created_files.empty():
825
+ file_info = created_files.get()
826
+ try:
827
+ if os.path.exists(file_info['path']):
828
+ if os.path.isfile(file_info['path']):
829
+ os.unlink(file_info['path'])
830
+ elif os.path.isdir(file_info['path']):
831
+ shutil.rmtree(file_info['path'])
832
+ except:
833
+ pass
834
+
835
+ atexit.register(cleanup_on_exit)
836
 
837
  # Gradio Interface
838
+ with gr.Blocks(title="AI File Processor - Self Correcting with TalkGPT Upload") as demo:
 
839
  gr.Markdown("""
840
+ # 🤖 AI File Processor - Self Correcting Edition with TalkGPT Upload
841
 
842
  این سیستم می‌تواند:
843
  - کد Python تولید کند
844
  - خطاها را تشخیص و تحلیل کند
845
  - به طور خودکار مشکلات را برطرف کند
846
  - تا 3 بار با رویکردهای مختلف تلاش کند
847
+ - فایل‌های خروجی را به TalkGPT آپلود کند (لینک 7 روزه)
848
+ - چندین درخواست را همزمان پردازش کند
849
+ - فایل‌های قدیمی را به طور خودکار حذف کند (بعد از 24 ساعت)
850
 
851
  **مثال دستورات:**
852
  - "یک فایل اکسل با 1000 نام و شماره تلفن ایرانی بساز"
 
875
  btn = gr.Button("🚀 اجرا", variant="primary")
876
 
877
  with gr.Row():
878
+ output = gr.Textbox(label="نتیجه", lines=15)
879
+ file_out = gr.File(label="فایل خروجی (اگر تولید شود، به TalkGPT آپلود می‌شود)")
880
 
881
  # Examples
882
  gr.Examples(
 
892
  btn.click(fn=process_request, inputs=[instruction, files, urls], outputs=[output, file_out])
893
 
894
  if __name__ == "__main__":
895
+ demo.launch(share=True)