Skip to content

Commit d16071f

Browse files
committed
Refactor compile and fix endpoints to remove MCP service dependency and implement direct handling of Rust code compilation and error fixing
1 parent 027c2bf commit d16071f

File tree

1 file changed

+189
-71
lines changed

1 file changed

+189
-71
lines changed

app/main.py

Lines changed: 189 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
import os
22
import uuid
33
import shutil
4-
import json # Move from within functions to top level
4+
import json
55
from typing import Dict, List, Optional
66
from dotenv import load_dotenv
7-
import tempfile # Import tempfile for temporary directory handling
7+
import tempfile
88

99
# Load environment variables from .env file
1010
load_dotenv()
1111

1212
from fastapi import FastAPI, BackgroundTasks, HTTPException
13-
from fastapi.responses import JSONResponse, PlainTextResponse # Move from within function to top level
13+
from fastapi.responses import JSONResponse, PlainTextResponse
1414
from pydantic import BaseModel
1515

1616
from app.prompt_generator import PromptGenerator
1717
from app.response_parser import ResponseParser
1818
from app.compiler import RustCompiler
1919
from app.llm_client import LlamaEdgeClient
2020
from app.vector_store import QdrantStore
21-
from app.mcp_service import RustCompilerMCP
21+
# Comment out MCP import until we're ready to use it
22+
# from app.mcp_service import RustCompilerMCP
2223

2324
app = FastAPI(title="Rust Project Generator API")
2425

@@ -50,8 +51,8 @@
5051
if vector_store.count("error_examples") == 0:
5152
load_error_examples()
5253

53-
# Initialize MCP service with vector store and LLM client
54-
rust_mcp = RustCompilerMCP(vector_store=vector_store, llm_client=llm_client)
54+
# Initialize MCP service with vector store and LLM client - commented out for now
55+
# rust_mcp = RustCompilerMCP(vector_store=vector_store, llm_client=llm_client)
5556

5657
# Project generation request
5758
class ProjectRequest(BaseModel):
@@ -103,15 +104,50 @@ async def get_project_status(project_id: str):
103104

104105
return ProjectResponse(**status)
105106

106-
@app.post("/compile") # Changed from /mcp/compile
107+
@app.post("/compile")
107108
async def compile_rust(request: dict):
108-
"""MCP endpoint to compile Rust code"""
109+
"""Endpoint to compile Rust code"""
109110
if "code" not in request:
110111
raise HTTPException(status_code=400, detail="Missing 'code' field")
111112

112-
return rust_mcp.compile_rust_code(request["code"])
113+
# Direct implementation instead of using MCP service
114+
# return rust_mcp.compile_rust_code(request["code"])
115+
116+
# Create temp directory
117+
with tempfile.TemporaryDirectory() as temp_dir:
118+
# Parse the multi-file content
119+
files = parser.parse_response(request["code"])
120+
121+
# Ensure project structure
122+
os.makedirs(os.path.join(temp_dir, "src"), exist_ok=True)
123+
124+
# Write files
125+
file_paths = parser.write_files(files, temp_dir)
126+
127+
# Compile the project
128+
success, output = compiler.build_project(temp_dir)
129+
130+
if success:
131+
# Try running if compilation succeeded
132+
run_success, run_output = compiler.run_project(temp_dir)
133+
134+
return {
135+
"success": True,
136+
"files": file_paths,
137+
"build_output": output or "Build successful",
138+
"run_output": run_output if run_success else "Failed to run project"
139+
}
140+
else:
141+
# Return error details
142+
error_context = compiler.extract_error_context(output)
143+
return {
144+
"success": False,
145+
"files": file_paths,
146+
"build_output": output,
147+
"error_details": error_context
148+
}
113149

114-
@app.post("/compile-and-fix") # Changed from /mcp/compile-and-fix
150+
@app.post("/compile-and-fix")
115151
async def compile_and_fix_rust(request: dict):
116152
"""Endpoint to compile and fix Rust code"""
117153
if "code" not in request or "description" not in request:
@@ -126,29 +162,111 @@ async def compile_and_fix_rust(request: dict):
126162
code = code.replace("println!(\"", "println!(\"")
127163
code = code.replace("\" //", "\"); //")
128164

