mgbam commited on
Commit
4fa5bec
·
verified ·
1 Parent(s): 256d4e5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +175 -129
app.py CHANGED
@@ -5,8 +5,12 @@ import time # For progress updates
5
 
6
  # --- Core Logic Imports ---
7
  # Initialize clients first to ensure API keys are loaded before other modules use them.
8
- from core.llm_clients import initialize_all_clients, GEMINI_API_CONFIGURED, HF_API_CONFIGURED
9
- initialize_all_clients() # Call initialization once when the app starts
 
 
 
 
10
 
11
  from core.generation_engine import generate_initial_solutions
12
  from core.evaluation_engine import evaluate_solution_candidate, EvaluationResult # Class for typed results
@@ -16,43 +20,32 @@ from prompts.prompt_templates import format_code_test_analysis_user_prompt
16
 
17
  # --- Application Configuration (Models, Defaults) ---
18
  AVAILABLE_MODELS_CONFIG = {}
19
- UI_DEFAULT_MODEL_KEY = None # Will be set based on configured APIs
20
-
21
- # --- Placeholder for the actual API model ID string ---
22
- # You need to find the correct string from Google's documentation or AI Studio for this model.
23
- # It might be something like "models/gemini-2.5-pro-preview-0506" or similar.
24
- GEMINI_2_5_PRO_PREVIEW_MODEL_ID = "YOUR_GEMINI_2.5_PRO_PREVIEW_0506_MODEL_ID_STRING_HERE"
25
- # Example: "gemini-experimental" or a more specific preview ID if available via API.
26
- # For now, if you don't have the exact ID, you can use a known working one like "gemini-1.5-pro-latest"
27
- # and then update this when you get the 2.5 Pro Preview ID.
28
- # If GEMINI_2_5_PRO_PREVIEW_MODEL_ID remains the placeholder, that model won't work.
29
- # Let's use a known one for now if the placeholder isn't replaced.
30
- if GEMINI_2_5_PRO_PREVIEW_MODEL_ID == "YOUR_GEMINI_2.5_PRO_PREVIEW_0506_MODEL_ID_STRING_HERE":
31
- print(f"WARNING: app.py - GEMINI_2_5_PRO_PREVIEW_MODEL_ID is a placeholder. Using 'gemini-1.5-pro-latest' as a stand-in for Gemini 2.5 Pro Preview.")
32
- SAFE_GEMINI_PRO_ID = "gemini-1.5-pro-latest" # A known recent Pro model
33
- else:
34
- SAFE_GEMINI_PRO_ID = GEMINI_2_5_PRO_PREVIEW_MODEL_ID
35
 
 
 
 
 
36
 
37
  # Populate with Gemini models first if API is configured
38
- if GEMINI_API_CONFIGURED:
39
  AVAILABLE_MODELS_CONFIG.update({
40
- # Update this line with the correct display name and ID once known
41
- "Google Gemini 2.5 Pro Preview (API)": {"id": SAFE_GEMINI_PRO_ID, "type": "google_gemini"},
42
- "Google Gemini 1.5 Flash (API - Fast)": {"id": "gemini-1.5-flash-latest", "type": "google_gemini"},
43
  "Google Gemini 1.0 Pro (API - Legacy)": {"id": "gemini-1.0-pro-latest", "type": "google_gemini"},
44
  })
45
- # Prioritize the newest Pro model as default if its ID is not the placeholder
46
- if SAFE_GEMINI_PRO_ID != "gemini-1.5-pro-latest" or GEMINI_2_5_PRO_PREVIEW_MODEL_ID != "YOUR_GEMINI_2.5_PRO_PREVIEW_0506_MODEL_ID_STRING_HERE":
47
- UI_DEFAULT_MODEL_KEY = "Google Gemini 2.5 Pro Preview (API)"
48
- else: # Fallback to Flash if 2.5 Pro ID is still placeholder
49
- UI_DEFAULT_MODEL_KEY = "Google Gemini 1.5 Flash (API - Fast)"
50
  print(f"INFO: app.py - Gemini models populated. Default set to: {UI_DEFAULT_MODEL_KEY}")
51
  else:
52
- print("WARNING: app.py - Gemini API not configured; Gemini models will be unavailable.")
53
 
