feat: switch summarizer to DeepSeek API, add cookie support for transcripts
This commit is contained in:
@@ -37,6 +37,11 @@ async def startup():
|
|||||||
async def health():
|
async def health():
|
||||||
return {"status": "ok"}
|
return {"status": "ok"}
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def root():
|
||||||
|
from fastapi.responses import FileResponse
|
||||||
|
return FileResponse(os.path.join(frontend_build_path, "index.html"))
|
||||||
|
|
||||||
@app.get("/api/videos")
|
@app.get("/api/videos")
|
||||||
async def get_videos(
|
async def get_videos(
|
||||||
status: Optional[str] = "pending",
|
status: Optional[str] = "pending",
|
||||||
|
|||||||
+20
-16
@@ -10,12 +10,9 @@ from db import DB_PATH
|
|||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Fallback pattern to retrieve the correct bytecatcode credentials
|
# Fallback pattern to retrieve the correct bytecatcode credentials
|
||||||
API_KEY = os.environ.get("ANTHROPIC_API_KEY")
|
API_KEY = os.environ.get("DEEPSEEK_API_KEY", os.environ.get("OPENAI_API_KEY", ""))
|
||||||
if not API_KEY:
|
BASE_URL = os.environ.get("DEEPSEEK_BASE_URL", "https://api.deepseek.com")
|
||||||
API_KEY = os.environ.get("OPENAI_API_KEY", "sk-Kq5JbgmnEEkdzTqNAQ6bV6nztQ0ngeHTHF9Vg8nUglQvrOlx")
|
MODEL = os.environ.get("DEEPSEEK_MODEL", "deepseek-chat")
|
||||||
|
|
||||||
BASE_URL = os.environ.get("ANTHROPIC_BASE_URL", "https://www.bytecatcode.org")
|
|
||||||
MODEL = "claude-haiku-4-5-20251001"
|
|
||||||
|
|
||||||
SYSTEM_PROMPT = "You are a professional video summarizing assistant. Create highly concise, structured summaries from video transcripts. Your output must be in Chinese if the transcript is Chinese, otherwise in English."
|
SYSTEM_PROMPT = "You are a professional video summarizing assistant. Create highly concise, structured summaries from video transcripts. Your output must be in Chinese if the transcript is Chinese, otherwise in English."
|
||||||
|
|
||||||
@@ -38,6 +35,15 @@ def download_transcript(video_id: str) -> str:
|
|||||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
||||||
"Accept-Language": "en-US,en;q=0.9"
|
"Accept-Language": "en-US,en;q=0.9"
|
||||||
})
|
})
|
||||||
|
# Load cookies to bypass YouTube IP block
|
||||||
|
for p in [os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "config/cookies.txt"),
|
||||||
|
"/app/config/cookies.txt"]:
|
||||||
|
if os.path.exists(p):
|
||||||
|
from http.cookiejar import MozillaCookieJar
|
||||||
|
cj = MozillaCookieJar(p)
|
||||||
|
cj.load(ignore_discard=True, ignore_expires=True)
|
||||||
|
session.cookies.update({c.name: c.value for c in cj})
|
||||||
|
break
|
||||||
transcript_list = YouTubeTranscriptApi(http_client=session).list(video_id)
|
transcript_list = YouTubeTranscriptApi(http_client=session).list(video_id)
|
||||||
|
|
||||||
# Try to find manual transcripts in preferred languages
|
# Try to find manual transcripts in preferred languages
|
||||||
@@ -71,20 +77,18 @@ async def summarize_video(video_id: str) -> str:
|
|||||||
await db.commit()
|
await db.commit()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# 2. Call Claude API
|
# 2. Call DeepSeek API (OpenAI-compatible)
|
||||||
headers = {
|
headers = {
|
||||||
"x-api-key": API_KEY,
|
"Authorization": f"Bearer {API_KEY}",
|
||||||
"anthropic-version": "2023-06-01",
|
"Content-Type": "application/json",
|
||||||
"content-type": "application/json",
|
"User-Agent": "t-youtube/0.1"
|
||||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Standard Anthropic payload format
|
|
||||||
payload = {
|
payload = {
|
||||||
"model": MODEL,
|
"model": MODEL,
|
||||||
"max_tokens": 1000,
|
"max_tokens": 1000,
|
||||||
"system": SYSTEM_PROMPT,
|
|
||||||
"messages": [
|
"messages": [
|
||||||
|
{"role": "system", "content": SYSTEM_PROMPT},
|
||||||
{"role": "user", "content": PROMPT.format(transcript=transcript[:50000])}
|
{"role": "user", "content": PROMPT.format(transcript=transcript[:50000])}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -92,15 +96,15 @@ async def summarize_video(video_id: str) -> str:
|
|||||||
async with httpx.AsyncClient(timeout=120) as client:
|
async with httpx.AsyncClient(timeout=120) as client:
|
||||||
try:
|
try:
|
||||||
resp = await client.post(
|
resp = await client.post(
|
||||||
f"{BASE_URL}/v1/messages",
|
f"{BASE_URL}/v1/chat/completions",
|
||||||
headers=headers,
|
headers=headers,
|
||||||
json=payload
|
json=payload
|
||||||
)
|
)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
data = resp.json()
|
data = resp.json()
|
||||||
summary = data["content"][0]["text"]
|
summary = data["choices"][0]["message"]["content"]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Claude API request failed for {video_id}: {e}")
|
log.error(f"DeepSeek API request failed for {video_id}: {e}")
|
||||||
summary = f"Error generating summary: {e}"
|
summary = f"Error generating summary: {e}"
|
||||||
|
|
||||||
# 3. Save transcript & summary to db
|
# 3. Save transcript & summary to db
|
||||||
|
|||||||
Generated
+2363
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user