File size: 5,116 Bytes
877b38e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eb71740
 
877b38e
 
 
 
 
 
 
 
 
 
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
# main.py
from fastapi import FastAPI, HTTPException, BackgroundTasks
from pydantic import BaseModel
import requests,time, os
from dotenv import load_dotenv
from github import Github  # from PyGithub
from llm_utils import generate_app_files  # your LLM logic
from typing import Optional, List, Dict

app = FastAPI()
load_dotenv()  # take environment variables from .env

SHARED_SECRET = os.getenv("SECRET_KEY")
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")

class TaskRequest(BaseModel):
    email: str
    task: str
    brief: str
    checks: List[str]
    round: int
    nonce: str
    secret: str
    evaluation_url: str
    attachments: Optional[List[Dict[str, str]]] = None  # added to accept attachments like data URIs

@app.get("/")
def root():
    return {"status": "ok"}

async def process_task_in_background(req: TaskRequest):
    # 2. Generate files and handle repo based on round
    app_files = generate_app_files(
        brief=req.brief, 
        checks=req.checks, 
        attachments=req.attachments,
        round=req.round,
        task=req.task
    )

    # Validate LLM output
    if not isinstance(app_files, dict) or "index" not in app_files or "README" not in app_files:
        raise HTTPException(status_code=500, detail="LLM did not return expected file structure")

    # Initialize GitHub client
    g = Github(GITHUB_TOKEN)
    user = g.get_user()
    repo_name = f"{req.task}"

    if req.round == 1:
        # Round 1: Create new repo
        try:
            repo = user.create_repo(repo_name, private=False, auto_init=False, license_template="mit")
        except Exception as e:
            raise HTTPException(status_code=500, detail=f"Failed to create repo: {e}")
    else:
        # Round >1: Get existing repo and update
        try:
            # Use get_repo with full path
            repo = g.get_repo(f"{user.login}/{repo_name}")
        except Exception as e:
            raise HTTPException(status_code=404, detail=f"Repository not found: {e}")

    # Prepare files to commit
    files_to_commit = {
        "index.html": app_files["index"],
        "README.md": app_files["README"],
    }
    if isinstance(app_files.get("assets"), dict):
        files_to_commit.update(app_files["assets"])

    # Add/Update files & commit
    for path, content in files_to_commit.items():
        try:
            if req.round == 1:
                # Create new file for round 1
                repo.create_file(path, f"add {path}", content)
            else:
                # Update existing file for later rounds
                try:
                    # Get current file content
                    file = repo.get_contents(path)
                    # Update file
                    repo.update_file(path, f"update {path} for round {req.round}", content, file.sha)
                except Exception:
                    # File doesn't exist, create it
                    repo.create_file(path, f"add {path} for round {req.round}", content)
        except Exception as e:
            raise HTTPException(status_code=500, detail=f"Failed to handle file {path}: {e}")

    # Enable GitHub Pages only for round 1
    if req.round == 1:
        try:
            requests.post(
                f"https://api.github.com/repos/{user.login}/{repo_name}/pages",
                headers={
                    "Authorization": f"token {GITHUB_TOKEN}",
                    "Accept": "application/vnd.github.v3+json",
                },
                json={"source": {"branch": "main", "path": "/"}}
            )
        except Exception:
            pass

    # Get latest commit SHA
    commit_sha = repo.get_commits()[0].sha

    # Prepare evaluation JSON
    payload = {
        "email": req.email,
        "task": req.task,
        "round": req.round,
        "nonce": req.nonce,
        "repo_url": repo.html_url,
        "commit_sha": commit_sha,
        "pages_url": f"https://{user.login}.github.io/{repo_name}/",
    }


    time.sleep(60)

    # 8. POST to evaluation URL (with exponential backoff) — include JSON Content-Type & try up to 5 times
    delay = 1
    headers = {"Content-Type": "application/json"}
    for _ in range(5):
        try:
            r = requests.post(req.evaluation_url, json=payload, headers=headers, timeout=10)
            if r.status_code == 200:
                break
        except Exception:
            pass
        time.sleep(delay)
        delay *= 2

@app.post("/task1")
async def handle_task(req: TaskRequest, background_tasks: BackgroundTasks):
    # 1. Secret verification
    if req.secret != SHARED_SECRET:
        raise HTTPException(status_code=403, detail="Invalid secret")
    if req.email!="22f3000730@ds.study.iitm.ac.in":
        raise HTTPException(status_code=403, detail="Invalid email")

    # Add the processing to background tasks
    background_tasks.add_task(process_task_in_background, req)

    # Return simple acknowledgment
    return {"status": "accepted", "message": "Request received and processing"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)