54
- # Populate with Hugging Face models if API is configured (as alternatives/fallbacks)
55
- if HF_API_CONFIGURED:
56
  AVAILABLE_MODELS_CONFIG.update({
57
  "Google Gemma 2B (HF - Quick Test)": {"id": "google/gemma-2b-it", "type": "hf"},
58
  "Mistral 7B Instruct (HF)": {"id": "mistralai/Mistral-7B-Instruct-v0.2", "type": "hf"},
@@ -64,44 +57,45 @@ if HF_API_CONFIGURED:
64
  else:
65
  print("INFO: app.py - HF models also populated as alternatives.")
66
  else:
67
- print("WARNING: app.py - Hugging Face API not configured; HF models will be unavailable.")
68
 
69
  # Absolute fallback if no models could be configured at all
70
  if not AVAILABLE_MODELS_CONFIG:
71
- print("CRITICAL APP ERROR: No models could be configured. Check API keys in Space Secrets.")
72
- AVAILABLE_MODELS_CONFIG["No Models Available (Check API Keys)"] = {"id": "dummy_error", "type": "none"}
73
- UI_DEFAULT_MODEL_KEY = "No Models Available (Check API Keys)"
74
- elif not UI_DEFAULT_MODEL_KEY and AVAILABLE_MODELS_CONFIG:
 
75
  UI_DEFAULT_MODEL_KEY = list(AVAILABLE_MODELS_CONFIG.keys())[0]
76
  print(f"WARNING: app.py - UI_DEFAULT_MODEL_KEY was not set by primary logic, falling back to first available: {UI_DEFAULT_MODEL_KEY}")
77
 
78
 
79
  # --- Main Orchestration Logic for Gradio ---
80
- # This function remains the same as in the previous "full rewrite" that included all files.
81
  def run_algoforge_simulation_orchestrator(
82
- problem_type_selected: str,
83
- problem_description_text: str,
84
- initial_hints_text: str,
85
  user_provided_tests_code: str,
86
- num_initial_solutions_to_gen: int,
87
  selected_model_ui_key: str,
88
  genesis_temp: float, genesis_max_tokens: int,
89
  critique_temp: float, critique_max_tokens: int,
90
  evolution_temp: float, evolution_max_tokens: int,
91
- progress=gr.Progress(track_tqdm=True)
92
  ):
93
  progress(0, desc="Initializing AlgoForge Prime™...")
94
  log_entries = [f"**AlgoForge Prime™ Cycle Starting at {time.strftime('%Y-%m-%d %H:%M:%S')}**"]
95
  start_time = time.time()
96
 
 
97
  if not problem_description_text.strip():
98
- error_msg = "CRITICAL INPUT ERROR: Problem Description is mandatory."
99
  log_entries.append(error_msg)
100
- return error_msg, "", "", "\n".join(log_entries), ""
101
 
102
  current_model_config = AVAILABLE_MODELS_CONFIG.get(selected_model_ui_key)
103
  if not current_model_config or current_model_config["type"] == "none":
104
- error_msg = f"CRITICAL CONFIG ERROR: No valid LLM selected ('{selected_model_ui_key}'). API keys might be missing or failed initialization. Please check Space Secrets & restart."
105
  log_entries.append(error_msg)
106
  return error_msg, "", "", "\n".join(log_entries), ""
107
 
@@ -109,58 +103,72 @@ def run_algoforge_simulation_orchestrator(
109
  log_entries.append(f"Problem Type: {problem_type_selected}")
110
  log_entries.append(f"User Unit Tests Provided: {'Yes' if user_provided_tests_code.strip() else 'No'}")
111
 
 
112
  llm_config_genesis = {"type": current_model_config["type"], "model_id": current_model_config["id"], "temp": genesis_temp, "max_tokens": genesis_max_tokens}
113
  llm_config_critique = {"type": current_model_config["type"], "model_id": current_model_config["id"], "temp": critique_temp, "max_tokens": critique_max_tokens}
114
  llm_config_evolution = {"type": current_model_config["type"], "model_id": current_model_config["id"], "temp": evolution_temp, "max_tokens": evolution_max_tokens}
115
 
116
- # STAGE 1: GENESIS
117
- progress(0.05, desc="Stage 1: Genesis Engine - Generating...") # Adjusted progress start
118
  log_entries.append("\n**------ STAGE 1: GENESIS ENGINE ------**")
 
119
  initial_raw_solutions = generate_initial_solutions(
120
  problem_description_text, initial_hints_text, problem_type_selected,
121
  num_initial_solutions_to_gen, llm_config_genesis
122
  )
123
- log_entries.append(f"Genesis Engine produced {len(initial_raw_solutions)} raw candidate(s).")
124
- for i, sol_text in enumerate(initial_raw_solutions): # Log snippets
125
- log_entries.append(f" Candidate {i+1} (Raw Snippet): {str(sol_text)[:120]}...")
126
-
127
 
128
- # STAGE 2: CRITIQUE & AUTOMATED EVALUATION
129
- progress(0.25, desc="Stage 2: Critique Crucible - Evaluating...") # Adjusted progress
130
  log_entries.append("\n**------ STAGE 2: CRITIQUE CRUCIBLE & AUTOMATED EVALUATION ------**")
131
- evaluated_candidates_list = []
 
 
132
  for i, candidate_solution_text in enumerate(initial_raw_solutions):
133
- current_progress = 0.25 + ((i + 1) / num_initial_solutions_to_gen) * 0.4 # Progress for evaluation
134
- progress(current_progress, desc=f"Evaluating Candidate {i+1}...")
135
  log_entries.append(f"\n--- Evaluating Candidate {i+1} ---")
136
- evaluation_obj = evaluate_solution_candidate(
137
- candidate_solution_text, problem_description_text, problem_type_selected,
 
 
138
  user_provided_tests_code, llm_config_critique
139
  )
140
- evaluated_candidates_list.append({
141
- "id": i + 1, "solution_text": candidate_solution_text, "evaluation_result": evaluation_obj
142
- })
143
  log_entries.append(f" Final Combined Score: {evaluation_obj.score}/10")
144
  log_entries.append(f" Automated Tests: {evaluation_obj.passed_tests}/{evaluation_obj.total_tests} passed.")
145
  if evaluation_obj.execution_summary: log_entries.append(f" Execution Summary: {evaluation_obj.execution_summary}")
146
  log_entries.append(f" LLM Critique (Snippet): {str(evaluation_obj.critique_text)[:150]}...")
 
 
 
 
 
 
147
 
148
-
149
  initial_solutions_display_markdown = []
150
- for data in evaluated_candidates_list: # Format display for initial solutions
151
  initial_solutions_display_markdown.append(
152
- f"**Candidate {data['id']}:**\n```python\n{data['solution_text']}\n```\n\n"
153
- f"**Evaluation Verdict (Combined Score: {data['evaluation_result'].score}/10):**\n{data['evaluation_result'].critique_text}\n---"
 
 
 
154
  )
155
-
156
- # STAGE 3: SELECTION OF CHAMPION
157
- progress(0.7, desc="Stage 3: Selecting Champion...")
158
  log_entries.append("\n**------ STAGE 3: CHAMPION SELECTION ------**")
 
159
  potentially_viable_candidates = [
160
- cand for cand in evaluated_candidates_list
161
  if cand["evaluation_result"] and cand["evaluation_result"].score > 0 and \
162
- cand["solution_text"] and not str(cand["solution_text"]).startswith("ERROR") # Ensure solution_text is str
163
  ]
 
164
  if not potentially_viable_candidates:
165
  final_error_msg = "No viable candidate solutions found after generation and evaluation. All attempts may have failed or scored too low."
166
  log_entries.append(f" CRITICAL: {final_error_msg}")
@@ -168,61 +176,75 @@ def run_algoforge_simulation_orchestrator(
168
 
169
  potentially_viable_candidates.sort(key=lambda x: x["evaluation_result"].score, reverse=True)
170
  champion_candidate_data = potentially_viable_candidates[0]
 
171
  log_entries.append(f"Champion Selected: Candidate {champion_candidate_data['id']} "
172
- f"(Solution Snippet: {str(champion_candidate_data['solution_text'])[:60]}...) " # str() for safety
173
  f"with evaluation score {champion_candidate_data['evaluation_result'].score}/10.")
 
174
  champion_display_markdown = (
175
  f"**Champion Candidate ID: {champion_candidate_data['id']} "
176
  f"(Original Combined Score: {champion_candidate_data['evaluation_result'].score}/10):**\n"
177
  f"```python\n{champion_candidate_data['solution_text']}\n```\n\n"
178
- f"**Original Comprehensive Evaluation for this Champion:**\n{champion_candidate_data['evaluation_result'].critique_text}"
 
179
  )
180
 
181
- # STAGE 4: EVOLUTIONARY FORGE
182
- progress(0.75, desc="Stage 4: Evolutionary Forge - Refining...")
183
  log_entries.append("\n**------ STAGE 4: EVOLUTIONARY FORGE ------**")
 
184
  evolved_solution_code = evolve_solution(
185
- str(champion_candidate_data["solution_text"]), # str() for safety
186
- str(champion_candidate_data["evaluation_result"].critique_text),
187
  champion_candidate_data["evaluation_result"].score,
188
- problem_description_text, problem_type_selected, llm_config_evolution
 
 
189
  )
190
  log_entries.append(f"Raw Evolved Solution Text (Snippet): {str(evolved_solution_code)[:150]}...")
 
191
  evolved_solution_display_markdown = ""
192
- ai_test_analysis_markdown = ""
193
 
194
- if str(evolved_solution_code).startswith("ERROR"): # str() for safety
195
  evolved_solution_display_markdown = f"**Evolution Stage Failed:**\n{evolved_solution_code}"
196
  else:
197
  evolved_solution_display_markdown = f"**✨ AlgoForge Prime™ Evolved Artifact ✨:**\n```python\n{evolved_solution_code}\n```"
 
198
  if "python" in problem_type_selected.lower() and user_provided_tests_code.strip():
199
- progress(0.9, desc="Post-Evolution: Testing Evolved Code...")
200
  log_entries.append("\n--- Post-Evolution Sanity Check (Automated Tests on Evolved Code) ---")
 
201
  evolved_critique_config = {"type": current_model_config["type"], "model_id": current_model_config["id"], "temp": 0.2, "max_tokens": critique_max_tokens}
202
- evolved_code_eval_result = evaluate_solution_candidate(
203
- str(evolved_solution_code), problem_description_text, problem_type_selected,
 
204
  user_provided_tests_code, evolved_critique_config
205
  )
 
206
  evolved_solution_display_markdown += (
207
  f"\n\n**Post-Evolution Automated Test Results (Simulated):**\n"
208
- f"{evolved_code_eval_result.execution_summary}\n"
209
  f"Passed: {evolved_code_eval_result.passed_tests}/{evolved_code_eval_result.total_tests}\n"
210
  )
211
  log_entries.append(f" Evolved Code Test Results: {evolved_code_eval_result.passed_tests}/{evolved_code_eval_result.total_tests} passed. "
212
  f"Summary: {evolved_code_eval_result.execution_summary}")
213
 
214
- if evolved_code_eval_result.total_tests > 0 :
215
  progress(0.95, desc="Post-Evolution: AI Analyzing Test Results...")
216
  log_entries.append("\n--- AI Analysis of Evolved Code's Test Results ---")
217
  analysis_user_prompt = format_code_test_analysis_user_prompt(
218
- str(evolved_solution_code), user_provided_tests_code,
219
- str(evolved_code_eval_result.execution_summary)
 
220
  )
221
  analysis_system_prompt = get_system_prompt("code_execution_explainer")
222
- llm_analysis_config = {"type": current_model_config["type"], "model_id": current_model_config["id"],
223
- "temp": 0.3, "max_tokens": critique_max_tokens + 150} # Ensure enough tokens for analysis
224
 
225
- from core.llm_clients import call_huggingface_api, call_gemini_api # Direct import for clarity
 
 
 
 
226
  explanation_response_obj = None
227
  if llm_analysis_config["type"] == "hf":
228
  explanation_response_obj = call_huggingface_api(analysis_user_prompt, llm_analysis_config["model_id"], llm_analysis_config["temp"], llm_analysis_config["max_tokens"], analysis_system_prompt)
@@ -245,8 +267,8 @@ def run_algoforge_simulation_orchestrator(
245
 
246
  # --- Gradio UI Definition ---
247
  intro_markdown = """
248
- # ✨ AlgoForge Prime™ ✨: Modular Algorithmic Evolution (v2.5 Gemini Focus)
249
- This version prioritizes the latest Google Gemini models and demonstrates a conceptual workflow for AI-assisted algorithm discovery,
250
  featuring (simulated) unit testing for Python code if provided.
251
 
252
  **API Keys Required in Space Secrets (should be working):**
@@ -255,70 +277,88 @@ featuring (simulated) unit testing for Python code if provided.
255
  """
256
 
257
  ui_token_status_md = ""
258
- if not GEMINI_API_CONFIGURED and not HF_API_CONFIGURED:
259
  ui_token_status_md = "<p style='color:red;'>⚠️ **CRITICAL: NEITHER GOOGLE_API_KEY NOR HF_TOKEN are configured or working correctly.** The application will not be able to call any LLMs.</p>"
260
  else:
261
- if GEMINI_API_CONFIGURED: ui_token_status_md += "<p style='color:green;'>✅ Google Gemini API Key detected and configured.</p>"
262
  else: ui_token_status_md += "<p style='color:orange;'>⚠️ **GOOGLE_API_KEY missing or failed to configure.** Gemini API models will be disabled.</p>"
263
- if HF_API_CONFIGURED: ui_token_status_md += "<p style='color:green;'>✅ Hugging Face API Token detected and client initialized.</p>"
264
  else: ui_token_status_md += "<p style='color:orange;'>⚠️ **HF_TOKEN missing or client failed to initialize.** Hugging Face models will be disabled.</p>"
265
 
266
 
267
- with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"), title="AlgoForge Prime™ v2.5") as app_demo: # Updated theme
268
  gr.Markdown(intro_markdown)
269
  gr.HTML(ui_token_status_md)
270
 
271
- if not AVAILABLE_MODELS_CONFIG or UI_DEFAULT_MODEL_KEY == "No Models Available (Check API Keys)" or (UI_DEFAULT_MODEL_KEY and AVAILABLE_MODELS_CONFIG[UI_DEFAULT_MODEL_KEY]["type"] == "none"):
272
- gr.Markdown("<h2 style='color:red;'>No LLM models are available. Please ensure API keys are correctly set in Space Secrets and that the Space has been restarted.</h2>")
 
 
 
 
 
 
273
  else:
274
  with gr.Row():
275
- with gr.Column(scale=2):
 
276
  gr.Markdown("## 💡 1. Define the Challenge")
277
  problem_type_dropdown = gr.Dropdown(
278
  choices=["Python Algorithm with Tests", "Python Algorithm (Critique Only)", "General Algorithm Idea", "Conceptual System Design", "Pseudocode Refinement"],
279
  label="Type of Problem / Algorithm", value="Python Algorithm with Tests",
280
- info="Select '...with Tests' to enable (simulated) unit testing."
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  )
282
- problem_description_textbox = gr.Textbox(lines=5, label="Problem Description / Desired Outcome", placeholder="Describe the algorithmic task clearly.")
283
- initial_hints_textbox = gr.Textbox(lines=3, label="Initial Thoughts / Constraints (Optional)", placeholder="Any specific approaches or limitations.")
284
- user_tests_textbox = gr.Textbox(lines=6, label="Python Unit Tests (Optional, one `assert` per line)", placeholder="assert function_name(input) == expected_output")
285
 
286
  gr.Markdown("## ⚙️ 2. Configure The Forge")
287
  model_selection_dropdown = gr.Dropdown(
288
  choices=list(AVAILABLE_MODELS_CONFIG.keys()),
289
- value=UI_DEFAULT_MODEL_KEY,
290
  label="Select LLM Core Model",
291
- info="Ensure the corresponding API key is working."
292
  )
293
- num_initial_solutions_slider = gr.Slider(minimum=1, maximum=3, value=2, step=1, label="Number of Initial Solutions") # Max 3 for faster iterations
294
 
295
  with gr.Accordion("Advanced LLM Parameters (Expert Users)", open=False):
296
  with gr.Row():
297
- genesis_temp_slider = gr.Slider(minimum=0.0, maximum=1.0, value=0.7, step=0.05, label="Genesis Temp")
298
- genesis_max_tokens_slider = gr.Slider(minimum=256, maximum=4096, value=1024, step=128, label="Genesis Max Tokens") # Increased range
299
  with gr.Row():
300
  critique_temp_slider = gr.Slider(minimum=0.0, maximum=1.0, value=0.4, step=0.05, label="Critique Temp")
301
- critique_max_tokens_slider = gr.Slider(minimum=150, maximum=2048, value=512, step=64, label="Critique Max Tokens")
302
  with gr.Row():
303
  evolution_temp_slider = gr.Slider(minimum=0.0, maximum=1.0, value=0.75, step=0.05, label="Evolution Temp")
304
- evolution_max_tokens_slider = gr.Slider(minimum=256, maximum=4096, value=1536, step=128, label="Evolution Max Tokens")
305
 
 
306
 
307
- engage_button = gr.Button("🚀 ENGAGE ALGOFORGE PRIME™ 🚀", variant="primary", size="lg")
308
-
309
- with gr.Column(scale=3):
310
  gr.Markdown("## 🔥 3. The Forge's Output")
311
- with gr.Tabs():
312
- with gr.TabItem("📜 Initial Candidates & Evaluations"):
313
- output_initial_solutions_markdown = gr.Markdown()
314
- with gr.TabItem("🏆 Champion Candidate"):
315
- output_champion_markdown = gr.Markdown()
316
- with gr.TabItem("🌟 Evolved Artifact & Test Analysis"):
317
- output_evolved_markdown = gr.Markdown()
318
- output_ai_test_analysis_markdown = gr.Markdown()
319
- with gr.TabItem("🛠️ Interaction Log"):
320
- output_interaction_log_markdown = gr.Markdown()
321
 
 
322
  engage_button.click(
323
  fn=run_algoforge_simulation_orchestrator,
324
  inputs=[
@@ -331,23 +371,29 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"), ti
331
  outputs=[
332
  output_initial_solutions_markdown, output_champion_markdown,
333
  output_evolved_markdown, output_interaction_log_markdown,
334
- output_ai_test_analysis_markdown
335
  ]
336
  )
 
337
  gr.Markdown("---")
338
  gr.Markdown(
339
- "**Disclaimer:** Conceptual demo. (Simulated) unit testing is illustrative. **NEVER run LLM-generated code from an untrusted source in an unrestricted environment.** Real sandboxing is critical for safety."
 
 
 
 
340
  )
341
 
342
  # --- Entry Point for Running the Gradio App ---
343
  if __name__ == "__main__":
344
  print("="*80)
345
- print("AlgoForge Prime™ (Modular Version v2.5 Gemini Focus) - Launching...")
346
- print(f" Google Gemini API Configured: {GEMINI_API_CONFIGURED}")
347
- print(f" Hugging Face API Configured: {HF_API_CONFIGURED}")
348
- if not GEMINI_API_CONFIGURED and not HF_API_CONFIGURED:
349
- print(" CRITICAL WARNING: No API keys seem to be configured. App will be non-functional.")
 
350
  print(f" UI Default Model Key: {UI_DEFAULT_MODEL_KEY}")
351
  print(f" Available models for UI: {list(AVAILABLE_MODELS_CONFIG.keys())}")
352
  print("="*80)
353
- app_demo.launch(debug=True, server_name="0.0.0.0") # server_name="0.0.0.0" for Docker/Spaces
 
5
 
6
  # --- Core Logic Imports ---
7
  # Initialize clients first to ensure API keys are loaded before other modules use them.
8
+ from core.llm_clients import initialize_all_clients, is_gemini_api_configured, is_hf_api_configured # Use getters
9
+ initialize_all_clients() # CRITICAL: Call initialization first
10
+
11
+ # Now get the status AFTER initialization
12
+ GEMINI_API_READY = is_gemini_api_configured()
13
+ HF_API_READY = is_hf_api_configured()
14
 
15
  from core.generation_engine import generate_initial_solutions
16
  from core.evaluation_engine import evaluate_solution_candidate, EvaluationResult # Class for typed results
 
20
 
21
  # --- Application Configuration (Models, Defaults) ---
22
  AVAILABLE_MODELS_CONFIG = {}
23
+ UI_DEFAULT_MODEL_KEY = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
+ # Define Gemini 1.5 model IDs (use the exact strings from Google's documentation)
26
+ # These are common aliases; specific versioned IDs might also be available.
27
+ GEMINI_1_5_PRO_LATEST_ID = "gemini-1.5-pro-latest"
28
+ GEMINI_1_5_FLASH_LATEST_ID = "gemini-1.5-flash-latest"
29
 
30
  # Populate with Gemini models first if API is configured
31
+ if GEMINI_API_READY:
32
  AVAILABLE_MODELS_CONFIG.update({
33
+ f"Google Gemini 1.5 Pro (API - Recommended)": {"id": GEMINI_1_5_PRO_LATEST_ID, "type": "google_gemini"},
34
+ f"Google Gemini 1.5 Flash (API - Fast)": {"id": GEMINI_1_5_FLASH_LATEST_ID, "type": "google_gemini"},
35
+ # You can add older Gemini versions here if needed
36
  "Google Gemini 1.0 Pro (API - Legacy)": {"id": "gemini-1.0-pro-latest", "type": "google_gemini"},
37
  })
38
+ # Prioritize 1.5 Pro as default
39
+ UI_DEFAULT_MODEL_KEY = f"Google Gemini 1.5 Pro (API - Recommended)"
40
+ # Fallback to Flash if Pro key somehow isn't in dict (shouldn't happen with this logic)
41
+ if UI_DEFAULT_MODEL_KEY not in AVAILABLE_MODELS_CONFIG: # Should not be needed if Pro ID is valid
42
+ UI_DEFAULT_MODEL_KEY = f"Google Gemini 1.5 Flash (API - Fast)"
43
  print(f"INFO: app.py - Gemini models populated. Default set to: {UI_DEFAULT_MODEL_KEY}")
44
  else:
45
+ print("WARNING: app.py - Gemini API not configured (checked via getter); Gemini models will be unavailable.")
46
 
47
+ # Populate with Hugging Face models if API is configured
48
+ if HF_API_READY:
49
  AVAILABLE_MODELS_CONFIG.update({
50
  "Google Gemma 2B (HF - Quick Test)": {"id": "google/gemma-2b-it", "type": "hf"},
51
  "Mistral 7B Instruct (HF)": {"id": "mistralai/Mistral-7B-Instruct-v0.2", "type": "hf"},
 
57
  else:
58
  print("INFO: app.py - HF models also populated as alternatives.")
59
  else:
60
+ print("WARNING: app.py - Hugging Face API not configured (checked via getter); HF models will be unavailable.")
61
 
62
  # Absolute fallback if no models could be configured at all
63
  if not AVAILABLE_MODELS_CONFIG:
64
+ print("CRITICAL APP ERROR: No models could be configured. Check API keys in Space Secrets and restart Space.")
65
+ AVAILABLE_MODELS_CONFIG["No Models Available (Check API Keys & Restart)"] = {"id": "dummy_error", "type": "none"}
66
+ UI_DEFAULT_MODEL_KEY = "No Models Available (Check API Keys & Restart)"
67
+ elif not UI_DEFAULT_MODEL_KEY and AVAILABLE_MODELS_CONFIG: # Should not happen if logic above is correct
68
+ # If somehow UI_DEFAULT_MODEL_KEY is still None, pick the first available model
69
  UI_DEFAULT_MODEL_KEY = list(AVAILABLE_MODELS_CONFIG.keys())[0]
70
  print(f"WARNING: app.py - UI_DEFAULT_MODEL_KEY was not set by primary logic, falling back to first available: {UI_DEFAULT_MODEL_KEY}")
71
 
72
 
73
  # --- Main Orchestration Logic for Gradio ---
 
74
  def run_algoforge_simulation_orchestrator(
75
+ problem_type_selected: str,
76
+ problem_description_text: str,
77
+ initial_hints_text: str,
78
  user_provided_tests_code: str,
79
+ num_initial_solutions_to_gen: int,
80
  selected_model_ui_key: str,
81
  genesis_temp: float, genesis_max_tokens: int,
82
  critique_temp: float, critique_max_tokens: int,
83
  evolution_temp: float, evolution_max_tokens: int,
84
+ progress=gr.Progress(track_tqdm=True) # Gradio progress tracker
85
  ):
86
  progress(0, desc="Initializing AlgoForge Prime™...")
87
  log_entries = [f"**AlgoForge Prime™ Cycle Starting at {time.strftime('%Y-%m-%d %H:%M:%S')}**"]
88
  start_time = time.time()
89
 
90
+ # Basic input validation
91
  if not problem_description_text.strip():
92
+ error_msg = "CRITICAL INPUT ERROR: Problem Description is mandatory. Please describe the problem."
93
  log_entries.append(error_msg)
94
+ return error_msg, "", "", "\n".join(log_entries), "" # Return 5 values for outputs
95
 
96
  current_model_config = AVAILABLE_MODELS_CONFIG.get(selected_model_ui_key)
97
  if not current_model_config or current_model_config["type"] == "none":
98
+ error_msg = f"CRITICAL CONFIG ERROR: No valid LLM selected ('{selected_model_ui_key}'). This usually means API keys are missing or failed to initialize. Check Space Secrets and restart."
99
  log_entries.append(error_msg)
100
  return error_msg, "", "", "\n".join(log_entries), ""
101
 
 
103
  log_entries.append(f"Problem Type: {problem_type_selected}")
104
  log_entries.append(f"User Unit Tests Provided: {'Yes' if user_provided_tests_code.strip() else 'No'}")
105
 
106
+ # Prepare LLM configurations for each stage
107
  llm_config_genesis = {"type": current_model_config["type"], "model_id": current_model_config["id"], "temp": genesis_temp, "max_tokens": genesis_max_tokens}
108
  llm_config_critique = {"type": current_model_config["type"], "model_id": current_model_config["id"], "temp": critique_temp, "max_tokens": critique_max_tokens}
109
  llm_config_evolution = {"type": current_model_config["type"], "model_id": current_model_config["id"], "temp": evolution_temp, "max_tokens": evolution_max_tokens}
110
 
111
+ # --- STAGE 1: GENESIS ---
112
+ progress(0.05, desc="Stage 1: Genesis Engine - Generating Solutions...")
113
  log_entries.append("\n**------ STAGE 1: GENESIS ENGINE ------**")
114
+
115
  initial_raw_solutions = generate_initial_solutions(
116
  problem_description_text, initial_hints_text, problem_type_selected,
117
  num_initial_solutions_to_gen, llm_config_genesis
118
  )
119
+ log_entries.append(f"Genesis Engine produced {len(initial_raw_solutions)} raw solution candidate(s).")
120
+ for i, sol_text in enumerate(initial_raw_solutions):
121
+ log_entries.append(f" Candidate {i+1} (Raw Snippet): {str(sol_text)[:120]}...") # str() for safety
 
122
 
123
+ # --- STAGE 2: CRITIQUE & AUTOMATED EVALUATION ---
124
+ progress(0.25, desc="Stage 2: Critique Crucible - Evaluating Candidates...")
125
  log_entries.append("\n**------ STAGE 2: CRITIQUE CRUCIBLE & AUTOMATED EVALUATION ------**")
126
+
127
+ evaluated_candidates_list = [] # Stores dicts: {"id": ..., "solution_text": ..., "evaluation_result": EvaluationResult}
128
+
129
  for i, candidate_solution_text in enumerate(initial_raw_solutions):
130
+ current_progress = 0.25 + ( (i + 1) / num_initial_solutions_to_gen ) * 0.4 # Progress for evaluation stage
131
+ progress(current_progress, desc=f"Evaluating Candidate {i+1} of {num_initial_solutions_to_gen}...")
132
  log_entries.append(f"\n--- Evaluating Candidate {i+1} ---")
133
+
134
+ evaluation_obj = evaluate_solution_candidate( # type: EvaluationResult
135
+ str(candidate_solution_text), # Ensure it's a string before passing
136
+ problem_description_text, problem_type_selected,
137
  user_provided_tests_code, llm_config_critique
138
  )
139
+
 
 
140
  log_entries.append(f" Final Combined Score: {evaluation_obj.score}/10")
141
  log_entries.append(f" Automated Tests: {evaluation_obj.passed_tests}/{evaluation_obj.total_tests} passed.")
142
  if evaluation_obj.execution_summary: log_entries.append(f" Execution Summary: {evaluation_obj.execution_summary}")
143
  log_entries.append(f" LLM Critique (Snippet): {str(evaluation_obj.critique_text)[:150]}...")
144
+
145
+ evaluated_candidates_list.append({
146
+ "id": i + 1,
147
+ "solution_text": str(candidate_solution_text),
148
+ "evaluation_result": evaluation_obj
149
+ })
150
 
151
+ # Format display for initial solutions & evaluations
152
  initial_solutions_display_markdown = []
153
+ for data in evaluated_candidates_list:
154
  initial_solutions_display_markdown.append(
155
+ f"**Candidate {data['id']}:**\n"
156
+ # Assuming python for display, adjust if problem_type varies widely in output format
157
+ f"```python\n{data['solution_text']}\n```\n\n"
158
+ f"**Evaluation Verdict (Combined Score: {data['evaluation_result'].score}/10):**\n"
159
+ f"{data['evaluation_result'].critique_text}\n---"
160
  )
161
+
162
+ # --- STAGE 3: SELECTION OF CHAMPION ---
163
+ progress(0.7, desc="Stage 3: Selecting Champion Candidate...")
164
  log_entries.append("\n**------ STAGE 3: CHAMPION SELECTION ------**")
165
+
166
  potentially_viable_candidates = [
167
+ cand for cand in evaluated_candidates_list
168
  if cand["evaluation_result"] and cand["evaluation_result"].score > 0 and \
169
+ cand["solution_text"] and not str(cand["solution_text"]).startswith("ERROR")
170
  ]
171
+
172
  if not potentially_viable_candidates:
173
  final_error_msg = "No viable candidate solutions found after generation and evaluation. All attempts may have failed or scored too low."
174
  log_entries.append(f" CRITICAL: {final_error_msg}")
 
176
 
177
  potentially_viable_candidates.sort(key=lambda x: x["evaluation_result"].score, reverse=True)
178
  champion_candidate_data = potentially_viable_candidates[0]
179
+
180
  log_entries.append(f"Champion Selected: Candidate {champion_candidate_data['id']} "
181
+ f"(Solution Snippet: {str(champion_candidate_data['solution_text'])[:60]}...) "
182
  f"with evaluation score {champion_candidate_data['evaluation_result'].score}/10.")
183
+
184
  champion_display_markdown = (
185
  f"**Champion Candidate ID: {champion_candidate_data['id']} "
186
  f"(Original Combined Score: {champion_candidate_data['evaluation_result'].score}/10):**\n"
187
  f"```python\n{champion_candidate_data['solution_text']}\n```\n\n"
188
+ f"**Original Comprehensive Evaluation for this Champion:**\n"
189
+ f"{champion_candidate_data['evaluation_result'].critique_text}"
190
  )
191
 
192
+ # --- STAGE 4: EVOLUTIONARY FORGE ---
193
+ progress(0.75, desc="Stage 4: Evolutionary Forge - Refining Champion...")
194
  log_entries.append("\n**------ STAGE 4: EVOLUTIONARY FORGE ------**")
195
+
196
  evolved_solution_code = evolve_solution(
197
+ str(champion_candidate_data["solution_text"]),
198
+ str(champion_candidate_data["evaluation_result"].critique_text),
199
  champion_candidate_data["evaluation_result"].score,
200
+ problem_description_text,
201
+ problem_type_selected,
202
+ llm_config_evolution
203
  )
204
  log_entries.append(f"Raw Evolved Solution Text (Snippet): {str(evolved_solution_code)[:150]}...")
205
+
206
  evolved_solution_display_markdown = ""
207
+ ai_test_analysis_markdown = ""
208
 
209
+ if str(evolved_solution_code).startswith("ERROR"):
210
  evolved_solution_display_markdown = f"**Evolution Stage Failed:**\n{evolved_solution_code}"
211
  else:
212
  evolved_solution_display_markdown = f"**✨ AlgoForge Prime™ Evolved Artifact ✨:**\n```python\n{evolved_solution_code}\n```"
213
+
214
  if "python" in problem_type_selected.lower() and user_provided_tests_code.strip():
215
+ progress(0.9, desc="Post-Evolution: Re-running Automated Tests on Evolved Code...")
216
  log_entries.append("\n--- Post-Evolution Sanity Check (Automated Tests on Evolved Code) ---")
217
+
218
  evolved_critique_config = {"type": current_model_config["type"], "model_id": current_model_config["id"], "temp": 0.2, "max_tokens": critique_max_tokens}
219
+
220
+ evolved_code_eval_result = evaluate_solution_candidate(
221
+ str(evolved_solution_code), problem_description_text, problem_type_selected,
222
  user_provided_tests_code, evolved_critique_config
223
  )
224
+
225
  evolved_solution_display_markdown += (
226
  f"\n\n**Post-Evolution Automated Test Results (Simulated):**\n"
227
+ f"{evolved_code_eval_result.execution_summary}\n" # This now comes from EvaluationResult
228
  f"Passed: {evolved_code_eval_result.passed_tests}/{evolved_code_eval_result.total_tests}\n"
229
  )
230
  log_entries.append(f" Evolved Code Test Results: {evolved_code_eval_result.passed_tests}/{evolved_code_eval_result.total_tests} passed. "
231
  f"Summary: {evolved_code_eval_result.execution_summary}")
232
 
233
+ if evolved_code_eval_result.total_tests > 0 :
234
  progress(0.95, desc="Post-Evolution: AI Analyzing Test Results...")
235
  log_entries.append("\n--- AI Analysis of Evolved Code's Test Results ---")
236
  analysis_user_prompt = format_code_test_analysis_user_prompt(
237
+ str(evolved_solution_code),
238
+ user_provided_tests_code,
239
+ str(evolved_code_eval_result.execution_summary)
240
  )
241
  analysis_system_prompt = get_system_prompt("code_execution_explainer")
 
 
242
 
243
+ llm_analysis_config = {"type": current_model_config["type"], "model_id": current_model_config["id"],
244
+ "temp": 0.3, "max_tokens": critique_max_tokens + 150}
245
+
246
+ from core.llm_clients import call_huggingface_api, call_gemini_api
247
+
248
  explanation_response_obj = None
249
  if llm_analysis_config["type"] == "hf":
250
  explanation_response_obj = call_huggingface_api(analysis_user_prompt, llm_analysis_config["model_id"], llm_analysis_config["temp"], llm_analysis_config["max_tokens"], analysis_system_prompt)
 
267
 
268
  # --- Gradio UI Definition ---
269
  intro_markdown = """
270
+ # ✨ AlgoForge Prime™ ✨: Modular Algorithmic Evolution (v1.5 Gemini Focus)
271
+ This version prioritizes Google Gemini 1.5 models and demonstrates a conceptual workflow for AI-assisted algorithm discovery,
272
  featuring (simulated) unit testing for Python code if provided.
273
 
274
  **API Keys Required in Space Secrets (should be working):**
 
277
  """
278
 
279
  ui_token_status_md = ""
280
+ if not GEMINI_API_READY and not HF_API_READY: # Use status from getters
281
  ui_token_status_md = "<p style='color:red;'>⚠️ **CRITICAL: NEITHER GOOGLE_API_KEY NOR HF_TOKEN are configured or working correctly.** The application will not be able to call any LLMs.</p>"
282
  else:
283
+ if GEMINI_API_READY: ui_token_status_md += "<p style='color:green;'>✅ Google Gemini API Key detected and configured.</p>"
284
  else: ui_token_status_md += "<p style='color:orange;'>⚠️ **GOOGLE_API_KEY missing or failed to configure.** Gemini API models will be disabled.</p>"
285
+ if HF_API_READY: ui_token_status_md += "<p style='color:green;'>✅ Hugging Face API Token detected and client initialized.</p>"
286
  else: ui_token_status_md += "<p style='color:orange;'>⚠️ **HF_TOKEN missing or client failed to initialize.** Hugging Face models will be disabled.</p>"
287
 
288
 
289
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="green", secondary_hue="lime"), title="AlgoForge Prime™ (1.5 Focus)") as app_demo:
290
  gr.Markdown(intro_markdown)
291
  gr.HTML(ui_token_status_md)
292
 
293
+ # Check if any models are actually usable based on API readiness
294
+ usable_models_available = any(
295
+ AVAILABLE_MODELS_CONFIG.get(key, {}).get("type") != "none"
296
+ for key in AVAILABLE_MODELS_CONFIG
297
+ )
298
+
299
+ if not usable_models_available:
300
+ gr.Markdown("<h2 style='color:red;'>No LLM models are available for use. Please ensure at least one API key (Google or Hugging Face) is correctly set in this Space's Secrets and that the Space has been restarted.</h2>")
301
  else:
302
  with gr.Row():
303
+ # Input Column
304
+ with gr.Column(scale=2):
305
  gr.Markdown("## 💡 1. Define the Challenge")
306
  problem_type_dropdown = gr.Dropdown(
307
  choices=["Python Algorithm with Tests", "Python Algorithm (Critique Only)", "General Algorithm Idea", "Conceptual System Design", "Pseudocode Refinement"],
308
  label="Type of Problem / Algorithm", value="Python Algorithm with Tests",
309
+ info="Select '...with Tests' to enable (simulated) unit testing if you provide tests below."
310
+ )
311
+ problem_description_textbox = gr.Textbox(
312
+ lines=5, label="Problem Description / Desired Outcome",
313
+ placeholder="Example for 'Python Algorithm with Tests':\n`def calculate_factorial(n: int) -> int:`\nCalculates factorial of n. Should handle n=0 (returns 1) and raise ValueError for n<0."
314
+ )
315
+ initial_hints_textbox = gr.Textbox(
316
+ lines=3, label="Initial Thoughts / Constraints (Optional)",
317
+ placeholder="E.g., 'Prefer an iterative solution over recursive for factorial.' or 'Consider time complexity.'"
318
+ )
319
+ user_tests_textbox = gr.Textbox(
320
+ lines=6, label="Python Unit Tests (Optional, one `assert` per line)",
321
+ placeholder="assert calculate_factorial(0) == 1\nassert calculate_factorial(5) == 120\n# For expected errors (advanced, not fully simulated here):\n# try:\n# calculate_factorial(-1)\n# assert False, \"ValueError not raised\"\n# except ValueError:\n# assert True",
322
+ info="For 'Python Algorithm with Tests'. Ensure function names match your problem description."
323
  )
 
 
 
324
 
325
  gr.Markdown("## ⚙️ 2. Configure The Forge")
326
  model_selection_dropdown = gr.Dropdown(
327
  choices=list(AVAILABLE_MODELS_CONFIG.keys()),
328
+ value=UI_DEFAULT_MODEL_KEY if UI_DEFAULT_MODEL_KEY in AVAILABLE_MODELS_CONFIG else (list(AVAILABLE_MODELS_CONFIG.keys())[0] if AVAILABLE_MODELS_CONFIG else None),
329
  label="Select LLM Core Model",
330
+ info="Ensure the corresponding API key (Google or HF) is configured and working."
331
  )
332
+ num_initial_solutions_slider = gr.Slider(minimum=1, maximum=3, value=2, step=1, label="Number of Initial Solutions (Genesis Engine)") # Max 3 for faster runs
333
 
334
  with gr.Accordion("Advanced LLM Parameters (Expert Users)", open=False):
335
  with gr.Row():
336
+ genesis_temp_slider = gr.Slider(minimum=0.0, maximum=1.0, value=0.7, step=0.05, label="Genesis Temp", info="Higher = more creative, Lower = more deterministic.")
337
+ genesis_max_tokens_slider = gr.Slider(minimum=256, maximum=4096, value=1024, step=128, label="Genesis Max Output Tokens")
338
  with gr.Row():
339
  critique_temp_slider = gr.Slider(minimum=0.0, maximum=1.0, value=0.4, step=0.05, label="Critique Temp")
340
+ critique_max_tokens_slider = gr.Slider(minimum=150, maximum=2048, value=512, step=64, label="Critique Max Output Tokens")
341
  with gr.Row():
342
  evolution_temp_slider = gr.Slider(minimum=0.0, maximum=1.0, value=0.75, step=0.05, label="Evolution Temp")
343
+ evolution_max_tokens_slider = gr.Slider(minimum=256, maximum=4096, value=1536, step=128, label="Evolution Max Output Tokens")
344
 
345
+ engage_button = gr.Button("🚀 ENGAGE ALGOFORGE PRIME™ 🚀", variant="primary", size="lg", elem_id="engage_button_elem")
346
 
347
+ # Output Column
348
+ with gr.Column(scale=3):
 
349
  gr.Markdown("## 🔥 3. The Forge's Output")
350
+ with gr.Tabs(elem_id="output_tabs_elem"):
351
+ with gr.TabItem("📜 Initial Candidates & Evaluations", id="tab_initial_evals"):
352
+ output_initial_solutions_markdown = gr.Markdown(label="Generated Solutions & Combined Evaluations")
353
+ with gr.TabItem("🏆 Champion Candidate (Pre-Evolution)", id="tab_champion"):
354
+ output_champion_markdown = gr.Markdown(label="Top Pick for Refinement")
355
+ with gr.TabItem("🌟 Evolved Artifact & Test Analysis", id="tab_evolved"):
356
+ output_evolved_markdown = gr.Markdown(label="Refined Solution from Evolutionary Forge")
357
+ output_ai_test_analysis_markdown = gr.Markdown(label="AI Analysis of Evolved Code's Test Performance")
358
+ with gr.TabItem("🛠️ Interaction Log (Developer View)", id="tab_log"):
359
+ output_interaction_log_markdown = gr.Markdown(label="Detailed Log of LLM Prompts & Responses")
360
 
361
+ # Connect button to the orchestration function
362
  engage_button.click(
363
  fn=run_algoforge_simulation_orchestrator,
364
  inputs=[
 
371
  outputs=[
372
  output_initial_solutions_markdown, output_champion_markdown,
373
  output_evolved_markdown, output_interaction_log_markdown,
374
+ output_ai_test_analysis_markdown # Matched to the 5 outputs of orchestrator
375
  ]
376
  )
377
+
378
  gr.Markdown("---")
379
  gr.Markdown(
380
+ "**Disclaimer:** This is a conceptual, educational demonstration. "
381
+ "The (simulated) unit testing feature is for illustrative purposes. "
382
+ "**NEVER run LLM-generated code from an untrusted source in an unrestricted environment.** "
383
+ "Implementing robust and secure code sandboxing is complex and absolutely critical for safety in real-world applications. "
384
+ "LLM outputs always require careful human review and verification."
385
  )
386
 
387
  # --- Entry Point for Running the Gradio App ---
388
  if __name__ == "__main__":
389
  print("="*80)
390
+ print("AlgoForge Prime™ (Modular Version - Gemini 1.5 Focus) - Launching...")
391
+ # Print status based on the variables set after calling initialize_all_clients()
392
+ print(f" Google Gemini API Configured: {GEMINI_API_READY}")
393
+ print(f" Hugging Face API Configured: {HF_API_READY}")
394
+ if not GEMINI_API_READY and not HF_API_READY:
395
+ print(" CRITICAL WARNING: No API keys seem to be configured correctly. The application will likely be non-functional.")
396
  print(f" UI Default Model Key: {UI_DEFAULT_MODEL_KEY}")
397
  print(f" Available models for UI: {list(AVAILABLE_MODELS_CONFIG.keys())}")
398
  print("="*80)
399
+ app_demo.launch(debug=True, server_name="0.0.0.0")