working demo
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
venv
|
venv
|
||||||
.venv
|
.venv
|
||||||
|
__pycache__
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
FROM python:3.14-alpine
|
||||||
|
WORKDIR /usr/src/llm-reviewer
|
||||||
|
COPY . .
|
||||||
|
RUN pip install -r requirements.txt
|
||||||
|
CMD uvicorn main:app --host 0.0.0.0 --port 8080
|
||||||
@@ -1 +1,21 @@
|
|||||||
# llm reviewer
|
# llm reviewer
|
||||||
|
|
||||||
|
running server
|
||||||
|
```bash
|
||||||
|
docker build -t llm-reviewer .
|
||||||
|
docker run -d --rm -p 8080:8080 --name llm-reviewer llm-reviewer
|
||||||
|
```
|
||||||
|
|
||||||
|
in gitea repository fill:
|
||||||
|
- secrets:
|
||||||
|
```
|
||||||
|
LLM_REVIEW_OPENROUTER_KEY
|
||||||
|
```
|
||||||
|
|
||||||
|
- variables:
|
||||||
|
```
|
||||||
|
LLM_REVIEW_HOST
|
||||||
|
LLM_REVIEW_MODEL
|
||||||
|
```
|
||||||
|
|
||||||
|
put `llm-reviewer.yaml` into `.gitea/workflows/`
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
name: LLM PR Review
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
llm-review:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Trigger AI Reviewer
|
||||||
|
run: |
|
||||||
|
curl -f -X POST "${{ vars.LLM_REVIEW_HOST }}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"gitea_token": "${{ secrets.GITHUB_TOKEN }}",
|
||||||
|
"gitea_host": "${{ github.server_url }}",
|
||||||
|
"openrouter_key": "${{ secrets.LLM_REVIEW_OPENROUTER_KEY }}",
|
||||||
|
"model": "${{ vars.LLM_REVIEW_MODEL }}",
|
||||||
|
"repo": "${{ github.repository }}",
|
||||||
|
"pr_number": ${{ github.event.pull_request.number }}
|
||||||
|
}'
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import requests
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from openai import OpenAI
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
class ReviewRequest(BaseModel):
|
||||||
|
gitea_token: str
|
||||||
|
gitea_host: str
|
||||||
|
openrouter_key: str
|
||||||
|
model: str
|
||||||
|
repo: str
|
||||||
|
pr_number: int
|
||||||
|
|
||||||
|
@app.post("/")
|
||||||
|
async def review(
|
||||||
|
request_body: ReviewRequest,
|
||||||
|
):
|
||||||
|
print('starting bg task with:')
|
||||||
|
print(f'request: {request_body}')
|
||||||
|
|
||||||
|
gitea_host = request_body.gitea_host.rstrip("/")
|
||||||
|
|
||||||
|
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."
|
||||||
|
"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"}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fastapi
|
||||||
|
uvicorn
|
||||||
|
openai
|
||||||
|
requests
|
||||||
|
pydantic
|
||||||
Reference in New Issue
Block a user