129-
result = rust_mcp.compile_and_fix_rust_code(
130-
code,
131-
request["description"],
132-
max_attempts=max_attempts
133-
)
134-
135-
# Format as text with filename markers
136-
output_text = ""
137-
for filename, content in result["final_files"].items():
138-
output_text += f"[filename: {filename}]\n{content}\n\n"
165+
# Using direct implementation instead of MCP service
166+
# result = rust_mcp.compile_and_fix_rust_code(
167+
# code,
168+
# request["description"],
169+
# max_attempts=max_attempts
170+
# )
139171

140-
# For successful fixes, return a text response with the combined code
141-
if result["success"]:
142-
return PlainTextResponse(content=output_text.strip())
143-
else:
144-
# For errors, return the JSON with detailed error information
145-
# Include the combined text in both the combined_text and final_files fields
172+
# Create temp directory
173+
with tempfile.TemporaryDirectory() as temp_dir:
174+
# Parse the multi-file content
175+
files = parser.parse_response(code)
176+
177+
# Ensure project structure
178+
os.makedirs(os.path.join(temp_dir, "src"), exist_ok=True)
179+
180+
# Write files
181+
file_paths = parser.write_files(files, temp_dir)
182+
183+
# Try compiling and fixing up to max_attempts
184+
attempts = []
185+
current_files = files.copy()
186+
187+
for attempt in range(max_attempts):
188+
# Compile the project
189+
success, output = compiler.build_project(temp_dir)
190+
191+
# Store this attempt
192+
attempts.append({
193+
"attempt": attempt + 1,
194+
"success": success,
195+
"output": output
196+
})
197+
198+
if success:
199+
# Try running if compilation succeeded
200+
run_success, run_output = compiler.run_project(temp_dir)
201+
202+
# Format as text with filename markers
203+
output_text = ""
204+
for filename, content in current_files.items():
205+
output_text += f"[filename: {filename}]\n{content}\n\n"
206+
207+
# For successful fixes, return a text response with the combined code
208+
return PlainTextResponse(content=output_text.strip())
209+
210+
# If we've reached max attempts without success, stop
211+
if attempt == max_attempts - 1:
212+
break
213+
214+
# Extract error context for LLM
215+
error_context = compiler.extract_error_context(output)
216+
217+
# Find similar errors in vector DB (commented out for now)
218+
similar_errors = []
219+
try:
220+
# Find similar errors in vector DB
221+
error_embedding = llm_client.get_embeddings([error_context["full_error"]])[0]
222+
similar_errors = vector_store.search("error_examples", error_embedding, limit=3)
223+
except Exception as e:
224+
print(f"Vector search error (non-critical): {e}")
225+
226+
# Generate fix prompt
227+
fix_examples = ""
228+
if similar_errors:
229+
fix_examples = "Here are some examples of similar errors and their fixes:\n\n"
230+
for i, err in enumerate(similar_errors):
231+
fix_examples += f"Example {i+1}:\n{err['error']}\nFix: {err['solution']}\n\n"
232+
233+
fix_prompt = f"""
234+
Here is a Rust project that failed to compile. Help me fix the compilation errors.
235+
236+
Project description: {request["description"]}
237+
238+
Compilation error:
239+
{error_context["full_error"]}
240+
241+
{fix_examples}
242+
243+
Please provide the fixed code for all affected files.
244+
"""
245+
246+
# Get fix from LLM
247+
fix_response = llm_client.generate_text(fix_prompt)
248+
249+
# Parse and apply fixes
250+
fixed_files = parser.parse_response(fix_response)
251+
for filename, content in fixed_files.items():
252+
file_path = os.path.join(temp_dir, filename)
253+
os.makedirs(os.path.dirname(file_path), exist_ok=True)
254+
with open(file_path, 'w') as f:
255+
f.write(content)
256+
current_files[filename] = content
257+
258+
# Format as text with filename markers for error response
259+
output_text = ""
260+
for filename, content in current_files.items():
261+
output_text += f"[filename: {filename}]\n{content}\n\n"
262+
263+
# If we've exhausted all attempts, return error
146264
return JSONResponse(content={
147265
"status": "error",
148-
"message": f"Failed to fix code: {result.get('build_output', '')}",
149-
"attempts": result.get("attempts", []),
266+
"message": f"Failed to fix code: {attempts[-1]['output']},
267+
"attempts": attempts,
150268
"combined_text": output_text.strip(),
151-
"final_files": result["final_files"] # Include the individual files in the response
269+
"final_files": current_files
152270
})
153271

