feat(lotto): /api/lotto/best에 5종 점수 array 노출 (agent-office sim_consensus 입력)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -645,30 +645,49 @@ def replace_best_picks(
|
|||||||
|
|
||||||
|
|
||||||
def get_best_picks(limit: int = 20) -> List[Dict[str, Any]]:
|
def get_best_picks(limit: int = 20) -> List[Dict[str, Any]]:
|
||||||
"""현재 활성화된 best_picks 조회 (점수 내림차순)"""
|
"""현재 활성화된 best_picks 조회 (점수 내림차순).
|
||||||
|
|
||||||
|
simulation_candidates와 LEFT JOIN하여 5종 점수 배열(scores)을 포함.
|
||||||
|
매칭 키: sc.run_id = bp.source_run_id AND sc.numbers = bp.numbers
|
||||||
|
LEFT JOIN 미매칭(NULL) 시 scores는 [0.0, 0.0, 0.0, 0.0, 0.0] 반환.
|
||||||
|
"""
|
||||||
with _conn() as conn:
|
with _conn() as conn:
|
||||||
rows = conn.execute(
|
rows = conn.execute(
|
||||||
"""
|
"""
|
||||||
SELECT id, numbers, score_total, rank_in_run, source_run_id, based_on_draw, created_at
|
SELECT bp.id, bp.numbers, bp.score_total, bp.rank_in_run,
|
||||||
FROM best_picks
|
bp.source_run_id, bp.based_on_draw, bp.created_at,
|
||||||
WHERE is_active = 1
|
sc.score_frequency, sc.score_fingerprint,
|
||||||
ORDER BY score_total DESC
|
sc.score_gap, sc.score_cooccur, sc.score_diversity
|
||||||
|
FROM best_picks bp
|
||||||
|
LEFT JOIN simulation_candidates sc
|
||||||
|
ON sc.run_id = bp.source_run_id
|
||||||
|
AND sc.numbers = bp.numbers
|
||||||
|
WHERE bp.is_active = 1
|
||||||
|
ORDER BY bp.score_total DESC
|
||||||
LIMIT ?
|
LIMIT ?
|
||||||
""",
|
""",
|
||||||
(limit,),
|
(limit,),
|
||||||
).fetchall()
|
).fetchall()
|
||||||
return [
|
result = []
|
||||||
{
|
for r in rows:
|
||||||
|
scores = [
|
||||||
|
float(r["score_frequency"] or 0.0),
|
||||||
|
float(r["score_fingerprint"] or 0.0),
|
||||||
|
float(r["score_gap"] or 0.0),
|
||||||
|
float(r["score_cooccur"] or 0.0),
|
||||||
|
float(r["score_diversity"] or 0.0),
|
||||||
|
]
|
||||||
|
result.append({
|
||||||
"id": int(r["id"]),
|
"id": int(r["id"]),
|
||||||
"numbers": json.loads(r["numbers"]),
|
"numbers": json.loads(r["numbers"]),
|
||||||
"score_total": r["score_total"],
|
"score_total": r["score_total"],
|
||||||
|
"scores": scores,
|
||||||
"rank_in_run": r["rank_in_run"],
|
"rank_in_run": r["rank_in_run"],
|
||||||
"source_run_id": r["source_run_id"],
|
"source_run_id": r["source_run_id"],
|
||||||
"based_on_draw": r["based_on_draw"],
|
"based_on_draw": r["based_on_draw"],
|
||||||
"created_at": r["created_at"],
|
"created_at": r["created_at"],
|
||||||
}
|
})
|
||||||
for r in rows
|
return result
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_simulation_runs(limit: int = 10) -> List[Dict[str, Any]]:
|
def get_simulation_runs(limit: int = 10) -> List[Dict[str, Any]]:
|
||||||
|
|||||||
@@ -435,6 +435,7 @@ def api_best_picks(limit: int = 20):
|
|||||||
"rank": p["rank_in_run"],
|
"rank": p["rank_in_run"],
|
||||||
"numbers": nums,
|
"numbers": nums,
|
||||||
"score_total": p["score_total"],
|
"score_total": p["score_total"],
|
||||||
|
"scores": p["scores"],
|
||||||
"based_on_draw": p["based_on_draw"],
|
"based_on_draw": p["based_on_draw"],
|
||||||
"simulation_run_id": p["source_run_id"],
|
"simulation_run_id": p["source_run_id"],
|
||||||
"created_at": p["created_at"],
|
"created_at": p["created_at"],
|
||||||
|
|||||||
Reference in New Issue
Block a user