diff --git a/gitpodcast-analysis.md b/gitpodcast-analysis.md new file mode 100644 index 0000000..376c6ee --- /dev/null +++ b/gitpodcast-analysis.md @@ -0,0 +1,590 @@ +# GitPodcast 项目深度分析报告 + +> **项目地址**: https://github.com/BandarLabs/gitpodcast +> **在线服务**: https://gitpodcast.com +> **许可证**: MIT +> **分析日期**: 2026-05-26 + +--- + +## 一、项目概述 + +GitPodcast 是一个能将任意 GitHub 仓库在数秒内转化为一段双人对话式播客音频的 Web 应用。用户只需将 GitHub URL 中的 `hub` 替换为 `podcast`(如 `github.com/user/repo` → `gitpodcast.com/user/repo`)即可直接访问对应的播客。 + +### 核心能力 +- **即时播客生成**:输入 GitHub 仓库 URL,自动生成 5~20 分钟的双人对话播客 +- **双模式输出**:Basic(~5 分钟)和 In-Depth(~10+ 分钟,含中场休息) +- **幻灯片生成**:同步生成 Marp 格式的 Markdown 幻灯片,支持 React Flow 渲染的幻灯片浏览 +- **字幕同步**:基于 WebVTT 格式的实时字幕与音频同步播放 +- **缓存机制**:PostgreSQL 缓存生成结果,避免重复调用 LLM/TTS +- **用户认证**:Clerk 登录后可解锁 In-Depth 模式 +- **URL 快捷方式**:`hub` → `podcast` 的 URL 替换快捷入口 + +--- + +## 二、整体架构 + +``` +┌──────────────────────────────────────────────────────────────────────┐ +│ Frontend (Next.js 15) │ +│ ┌──────────┐ ┌──────────────┐ ┌────────────┐ ┌──────────────┐ │ +│ │ 首页/入口 │ │ /[user]/[repo]│ │ ReactFlow │ │ 音频播放器 │ │ +│ │ (MainCard)│ │ 页面 │ │ 幻灯片视图 │ │ 字幕同步显示 │ │ +│ └──────────┘ └──────┬───────┘ └────────────┘ └──────────────┘ │ +│ │ fetch (REST) │ +│ ┌─────────────────────┴────────────────────────────────────────┐ │ +│ │ Server Actions (cache.ts / repo.ts / github.ts) │ │ +│ │ Drizzle ORM → PostgreSQL │ │ +│ └──────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────┬────────────────────────────────────────┘ + │ HTTP POST + ▼ +┌──────────────────────────────────────────────────────────────────────┐ +│ Backend (FastAPI, Python 3.12, Docker) │ +│ │ +│ ┌───────────┐ ┌──────────────┐ ┌───────────────┐ │ +│ │ Routers │ │ Services │ │ Core Utils │ │ +│ │ generate/ │──▶│ github_svc │ │ slowapi limiter│ │ +│ │ modify/ │ │ claude_svc │ │ JWT/Clerk auth │ │ +│ └───────────┘ │ openai_svc │ └───────────────┘ │ +│ │ gemini_svc │ │ +│ │ speech_svc │──▶ Azure Speech Batch Synthesis │ +│ │ slide_svc │ │ +│ └──────────────┘ │ +└──────────────────────────────────────────────────────────────────────┘ + │ │ │ + ▼ ▼ ▼ + GitHub API Azure OpenAI / Azure Cognitive + (file tree, Gemini Flash / Services Speech + README, Claude 3.5 Sonnet (TTS Batch) + file content) +``` + +--- + +## 三、技术栈详解 + +### 3.1 前端 (Frontend) + +| 技术 | 版本 | 用途 | +|------|------|------| +| **Next.js** | ^15.2.3 | React 全栈框架 (App Router) | +| **TypeScript** | ^5.5.3 | 类型安全 | +| **React** | ^18.3.1 | UI 库 | +| **Tailwind CSS** | ^3.4.3 | 原子化 CSS | +| **ShadCN UI** (Radix) | - | 基于 Radix UI 的组件库 (Dialog/Label/Progress/Radio/Tooltip/Card/Button) | +| **@xyflow/react** | ^12.4.4 | 幻灯片画布渲染 (React Flow) | +| **Mermaid.js** | ^11.4.1 | 系统架构图渲染 | +| **Reveal.js** | ^5.1.0 | 幻灯片展示框架 | +| **WaveSurfer.js** | ^1.3.4 | 音频波形可视化 | +| **AudioMotion-Analyzer** | ^4.5.0 | 音频频谱分析 | +| **Highlight.js** | ^11.11.1 | 代码高亮 | +| **React Markdown** | ^10.1.0 | Markdown 渲染 | +| **Remark/Rehype** | - | Markdown 处理管线 (GFM, parse, highlight, stringify) | +| **PostHog** | ^1.203.1 | 前端行为分析 | +| **@clerk/nextjs** | ^6.13.0 | 用户认证 | +| **Zod** | ^3.23.3 | 运行时类型校验 (配合 @t3-oss/env-nextjs) | +| **Geist** | ^1.3.0 | 字体 | +| **Lucide React** | ^0.468.0 | 图标库 | + +**前端初始化框架**: T3 Stack (create-t3-app v7.38.1),预配置了 Tailwind + Drizzle + tRPC (本项目未使用 tRPC) + Next.js Auth。 + +### 3.2 后端 (Backend) + +| 技术 | 版本 | 用途 | +|------|------|------| +| **FastAPI** | 0.115.6 | Python Web 框架 | +| **Python** | 3.12 | 后端运行时 | +| **Uvicorn** | 0.34.0 | ASGI 服务器 | +| **SlowAPI** | 0.1.9 | API 限流 (基于 IP) | +| **Pydantic** | 2.10.3 | 请求/响应数据验证 | +| **PyJWT** | 2.10.1 | GitHub App JWT 认证 | +| **Requests** | 2.32.3 | HTTP 客户端 | +| **PyDub** | - | 音频处理 (MP3 时长检测) | +| **Docker** | Python 3.12-slim | 容器化部署 | +| **FFmpeg** | (系统依赖) | 音频编解码支持 | +| **api-analytics** | 1.2.5 | API 使用量分析 | +| **clerk-backend-api** | - | Clerk 后端认证校验 | + +### 3.3 数据库与 ORM + +| 技术 | 版本 | 用途 | +|------|------|------| +| **PostgreSQL** | - | 主数据库 (Neon Serverless 或本地 Docker) | +| **Drizzle ORM** | ^0.33.0 | 类型安全 ORM | +| **Drizzle Kit** | ^0.24.0 | 数据库迁移工具 | +| **@neondatabase/serverless** | ^0.10.4 | Neon 无服务器 PostgreSQL 驱动 | +| **Postgres.js** | ^3.4.4 | PostgreSQL 驱动 (本地开发) | + +**数据库表结构** (表前缀 `gitdiagram_`,继承自 GitDiagram 项目): + +1. **`diagram_cache`**: 缓存 Mermaid 图表代码和文本解释 + - PK: `(username, repo)` + - 字段: `diagram`, `explanation`, `createdAt`, `updatedAt` + +2. **`audio_blob_storage`**: 缓存生成的音频和字幕 + - PK: `(username, repo)` — repo 字段实际存 `reponame|audio_length` + - 字段: `audioBase64`, `duration`, `format`, `webVtt`, `createdAt`, `updatedAt` + +### 3.4 AI 与大模型服务 + +| 服务 | 模型 | 角色 | +|------|------|------| +| **Azure OpenAI** | GPT-4o | 关键文件选择 + SSML 播客脚本生成 (主力) | +| **Gemini** | Flash 2.0 Experimental | SSML 生成的免费备选方案 (15 次/分钟) | +| **Anthropic Claude** | 3.5 Sonnet | Mermaid 图表生成/修改 + Token 计数 (遗留自 GitDiagram) | +| **Azure Speech** | Batch Synthesis API | SSML → MP3 音频合成 (TTS) | + +**TTS 语音角色**: +- 主持人 (Host): `en-US-AvaMultilingualNeural` +- 嘉宾 (Guest): `en-US-DustinMultilingualNeural` + +### 3.5 部署与基础设施 + +| 组件 | 方案 | +|------|------| +| **前端托管** | Vercel (Next.js SSR) | +| **后端托管** | AWS EC2 (Docker + Nginx) | +| **数据库** | Neon Serverless PostgreSQL / 本地 Docker PostgreSQL | +| **CDN/代理** | Nginx (后端反向代理) | +| **CI/CD** | GitHub Actions | +| **监控** | PostHog (前端) + api-analytics (后端) | + +--- + +## 四、核心数据流程 + +### 4.1 播客生成流程 + +``` +用户输入 GitHub URL + │ + ▼ + ┌─────────────────┐ + │ 1. 解析 URL │ 提取 username/repo + └────────┬────────┘ + ▼ + ┌─────────────────┐ + │ 2. 获取仓库数据 │ GitHubService + │ │ ├─ get_default_branch() → 默认分支 + │ │ ├─ get_github_file_paths_as_list() → 文件树 (排除 node_modules 等) + │ │ ├─ get_github_readme() → README + │ │ └─ get_github_file_content() → 关键文件内容 (OpenAI 选出 ≤10 个文件,每个截断 50KB) + └────────┬────────┘ + │ LRU Cache (5 分钟) + ▼ + ┌───────────────────────────────────┐ + │ 3. 生成 SSML 播客脚本 │ + │ │ + │ Short 模式: │ + │ 单次 LLM 调用 │ + │ 输入: file_tree + README + 关键文件 │ + │ Prompt: PODCAST_SSML_PROMPT │ + │ │ + │ Long 模式: │ + │ 两个并发 LLM 调用 (ThreadPool) │ + │ ├─ Call A: tree + README │ → PODCAST_SSML_PROMPT_BEFORE_BREAK + │ └─ Call B: 关键文件内容 │ → PODCAST_SSML_PROMPT_AFTER_BREAK + │ 合并后包裹在 标签内 │ + └────────┬──────────────────────────┘ + ▼ + ┌─────────────────────────────────┐ + │ 4. SSML 校验与清洗 │ + │ ├─ XML 解析验证 (ET.fromstring)│ + │ ├─ 过滤 ``` 代码块标记 │ + │ ├─ sanitize: 移除非法标签 │ + │ └─ 最多 3 次重试 │ + └────────┬────────────────────────┘ + ▼ + ┌─────────────────────────────────┐ + │ 5. TTS 语音合成 │ Azure Speech Batch Synthesis API + │ ├─ PUT 请求提交 SSML │ + │ ├─ 轮询合成状态 (Succeeded) │ + │ ├─ 下载 ZIP → 提取音频 │ + │ └─ 最多 3 次重试 │ + └────────┬────────────────────────┘ + ▼ + ┌─────────────────────────────────┐ + │ 6. 生成 WebVTT 字幕 │ + │ ├─ 从 SSML 提取纯文本 │ + │ ├─ 按 WPM 计算每行时间戳 │ + │ └─ 输出 WebVTT 格式 │ + └────────┬────────────────────────┘ + ▼ + ┌─────────────────────────────────┐ + │ 7. 响应返回与缓存 │ + │ ├─ 音频: MP3 bytes (Response) │ + │ ├─ 字幕: Base64 编码放 X-VTT-Content Header │ + │ ├─ 音频: Base64 存入 PostgreSQL│ + │ └─ WebVTT: 存入 PostgreSQL │ + └─────────────────────────────────┘ +``` + +### 4.2 SSML Prompt 设计 + +播客采用双人对话形式 (Host + Guest),核心 prompt 策略: + +| Prompt | 用途 | 覆盖内容 | +|--------|------|---------| +| `PODCAST_SSML_PROMPT` | Short 模式单次生成 | 项目概述 + 架构 + 技术特色 | +| `PODCAST_SSML_PROMPT_BEFORE_BREAK` | Long 模式前半段 | 同上 + "中场休息前"提示 | +| `PODCAST_SSML_PROMPT_AFTER_BREAK` | Long 模式后半段 | 重要代码 + 优化 + 调用关系 + "中场休息后"提示 | +| `SLIDE_PROMPT` | 幻灯片生成 | Marp Markdown 格式的技术幻灯片 | + +**Prompt 工程细节**: +- 要求生成 ≥200 个 `` 标签 per 角色 +- 添加自然填充词 (`um`, `uh`) 增强真实感 +- 要求混合长短回答,避免单调 +- 目标时长 20+ 分钟 +- 使用 `` 标签模拟自然停顿 +- 讨论架构模式、设计原则、组件关系、技术亮点 + +### 4.3 关键文件选择流程 + +``` +File Tree (完整) + │ + ▼ +OpenAI GPT-4o (Structured Output) + │ System: "选出最多 10 个最重要的文件路径" + │ Response Format: Pydantic FileListFormat + │ + ▼ +[file1.py, file2.ts, ..., file_n.py] (≤10 个) + │ + ▼ 逐个获取内容 (base64 解码) + │ + ▼ +每个文件截断到 50,000 字符 + │ + ▼ +拼接为: "FPATH: xxx \n CONTENT: ..." +``` + +--- + +## 五、关键服务模块详解 + +### 5.1 `github_service.py` — GitHub API 交互 + +- **认证优先级**: GitHub App (JWT + Installation Token) > GitHub PAT > 无认证 (60 req/hr) +- **JWT 生成**: RS256 签名,10 分钟有效期 +- **文件树获取**: 使用 Git Trees API (`recursive=1`),自动过滤 `node_modules/`, `.min.`, 图片, 锁文件等 +- **分支回退**: 先查 default_branch,失败后依次尝试 `main` → `master` +- **文件内容**: Contents API 返回 Base64 编码,客户端解码 + +### 5.2 `speech_service.py` — Azure 语音合成 + +- **合成方式**: 使用 Azure Batch Synthesis API (`/texttospeech/batchsyntheses/`),而非实时 SDK +- **音频格式**: `audio-16khz-32kbitrate-mono-mp3` +- **轮询机制**: 每 2 秒轮询一次合成状态,支持 `Running` → `Succeeded` → 下载 ZIP +- **ZIP 提取**: 下载结果中的 `.wav`/`.mp3` 文件 +- **字幕生成** (`ssml_to_webvtt`): + - 从 SSML 提取纯文本 (去除 ``, ``, `` 等标签) + - 基于 WPM (words per minute) 动态计算每段字幕时长 + - 自动换行 (max 45 字符) 和分词 (max 30 词/cue) + - 输出标准 WebVTT 格式 +- **SSML 清洗**: XML 解析验证 + 移除非 `` 子元素 + 去除 Markdown 代码块标记 + +### 5.3 `openai_service.py` — Azure OpenAI 调用 + +- **模型**: Azure OpenAI GPT-4o (可通过 `AZURE_OPENAI_MODEL_NAME` 配置) +- **关键文件选择**: 使用 Structured Output (`response_format=FileListFormat`) 确保返回格式化的文件列表 +- **API 版本**: `2024-10-21` + +### 5.4 `gemini_service.py` — Gemini Flash 备选 + +- **模型**: `gemini-2.0-flash-exp` +- **流程**: 上传文件 → 等待处理 → Chat Session → 生成 SSML +- **参数**: temperature=1, top_p=0.95, top_k=40, max_output_tokens=8192 + +### 5.5 `claude_service.py` — Claude 服务 (遗留) + +- **用途**: Mermaid 图表的修改功能 + Token 计数 +- **模型**: `claude-3-5-sonnet-latest` +- **注意**: 该服务继承自 GitDiagram 项目,在本项目中图表生成功能已基本弃用 + +--- + +## 六、前端架构 + +### 6.1 页面路由 + +``` +/ → 首页 (page.tsx): MainCard + Hero +/[username]/[repo]/ → 仓库播客页: 核心交互页面 +``` + +### 6.2 核心组件层级 + +``` +app/layout.tsx (PostHogProvider + GlobalStateProvider + ClerkProvider) +├── app/page.tsx (首页) +│ ├── Hero (品牌标题) +│ ├── MainCard (URL 输入 + 模式选择 + 示例仓库) +│ └── ProductHuntEmbed +│ +└── app/[username]/[repo]/page.tsx (仓库页面) + ├── MainCard (修改/重新生成/自定义) + ├──