| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- import type { TemplateType } from "../../constants.js";
- export function getParsePrompt(
- template: TemplateType,
- source?: string
- ): string {
- const base = `You are a video script structuring assistant. Convert the input text into a JSON object for video generation.
- The output JSON must follow this exact schema:
- {
- "title": "string — video title, concise and catchy",
- "summary": "string — one-sentence summary",
- "trendSummary": "string — OPTIONAL, github-trending only. One short sentence (≤30 chars) synthesizing the day's overall trend. Omit for other templates.",
- "publish": "object — OPTIONAL, github-trending only. Posting metadata for the video page: { title, description, tags[] }. See template-specific rules. Omit for other templates.",
- "scenes": [
- {
- "id": "scene-N",
- "index": 0,
- "narration": "string — the voiceover text for this scene (Chinese, natural and conversational)",
- "displayText": "string — optional, the text to display on screen (omit if same as narration; use when narration includes a greeting that should not appear visually)",
- "keyframes": [
- { "type": "text|highlight|image|icon|transition", "content": "string" }
- ],
- "images": "array — optional, image references. Entries may use { path } for local files, { url } for remote URLs, or { repoSocialPreview: \"owner/name\" } for GitHub repo social preview cards (only used by github-trending template).",
- "github": "object — optional, only for github-trending template. Shape: { repo: { owner, name, fullName, language, languageColor, stars, forks, license, todayStars }, highlights, intro, review }. See template-specific rules.",
- "durationHint": 10,
- "backgroundQuery": "string — describe the ideal background image",
- "layoutHint": "full-text|split|centered|bullet-list"
- }
- ],
- "outro": {
- "text": "string — closing message (e.g. 感谢观看, 今天的内容就到这里)",
- "narration": "string — voiceover for outro (optional, defaults to text)",
- "cta": "string — call-to-action (e.g. 点赞关注, 订阅获取更多)"
- },
- "globalStyle": {
- "tone": "formal|casual|energetic|calm",
- "pace": "slow|normal|fast",
- "targetDuration": 60
- }
- }
- Rules:
- - Each scene should be 5-15 seconds of narration
- - narration must be under 200 characters per scene — if content is long, split it into more scenes rather than making narration too long
- - narration should be natural spoken Chinese, suitable for TTS
- - Split the content into 3-8 scenes depending on length
- - keyframes should highlight the main visual points
- - The first scene's narration may include a brief greeting (e.g. "大家好,"), but set displayText to the content without the greeting — the greeting should only be heard, not shown as main text
- - The last content scene should NOT include a conclusion or closing — outro handles that
- - outro.text should be a short, natural closing (10-30 characters)
- - outro.cta should encourage audience engagement
- CRITICAL — Text content restrictions:
- - All visible-text fields (title, summary, narration, displayText, keyframes[].content, outro.text, outro.cta) must contain ONLY plain text characters: Chinese characters, English letters, Arabic numerals, standard Chinese/English punctuation (。,!?、;:""''()【】《》 .,!?:;"'()-/), and regular spaces/newlines.
- - NEVER use emoji (🚀💻🔥 etc.), dingbats (★✓✗), arrows (→←↑↓), or any decorative Unicode symbols. These render as missing-glyph boxes (tofu) in the video because the font only covers plain CJK + Latin text. If you feel tempted to add a symbol, use plain punctuation instead (e.g. write "->" or "—" instead of "→").`;
- const templateSpecific: Record<TemplateType, string> = {
- news: `
- Template: News Report (资讯报道)
- - Use a formal, authoritative tone
- - First scene: headline + key fact intro
- - Middle scenes: key facts, data points, quotes from sources
- - Last scene: implications or future outlook (do NOT summarize or conclude — outro handles closing)
- - layoutHint preference: "split" for data, "full-text" for quotes`,
- knowledge: `
- Template: Knowledge Explanation (知识讲解)
- - Use a calm, educational tone
- - First scene: topic introduction + why it matters
- - Middle scenes: step-by-step explanation with clear logic
- - Last scene: final insight or extension (do NOT summarize — outro handles closing)
- - layoutHint preference: "centered" for key concepts, "bullet-list" for steps`,
- opinion: `
- Template: Opinion Sharing (观点分享)
- - Use a casual, conversational tone
- - First scene: hook + personal stance
- - Middle scenes: arguments, examples, counterpoints
- - Last scene: final thought or reflection (do NOT conclude — outro handles closing)
- - layoutHint preference: "centered" for quotes, "full-text" for arguments`,
- marketing: `
- Template: Product Marketing (产品营销)
- - Use an energetic, persuasive tone
- - First scene: pain point / hook
- - Middle scenes: product features, benefits, social proof
- - Last scene: strongest benefit or proof (do NOT add CTA — outro handles CTA)
- - layoutHint preference: "split" for features, "centered" for highlights`,
- "github-trending": `
- Template: GitHub Trending Showcase (GitHub 每日热榜)
- - Use a pragmatic, factual tone for a developer audience — no hype, no marketing fluff.
- - Each repository produces EXACTLY ONE scene.
- - Do not create overview, summary, or trend-overview SCENES. The opening title screen (cover) is built by the pipeline; it does not need a scene. Instead, convey the day's overall theme via the two top-level cover metadata fields below. Each repo scene MUST focus on its own repo.
- - The output for this template relies on structured metadata embedded in the input. Treat that metadata as authoritative — DO NOT paraphrase or invent values.
- COVER METADATA (github-trending only — emit this TOP-LEVEL field alongside title/summary; omit it for every other template):
- - trendSummary: one short sentence (≤30 chars) synthesizing the overall trend across today's repos — what theme is hot or emerging. Must read as an editorial insight, NOT a restatement of the repo list or a generic filler. Example: "AI Agent 与代码智能工具持续升温". Plain CJK/ASCII only.
- PUBLISH METADATA (github-trending only — emit this TOP-LEVEL \`publish\` object alongside title/summary; omit it for every other template). These fields become the video's posting metadata on the target platform (Bilibili/Douyin 简介与标签), NOT anything shown in the video itself:
- - publish.title: a catchy POSTING title for the video page. It MUST be distinct from the fixed cover masthead "GitHub 每日热榜" — weave in the day's overall trend or the single most notable repo. ≤ 40 chars. Example: "GitHub 今日热榜:AI Agent 与代码工具持续升温". Plain CJK/ASCII only.
- - publish.description: a 1–3 sentence video 简介 summarizing which repos/themes today's video covers and why a developer should watch. ≤ 200 chars. Plain CJK/ASCII only.
- - publish.tags: 3–8 话题 tags as an array of short strings, each ≤ 12 chars (e.g. ["GitHub","开源","AI Agent","编程","前端"]). Plain CJK/ASCII only.
- PER-REPO SCENE STRUCTURE (mandatory for every repo scene):
- displayText: the repo's fullName (e.g. "facebook/react"). Nothing else.
- github.repo: COPY the contents of the corresponding "<!-- repo-meta: ... -->" block from the input VERBATIM into scene.github.repo. Do not drop fields, do not rename keys, do not reformat numbers (keep stars as an integer). If license is empty string, keep it as empty string — the template will skip the license tag. If the repo-meta block omits todayStars but the repo's text contains a "Today: +N" line, extract the integer N and set github.repo.todayStars to it.
- images: array of EXACTLY TWO entries, copied from the corresponding "<!-- repo-images: ... -->" block:
- 1. { "repoSocialPreview": "owner/name" } — DO NOT expand this into a URL. The assets stage resolves it.
- 2. { "url": "https://api.star-history.com/svg?repos=owner/name&type=Date" } — copy the starHistory URL verbatim.
- Order matters: social preview first, star history second.
- github.highlights (项目亮点): one short phrase, ≤ 30 Chinese characters, naming the single most distinctive technical capability or signal. Example: "声明式 UI + 虚拟 DOM,生态最大". No filler ("这是一个强大的..."), no marketing adjectives, no language mention unless language IS the value proposition.
- github.intro (项目介绍): a DETAILED, multi-sentence project description, up to 200 Chinese characters. Aim for the upper end of the budget — the goal is comprehensive coverage, not brevity. Cover: what the project actually does (concrete capabilities, not category labels), the problem it solves and for whom, 1-2 distinguishing mechanisms or technical choices (e.g. "用 Rust 实现", "采用 CRDT 算法", "基于 MCP 协议"), notable ecosystem signals (contributors, recent activity, adoption) if space allows, and the typical workflow or integration pattern. Pull specifics from the README — names of features, numbers, comparisons — rather than restating the headline. Stay factual; do NOT include a language bullet unless language IS the value proposition.
- github.review (点评推荐): one short recommendation, ≤ 30 Chinese characters, naming the target user / scenario or a one-line verdict. Example: "适合追求极致启动速度的 CLI 与服务端场景". Stay neutral — avoid superlatives like "最强" or "神器".
- narration (口播): ≤ 200 characters. Cover what the project does (deeper than intro), why it is notable today (timing / trend / adoption), and one distinctive characteristic a developer cares about. Pack specifics — numbers, comparisons, concrete use cases. Do NOT include a language bullet unless language is core to the value; do NOT read out the GitHub URL.
- GREETING RULE (overrides the base prompt's first-scene greeting rule): the cover scene for this template already opens with a greeting ("大家好,…"), so EVERY content scene's narration — including the first repo scene — MUST NOT begin with any of the following:
- - A greeting: "大家好", "各位", "哈喽", "嗨", time-of-day greetings.
- - A show-opener that references the day, show, or format: "今天是GitHub热榜速览", "今天为大家带来...", "今天给大家介绍...", "本期节目...", "本周热榜...", "欢迎收看...".
- - Any meta lead-in. The narration must start DIRECTLY with project content (e.g. "首先要聊的是 React...", "接下来这个项目...", "React 是一款声明式 UI 库...").
- PROJECT NAME RULE: in narration, refer to each project by its SHORT repo name only (e.g. "React", "next.js", "bun"). NEVER read the owner/author prefix ("Facebook", "openai", "facebook/react") — the owner already appears on the GitHub 地址 card, and reading it aloud in a brief intro adds no information and can cause ambiguity (it is unclear whether you mean the person/org or the project). This applies to narration only; displayText and keyframe cards keep the owner/name form.
- CHARACTER LIMITS ARE STRICT — exceeding them breaks the layout. If content does not fit, drop the least important detail rather than compressing into a longer sentence.
- Number formatting: stars/forks/etc. always render with lowercase k suffix when ≥ 1000 (e.g. 1234 → "1.2k", 12345 → "12.3k", 123456 → "123k"). Values under 1000 stay as plain integers. The collector already formats them in markdown text, but when you write counts into github.highlights / intro / review / narration yourself, apply the same rule.
- FORBIDDEN: emoji, arrows, dingbats, decorative unicode. Plain CJK + ASCII only.`,
- };
- const githubProjectIntroRule = `
- Per-project scene structure (applies to EVERY GitHub repository you introduce):
- OVERLAP RULE (most important): the headline (displayText) and the content (keyframe cards + narration) must have MINIMAL semantic overlap. The headline stays short and abstract; the cards and narration carry the actual detail. Do NOT make the headline echo what the 功能简介 card already says.
- A. Project name + ultra-short category → displayText (the prominent on-screen headline)
- Format: "{owner}/{repo}" OR "{owner}/{repo} — {极简类别,2-5 字}".
- Examples (good): "facebook/react", "vercel/next.js — 应用框架", "openai/whisper — 语音识别", "oven-sh/bun — JS 运行时".
- The category tag (if present) must be ≤ 5 Chinese characters and stay at the level of "what kind of thing" (UI 库 / 框架 / CLI 工具 / 运行时 / 数据库 / 编辑器 / AI 模型). NEVER expand it into a one-line positioning sentence like "声明式用户界面库" — that level of detail belongs in the 功能简介 card. The headline ALREADY carries the project name; do NOT repeat it inside keyframe cards.
- B. Keyframe cards (4 cards ideally, 3-4 acceptable). Pick content that ADDS value beyond the headline.
- These 3 cards are MANDATORY for every project:
- - 功能简介 (what it actually does): format "功能:{2-4 句话具体说明这个工具能做什么、解决什么问题、有什么核心能力}". Example: "功能:声明式组件化 UI 构建方式,状态变化自动驱动视图更新,虚拟 DOM 优化渲染性能,适合处理复杂交互的 Web 应用". This must be DENSE and SPECIFIC — describe the actual capability, the problem it solves, and 1-2 distinguishing mechanisms. Do NOT parrot the headline category (e.g. if the headline already says "UI 库", this card must NOT just say "是一个 UI 库" — explain HOW it works and what makes it different).
- - GitHub 地址: format "github.com/{owner}/{repo}". Display-only — narration should NOT spell out the URL, just refer to the project by name.
- - 使用场景: format "使用场景:{目标用户 / 典型场景 / 不适用场景可选}". Example: "使用场景:中大型 Web 应用、组件化 UI 开发;不适合简单静态页面".
- Then ADD 1-2 of the following cards to enrich the scene (do not leave the scene with only the 3 mandatory cards unless the project truly has no extra distinctive information):
- - 核心特性 / 关键卖点: e.g. "特性:虚拟 DOM、单向数据流、Hooks"
- - 数据信号: e.g. "Stars: 12.3k · 今日 +120" (only stars / growth — NEVER include programming language)
- - 快速上手: e.g. "安装:npm i react react-dom"
- - 知名采用: e.g. "采用:Facebook、Netflix、Airbnb"
- - 生态地位: e.g. "生态:最主流的前端框架之一"
- - 对比优势: e.g. "对比:相比 Vue,生态更成熟;相比 Angular,学习曲线更平缓"
- FORBIDDEN card content — these add no value for a developer audience, NEVER put them on a card:
- - Programming language (语言 / Language) as its own information item — e.g. "语言:TypeScript" is forbidden. The language only matters if it IS the value proposition (e.g. "Rust 写的高性能 HTTP 服务器"), in which case it belongs inside 功能简介 or narration, not on its own card.
- - 技术栈 (tech stack) as a generic label — too vague to be useful.
- - 协议 / License, repo size, file count, fork count on its own — these are visible on GitHub and waste a card slot.
- - Any card that just restates the displayText category (e.g. headline "UI 库" + card "类型:UI 库") — that is pure overlap and wastes a card slot.
- Number formatting rule (STRICT): whenever a count >= 1000 appears (stars, forks, contributors, today's growth, etc.), display it with a lowercase k suffix, NOT the raw integer. Examples: 1234 → "1.2k", 12345 → "12.3k", 123456 → "123k", 1234567 → "1235k", 999 → "999" (unchanged). NEVER use the m suffix — counts stay in k even past one million. The input text from the collector is already in this format — preserve it; if you ever compute or restate a count yourself, apply the same formatting before writing it into a card.
- C. 详细描述 → narration (口播)
- Must be information-dense within the 200-char limit. Cover: what the project does (deeper than the headline), why it is notable, and 1-2 distinctive characteristics a developer would care about. Pack specifics — numbers, comparisons, concrete use cases — instead of filler phrases. Refer to the project by its SHORT repo name only — do NOT read the owner/author in narration (e.g. say "React", not "Facebook 的 React" or "facebook/react"); the owner is already shown on the GitHub 地址 card, and reading it aloud can cause ambiguity. Do NOT include a language bullet; mention the language only in passing if it is core to the value (e.g. "用 Rust 实现,启动速度比 Node 同类快数倍").
- If the content does not fit in 200 chars, split the project across 2 scenes — first scene uses the structure above with concise narration; second scene expands with deeper detail on features, comparisons, or ecosystem.
- A typical single-project scene therefore looks like: short displayText (项目名 [+ 极简类别]) + 3 mandatory keyframe cards (功能简介 / GitHub 地址 / 使用场景) + 1-2 value-add cards + dense narration (口播详细描述).
- For multi-project sources, EACH project scene follows this same structure independently — do not mix two projects into one scene.`;
- const sourceSpecific: Record<string, string> = {
- "github-trending": `
- Data source: GitHub Trending (热门仓库列表)
- - The input is a list of multiple trending repositories. Treat it as a roundup.
- - Select EXACTLY the 6 repos with the highest today's star gain (github.repo.todayStars, mirrored by the 'Today: +N' line), in descending order. Produce one scene per repo in that order so the video follows the same ranking shown on the cover. If the input has fewer than 6 repos, use all of them.
- - One scene per repo. EVERY repo scene MUST follow the per-project scene structure below (headline + mandatory 功能简介 / GitHub 地址 / 使用场景 cards + optional value-add card + detailed narration).
- - Connect repos with a short narrative thread between scenes if there's a shared theme (e.g. "今天 AI Agent 持续火热"), but each project scene stands on its own.
- - Tone: pragmatic, factual, no hype. The audience is developers.
- ${githubProjectIntroRule}`,
- "github-repo": `
- Data source: Single GitHub Repository (单个仓库详情)
- - The input is one repository's metadata + README excerpt. Go deep on this single project.
- - First scene MUST follow the per-project scene structure below (headline + mandatory 功能简介 / GitHub 地址 / 使用场景 cards + optional value-add card + detailed narration) — this is the project's introduction scene.
- - Subsequent scenes (1-2 more) can elaborate: distinctive features pulled from the README, technical highlights, ecosystem signals (contributors, recent activity). They do NOT need to repeat the GitHub 地址 card, the 功能简介 card, or restate the headline.
- - Avoid enumerating every README section. Pick the 2-3 most distinctive aspects for the deeper scenes.
- - Tone: focused technical introduction, like a colleague recommending a tool.
- ${githubProjectIntroRule}`,
- "github-daily": `
- Data source: GitHub Daily (trending + 多仓库详情组合)
- - The input combines today's trending list with detailed info on selected repos.
- - Suggested structure: 1-2 opening scenes surveying today's overall trend theme (what topics dominate, what's heating up) — these overview scenes do NOT need the per-project structure. Then 1 scene per notable repo, and EVERY repo scene MUST follow the per-project scene structure below (headline + mandatory 功能简介 / GitHub 地址 / 使用场景 cards + optional value-add card + detailed narration).
- - Total 4-7 scenes is the sweet spot. If trending has many repos, group similar ones or pick only the top 3-4 to dive into.
- ${githubProjectIntroRule}`,
- };
- const parts = [base, templateSpecific[template]];
- if (source && sourceSpecific[source]) {
- parts.push(sourceSpecific[source]);
- }
- return parts.join("\n\n");
- }
|