All checks were successful
news-summary-bot-cicd / build_push_deploy (push) Successful in 11m18s
요약 프롬프트에 증권 애널리스트 역할을 통합하여 API 1회 호출로 시장 영향, 관련 섹터, 주목 종목, 전망을 함께 생성. 모든 필드는 단순 문자열로 유지하여 파싱 안정성 확보. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
68 lines
2.1 KiB
Python
68 lines
2.1 KiB
Python
from fastapi import FastAPI, Header, HTTPException
|
|
from pydantic import BaseModel
|
|
|
|
from app.config import settings
|
|
from app.summarizer import summarize
|
|
from app.transcript import SkipVideo, extract_video_id, fetch_transcript
|
|
|
|
app = FastAPI(title="News Summary Bot")
|
|
|
|
|
|
class SummarizeRequest(BaseModel):
|
|
video_url: str
|
|
title: str = ""
|
|
channel_name: str = ""
|
|
|
|
|
|
@app.post("/summarize")
|
|
async def summarize_video(
|
|
req: SummarizeRequest,
|
|
x_api_secret: str = Header(default=""),
|
|
):
|
|
if settings.api_secret and x_api_secret != settings.api_secret:
|
|
raise HTTPException(status_code=401, detail="Unauthorized")
|
|
|
|
title = req.title or "제목 없음"
|
|
|
|
channel_name = req.channel_name or ""
|
|
base = {"video_url": req.video_url, "title": title, "channel_name": channel_name}
|
|
|
|
try:
|
|
video_id = extract_video_id(req.video_url)
|
|
transcript = fetch_transcript(video_id)
|
|
summary = summarize(transcript, title)
|
|
except SkipVideo as e:
|
|
return {**base, "status": "skipped", "reason": str(e)}
|
|
except Exception as e:
|
|
return {
|
|
**base,
|
|
"status": "error",
|
|
"error_type": type(e).__name__,
|
|
"error_message": str(e),
|
|
}
|
|
|
|
# Discord embed description용 통합 요약
|
|
parts = []
|
|
if summary.get("oneliner"):
|
|
parts.append(f"💡 **{summary['oneliner']}**")
|
|
if summary.get("main_points"):
|
|
parts.append(f"\n📌 **주요 내용**\n{summary['main_points']}")
|
|
if summary.get("conclusion"):
|
|
parts.append(f"\n🎯 **결론**\n> {summary['conclusion']}")
|
|
if summary.get("market_impact"):
|
|
parts.append(f"\n📈 **시장 영향**\n{summary['market_impact']}")
|
|
if summary.get("sectors"):
|
|
parts.append(f"\n🏭 **관련 섹터**\n{summary['sectors']}")
|
|
if summary.get("watchlist"):
|
|
parts.append(f"\n👀 **주목 종목**\n{summary['watchlist']}")
|
|
if summary.get("outlook"):
|
|
parts.append(f"\n🔮 **전망**\n{summary['outlook']}")
|
|
summary["summary"] = "\n".join(parts)
|
|
|
|
return {**base, "status": "ok", **summary}
|
|
|
|
|
|
@app.get("/health")
|
|
async def health():
|
|
return {"status": "ok"}
|