eunzzang's picture
chore: sync space contents
2c1dae0
|
Raw
History Blame Contribute Delete
5.25 kB

API ๋ช…์„ธ์„œ (v1)

Base URL

/api/v1

์š”์•ฝ

  • ์ฃผ์š” ๋ฆฌ์†Œ์Šค: /posts, /predict, /uploads, /stats
  • ์‘๋‹ต ํฌ๋งท: JSON (HTML ํŽ˜์ด์ง€๋Š” ์›น ๋ผ์šฐํŠธ๋กœ ๋ณ„๋„ ์ œ๊ณต)
  • ํ•„๋“œ ๋„ค์ด๋ฐ: snake_case
  • ๋‚ ์งœ/์‹œ๊ฐ„: ISO 8601 (์˜ˆ: 2026-04-28T12:34:56Z)

๊ณตํ†ต ์—๋Ÿฌ ์‘๋‹ต (์˜ˆ์‹œ)

{
  "success": false,
  "error": {
    "code": 400,
    "message": "Bad Request",
    "details": null
  }
}

์ธ์ฆ / Rate limiting

  • ์ธ์ฆ: ์„ ํƒ(์˜ˆ: JWT Authorization: Bearer ), ํ•„์š”ํ•œ ์—”๋“œํฌ์ธํŠธ์— ํ‘œ๊ธฐ
  • Rate limit: ์˜ˆ์‹œ - 60 requests/min (๋ฌธ์„œํ™” ๊ถŒ์žฅ)

๋ชจ๋ธ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(๊ถŒ์žฅ ์‘๋‹ต ํ•„๋“œ)

  • model_name, model_version, inference_time_ms

1. ์›น ํŽ˜์ด์ง€ ๋ผ์šฐํŒ… (HTML)

(์›น ์„œ๋ฒ„ ํ…œํ”Œ๋ฆฟ์šฉ; API Base URL ์ ์šฉ ์—†์Œ)

  • GET / โ†’ 200 HTML (index.html)
  • GET /board โ†’ 200 HTML (board.html)
  • GET /posts/{post_id} โ†’ 200 HTML (post detail)

2. ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜ API (routers/predict.py)

[POST] ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜

POST /api/v1/predict Headers:

  • Content-Type: multipart/form-data Request (form-data):
  • file: (required) image file, field name file (max 10MB, allowed: .jpg, .jpeg, .png) Response 200:
{
  "success": true,
  "filename": "cat.jpg",
  "predicted_class": "cat",
  "confidence": 0.9821,
  "top_k": [
    {"label":"cat","score":0.9821},
    {"label":"dog","score":0.0121}
  ],
  "model": {
    "name": "classifier",
    "version": "v1.0.0"
  },
  "inference_time_ms": 123
}

Errors:

  • 400: missing file / invalid file type
  • 413: payload too large
  • 500: model inference failure

[POST] ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ + ๋ถ„๋ฅ˜ + ๊ฒŒ์‹œ๊ธ€ ์ž๋™ ์ƒ์„ฑ

POST /api/v1/predict/upload Headers:

  • Content-Type: multipart/form-data Request (form-data):
  • title: string (required)
  • content: string (optional)
  • image: file (required) field name image Response 201:
{
  "success": true,
  "post_id": 15,
  "prediction": "cat",
  "confidence": 0.98,
  "model": {"name":"classifier","version":"v1.0.0"}
}

[GET] ๋ชจ๋ธ ๋ผ๋ฒจ ๋ชฉ๋ก

GET /api/v1/predict/labels Response 200:

{
  "classes": ["cat","dog","car","person"]
}

3. ๊ฒŒ์‹œ๊ธ€ API (routers/post.py)

[GET] ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก (ํŽ˜์ด์ง•/ํ•„ํ„ฐ)

GET /api/v1/posts Query params:

  • page: int (default 1)
  • size: int (default 10)
  • category: string (optional) Response 200:
{
  "items": [
    {
      "id": 1,
      "title": "๊ณ ์–‘์ด ๋ถ„๋ฅ˜ ์„ฑ๊ณต",
      "prediction": "cat",
      "confidence": 0.98,
      "created_at": "2026-04-28T12:00:00Z"
    }
  ],
  "page": 1,
  "size": 10,
  "total": 34
}

