尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Automated podcast highlight clipper using AI for content discovery and video generation.
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
Automatically transform long podcast videos into engaging short-form vertical clips with AI-powered speaker detection and multilingual subtitles.
AI Podcast Clipper (ApcH) is an intelligent video processing platform that extracts viral-worthy moments from podcast episodes. The system analyzes video content to identify engaging Q&A segments, tracks active speakers, generates social media-optimized vertical videos, and overlays professional-styled subtitles in multiple languages (English, Korean).檢視完整 README ↗Automatically transform long podcast videos into engaging short-form vertical clips with AI-powered speaker detection and multilingual subtitles.
AI Podcast Clipper (ApcH) is an intelligent video processing platform that extracts viral-worthy moments from podcast episodes. The system analyzes video content to identify engaging Q&A segments, tracks active speakers, generates social media-optimized vertical videos, and overlays professional-styled subtitles in multiple languages (English, Korean).
┌─────────────────────────────────────────────────────────────────┐
│ Frontend (Next.js) │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────────┐ │
│ │ Homepage │ │ Dashboard │ │ Upload Detail │ │
│ │ │ │ - Uploads │ │ - Clip Gallery │ │
│ │ │ │ - Queue │ │ - Timeline │ │
│ └──────────────┘ └──────────────┘ └────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ NextAuth + Prisma (PostgreSQL) │ │
│ │ User Management & Credit System │ │
│ └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────┬──────────────────────────────────┘
│
│ API Calls
│
┌──────────────────────────────┴───────────────────────────────────┐
│ AWS S3 Storage │
│ - Users upload videos via presigned URLs │
│ - Backend stores processed clips │
└──────────────────────────────┬───────────────────────────────────┘
│
│ Inngest Events
│
┌──────────────────────────────┴───────────────────────────────────┐
│ Backend (Modal.com Serverless GPU) │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Processing Pipeline (L40S GPU - 3600s timeout) │ │
│ │ │ │
│ │ 1. WhisperX Transcription │ │
│ │ └─> Word-level timestamps (large-v2 model) │ │
│ │ │ │
│ │ 2. Gemini Highlight Detection │ │
│ │ └─> Identify Q&A clips (30-90s, non-overlapping) │ │
│ │ │ │
│ │ 3. Columbia ASD (Active Speaker Detection) │ │
│ │ └─> Face tracking + speaker scoring │ │
│ │ │ │
│ │ 4. Vertical Video Generation │ │
│ │ └─> Smart crop (speaker tracking) or blur background │ │
│ │ │ │
│ │ 5. Subtitle Overlay (FFmpeg + ASS) │ │
│ │ └─> English or Korean with custom styling │ │
│ │ │ │
│ │ 6. S3 Upload │ │
│ │ └─> Store final clips with language suffix (_en/_kr) │ │
│ └────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
NEXT_PUBLIC_SUBSCRIPTION_ENABLEDThis repository is an npm workspaces monorepo. Run every command from the
repository root — there is a single .env and a single lockfile.
# Install dependencies for all workspaces
npm install
# Configure environment variables
cp .env.example .env
# Initialize database
npm run db:push
# Start development servers
npm run dev # web
npm run dev:admin # admin
# Start Inngest development server (separate terminal)
npm run inngest-dev -w apps/web
.env.example lists the variables — auth (AUTH_SECRET, AUTH_URL,
AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET), the database, S3, the Modal endpoint,
Inngest keys, Polar billing, Sentry, and ADMIN_EMAILS for the admin app.
apps/web/src/env.js is what enforces them: it validates at build time and
fails the build when a required variable is missing, so start there when a build
complains rather than trusting any list. This README deliberately does not repeat
the list — a duplicated list drifts, and the variable it drops is always the one
nobody copied.
| App | Local | Production |
|---|---|---|
apps/web | http://localhost:3000 | https://a-pch.com |
apps/admin | http://localhost:3001 | https://admin.a-pch.com |
The two apps deploy as separate Vercel projects, with Root Directory set to
apps/web and apps/admin respectively.
The local Python venv is kept outside the repository; apps/backend/CLAUDE.md
records the path and the reason. Modal builds its own image from
requirements.txt, so the venv is only needed to run Python locally.
cd apps/backend
# Create Modal secret with required environment variables
modal secret create ai-podcast-clipper-secret \
AWS_ACCESS_KEY_ID=<your-aws-key> \
AWS_SECRET_ACCESS_KEY=<your-aws-secret> \
AWS_DEFAULT_REGION=ap-southeast-2 \
GEMINI_API_KEY=<your-gemini-key> \
AUTH_TOKEN=<generate-secure-token> \
MODAL_WEBHOOK_SECRET=<same value as MODAL_WEBHOOK_SECRET in .env>
# Deploy to Modal
modal deploy main.py
# Local testing (calls deployed endpoint)
modal run main.py
/signup or log in at /login/dashboard and upload an MP4 video to S3analyze mode — WhisperX
transcription plus Gemini moment detectionreview_pending and the proposals
are stored as ClipDraft rows. Adjust each clip's start/end, deselect clips
you do not want, and override caption style per clip. The AI's original range
is kept separately (aiStartSeconds / aiEndSeconds) so a reset is possible.render modeUser.credits defaults to 3)/api/checkout, /api/portal, and
/api/webhooks/polar, with Subscription and Order rows in the database/dashboard/billing and the whole flow is gated by
NEXT_PUBLIC_SUBSCRIPTION_ENABLEDURL: https://[your-modal-username]--ai-podcast-clipper-process-video.modal.run
Method: POST
Headers:
{
"Authorization": "Bearer <AUTH_TOKEN>",
"Content-Type": "application/json"
}
Request Body:
{
"s3_key": "user-id/video-name.mp4",
"clip_count": 3,
"language": "Korean",
"callback_url": "https://a-pch.com/api/webhooks/modal",
"uploaded_file_id": "clx...",
"mode": "auto"
}
s3_key and clip_count are required. clip_count has no default — omitting
it returns 422.language: "English" or "Korean" (default "Korean").mode: "auto" (transcribe → detect → render), "analyze" (stop after
detection, for the review step), or "render" (render supplied moments).
Default "auto".callback_url decides the execution model. With it the call is dispatched via
.spawn() and returns immediately; without it the endpoint runs the pipeline
synchronously and returns its result.moments, transcript_s3_key, output_prefix, and attempt are used by
render mode.Response (async — callback_url present):
{
"status": "accepted",
"call_id": "fc-..."
}
Without callback_url the endpoint returns the pipeline result itself rather
than an acknowledgement.
Input: MP4 video uploaded to S3 bucket ai-podcast-clipper-hamsoo
Output:
{s3_key_dir}/clip_{index}_en.mp4{s3_key_dir}/clip_{index}_kr.mp4Constraints:
ApcH/
├── package.json # npm workspaces: apps/*, packages/*
├── .env # single file, shared by both apps and Prisma
├── apps/
│ ├── web/ # a-pch.com — the product
│ │ └── src/
│ │ ├── app/ # Next.js App Router
│ │ ├── fsd/ # Feature-Sliced Design
│ │ │ ├── pages/ # page components
│ │ │ ├── widgets/ # composite blocks
│ │ │ ├── features/ # server actions + interactions
│ │ │ ├── entities/ # domain models
│ │ │ └── shared/ # analytics, ui, lib
│ │ └── inngest/ # async video pipeline workers
│ ├── admin/ # admin.a-pch.com — internal dashboard
│ │ └── src/
│ │ ├── app/ # /login, /analytics, /observability
│ │ ├── analytics/ # aggregation queries
│ │ └── auth/ # standalone auth (ADMIN_EMAILS allowlist)
│ └── backend/ # Python (Modal). No package.json, so not an npm workspace
└── packages/
└── db/ # @repo/db
├── prisma/schema.prisma # database schema
└── src/analytics-contract.ts # event names, funnels, shared types
packages/db exists so the analytics contract has exactly one definition. web
writes events and admin aggregates them; if the contract were duplicated,
renaming an event on one side would still compile on the other and the dashboard
would silently report zero.
apps/backend/
├── main.py # Modal app entry point
├── asd/ # Columbia ASD model
│ ├── Columbia_test.py # Active speaker detection
│ ├── ASD.py # Model architecture
│ └── weight/ # Model weights
├── requirements.txt # Python dependencies (torch pinned, so are its peers)
├── CLAUDE.md # backend conventions, incl. where the venv lives
└── ytdownload.py # YouTube download utility
Frontend Pages:
/ - Feature showcase homepage/dashboard - User dashboard with upload queue/dashboard/uploads/[uploadedFileId] - Clip review, gallery, and processing timeline/dashboard/billing - Plan and credit balance (Polar)/login, /signup, /privacy, /terms(public-marketing)/ - marketing and SEO route group: /pricing, /features,
/how-it-works, /product-tour, /compare, /guides/[slug], /about,
/contact, /security, /changelog, and the landing pages
/ai-podcast-clipper, /podcast-to-shorts, /youtube-shorts-generatorBackend Functions:
transcribe_video() - WhisperX word-level transcriptionidentify_moments() - Gemini Q&A extractionprocess_clip() - Complete clip processing pipelinecreate_vertical_video() - Smart crop and vertical conversioncreate_subtitles_with_ffmpeg() - English subtitle overlaycreate_korean_subtitles_with_ffmpeg() - Korean translation and subtitlesmodal run, set KEEP_TEMP_ON_FAILURE=1 to keep them after a failure for debuggingPrivate project - All rights reserved