File size: 4,270 Bytes
a937307
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
api.py
======
FastAPI wrapper around the 3-phase AI code detector.

Endpoints:
    GET  /          β†’ welcome + available endpoints
    GET  /health    β†’ status check
    POST /detect    β†’ run detection on submitted code

Usage:
    cd C:\\Users\\DEY STORE\\ai-code-detector
    uvicorn api:app --reload --port 8000

    Then visit http://localhost:8000/docs for the Swagger UI.

Test from PowerShell:
    $body = @{ code = "def hello():\n    print('hi')\n    return 42\n\nhello()\nprint('done')\nprint('end')\nprint('really')\nprint('yes')"; language = "python" } | ConvertTo-Json
    Invoke-RestMethod -Uri "http://localhost:8000/detect" -Method POST -Body $body -ContentType "application/json"
"""

import sys
import os
from pathlib import Path

# Make project root importable
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field

from orchestrator import detect, build_report


app = FastAPI(
    title="AI Code Detector",
    description=(
        "Three-phase detector for AI-generated source code.\n\n"
        "Phase 1: Stylometric analysis (Python only, AUC 0.966)\n"
        "Phase 2: Multi-LLM rewrite similarity (AUC 0.653)\n"
        "Phase 3: Neural code classifier (AUC 0.753)\n\n"
        "Based on: 'Uncovering LLM-Generated Code' (AAAI 2025)"
    ),
    version="1.0.0",
)


# ── Request / Response models ─────────────────────────────────────────────────

class DetectRequest(BaseModel):
    code: str = Field(
        ...,
        min_length=1,
        description="Source code to analyze",
        json_schema_extra={
            "example": "import sys\nfrom collections import Counter\n\ndef solve(arr):\n    if not arr:\n        return 0\n    return max(Counter(arr).values())\n\nif __name__ == '__main__':\n    arr = list(map(int, sys.stdin.read().split()))\n    print(solve(arr))"
        },
    )
    language: str = Field(
        "python",
        description="Programming language of the code",
        json_schema_extra={"example": "python"},
    )


class DetectResponse(BaseModel):
    verdict: str
    confidence: float | None
    p1: float | None = None
    p2: float | None = None
    p3: float | None = None
    suspected_model: str | None = None
    language: str
    phases_used: int | None = None
    report: str
    timings: dict | None = None
    total_time_seconds: float | None = None
    errors: dict | None = None


# ── Endpoints ─────────────────────────────────────────────────────────────────

@app.get("/")
def root():
    return {
        "name": "AI Code Detector",
        "version": "1.0.0",
        "status": "running",
        "endpoints": {
            "/detect": "POST β€” submit code for detection",
            "/health": "GET β€” health check",
            "/docs": "GET β€” Swagger UI (interactive API docs)",
        },
    }


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


@app.post("/detect", response_model=DetectResponse)
def detect_endpoint(req: DetectRequest):
    """
    Analyze a code snippet for AI authorship.

    Runs up to 3 detection phases in parallel and returns a combined verdict.
    Phase 2 requires a Groq API key and may take 5-15 seconds.
    """
    if len(req.code.strip()) < 10:
        raise HTTPException(status_code=400, detail="Code too short (< 10 chars)")

    try:
        result = detect(req.code, req.language)
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Detection failed: {e}")

    result["report"] = build_report(result)
    return result


# ── Run directly ──────────────────────────────────────────────────────────────

if __name__ == "__main__":
    import uvicorn
    print("Starting API server at http://localhost:8000")
    print("Swagger UI at http://localhost:8000/docs")
    uvicorn.run("api:app", host="0.0.0.0", port=8000, reload=True)