불러오는 중…
경기 시작 전까지만 투표할 수 있습니다. 한 경기에 한 번이고, 다시 누르면 바꿉니다. 상금도 참가비도 없는 참여형 예측입니다 — 이 서비스는 배당을 만들지 않습니다.
불러오는 중…
LP 내림차순입니다. 이름을 누르면 그 유저의 최근 경기를 10분 시점으로 분석합니다. 랭킹은 주기적으로 갱신한 스냅샷이라 실시간 순위와 다를 수 있습니다.
10분 시점 경기 상태(블루−레드 차이 13개)를 JSON 으로 보내면 블루팀 승리 확률 · 승리요인 · 이상탐지 · 코칭을 돌려주는 독립 HTTP 서버입니다. 어느 언어에서든 부를 수 있고, 이 화면과 같은 모델을 씁니다.
https://p4.sumzip.com/model-api
python lol_model_api_client.py 로 바로 확인.POST /predict 본문 그대로.POST /predict/batch 본문 그대로.브라우저에서 바로 호출해 보려면 Swagger UI · 읽기용 문서는 ReDoc 입니다.
| 메서드 · 경로 | 무엇을 하나 | 입력 | 응답 (200) |
|---|---|---|---|
GET /health | 판단할 준비가 됐는지 | — | status ok / loading · model_version |
GET /schema | 입력 13개의 뜻 · 형 · 학습 범위 | — | 입력 폼을 만들 때 쓰는 원문 |
GET /examples | 예시 입력 3건 | — | [{id, label, payload}] |
POST /predict | 한 경기를 판단 | 피처 13개 객체 | label · win_prob_blue · top_factors · anomaly · warnings |
POST /predict/batch | 여러 경기를 한 번에 (1~32건) | {"items": [...]} | {"results": [...], "count": n} 입력 순서 유지 |
POST /coach | 무엇을 했다면 승률이 얼마나 올랐나 | 피처 13개 (+ 선택 verdict) | actions 3개 · how_to_read |
GET /metrics | 운영 지표 | — | 요청 수 · 오류율 · p95 지연 · 보류율 · 라벨 분포 |
GET /docs · /redoc · /openapi.json | Swagger · ReDoc · OpenAPI 명세 | — | HTML · JSON |
| 피처 | 뜻 | 형 · 받는 범위 |
|---|---|---|
FirstBlood | 첫 킬을 블루가 가졌나 | 0 또는 1 |
KillsDiff | 킬 차이 | 정수 −50~50 |
GoldDiff | 골드 차이 | 정수 −30000~30000 |
ExpDiff | 경험치 차이 | 정수 −30000~30000 |
WardsPlacedDiff | 와드 설치 차이 | 정수 −500~500 |
WardsDestroyedDiff | 와드 제거 차이 | 정수 −100~100 |
AssistsDiff | 어시스트 차이 | 정수 −100~100 |
DragonsDiff | 드래곤 차이 | 정수 −1~1 |
HeraldsDiff | 전령 차이 | 정수 −1~1 |
TowersDestroyedDiff | 타워 파괴 차이 | 정수 −11~11 |
AvgLevelDiff | 평균 레벨 차이 | 실수 −10~10 |
TotalMinionsKilledDiff | 미니언(CS) 차이 | 정수 −500~500 |
TotalJungleMinionsKilledDiff | 정글 몬스터 차이 | 정수 −300~300 |
13개가 전부 있어야 하고 모르는 키는 거부합니다(422). «받는 범위» 안이지만 학습 범위 밖이면 200 으로 답하되 warnings 에 적습니다.
POST /predict{
"label": "블루 승리 예측", // 블루 승리 예측 · 레드 승리 예측 · 판단보류(확률이 0.5±0.10 안인 접전)
"win_prob_blue": 0.9461, // 0~1
"pred": 1, // win_prob_blue ≥ 0.5 이면 1
"top_factors": [ // 5개, 기여도 절대값 내림차순
{"feature": "GoldDiff", "name": "골드(돈) 차이", "value": 4500.0, "contribution": 2.24, "direction": "블루에 유리"}
],
"anomaly": {"is_anomaly": false, "score": 0.53, "percentile": 93.7, "label": "…", "unusual_features": []},
"warnings": [], // 비어 있으면 정상. 있으면 사용자에게 그대로 보여주세요
"model_version": "lolwin-1.0"
}
| HTTP | 언제 | 본문 |
|---|---|---|
| 422 | 피처 누락 · 모르는 키 · 형 오류 · 범위 밖 · 배치 33건 이상 | {"detail": [{"loc": ["body","GoldDiff"], "msg": "Field required"}]} |
| 401 | 키 검사가 켜진 서버에 X-API-Key 가 없거나 틀림 | {"detail": "..."} |
| 503 | 모델 적재 중 (기동 직후 1~2초) | 잠시 후 재시도 |
| 500 | 서버 내부 오류 | 응답 헤더 X-Request-ID 로 로그 추적 |
BASE=https://p4.sumzip.com/model-api
curl -s $BASE/health
curl -s -X POST $BASE/predict -H 'Content-Type: application/json' \
-d '{"FirstBlood":1,"KillsDiff":5,"GoldDiff":4500,"ExpDiff":3000,"WardsPlacedDiff":5,"WardsDestroyedDiff":2,"AssistsDiff":6,"DragonsDiff":1,"HeraldsDiff":1,"TowersDestroyedDiff":1,"AvgLevelDiff":1.2,"TotalMinionsKilledDiff":30,"TotalJungleMinionsKilledDiff":10}'
curl -s -X POST $BASE/predict/batch -H 'Content-Type: application/json' -d @request_batch.json
import json, urllib.request
BASE = "https://p4.sumzip.com/model-api"
def predict(state: dict) -> dict:
req = urllib.request.Request(f"{BASE}/predict", data=json.dumps(state).encode(),
headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=10) as r: # 422·503 은 HTTPError 로 옵니다
return json.loads(r.read())
r = predict({"FirstBlood": 1, "KillsDiff": 5, "GoldDiff": 4500, "ExpDiff": 3000,
"WardsPlacedDiff": 5, "WardsDestroyedDiff": 2, "AssistsDiff": 6,
"DragonsDiff": 1, "HeraldsDiff": 1, "TowersDestroyedDiff": 1,
"AvgLevelDiff": 1.2, "TotalMinionsKilledDiff": 30, "TotalJungleMinionsKilledDiff": 10})
print(r["label"], r["win_prob_blue"], r["top_factors"][0]["name"])
const BASE = "https://p4.sumzip.com/model-api"; // 이 화면 안에서는 "/model-api" 처럼 경로만 써도 됩니다
const [example] = await (await fetch(`${BASE}/examples`)).json();
const r = await fetch(`${BASE}/predict`, {
method: "POST", headers: {"Content-Type": "application/json"},
body: JSON.stringify(example.payload),
});
if (r.status === 422) console.error(await r.json()); // 입력 문제 — detail 에 어느 필드인지 있습니다
else { const d = await r.json(); console.log(d.label, d.win_prob_blue); }
아래 본문이 그대로 POST /model-api/predict 로 나갑니다. 숫자를 바꿔 보세요.
GET /health 가 ok 일 때만 판단 요청을 보냅니다. loading 이면 잠시 후 재시도.label 이 판단보류면 «접전»이라고 함께 알립니다. 확률만 보여주면 51% 가 확신처럼 읽힙니다.warnings 가 있으면 사용자에게 그대로 보여줍니다. 믿을지 말지는 쓰는 쪽이 정합니다.top_factors[].contribution 을 «이 지표를 올리면 이긴다»로 옮기지 않습니다. 처방이 필요하면 POST /coach./predict/batch 로 32건씩. 건당 약 10 ms 입니다.외부 도메인의 브라우저에서 직접 부르려면 서버 설정 CORS_ORIGINS 에 그 오리진이 있어야 합니다. 서버 간 호출(curl·Python)은 제약이 없습니다.
호출자 구분이 필요하면 API_KEYS 를 켜고 X-API-Key 헤더를 씁니다.
10분에 앞섰나 밀렸나, 그리고 이겼나 졌나 — 두 가지를 교차하면 네 갈래가 됩니다.
| 이겼다 | 졌다 | |
|---|---|---|
| 10분에 앞섬 | ▲ 우세승 앞서서 그대로 이김 — 가장 이상적 | ↘ 역전패 앞서고도 짐 — 먼저 다시 볼 판 |
| 10분에 밀림 | ↗ 역전승 밀렸는데 뒤집음 — 후반 집중력 | ▼ 열세패 밀린 채 그대로 짐 — 시작이 문제 |
같은 패배라도 처방이 정반대입니다 — 열세패는 10분까지 버티는 법을, 역전패는 앞선 판을 끝내는 법을 고쳐야 합니다. 이 구분은 10분 시점 승률을 계산할 수 있어야만 나옵니다.
불러오는 중…
마스터 이상 솔로랭크에서 실제로 관찰된 승률입니다. 우리 모델의 예측이 아니고, "이 챔피언을 하면 이긴다"는 뜻도 아닙니다 — 잘하는 사람이 고르는 챔피언일 수도 있습니다.
숨기지 않고 그대로 보여드립니다 — 저희가 잘 맞히는 판과 자주 틀리는 판.
불러오는 중…
전부 블루 − 레드 차이값. 양수면 블루가 앞선 것입니다. 감이 안 오시면 아래 버튼을 누르세요 — 실제 있을 법한 수치가 채워집니다. 고쳐서 판정해도 됩니다.