Spaces:
Sleeping
Sleeping
File size: 5,892 Bytes
f1080fa 069a92b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | from fastapi import FastAPI, Request, BackgroundTasks
import os, json, base64
# from dotenv import load_dotenv
import time
from src.llm_generator import generate_app_code, decode_attachments
from src.github_utils import (
create_repo,
create_or_update_file,
enable_pages,
generate_mit_license,
)
from src.notify import notify_evaluation_server
from src.github_utils import create_or_update_binary_file
# load_dotenv()
USER_SECRET = os.getenv("USER_SECRET")
USERNAME = os.getenv("GITHUB_USERNAME")
PROCESSED_PATH = "/tmp/processed_requests.json"
app = FastAPI()
# === Persistence for processed requests ===
def load_processed():
if os.path.exists(PROCESSED_PATH):
try:
return json.load(open(PROCESSED_PATH))
except json.JSONDecodeError:
return {}
return {}
def save_processed(data):
json.dump(data, open(PROCESSED_PATH, "w"), indent=2)
# === Background task ===
def process_request(data):
round_num = data.get("round", 1)
task_id = data["task"]
print(f"β Starting background process for task {task_id} (round {round_num})")
attachments = data.get("attachments", [])
saved_attachments = decode_attachments(attachments)
print("Attachments saved:", saved_attachments)
# Optional: fetch previous README for round 2
prev_readme = None
if round_num == 2:
try:
readme = repo.get_contents("README.md")
prev_readme = readme.decoded_content.decode("utf-8", errors="ignore")
print("π Loaded previous README for round 2 context.")
except Exception:
prev_readme = None
gen = generate_app_code(
data["brief"],
attachments=attachments,
checks=data.get("checks", []),
round_num=round_num,
prev_readme=prev_readme
)
files = gen.get("files", {})
saved_info = gen.get("attachments", [])
# Step 1: Get or create repo
repo = create_repo(task_id, description=f"Auto-generated app for task: {data['brief']}")
# Step 2: Round-specific logic
if round_num == 1:
print("π Round 1: Building fresh repo...")
# Add attachments
for att in saved_info:
path = att["name"]
try:
with open(att["path"], "rb") as f:
content_bytes = f.read()
if att["mime"].startswith("text") or att["name"].endswith((".md", ".csv", ".json", ".txt")):
text = content_bytes.decode("utf-8", errors="ignore")
create_or_update_file(repo, path, text, f"Add attachment {path}")
else:
create_or_update_binary_file(repo, path, content_bytes, f"Add binary {path}")
b64 = base64.b64encode(content_bytes).decode("utf-8")
create_or_update_file(repo, f"attachments/{att['name']}.b64", b64, f"Backup {att['name']}.b64")
except Exception as e:
print("β Attachment commit failed:", e)
else:
print("π Round 2: Revising existing repo...")
# For round 2, update existing code and README
# Commit new files on top of existing repo
for fname, content in files.items():
create_or_update_file(repo, fname, content, f"Update {fname} for round 2")
# Step 3: Common steps for both rounds
for fname, content in files.items():
create_or_update_file(repo, fname, content, f"Add/Update {fname}")
mit_text = generate_mit_license()
create_or_update_file(repo, "LICENSE", mit_text, "Add MIT license")
# Step 6: Handle GitHub Pages enablement or reuse existing
if data["round"] == 1:
pages_ok = enable_pages(task_id)
pages_url = f"https://{USERNAME}.github.io/{task_id}/" if pages_ok else None
else:
# For round 2 or later, Pages already exist
pages_ok = True
pages_url = f"https://{USERNAME}.github.io/{task_id}/"
try:
commit_sha = repo.get_commits()[0].sha
except Exception:
commit_sha = None
payload = {
"email": data["email"],
"task": data["task"],
"round": round_num,
"nonce": data["nonce"],
"repo_url": repo.html_url,
"commit_sha": commit_sha,
"pages_url": pages_url,
}
time.sleep(180) # Ensure GitHub Pages is ready
notify_evaluation_server(data["evaluation_url"], payload)
processed = load_processed()
key = f"{data['email']}::{data['task']}::round{round_num}::nonce{data['nonce']}"
processed[key] = payload
save_processed(processed)
print(f"β
Finished round {round_num} for {task_id}")
# === Main endpoint ===
@app.post("/api-endpoint")
async def receive_request(request: Request, background_tasks: BackgroundTasks):
data = await request.json()
print("π© Received request:", data)
# Step 0: Verify secret
if data.get("secret") != USER_SECRET:
print("β Invalid secret received.")
return {"error": "Invalid secret"}
processed = load_processed()
key = f"{data['email']}::{data['task']}::round{data['round']}::nonce{data['nonce']}"
# Duplicate detection
if key in processed:
print(f"β Duplicate request detected for {key}. Re-notifying only.")
prev = processed[key]
notify_evaluation_server(data.get("evaluation_url"), prev)
return {"status": "ok", "note": "duplicate handled & re-notified"}
# Schedule background task (non-blocking)
background_tasks.add_task(process_request, data)
# Immediate HTTP 200 acknowledgment
return {"status": "accepted", "note": f"processing round {data['round']} started"}
print("π GITHUB_TOKEN present:", bool(os.getenv("GITHUB_TOKEN")))
print("π GITHUB_USERNAME:", os.getenv("GITHUB_USERNAME"))
print("π OPENAI_API_KEY present:", bool(os.getenv("OPENAI_API_KEY"))) |