Advertisement
Guest User

Untitled

a guest
Jan 2nd, 2025
49
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.00 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3.  
  4. import os
  5. import time
  6. import subprocess
  7. import filecmp
  8. import json
  9. import datetime
  10. from openai import OpenAI
  11.  
  12. # -------------------------------------------------------------------------
  13. # 1) Configure your DeepSeek credentials
  14. # -------------------------------------------------------------------------
  15. DEEPSEEK_API_KEY = "YOURDEEPSEEKAPIKEY"
  16. client = OpenAI(api_key=DEEPSEEK_API_KEY, base_url="https://api.deepseek.com")
  17.  
  18. # -------------------------------------------------------------------------
  19. # 2) Base system prompt for the LLM
  20. # -------------------------------------------------------------------------
  21. BASE_SYSTEM_PROMPT = {
  22. "role": "system",
  23. "content": (
  24. "You are an advanced optimization assistant. Your ONLY goal is "
  25. "to optimize the user's Python code to reduce runtime as much as possible, "
  26. "while producing an identical final_output.ppm image bit-for-bit. "
  27. "Do NOT focus on readability or comments. Do not break the code. "
  28. "If you introduce new dependencies, ensure they don't cause errors. "
  29. "Return a JSON object with the following format:\n"
  30. "{\n"
  31. ' "code": "... optimized code ...",\n'
  32. ' "changes": "Brief description of key optimizations",\n'
  33. ' "estimated_impact": "Expected performance impact"\n'
  34. "}"
  35. )
  36. }
  37.  
  38. # -------------------------------------------------------------------------
  39. # 3) Helper functions
  40. # -------------------------------------------------------------------------
  41. def write_code_to_file(code_str, filename):
  42. """Write the given code string to a file, using UTF-8 encoding."""
  43. with open(filename, "w", encoding="utf-8") as f:
  44. f.write(code_str)
  45.  
  46. def run_code_and_measure(pyfile):
  47. """
  48. Run the given Python script, measure how long it takes.
  49. Returns: (time_taken, success, error_msg).
  50. """
  51. start_time = time.time()
  52. try:
  53. print(f"[DEBUG] Running '{pyfile}' to measure performance.")
  54. subprocess.check_output(["python", pyfile], stderr=subprocess.STDOUT)
  55. end_time = time.time()
  56. return (end_time - start_time, True, "")
  57. except subprocess.CalledProcessError as e:
  58. end_time = time.time()
  59. error_msg = e.output.decode("utf-8", errors="ignore")
  60. return (end_time - start_time, False, error_msg)
  61.  
  62. def compare_ppm_files(file1="final_output.ppm", file2="original_output.ppm"):
  63. """Byte-for-byte check of two PPM files."""
  64. if not (os.path.exists(file1) and os.path.exists(file2)):
  65. return False
  66. return filecmp.cmp(file1, file2, shallow=False)
  67.  
  68. def read_original_script():
  69. """Read the original 'render.py' content as UTF-8 safely."""
  70. if not os.path.exists("render.py"):
  71. print("No 'render.py' found. Exiting.")
  72. return None
  73. with open("render.py", "r", encoding="latin-1") as f:
  74. return f.read().encode("utf-8", errors="ignore").decode("utf-8")
  75.  
  76. # -------------------------------------------------------------------------
  77. # 4) Main optimization loop
  78. # -------------------------------------------------------------------------
  79. def main_optimization_loop(rounds=10):
  80. # Create output directory and set log file path ONCE at the start
  81. output_dir = "./loopOptimizer"
  82. os.makedirs(output_dir, exist_ok=True)
  83. log_file = os.path.join(output_dir, "optimization_results.txt")
  84.  
  85. # (A) Read the baseline code from 'render.py'
  86. original_content = read_original_script()
  87. if not original_content:
  88. return
  89.  
  90. # We'll run the baseline to measure time and produce original_output.ppm if needed
  91. baseline_file = "render_baseline.py"
  92. write_code_to_file(original_content, baseline_file)
  93.  
  94. print("=== Running baseline code (render.py) ===")
  95. orig_time, orig_success, orig_err = run_code_and_measure(baseline_file)
  96. if not orig_success:
  97. print("[DEBUG] Baseline code error:")
  98. print(orig_err)
  99. return
  100.  
  101. if not os.path.exists("original_output.ppm"):
  102. if os.path.exists("final_output.ppm"):
  103. os.rename("final_output.ppm", "original_output.ppm")
  104. print("Saved reference image as 'original_output.ppm'.")
  105. else:
  106. print("ERROR: 'final_output.ppm' not found; cannot create reference.")
  107. return
  108. else:
  109. print("=== Using existing 'original_output.ppm' as reference ===")
  110.  
  111. best_time = orig_time
  112. current_code = original_content
  113.  
  114. # (B) Prepare conversation messages
  115. messages = [BASE_SYSTEM_PROMPT]
  116.  
  117. # We'll keep a local performance history in memory
  118. # e.g. list of dicts: [{'round': 1, 'time': 10.5, 'match': False, 'success': True}, ...]
  119. performance_history = []
  120.  
  121. # Initial header write
  122. timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  123. with open(log_file, "a", encoding="utf-8") as lf:
  124. lf.write(f"{'=' * 50}\n")
  125. lf.write(f"Optimization Run: {timestamp}\n")
  126. lf.write(f"{'=' * 50}\n\n")
  127. lf.write("=== STARTING OPTIMIZATION ===\n")
  128. lf.write(f"Original time: {orig_time:.2f}s\n\n")
  129.  
  130. # Track failed attempts per round
  131. failed_attempts = {} # {round_num: num_fails}
  132.  
  133. for iteration in range(1, rounds + 1):
  134. # Calculate current round number with retries
  135. if iteration in failed_attempts:
  136. round_num = f"{iteration}.{failed_attempts[iteration]}"
  137. failed_attempts[iteration] += 1
  138. else:
  139. round_num = str(iteration)
  140. failed_attempts[iteration] = 1
  141.  
  142. # Update version file path
  143. version_file = os.path.join(output_dir, f"render_v{round_num}.py")
  144. abs_version_file = os.path.abspath(version_file)
  145.  
  146. print(f"\n=== OPTIMIZATION ROUND {iteration} ===")
  147.  
  148. # We'll build a short summary of performance so far
  149. # e.g., "Round1: 10.20s, Round2: 9.50s..."
  150. perf_summary = []
  151. for rec in performance_history:
  152. perf_summary.append(f"Round{rec['round']}: {rec['time']:.2f}s")
  153. perf_string = ", ".join(perf_summary) if perf_summary else "No prior performance data yet."
  154.  
  155. # We'll feed the last best time plus the performance summary
  156. user_prompt = (
  157. f"Performance history so far: {perf_string}\n\n"
  158. f"Last known best run time: {best_time:.2f} seconds.\n"
  159. "Here is the current code:\n[ ... ]\n\n" # Redact actual code in the debug prompt
  160. "Please optimize further while preserving EXACT output.\n"
  161. "You MUST return a JSON object with 'code', 'changes', and 'estimated_impact'."
  162. )
  163.  
  164. # We'll store the actual code in memory but not show it in debug
  165. # We'll still *send* that code to the LLM by appending it to user_prompt behind the scenes,
  166. # but for demonstration, we can just do something like:
  167. full_user_prompt = user_prompt + f"\n\nActual code content:\n{current_code}"
  168.  
  169. # Debug print: Show the entire conversation except the actual code
  170. # We'll replace the code with "[ ... ]" in logs
  171. print("[DEBUG] Building conversation for LLM:")
  172. # System prompt is already in messages[0], so let's show them in short
  173. for idx, msg in enumerate(messages, 1):
  174. # We'll never print out the entire code or entire content if it's too large
  175. role = msg["role"].upper()
  176. truncated = msg["content"][:250] + ("..." if len(msg["content"]) > 250 else "")
  177. print(f" [{idx}] {role}: {truncated}")
  178.  
  179. # Add the user prompt to messages
  180. messages.append({"role": "user", "content": full_user_prompt})
  181.  
  182. # Debug print: show just the user prompt without full code
  183. prompt_truncated = user_prompt[:400] + ("..." if len(user_prompt) > 400 else "")
  184. print(f"[DEBUG] SENDING USER PROMPT: {prompt_truncated}")
  185.  
  186. # Now call the LLM
  187. try:
  188. response = client.chat.completions.create(
  189. model="deepseek-chat",
  190. messages=messages,
  191. response_format={"type": "json_object"}, # no max_tokens
  192. stream=False
  193. )
  194. except Exception as e:
  195. print(f"[DEBUG] Error calling LLM: {str(e)}")
  196. # Log the error
  197. with open("optimization_results.txt", "a", encoding="utf-8") as lf:
  198. lf.write(f"\n[ROUND {iteration}]\nTime: N/A (Error calling LLM)\n")
  199. lf.write("Output Match: False\nChanges: Unknown\nEstimated Impact: Unknown\n")
  200. lf.write(f"ERROR: {str(e)}\n")
  201. continue
  202.  
  203. # Attempt to parse JSON from the LLM's reply
  204. raw_json = response.choices[0].message.content
  205. print(f"[DEBUG] Raw LLM response (500 chars max): {raw_json[:500]}{'...' if len(raw_json)>500 else ''}")
  206.  
  207. new_code = ""
  208. changes = ""
  209. impact = ""
  210. success = False
  211. match = False
  212. time_taken = 0.0
  213. error_msg = ""
  214.  
  215. try:
  216. result = json.loads(raw_json)
  217. new_code = result.get("code", "")
  218. changes = result.get("changes", "")
  219. impact = result.get("estimated_impact", "")
  220. success = True # means we got valid JSON
  221. except json.JSONDecodeError as e:
  222. print("[DEBUG] Failed to parse JSON, continuing to next round.")
  223. parse_fail_msg = (
  224. "Your output was invalid JSON. Please return valid JSON next time "
  225. "using the specified format with code, changes, and estimated_impact."
  226. )
  227. messages.append({"role": "user", "content": parse_fail_msg})
  228. # Log
  229. with open("optimization_results.txt", "a", encoding="utf-8") as lf:
  230. lf.write(f"\n[ROUND {iteration}]\nTime: N/A (JSON parse failed)\n")
  231. lf.write("Output Match: False\nChanges: Unknown\nEstimated Impact: Unknown\n")
  232. lf.write(f"ERROR: JSON parse error: {str(e)}\n")
  233. performance_history.append({"round": iteration, "time": 0.0, "match": False, "success": False})
  234. continue
  235.  
  236. # We add the entire successful JSON reply as assistant content for the next iteration
  237. messages.append({"role": "assistant", "content": raw_json})
  238.  
  239. # (E) Let's run & measure this new code
  240. version_file = f"render_v{iteration}.py"
  241. write_code_to_file(new_code, version_file)
  242. time_taken, code_success, error_msg = run_code_and_measure(version_file)
  243. if code_success:
  244. match = compare_ppm_files("final_output.ppm", "original_output.ppm")
  245.  
  246. # (F) Log results in optimization_results.txt
  247. with open(log_file, "a", encoding="utf-8") as lf:
  248. log_entry = (
  249. f"{'=' * 20} Round {round_num} {'=' * 20}\n"
  250. f"{abs_version_file}\n"
  251. )
  252.  
  253. if success:
  254. time_diff_pct = ((time_taken - orig_time) / orig_time) * 100
  255. log_entry += f"Time: {time_taken:.2f}s ({time_diff_pct:+.1f}% vs original)\n"
  256. else:
  257. log_entry += "Time: N/A (Script failed to run)\n"
  258.  
  259. log_entry += (
  260. f"Output Match: {match}\n"
  261. f"Changes: {changes}\n"
  262. f"Expected Impact: {impact}\n"
  263. )
  264.  
  265. if not success:
  266. log_entry += f"ERROR: {error_msg}\n"
  267.  
  268. lf.write(log_entry + "\n")
  269.  
  270. # (G) If code fails or mismatches, tell LLM
  271. if not code_success:
  272. short_err = error_msg[:600]
  273. fail_msg = (
  274. f"Your code threw an error:\n\n{short_err}\n\n"
  275. "Please fix this and ensure the output matches exactly next time."
  276. )
  277. messages.append({"role": "user", "content": fail_msg})
  278. print(f"[DEBUG] Round {iteration} code run ERROR, time={time_taken:.2f}\n{error_msg}")
  279. elif not match:
  280. mismatch_msg = (
  281. "Your code ran but final_output.ppm != original_output.ppm.\n"
  282. "Please fix this so the output is bit-for-bit identical."
  283. )
  284. messages.append({"role": "user", "content": mismatch_msg})
  285. print(f"[DEBUG] Round {iteration} MISMATCH, time={time_taken:.2f}.")
  286. else:
  287. # Code success & matched => adopt new code
  288. current_code = new_code
  289. best_time = time_taken
  290. print(f"[DEBUG] Round {iteration}: SUCCESS. time={time_taken:.2f}, output matched.")
  291.  
  292. # (H) Record this round's performance in memory
  293. performance_history.append({
  294. "round": iteration,
  295. "time": time_taken if code_success else 0.0,
  296. "match": match,
  297. "success": code_success
  298. })
  299.  
  300. print("\n=== Optimization loop finished. Check 'optimization_results.txt' for details. ===")
  301.  
  302.  
  303. if __name__ == "__main__":
  304. main_optimization_loop(rounds=10)
  305.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement