11import os
22import uuid
33import shutil
4- import json # Move from within functions to top level
4+ import json
55from typing import Dict , List , Optional
66from dotenv import load_dotenv
7- import tempfile # Import tempfile for temporary directory handling
7+ import tempfile
88
99# Load environment variables from .env file
1010load_dotenv ()
1111
1212from 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
1414from pydantic import BaseModel
1515
1616from app .prompt_generator import PromptGenerator
1717from app .response_parser import ResponseParser
1818from app .compiler import RustCompiler
1919from app .llm_client import LlamaEdgeClient
2020from 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
2324app = FastAPI (title = "Rust Project Generator API" )
2425
5051if 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
5758class 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" )
107108async 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" )
115151async 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' ]} \n Fix: { 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
154272async 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' ]} \n Fix: { 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' ]} \n Fix: { err ['solution' ]} \n \n "
609+
610+ fix_prompt = f"""
493611Here is a Rust project that failed to compile. Help me fix the compilation errors.
494612
495613Project description: { request .description }
@@ -501,42 +619,42 @@ async def generate_project_sync(request: ProjectRequest):
501619
502620Please 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