import os import requests from fastapi import FastAPI, HTTPException, status from openai import OpenAI from pydantic import BaseModel allowed_host_env = os.getenv("LLM_REVIEW_ALLOWED_HOST") allowed_hosts = [] allowed_hosts_not_empty = True if allowed_host_env is None: allowed_hosts_not_empty = False else: allowed_hosts = allowed_host_env.split(',') if len(allowed_hosts) == 0: allowed_hosts_not_empty = False for (i, host) in enumerate(allowed_hosts): allowed_hosts[i] = host.rstrip('/') print(f'allowed host: {allowed_hosts}') app = FastAPI() class ReviewRequest(BaseModel): gitea_token: str gitea_host: str openrouter_key: str model: str repo: str pr_number: int @app.get("/health") def test(): try: r = requests.get("https://openrouter.ai/api/v1/models") r.raise_for_status() return {"status": "ok"} except requests.exceptions.RequestException as e: raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail=f"OpenRouter health check failed: {e}", ) @app.post("/") def review( request_body: ReviewRequest, ): gitea_host = request_body.gitea_host.rstrip("/") if allowed_hosts_not_empty and gitea_host not in allowed_hosts: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Request source is not allowed host", ) headers = {"Authorization": f"token {request_body.gitea_token}"} diff_res = requests.get(f"{gitea_host}/api/v1/repos/{request_body.repo}/pulls/{request_body.pr_number}.diff", headers=headers) if diff_res.status_code != 200 or not diff_res.text.strip(): return diff_text = diff_res.text client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key=request_body.openrouter_key) prompt = ( "You are an automated senior code reviewer. Review the following git diff.\n" "Focus on: critical bugs, security vulnerabilities, edge cases, and code smells.\n" "Keep it short and clear, don't give me long solutions.\n" "Dont point out good things only problems, errors, etc.\n" "Format your answer cleanly in Markdown with actionable feedback.\n\n" f"```diff\n{diff_text}\n```" ) completion = client.chat.completions.create( model=request_body.model, messages=[{"role": "user", "content": prompt}] ) review_content = completion.choices[0].message.content review_body = f"# llm review\n\n{review_content}" requests.post( f"{gitea_host}/api/v1/repos/{request_body.repo}/pulls/{request_body.pr_number}/reviews", headers=headers, json={"body": review_body, "event": "COMMENT"} ) return {"status": "done"}