Skip to content

Commit fcd5e84

Browse files
committed
Add synchronous project generation endpoint with vector search handling
1 parent fde7150 commit fcd5e84

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

app/main.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import json # Move from within functions to top level
55
from typing import Dict, List, Optional
66
from dotenv import load_dotenv
7+
import tempfile # Import tempfile for temporary directory handling
78

89
# Load environment variables from .env file
910
load_dotenv()
@@ -358,6 +359,150 @@ async def download_project(project_id: str):
358359
media_type="application/zip"
359360
)
360361

362+
@app.post("/generate-sync")
363+
async def generate_project_sync(request: ProjectRequest):
364+
"""
365+
Generate a Rust project synchronously and return all files in text format.
366+
This endpoint will wait for the full generation process to complete.
367+
"""
368+
try:
369+
# Create temporary directory for generation
370+
with tempfile.TemporaryDirectory() as temp_dir:
371+
# Set up status tracking
372+
status = {
373+
"status": "generating",
374+
"message": "Generating project code"
375+
}
376+
377+
# Skip vector search if environment variable is set
378+
skip_vector_search = os.getenv("SKIP_VECTOR_SEARCH", "").lower() == "true"
379+
380+
example_text = ""
381+
if not skip_vector_search:
382+
try:
383+
# Check for similar projects in vector DB
384+
query_embedding = llm_client.get_embeddings([request.description])[0]
385+
similar_projects = vector_store.search("project_examples", query_embedding, limit=1)
386+
387+
if similar_projects:
388+
example_text = f"\nHere's a similar project you can use as reference:\n{similar_projects[0]['example']}"
389+
except Exception as e:
390+
print(f"Vector search error (non-critical): {e}")
391+
392+
requirements = request.requirements or ""
393+
if example_text:
394+
requirements = f"{requirements}\n{example_text}" if requirements else example_text
395+
396+
# Generate prompt and get response from LLM
397+
prompt = prompt_gen.generate_prompt(request.description, requirements)
398+
399+
system_message = """You are an expert Rust developer. Create a complete, working Rust project.
400+
Always include at minimum these files: Cargo.toml, src/main.rs, and README.md.
401+
For Cargo.toml, include proper dependencies and metadata.
402+
Format your response with clear file headers like:
403+
404+
[filename: Cargo.toml]
405+
<file content>
406+
407+
[filename: src/main.rs]
408+
<file content>
409+
"""
410+
411+
response = llm_client.generate_text(prompt, system_message=system_message)
412+
413+
# Parse response into files
414+
files = parser.parse_response(response)
415+
416+
# Ensure essential files exist
417+
if "Cargo.toml" not in files:
418+
project_name = request.description.lower().replace(" ", "_").replace("-", "_")[:20]
419+
files["Cargo.toml"] = f"""[package]
420+
name = "{project_name}"
421+
version = "0.1.0"
422+
edition = "2021"
423+
424+
[dependencies]
425+
"""
426+
427+
if "src/main.rs" not in files and "src\\main.rs" not in files:
428+
files["src/main.rs"] = """fn main() {
429+
println!("Hello, world!");
430+
}
431+
"""
432+
433+
# Write files
434+
parser.write_files(files, temp_dir)
435+
436+
# Compile the project
437+
success, output = compiler.build_project(temp_dir)
438+
439+
if not success:
440+
# Try to fix compilation errors
441+
error_context = compiler.extract_error_context(output)
442+
443+
# Skip vector search if environment variable is set
444+
similar_errors = []
445+
if not skip_vector_search:
446+
try:
447+
error_embedding = llm_client.get_embeddings([error_context["full_error"]])[0]
448+
similar_errors = vector_store.search("error_examples", error_embedding, limit=3)
449+
except Exception as e:
450+
print(f"Vector search error (non-critical): {e}")
451+
452+
# Generate fix prompt
453+
fix_examples = ""
454+
if similar_errors:
455+
fix_examples = "Here are some examples of similar errors and their fixes:\n\n"
456+
for i, err in enumerate(similar_errors):
457+
fix_examples += f"Example {i+1}:\n{err['error']}\nFix: {err['solution']}\n\n"
458+
459+
fix_prompt = f"""
460+
Here is a Rust project that failed to compile. Help me fix the compilation errors.
461+
462+
Project description: {request.description}
463+
464+
Compilation error:
465+
{error_context["full_error"]}
466+
467+
{fix_examples}
468+
469+
Please provide the fixed code for all affected files.
470+
"""
471+
472+
# Get fix from LLM
473+
fix_response = llm_client.generate_text(fix_prompt)
474+
475+
# Parse and apply fixes
476+
fixed_files = parser.parse_response(fix_response)
477+
for filename, content in fixed_files.items():
478+
files[filename] = content # Update our files dictionary
479+
file_path = os.path.join(temp_dir, filename)
480+
os.makedirs(os.path.dirname(file_path), exist_ok=True)
481+
with open(file_path, 'w') as f:
482+
f.write(content)
483+
484+
# Try compiling again
485+
success, output = compiler.build_project(temp_dir)
486+
487+
# Format as raw text with filename markers
488+
output_text = ""
489+
for filename, content in files.items():
490+
output_text += f"[filename: {filename}]\n{content}\n\n"
491+
492+
# Include build result as a comment
493+
build_status = "# Build succeeded" if success else f"# Build failed\n# {output}"
494+
output_text += f"{build_status}\n"
495+
496+
# Return as plain text
497+
return PlainTextResponse(content=output_text.strip())
498+
499+
except Exception as e:
500+
# Return error message
501+
return JSONResponse(
502+
status_code=500,
503+
content={"error": f"Project generation failed: {str(e)}"}
504+
)
505+
361506
if __name__ == "__main__":
362507
import uvicorn
363508
uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True)

0 commit comments

Comments
 (0)