154272
async def handle_project_generation(
@@ -482,14 +600,14 @@ async def generate_project_sync(request: ProjectRequest):
482600
print(f"Vector search error (non-critical): {e}")
483601
# Continue without vector search results
484602

485-
# Generate fix prompt
486-
fix_examples = ""
487-
if similar_errors:
488-
fix_examples = "Here are some examples of similar errors and their fixes:\n\n"
489-
for i, err in enumerate(similar_errors):
490-
fix_examples += f"Example {i+1}:\n{err['error']}\nFix: {err['solution']}\n\n"
491-
492-
fix_prompt = f"""
603+
# Generate fix prompt
604+
fix_examples = ""
605+
if similar_errors:
606+
fix_examples = "Here are some examples of similar errors and their fixes:\n\n"
607+
for i, err in enumerate(similar_errors):
608+
fix_examples += f"Example {i+1}:\n{err['error']}\nFix: {err['solution']}\n\n"
609+
610+
fix_prompt = f"""
493611
Here is a Rust project that failed to compile. Help me fix the compilation errors.
494612
495613
Project description: {request.description}
@@ -501,42 +619,42 @@ async def generate_project_sync(request: ProjectRequest):
501619
502620
Please provide the fixed code for all affected files.
503621
"""
622+
623+
# Get fix from LLM
624+
fix_response = llm_client.generate_text(fix_prompt)
504625

505-
# Get fix from LLM
506-
fix_response = llm_client.generate_text(fix_prompt)
507-
508-
# Parse and apply fixes
509-
fixed_files = parser.parse_response(fix_response)
510-
for filename, content in fixed_files.items():
511-
file_path = os.path.join(temp_dir, filename)
512-
with open(file_path, 'w') as f:
513-
f.write(content)
514-
515-
# Try compiling again
516-
success, output = compiler.build_project(temp_dir)
626+
# Parse and apply fixes
627+
fixed_files = parser.parse_response(fix_response)
628+
for filename, content in fixed_files.items():
629+
file_path = os.path.join(temp_dir, filename)
630+
with open(file_path, 'w') as f:
631+
f.write(content)
517632

518-
if success:
519-
# Project compiled successfully, try running it
520-
run_success, run_output = compiler.run_project(temp_dir)
521-
522-
status.update({
523-
"status": "completed",
524-
"message": "Project generated successfully",
525-
"build_output": output,
526-
"run_output": run_output if run_success else "Failed to run project"
527-
})
528-
529-
# Return all files as text with build success marker
530-
all_files_content = "\n".join([f"[filename: {f}]\n{open(os.path.join(temp_dir, f)).read()}\n" for f in file_paths])
531-
all_files_content += "\n# Build succeeded\n"
532-
return PlainTextResponse(content=all_files_content)
533-
else:
534-
status.update({
535-
"status": "failed",
536-
"message": "Failed to generate working project",
537-
"build_output": output
538-
})
633+
# Try compiling again
634+
success, output = compiler.build_project(temp_dir)
635+
636+
if success:
637+
# Project compiled successfully, try running it
638+
run_success, run_output = compiler.run_project(temp_dir)
539639

540-
save_status(temp_dir, status)
640+
status.update({
641+
"status": "completed",
642+
"message": "Project generated successfully",
643+
"build_output": output,
644+
"run_output": run_output if run_success else "Failed to run project"
645+
})
646+
647+
# Return all files as text with build success marker
648+
all_files_content = "\n".join([f"[filename: {f}]\n{open(os.path.join(temp_dir, f)).read()}\n" for f in file_paths])
649+
all_files_content += "\n# Build succeeded\n"
650+
return PlainTextResponse(content=all_files_content)
651+
else:
652+
status.update({
653+
"status": "failed",
654+
"message": "Failed to generate working project",
655+
"build_output": output
656+
})
657+
658+
save_status(temp_dir, status)
541659
except Exception as e:
542660
raise HTTPException(status_code=500, detail=f"Error generating project: {str(e)}")

0 commit comments

Comments
 (0)