[GET] ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ธ

GET /api/v1/posts/{id} Response 200:

{
  "id": 1,
  "title": "๊ณ ์–‘์ด ๋ถ„๋ฅ˜ ์„ฑ๊ณต",
  "content": "ํ…Œ์ŠคํŠธ ๊ธ€",
  "image_url": "/uploads/cat.jpg",
  "prediction": "cat",
  "confidence": 0.98,
  "created_at": "2026-04-28T12:00:00Z"
}

404: post not found

[POST] ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ฑ

POST /api/v1/posts Headers:

  • Content-Type: application/json Request body:
{
  "title":"์ƒˆ ๊ฒŒ์‹œ๊ธ€",
  "content":"๋‚ด์šฉ",
  "image_url":"/uploads/sample.jpg",
  "prediction":"cat",
  "confidence":0.95
}

Response 201:

{"success": true, "id": 123}

Validation: title required, image_url optional, confidence 0.0-1.0

[PUT] ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •

PUT /api/v1/posts/{id} Request body (partial ํ—ˆ์šฉ):

{"title":"์ˆ˜์ • ์ œ๋ชฉ","content":"์ˆ˜์ • ๋‚ด์šฉ"}

Response 200: {"success": true}

[DELETE] ๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ

DELETE /api/v1/posts/{id} Response 200:

{"success": true, "message": "์‚ญ์ œ ์™„๋ฃŒ"}

4. ์ข‹์•„์š” / ์ถ”์ฒœ

POST /api/v1/posts/{id}/like Response 200:

{"success": true, "likes": 12}

5. ํ†ต๊ณ„ API (๋Œ€์‹œ๋ณด๋“œ์šฉ)

GET /api/v1/stats/classes Query params (optional):

  • start_date, end_date (ISO 8601) Response 200:
{"cat":34,"dog":20,"car":14}

๋ฐ์ดํ„ฐ/์‘๋‹ต ์Šคํ‚ค๋งˆ (schemas.py)

PostCreate

  • title: string (required)
  • content: string (optional)
  • image_url: string (optional, ๊ฒฝ๋กœ)
  • prediction: string (optional)
  • confidence: float (0.0 - 1.0, optional)

PostResponse

  • id: int
  • title: string
  • content: string
  • image_url: string
  • prediction: string
  • confidence: float
  • created_at: datetime (ISO 8601)

PredictResponse

  • success: bool
  • filename: string
  • predicted_class: string
  • confidence: float
  • top_k: [{label: string, score: float}]
  • model: {name:string, version:string}
  • inference_time_ms: int

ErrorResponse

  • success: false
  • error: {code:int, message:string, details:object|null}

๊ตฌํ˜„/์šด์˜ ๊ถŒ์žฅ์‚ฌํ•ญ

  • ๋ชจ๋“  API๋Š” /api/v1/ ์ ‘๋‘์‚ฌ๋ฅผ ์‚ฌ์šฉํ•ด ๋ฒ„์ „ ๊ด€๋ฆฌ
  • ์š”์ฒญ/์‘๋‹ต ์˜ˆ์‹œ๋Š” OpenAPI(Swagger)๋กœ ์ž‘์„ฑํ•ด ์ž๋™ ๋ฌธ์„œํ™” ๊ถŒ์žฅ
  • ํŒŒ์ผ ์—…๋กœ๋“œ๋Š” ์ €์žฅ์†Œ ์šฉ๋Ÿ‰, ํ™•์žฅ์ž ๊ฒ€์‚ฌ, ์•…์„ฑ ํŒŒ์ผ ๊ฒ€์‚ฌ ๊ตฌํ˜„
  • ๋ฏผ๊ฐํ•œ ํŒŒ์ผ ์—…๋กœ๋“œ๋Š” ์ธ์ฆ/ACL ์ ์šฉ
  • ๋ชจ๋ธ ๋ฒ„์ „ ๊ด€๋ฆฌ ๋ฐ A/B ํ…Œ์ŠคํŠธ ๋กœ๊ทธ ๋‚จ๊ธฐ๊ธฐ
  • ์ž์„ธํ•œ ๋กœ๊น…(์š”์ฒญ id, inference time, model version)์œผ๋กœ ๋ฌธ์ œ ์ถ”์ 