추천 단계에 진행 표시 추가 (최대 450초 무반응 제거)
/auto/stream 은 하이라이트 5개를 순차로 돌며 각각 Gemini 를 부른다(timeout=90). manifest 에 recommend 스텝이 없고 루프 안에 로그도 없어서, 마지막으로 보이는 게 "댓글 수집 done" 이고 그 뒤 최악 450초 동안 아무 이벤트도 안 나갔다. 사용자가 멈춘 줄 알고 새로고침하면 분석이 통째로 날아간다. 순차 호출 자체는 유지한다 — 동시에 5발을 쏘면 429 가 난다(Step 3 도 같은 이유로 시차 재시도를 쓴다). 대신 보이게만 만든다: - 세 갈래 manifest(paste / wpaste / else) 전부에 recommend 스텝 추가 - 루프 앞뒤로 step start/done(detail = 처리한 하이라이트 수) - 하이라이트마다 "ID n 컷별 댓글 추천 중… (i/N, 컷 M개)" 로그 한 줄 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1e43530933
commit
4e479b50ce
@ -12,6 +12,7 @@ import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import time
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
@ -354,6 +355,7 @@ async def auto_stream(aid: str) -> StreamingResponse:
|
||||
yield _sse({"type": "manifest", "steps": [
|
||||
{"id": "parse", "label": "오팔 JSON 파싱"},
|
||||
{"id": "comments", "label": "댓글 수집 (h-lab)"},
|
||||
{"id": "recommend", "label": "컷별 댓글 추천"},
|
||||
]})
|
||||
yield _sse({"type": "step", "id": "parse", "status": "start"})
|
||||
import re as _re
|
||||
@ -427,6 +429,7 @@ async def auto_stream(aid: str) -> StreamingResponse:
|
||||
yield _sse({"type": "manifest", "steps": [
|
||||
{"id": "parse", "label": "구간 JSON 파싱"},
|
||||
{"id": "comments", "label": "댓글 수집 (h-lab)"},
|
||||
{"id": "recommend", "label": "컷별 댓글 추천"},
|
||||
]})
|
||||
yield _sse({"type": "step", "id": "parse", "status": "start"})
|
||||
try:
|
||||
@ -444,6 +447,7 @@ async def auto_stream(aid: str) -> StreamingResponse:
|
||||
if mode == "full":
|
||||
steps.append({"id": "step3", "label": "편집안 생성 (Gemini, 구간별 동시)"})
|
||||
steps.append({"id": "comments", "label": "댓글 수집 (h-lab)"})
|
||||
steps.append({"id": "recommend", "label": "컷별 댓글 추천"})
|
||||
yield _sse({"type": "manifest", "steps": steps})
|
||||
# 댓글은 URL을 이미 아니까 Step1 과 동시에 수집
|
||||
com_task = asyncio.create_task(asyncio.to_thread(hlab.fetch_comments, url))
|
||||
@ -526,13 +530,21 @@ async def auto_stream(aid: str) -> StreamingResponse:
|
||||
# 후보(candidates)는 분:초 언급이 아예 없는 댓글만 — 타임스탬프 댓글은
|
||||
# 자기 구간의 ⭐에서 잡히므로, 다른 구간 얘기하는 댓글이 섞이지 않게.
|
||||
#
|
||||
# 하이라이트마다 Gemini 를 순차로 부른다(동시 호출은 429 를 부른다 — Step 3 도 같은 이유로
|
||||
# 시차 재시도를 쓴다). 최악 5×90초라 진행 표시가 없으면 사용자가 멈춘 줄 알고 새로고침해
|
||||
# 분석이 통째로 날아간다 → 스텝 + 하이라이트별 로그를 반드시 흘린다.
|
||||
no_ts = [c for c in comments if not c["times"]]
|
||||
for h in highlights:
|
||||
if "paste" not in h:
|
||||
continue
|
||||
targets = [h for h in highlights if "paste" in h]
|
||||
yield _sse({"type": "step", "id": "recommend", "status": "start"})
|
||||
t_rec = time.perf_counter()
|
||||
for n, h in enumerate(targets, 1):
|
||||
matched = hlab.match_window(comments, h["start"], h["end"])
|
||||
h["matched"] = matched
|
||||
h["candidates"] = hlab.top_liked(no_ts, set(matched), len(no_ts))
|
||||
yield _sse({"type": "log",
|
||||
"msg": f"ID {h.get('id')} 컷별 댓글 추천 중… "
|
||||
f"({n}/{len(targets)}, 컷 "
|
||||
f"{len(h['paste'].get('cuts') or [])}개)"})
|
||||
# 컷별 추천 — 실패해도 위의 matched/candidates 로 화면이 돌아간다.
|
||||
# Gemini 호출이 섞여 있어 블로킹이므로 스레드로 뺀다.
|
||||
try:
|
||||
@ -549,6 +561,9 @@ async def auto_stream(aid: str) -> StreamingResponse:
|
||||
warnings.append(
|
||||
f"ID {h.get('id')} 컷별 추천 실패 — 기존 방식으로 표시 "
|
||||
f"({type(exc).__name__}: {exc})")
|
||||
yield _sse({"type": "step", "id": "recommend", "status": "done",
|
||||
"elapsed": round(time.perf_counter() - t_rec, 1),
|
||||
"detail": f"{len(targets)}개 하이라이트"})
|
||||
yield _sse({"type": "result", "highlights": highlights,
|
||||
"comments": comments, "warnings": warnings})
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user