File size: 1,539 Bytes
32f55d0
 
1751b09
 
 
 
32f55d0
1751b09
 
 
32f55d0
 
 
 
1751b09
 
32f55d0
 
1751b09
32f55d0
 
 
 
1751b09
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32f55d0
 
 
1751b09
32f55d0
 
 
1751b09
 
 
 
 
 
 
 
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
"""FastAPI service exposing the memorization guardrail.

Runs the canonical MemGuard flow -- ``prompt -> Stable Diffusion ->
memorization score`` -- with the real anisotropy metric. The Stable Diffusion
pipeline is loaded once, lazily, on the first request.

Run locally:  uvicorn app.api:app --reload
Requires the ``api`` + ``diffusers`` extras (the metric needs a real model):
    pip install ".[api,diffusers]"
First scored request downloads SD v1-4 (~4 GB) and is slow on CPU.
"""

from __future__ import annotations

from fastapi import FastAPI
from pydantic import BaseModel

from memguard.detector import MemorizationDetector
from memguard.pipeline import DEFAULT_MODEL_ID, load_sd_pipeline

app = FastAPI(title="MemGuard", version="0.1.0")
detector = MemorizationDetector()

_pipe = None


def _get_pipe():
    """Load Stable Diffusion once (lazily) so startup/health stay cheap."""
    global _pipe
    if _pipe is None:
        _pipe = load_sd_pipeline(DEFAULT_MODEL_ID)
    return _pipe


class ScoreRequest(BaseModel):
    prompt: str
    seed: int | None = None


@app.get("/health")
def health() -> dict:
    return {"status": "ok", "version": "0.1.0", "model": DEFAULT_MODEL_ID}


@app.post("/score")
def score(req: ScoreRequest) -> dict:
    """Score a prompt for training-data memorization on Stable Diffusion v1-4."""
    kwargs = {}
    if req.seed is not None:
        import torch

        kwargs["generator"] = torch.Generator().manual_seed(int(req.seed))
    return detector.check(_get_pipe(), req.prompt, **kwargs)