video-context-mcp-server 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +249 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +122 -0
- package/dist/index.js.map +1 -0
- package/dist/services/ffmpeg.d.ts +47 -0
- package/dist/services/ffmpeg.d.ts.map +1 -0
- package/dist/services/ffmpeg.js +170 -0
- package/dist/services/ffmpeg.js.map +1 -0
- package/dist/services/glmClient.d.ts +50 -0
- package/dist/services/glmClient.d.ts.map +1 -0
- package/dist/services/glmClient.js +196 -0
- package/dist/services/glmClient.js.map +1 -0
- package/dist/services/kimiClient.d.ts +45 -0
- package/dist/services/kimiClient.d.ts.map +1 -0
- package/dist/services/kimiClient.js +152 -0
- package/dist/services/kimiClient.js.map +1 -0
- package/dist/services/providerRouter.d.ts +23 -0
- package/dist/services/providerRouter.d.ts.map +1 -0
- package/dist/services/providerRouter.js +70 -0
- package/dist/services/providerRouter.js.map +1 -0
- package/dist/tools/analyzeVideo.d.ts +18 -0
- package/dist/tools/analyzeVideo.d.ts.map +1 -0
- package/dist/tools/analyzeVideo.js +81 -0
- package/dist/tools/analyzeVideo.js.map +1 -0
- package/dist/tools/extractFrames.d.ts +22 -0
- package/dist/tools/extractFrames.d.ts.map +1 -0
- package/dist/tools/extractFrames.js +64 -0
- package/dist/tools/extractFrames.js.map +1 -0
- package/dist/tools/getVideoInfo.d.ts +18 -0
- package/dist/tools/getVideoInfo.d.ts.map +1 -0
- package/dist/tools/getVideoInfo.js +34 -0
- package/dist/tools/getVideoInfo.js.map +1 -0
- package/dist/tools/searchTimestamp.d.ts +25 -0
- package/dist/tools/searchTimestamp.d.ts.map +1 -0
- package/dist/tools/searchTimestamp.js +110 -0
- package/dist/tools/searchTimestamp.js.map +1 -0
- package/dist/tools/summarizeVideo.d.ts +18 -0
- package/dist/tools/summarizeVideo.d.ts.map +1 -0
- package/dist/tools/summarizeVideo.js +117 -0
- package/dist/tools/summarizeVideo.js.map +1 -0
- package/dist/utils/base64.d.ts +35 -0
- package/dist/utils/base64.d.ts.map +1 -0
- package/dist/utils/base64.js +50 -0
- package/dist/utils/base64.js.map +1 -0
- package/dist/utils/tempFiles.d.ts +20 -0
- package/dist/utils/tempFiles.d.ts.map +1 -0
- package/dist/utils/tempFiles.js +31 -0
- package/dist/utils/tempFiles.js.map +1 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# Video Context MCP Server
|
|
2
|
+
|
|
3
|
+
Video Context MCP Server is a Model Context Protocol (MCP) server that gives GitHub Copilot in VS Code the ability to understand and analyze video content. Supports two AI backends: **Kimi K2.5** (Moonshot AI) and **GLM-4.6V** (Z.AI).
|
|
4
|
+
|
|
5
|
+
## Current Status
|
|
6
|
+
|
|
7
|
+
- ✅ Project scaffold, MCP registration, ffmpeg helpers, lint/build/format pipeline
|
|
8
|
+
- ✅ Phase 2A complete: core Kimi/GLM client analysis methods implemented
|
|
9
|
+
- ✅ Phase 2B complete: all MCP tool handlers implemented
|
|
10
|
+
- ✅ Phase 2C automated coverage complete: ffmpeg service tests + mocked orchestration tests for AI-dependent tools
|
|
11
|
+
- ✅ Phase 2C reasoning-mode methods complete: `KimiClient.analyzeVideoWithThinking()` and `GLMClient.analyzeWithThinking()`
|
|
12
|
+
- ✅ Phase 2C complete (Tier A): runtime integration validation with real ffmpeg fixtures + deterministic mocked AI-provider orchestration
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
- 🎬 **Video Q&A** — Ask questions about video content and get AI-powered answers
|
|
17
|
+
- 📝 **Video Summarization** — Generate structured summaries with key scenes and timelines
|
|
18
|
+
- 🖼️ **Frame Extraction** — Extract frames at specific timestamps or intervals
|
|
19
|
+
- 🔍 **Timestamp Search** — Find the exact moment when something happens in a video
|
|
20
|
+
- 📊 **Video Metadata** — Get duration, resolution, fps, codec, and other technical details
|
|
21
|
+
- 🔄 **Dual Backend Support** — Auto-routes to GLM-4.6V (cheap/free) or Kimi K2.5 (large videos)
|
|
22
|
+
- 🎯 **Smart Video Handling** — Extracts keyframes from long videos to reduce token usage
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
### 1. Install Dependencies
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 2. Configure API Keys
|
|
33
|
+
|
|
34
|
+
You'll need API keys for one or both backends:
|
|
35
|
+
|
|
36
|
+
- **Kimi K2.5 (Moonshot AI)**: [Get API Key](https://platform.moonshot.ai)
|
|
37
|
+
- **GLM-4.6V (Z.AI)**: [Get API Key](https://z.ai/manage-apikey/apikey-list)
|
|
38
|
+
|
|
39
|
+
### 3. Configure VS Code
|
|
40
|
+
|
|
41
|
+
Recommended: copy `.vscode-template/mcp.json` to `.vscode/mcp.json` and fill in your own keys locally.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
cp .vscode-template/mcp.json .vscode/mcp.json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Template options:
|
|
48
|
+
|
|
49
|
+
- `.vscode-template/mcp.json` — default (watch enabled, debug disabled)
|
|
50
|
+
- `.vscode-template/mcp.quiet.json` — quiet dev mode (watch enabled, debug disabled)
|
|
51
|
+
- `.vscode-template/mcp.debug.json` — verbose dev mode (watch + node debug enabled)
|
|
52
|
+
|
|
53
|
+
If you want the debug variant directly:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
cp .vscode-template/mcp.debug.json .vscode/mcp.json
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Do not commit real API keys to the repository.
|
|
60
|
+
|
|
61
|
+
You can also create `.vscode/mcp.json` manually:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"servers": {
|
|
66
|
+
"videoMcp": {
|
|
67
|
+
"type": "stdio",
|
|
68
|
+
"command": "node",
|
|
69
|
+
"args": ["${workspaceFolder}/dist/index.js"],
|
|
70
|
+
"env": {
|
|
71
|
+
"MOONSHOT_API_KEY": "${input:moonshot-key}",
|
|
72
|
+
"Z_AI_API_KEY": "${input:zai-key}"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"inputs": [
|
|
77
|
+
{
|
|
78
|
+
"type": "promptString",
|
|
79
|
+
"id": "moonshot-key",
|
|
80
|
+
"description": "Moonshot API Key for Kimi K2.5",
|
|
81
|
+
"password": true
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"type": "promptString",
|
|
85
|
+
"id": "zai-key",
|
|
86
|
+
"description": "Z.AI API Key for GLM-4.6V",
|
|
87
|
+
"password": true
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 4. Build and Run
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm run build
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The MCP server will be automatically started by VS Code when Copilot Chat is opened.
|
|
100
|
+
|
|
101
|
+
### 5. Debugging Behavior in VS Code
|
|
102
|
+
|
|
103
|
+
When your `.vscode/mcp.json` includes a `dev` block such as:
|
|
104
|
+
|
|
105
|
+
```jsonc
|
|
106
|
+
"dev": {
|
|
107
|
+
"watch": "src/**/*.ts",
|
|
108
|
+
"debug": { "type": "node" }
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
you may see frequent logs in the **Output** panel under `MCP: videoMcp`.
|
|
113
|
+
|
|
114
|
+
This is expected in development mode:
|
|
115
|
+
|
|
116
|
+
- `watch` restarts/reloads the MCP server when TypeScript files change
|
|
117
|
+
- `debug` enables Node debug integration
|
|
118
|
+
- MCP protocol payloads (tool schemas, discovery events, lifecycle messages) are printed in that output channel
|
|
119
|
+
|
|
120
|
+
If you want less noise, remove either:
|
|
121
|
+
|
|
122
|
+
- `dev.debug` (keeps auto-watch, disables debug integration), or
|
|
123
|
+
- the full `dev` block (disables watch + debug behavior)
|
|
124
|
+
|
|
125
|
+
## Available Tools
|
|
126
|
+
|
|
127
|
+
| Tool | Description | Parameters |
|
|
128
|
+
| ------------------ | ------------------------------------ | ------------------------------------------------ |
|
|
129
|
+
| `analyze_video` | Ask questions about video content | `videoPath`, `question`, `provider?` |
|
|
130
|
+
| `summarize_video` | Generate a structured video summary | `videoPath`, `provider?` |
|
|
131
|
+
| `extract_frames` | Extract frames from a video | `videoPath`, `mode`, `count/interval/timestamps` |
|
|
132
|
+
| `search_timestamp` | Find when something specific happens | `videoPath`, `query`, `provider?` |
|
|
133
|
+
| `get_video_info` | Get video metadata | `videoPath` |
|
|
134
|
+
|
|
135
|
+
## Usage Examples
|
|
136
|
+
|
|
137
|
+
### Analyze Video
|
|
138
|
+
|
|
139
|
+
Ask Copilot Chat:
|
|
140
|
+
|
|
141
|
+
> "Analyze the video at `./demo.mp4` and tell me what happens in it"
|
|
142
|
+
|
|
143
|
+
### Summarize Video
|
|
144
|
+
|
|
145
|
+
> "Summarize the video at `./long-video.mp4`"
|
|
146
|
+
|
|
147
|
+
### Extract Frames
|
|
148
|
+
|
|
149
|
+
> "Extract 5 evenly-spaced frames from `./video.mp4`"
|
|
150
|
+
|
|
151
|
+
> "Extract a frame at timestamp 30 seconds from `./video.mp4`"
|
|
152
|
+
|
|
153
|
+
### Search Timestamp
|
|
154
|
+
|
|
155
|
+
> "In `./video.mp4`, at what timestamp does the person wave?"
|
|
156
|
+
|
|
157
|
+
### Get Video Info
|
|
158
|
+
|
|
159
|
+
> "Get the video info for `./video.mp4`"
|
|
160
|
+
|
|
161
|
+
## Backend Comparison
|
|
162
|
+
|
|
163
|
+
| Feature | GLM-4.6V | Kimi K2.5 |
|
|
164
|
+
| -------------- | ----------------------------- | ---------------------------------------------- |
|
|
165
|
+
| Video formats | mp4, avi, mov, wmv, webm, m4v | mp4, mpeg, mov, avi, flv, mpg, webm, wmv, 3gpp |
|
|
166
|
+
| Max video size | 8 MB | 100 MB + file upload API |
|
|
167
|
+
| Price | $0.30 input / $0.90 output | $0.60 input / $3.00 output |
|
|
168
|
+
| Free tier | Yes (GLM-4.6V-Flash) | No |
|
|
169
|
+
| Context window | 128K | 256K |
|
|
170
|
+
| Best for | Short clips, cost efficiency | Large videos, broader format support |
|
|
171
|
+
|
|
172
|
+
The server auto-routes to the best backend based on video size:
|
|
173
|
+
|
|
174
|
+
- Videos ≤ 8 MB → GLM-4.6V (cheaper, free tier available)
|
|
175
|
+
- Videos > 8 MB → Kimi K2.5 (larger support)
|
|
176
|
+
|
|
177
|
+
## Environment Variables
|
|
178
|
+
|
|
179
|
+
| Variable | Description | Required |
|
|
180
|
+
| ---------------------------- | --------------------------------------- | -------------------------- |
|
|
181
|
+
| `MOONSHOT_API_KEY` | Moonshot AI API key for Kimi K2.5 | Optional (if using GLM) |
|
|
182
|
+
| `Z_AI_API_KEY` | Z.AI API key for GLM-4.6V | Optional (if using Kimi) |
|
|
183
|
+
| `VIDEO_MCP_DEFAULT_PROVIDER` | Default backend (`auto`, `glm`, `kimi`) | Optional (default: `auto`) |
|
|
184
|
+
| `VIDEO_MCP_MAX_FRAMES` | Max frames for summarization | Optional (default: 20) |
|
|
185
|
+
|
|
186
|
+
## Development
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# Install dependencies
|
|
190
|
+
npm install
|
|
191
|
+
|
|
192
|
+
# Run in development (auto-restart on changes)
|
|
193
|
+
npm run dev
|
|
194
|
+
|
|
195
|
+
# Build for production
|
|
196
|
+
npm run build
|
|
197
|
+
|
|
198
|
+
# Run type checking
|
|
199
|
+
npm run type-check
|
|
200
|
+
|
|
201
|
+
# Run linter
|
|
202
|
+
npm run lint
|
|
203
|
+
|
|
204
|
+
# Run automated tests
|
|
205
|
+
npm run test
|
|
206
|
+
|
|
207
|
+
# Run tests in watch mode
|
|
208
|
+
npm run test:watch
|
|
209
|
+
|
|
210
|
+
# Run tests with coverage
|
|
211
|
+
npm run test:coverage
|
|
212
|
+
|
|
213
|
+
# Format all files
|
|
214
|
+
npm run format
|
|
215
|
+
|
|
216
|
+
# Check formatting only
|
|
217
|
+
npm run format:check
|
|
218
|
+
|
|
219
|
+
# Lint + Type-check + Format + Build
|
|
220
|
+
npm run ltfb
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Architecture
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
video-mcp/
|
|
227
|
+
├── src/
|
|
228
|
+
│ ├── index.ts # MCP server entry point
|
|
229
|
+
│ ├── tools/ # MCP tool implementations
|
|
230
|
+
│ ├── services/ # Backend clients (Kimi, GLM, ffmpeg)
|
|
231
|
+
│ └── utils/ # Helpers (temp files, base64)
|
|
232
|
+
├── .vscode/
|
|
233
|
+
│ └── mcp.json # VS Code MCP configuration
|
|
234
|
+
├── docs/
|
|
235
|
+
│ └── technical/ # Technical documentation
|
|
236
|
+
└── .github/
|
|
237
|
+
└── copilot-instructions.md # Copilot AI assistant guidelines
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## License
|
|
241
|
+
|
|
242
|
+
MIT
|
|
243
|
+
|
|
244
|
+
## Credits
|
|
245
|
+
|
|
246
|
+
- [MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk) by Anthropic
|
|
247
|
+
- [Kimi K2.5](https://github.com/MoonshotAI/Kimi-K2.5) by Moonshot AI
|
|
248
|
+
- [GLM-4.6V](https://docs.z.ai/guides/vlm/glm-4.6v) by Z.AI
|
|
249
|
+
- [ffmpeg](https://ffmpeg.org/) for video processing
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
// Import tool handlers
|
|
6
|
+
import { analyzeVideoTool } from './tools/analyzeVideo.js';
|
|
7
|
+
import { summarizeVideoTool } from './tools/summarizeVideo.js';
|
|
8
|
+
import { extractFramesTool } from './tools/extractFrames.js';
|
|
9
|
+
import { searchTimestampTool } from './tools/searchTimestamp.js';
|
|
10
|
+
import { getVideoInfoTool } from './tools/getVideoInfo.js';
|
|
11
|
+
/**
|
|
12
|
+
* Main entry point for the Video Context MCP Server
|
|
13
|
+
* Creates an MCP server, registers all video analysis tools, and connects via stdio
|
|
14
|
+
*/
|
|
15
|
+
async function main() {
|
|
16
|
+
// Create MCP server with name and version
|
|
17
|
+
const server = new McpServer({
|
|
18
|
+
name: 'video-mcp',
|
|
19
|
+
version: '1.0.0',
|
|
20
|
+
}, {
|
|
21
|
+
capabilities: {
|
|
22
|
+
logging: {}, // Enable logging for progress reporting
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
// Register all video analysis tools
|
|
26
|
+
// Tool 1: analyze_video - Ask questions about video content
|
|
27
|
+
server.registerTool('analyze_video', {
|
|
28
|
+
title: 'Analyze Video',
|
|
29
|
+
description: 'Ask questions about video content and get AI-powered answers. Supports both local files and URLs.',
|
|
30
|
+
inputSchema: z.object({
|
|
31
|
+
videoPath: z
|
|
32
|
+
.string()
|
|
33
|
+
.describe('Path to the video file (local path or URL)'),
|
|
34
|
+
question: z
|
|
35
|
+
.string()
|
|
36
|
+
.describe('Question to ask about the video content'),
|
|
37
|
+
provider: z
|
|
38
|
+
.enum(['auto', 'glm', 'kimi'])
|
|
39
|
+
.optional()
|
|
40
|
+
.describe("AI backend to use: 'auto' (default), 'glm' (GLM-4.6V), or 'kimi' (Kimi K2.5)"),
|
|
41
|
+
}),
|
|
42
|
+
}, analyzeVideoTool);
|
|
43
|
+
// Tool 2: summarize_video - Generate structured video summary
|
|
44
|
+
server.registerTool('summarize_video', {
|
|
45
|
+
title: 'Summarize Video',
|
|
46
|
+
description: 'Generate a structured summary of the video including overview, key scenes, and timeline. For long videos (>5 min), extracts keyframes to reduce token usage.',
|
|
47
|
+
inputSchema: z.object({
|
|
48
|
+
videoPath: z
|
|
49
|
+
.string()
|
|
50
|
+
.describe('Path to the video file (local path or URL)'),
|
|
51
|
+
provider: z
|
|
52
|
+
.enum(['auto', 'glm', 'kimi'])
|
|
53
|
+
.optional()
|
|
54
|
+
.describe("AI backend to use: 'auto' (default), 'glm' (GLM-4.6V), or 'kimi' (Kimi K2.5)"),
|
|
55
|
+
}),
|
|
56
|
+
}, summarizeVideoTool);
|
|
57
|
+
// Tool 3: extract_frames - Extract frames from video
|
|
58
|
+
server.registerTool('extract_frames', {
|
|
59
|
+
title: 'Extract Frames',
|
|
60
|
+
description: 'Extract frames from a video at specific timestamps or intervals. This is a local-only operation (no AI backend required).',
|
|
61
|
+
inputSchema: z.object({
|
|
62
|
+
videoPath: z
|
|
63
|
+
.string()
|
|
64
|
+
.describe('Path to the video file (local path only)'),
|
|
65
|
+
mode: z
|
|
66
|
+
.enum(['even', 'interval', 'timestamps'])
|
|
67
|
+
.describe("Extraction mode: 'even' (N evenly-spaced frames), 'interval' (every N seconds), or 'timestamps' (at specific times)"),
|
|
68
|
+
count: z
|
|
69
|
+
.number()
|
|
70
|
+
.int()
|
|
71
|
+
.min(1)
|
|
72
|
+
.max(100)
|
|
73
|
+
.optional()
|
|
74
|
+
.describe("Number of frames to extract (required for 'even' mode)"),
|
|
75
|
+
intervalSec: z
|
|
76
|
+
.number()
|
|
77
|
+
.min(0.1)
|
|
78
|
+
.optional()
|
|
79
|
+
.describe("Interval in seconds between frames (required for 'interval' mode)"),
|
|
80
|
+
timestamps: z
|
|
81
|
+
.array(z.number().min(0))
|
|
82
|
+
.optional()
|
|
83
|
+
.describe("Array of timestamps in seconds (required for 'timestamps' mode)"),
|
|
84
|
+
}),
|
|
85
|
+
}, extractFramesTool);
|
|
86
|
+
// Tool 4: search_timestamp - Find when something happens in video
|
|
87
|
+
server.registerTool('search_timestamp', {
|
|
88
|
+
title: 'Search Timestamp',
|
|
89
|
+
description: 'Find the timestamp when something specific happens in a video. Extracts frames and uses AI to locate the content.',
|
|
90
|
+
inputSchema: z.object({
|
|
91
|
+
videoPath: z
|
|
92
|
+
.string()
|
|
93
|
+
.describe('Path to the video file (local path only)'),
|
|
94
|
+
query: z
|
|
95
|
+
.string()
|
|
96
|
+
.describe("What to search for, e.g., 'person waves', 'dog runs', 'car crash'"),
|
|
97
|
+
provider: z
|
|
98
|
+
.enum(['auto', 'glm', 'kimi'])
|
|
99
|
+
.optional()
|
|
100
|
+
.describe("AI backend to use: 'auto' (default), 'glm' (GLM-4.6V), or 'kimi' (Kimi K2.5)"),
|
|
101
|
+
}),
|
|
102
|
+
}, searchTimestampTool);
|
|
103
|
+
// Tool 5: get_video_info - Get video metadata
|
|
104
|
+
server.registerTool('get_video_info', {
|
|
105
|
+
title: 'Get Video Info',
|
|
106
|
+
description: 'Get video metadata including duration, resolution, fps, codec, file size, and format. This is a local-only operation (no AI backend required).',
|
|
107
|
+
inputSchema: z.object({
|
|
108
|
+
videoPath: z
|
|
109
|
+
.string()
|
|
110
|
+
.describe('Path to the video file (local path only)'),
|
|
111
|
+
}),
|
|
112
|
+
}, getVideoInfoTool);
|
|
113
|
+
// Connect to VS Code via stdio transport
|
|
114
|
+
const transport = new StdioServerTransport();
|
|
115
|
+
await server.connect(transport);
|
|
116
|
+
// Server is now running, listening for tool calls from Copilot
|
|
117
|
+
}
|
|
118
|
+
main().catch((error) => {
|
|
119
|
+
console.error('Fatal error starting video-mcp server:', error);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
});
|
|
122
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Video Metadata
|
|
3
|
+
*/
|
|
4
|
+
export interface VideoMetadata {
|
|
5
|
+
duration: number;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
fps: number;
|
|
9
|
+
codec: string;
|
|
10
|
+
fileSize: number;
|
|
11
|
+
format: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get video metadata using ffprobe
|
|
15
|
+
* @param videoPath - Path to the video file
|
|
16
|
+
* @returns Video metadata
|
|
17
|
+
*/
|
|
18
|
+
export declare function getVideoMetadata(videoPath: string): Promise<VideoMetadata>;
|
|
19
|
+
/**
|
|
20
|
+
* Extract a single frame at a specific timestamp
|
|
21
|
+
* @param videoPath - Path to the video file
|
|
22
|
+
* @param timestampSec - Timestamp in seconds
|
|
23
|
+
* @returns Buffer containing the PNG frame
|
|
24
|
+
*/
|
|
25
|
+
export declare function extractFrameAt(videoPath: string, timestampSec: number): Promise<Buffer>;
|
|
26
|
+
/**
|
|
27
|
+
* Extract N evenly-spaced frames from a video
|
|
28
|
+
* @param videoPath - Path to the video file
|
|
29
|
+
* @param count - Number of frames to extract
|
|
30
|
+
* @returns Array of PNG buffers
|
|
31
|
+
*/
|
|
32
|
+
export declare function extractFramesEvenly(videoPath: string, count: number): Promise<Buffer[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Extract frames at regular intervals
|
|
35
|
+
* @param videoPath - Path to the video file
|
|
36
|
+
* @param intervalSec - Interval in seconds between frames
|
|
37
|
+
* @returns Array of PNG buffers
|
|
38
|
+
*/
|
|
39
|
+
export declare function extractFramesAtInterval(videoPath: string, intervalSec: number): Promise<Buffer[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Extract frames at specific timestamps
|
|
42
|
+
* @param videoPath - Path to the video file
|
|
43
|
+
* @param timestamps - Array of timestamps in seconds
|
|
44
|
+
* @returns Array of PNG buffers (same order as timestamps)
|
|
45
|
+
*/
|
|
46
|
+
export declare function extractFramesAtTimestamps(videoPath: string, timestamps: number[]): Promise<Buffer[]>;
|
|
47
|
+
//# sourceMappingURL=ffmpeg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ffmpeg.d.ts","sourceRoot":"","sources":["../../src/services/ffmpeg.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,CAAC,CA0BxB;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAoBjB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,EAAE,CAAC,CA6BnB;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,EAAE,CAAC,CAyBnB;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC,MAAM,EAAE,CAAC,CA0BnB"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import ffmpeg from 'fluent-ffmpeg';
|
|
2
|
+
import ffmpegInstaller from '@ffmpeg-installer/ffmpeg';
|
|
3
|
+
import ffprobeInstaller from '@ffprobe-installer/ffprobe';
|
|
4
|
+
import * as fs from 'fs/promises';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { mkdtemp, rm } from 'fs/promises';
|
|
7
|
+
import { tmpdir } from 'os';
|
|
8
|
+
// Set paths to bundled ffmpeg and ffprobe binaries
|
|
9
|
+
ffmpeg.setFfmpegPath(ffmpegInstaller.path);
|
|
10
|
+
ffmpeg.setFfprobePath(ffprobeInstaller.path);
|
|
11
|
+
/**
|
|
12
|
+
* Get video metadata using ffprobe
|
|
13
|
+
* @param videoPath - Path to the video file
|
|
14
|
+
* @returns Video metadata
|
|
15
|
+
*/
|
|
16
|
+
export async function getVideoMetadata(videoPath) {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
ffmpeg.ffprobe(videoPath, (err, metadata) => {
|
|
19
|
+
if (err) {
|
|
20
|
+
reject(err);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const videoStream = metadata.streams.find((s) => s.codec_type === 'video');
|
|
24
|
+
if (!videoStream) {
|
|
25
|
+
reject(new Error('No video stream found in file'));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
resolve({
|
|
29
|
+
duration: metadata.format.duration || 0,
|
|
30
|
+
width: videoStream.width || 0,
|
|
31
|
+
height: videoStream.height || 0,
|
|
32
|
+
fps: parseFps(videoStream.r_frame_rate),
|
|
33
|
+
codec: videoStream.codec_name || 'unknown',
|
|
34
|
+
fileSize: metadata.format.size || 0,
|
|
35
|
+
format: metadata.format.format_name || 'unknown',
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Extract a single frame at a specific timestamp
|
|
42
|
+
* @param videoPath - Path to the video file
|
|
43
|
+
* @param timestampSec - Timestamp in seconds
|
|
44
|
+
* @returns Buffer containing the PNG frame
|
|
45
|
+
*/
|
|
46
|
+
export async function extractFrameAt(videoPath, timestampSec) {
|
|
47
|
+
const tempDir = await mkdtemp(path.join(tmpdir(), 'video-mcp-'));
|
|
48
|
+
const outputPath = path.join(tempDir, 'frame.png');
|
|
49
|
+
try {
|
|
50
|
+
await new Promise((resolve, reject) => {
|
|
51
|
+
ffmpeg(videoPath)
|
|
52
|
+
.seekInput(timestampSec)
|
|
53
|
+
.frames(1)
|
|
54
|
+
.output(outputPath)
|
|
55
|
+
.on('end', () => resolve())
|
|
56
|
+
.on('error', reject)
|
|
57
|
+
.run();
|
|
58
|
+
});
|
|
59
|
+
const frameBuffer = await fs.readFile(outputPath);
|
|
60
|
+
return frameBuffer;
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Extract N evenly-spaced frames from a video
|
|
68
|
+
* @param videoPath - Path to the video file
|
|
69
|
+
* @param count - Number of frames to extract
|
|
70
|
+
* @returns Array of PNG buffers
|
|
71
|
+
*/
|
|
72
|
+
export async function extractFramesEvenly(videoPath, count) {
|
|
73
|
+
const tempDir = await mkdtemp(path.join(tmpdir(), 'video-mcp-'));
|
|
74
|
+
try {
|
|
75
|
+
await new Promise((resolve, reject) => {
|
|
76
|
+
ffmpeg(videoPath)
|
|
77
|
+
.screenshots({
|
|
78
|
+
count,
|
|
79
|
+
folder: tempDir,
|
|
80
|
+
filename: 'frame-%i.png',
|
|
81
|
+
size: '1280x?', // Resize width to 1280, maintain aspect ratio
|
|
82
|
+
})
|
|
83
|
+
.on('end', () => resolve())
|
|
84
|
+
.on('error', reject);
|
|
85
|
+
});
|
|
86
|
+
// Read all generated frame files
|
|
87
|
+
const framePaths = (await fs.readdir(tempDir))
|
|
88
|
+
.filter((f) => f.endsWith('.png'))
|
|
89
|
+
.sort();
|
|
90
|
+
const frames = await Promise.all(framePaths.map((f) => fs.readFile(path.join(tempDir, f))));
|
|
91
|
+
return frames;
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Extract frames at regular intervals
|
|
99
|
+
* @param videoPath - Path to the video file
|
|
100
|
+
* @param intervalSec - Interval in seconds between frames
|
|
101
|
+
* @returns Array of PNG buffers
|
|
102
|
+
*/
|
|
103
|
+
export async function extractFramesAtInterval(videoPath, intervalSec) {
|
|
104
|
+
const tempDir = await mkdtemp(path.join(tmpdir(), 'video-mcp-'));
|
|
105
|
+
try {
|
|
106
|
+
await new Promise((resolve, reject) => {
|
|
107
|
+
ffmpeg(videoPath)
|
|
108
|
+
.outputOptions([`-vf fps=1/${intervalSec}`])
|
|
109
|
+
.output(path.join(tempDir, 'frame-%04d.png'))
|
|
110
|
+
.on('end', () => resolve())
|
|
111
|
+
.on('error', reject)
|
|
112
|
+
.run();
|
|
113
|
+
});
|
|
114
|
+
const framePaths = (await fs.readdir(tempDir))
|
|
115
|
+
.filter((f) => f.endsWith('.png'))
|
|
116
|
+
.sort();
|
|
117
|
+
const frames = await Promise.all(framePaths.map((f) => fs.readFile(path.join(tempDir, f))));
|
|
118
|
+
return frames;
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Extract frames at specific timestamps
|
|
126
|
+
* @param videoPath - Path to the video file
|
|
127
|
+
* @param timestamps - Array of timestamps in seconds
|
|
128
|
+
* @returns Array of PNG buffers (same order as timestamps)
|
|
129
|
+
*/
|
|
130
|
+
export async function extractFramesAtTimestamps(videoPath, timestamps) {
|
|
131
|
+
const frames = [];
|
|
132
|
+
const tempDir = await mkdtemp(path.join(tmpdir(), 'video-mcp-'));
|
|
133
|
+
try {
|
|
134
|
+
for (let i = 0; i < timestamps.length; i++) {
|
|
135
|
+
const outputPath = path.join(tempDir, `frame-${i}.png`);
|
|
136
|
+
const timestamp = timestamps[i];
|
|
137
|
+
await new Promise((resolve, reject) => {
|
|
138
|
+
ffmpeg(videoPath)
|
|
139
|
+
.seekInput(timestamp)
|
|
140
|
+
.frames(1)
|
|
141
|
+
.output(outputPath)
|
|
142
|
+
.on('end', () => resolve())
|
|
143
|
+
.on('error', reject)
|
|
144
|
+
.run();
|
|
145
|
+
});
|
|
146
|
+
frames.push(await fs.readFile(outputPath));
|
|
147
|
+
}
|
|
148
|
+
return frames;
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Parse fps string (e.g., "24/1" or "30/1") to number
|
|
156
|
+
*/
|
|
157
|
+
function parseFps(fpsString) {
|
|
158
|
+
if (!fpsString)
|
|
159
|
+
return 0;
|
|
160
|
+
const parts = fpsString.split('/');
|
|
161
|
+
if (parts.length === 2) {
|
|
162
|
+
const numerator = parseInt(parts[0], 10);
|
|
163
|
+
const denominator = parseInt(parts[1], 10);
|
|
164
|
+
if (denominator !== 0) {
|
|
165
|
+
return numerator / denominator;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return parseInt(fpsString, 10) || 0;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=ffmpeg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ffmpeg.js","sourceRoot":"","sources":["../../src/services/ffmpeg.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GLM-4.6V Client
|
|
3
|
+
* Handles video analysis using Z.AI's API
|
|
4
|
+
*/
|
|
5
|
+
export interface GLMClientOptions {
|
|
6
|
+
apiKey: string;
|
|
7
|
+
baseURL?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class GLMClient {
|
|
10
|
+
private apiKey;
|
|
11
|
+
private baseURL;
|
|
12
|
+
constructor(options: GLMClientOptions);
|
|
13
|
+
/**
|
|
14
|
+
* Analyze a video using base64-encoded data
|
|
15
|
+
* @param base64Data - Base64-encoded video data
|
|
16
|
+
* @param question - The question to ask about the video
|
|
17
|
+
* @param useFlash - Use the free-tier flash model
|
|
18
|
+
* @returns The AI analysis response
|
|
19
|
+
*/
|
|
20
|
+
analyzeVideoBase64(base64Data: string, question: string, useFlash?: boolean): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Analyze a video from a URL
|
|
23
|
+
* @param url - URL of the video
|
|
24
|
+
* @param question - The question to ask about the video
|
|
25
|
+
* @param useFlash - Use the free-tier flash model
|
|
26
|
+
* @returns The AI analysis response
|
|
27
|
+
*/
|
|
28
|
+
analyzeVideoUrl(url: string, question: string, useFlash?: boolean): Promise<string>;
|
|
29
|
+
/**
|
|
30
|
+
* Analyze multiple images (e.g., extracted frames)
|
|
31
|
+
*/
|
|
32
|
+
analyzeImages(images: Array<{
|
|
33
|
+
data: string;
|
|
34
|
+
mimeType: string;
|
|
35
|
+
}>, prompt: string, useFlash?: boolean): Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Analyze with thinking mode enabled
|
|
38
|
+
*/
|
|
39
|
+
analyzeWithThinking(content: any[], prompt: string, useFlash?: boolean): Promise<{
|
|
40
|
+
reasoning: string;
|
|
41
|
+
answer: string;
|
|
42
|
+
}>;
|
|
43
|
+
private requestChatCompletion;
|
|
44
|
+
private extractTextFromContent;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Create a GLM client instance from environment variables
|
|
48
|
+
*/
|
|
49
|
+
export declare function createGLMClient(): GLMClient | null;
|
|
50
|
+
//# sourceMappingURL=glmClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glmClient.d.ts","sourceRoot":"","sources":["../../src/services/glmClient.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAwBD,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAQ;gBAEX,OAAO,EAAE,gBAAgB;IAKrC;;;;;;OAMG;IACG,kBAAkB,CACtB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,OAAc,GACvB,OAAO,CAAC,MAAM,CAAC;IAsBlB;;;;;;OAMG;IACG,eAAe,CACnB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,OAAc,GACvB,OAAO,CAAC,MAAM,CAAC;IAoBlB;;OAEG;IACG,aAAa,CACjB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,EACjD,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,OAAc,GACvB,OAAO,CAAC,MAAM,CAAC;IAwBlB;;OAEG;IACG,mBAAmB,CACvB,OAAO,EAAE,GAAG,EAAE,EACd,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,OAAc,GACvB,OAAO,CAAC;QACT,SAAS,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,MAAM,CAAA;KACf,CAAC;YAqEY,qBAAqB;IA2BnC,OAAO,CAAC,sBAAsB;CAoB/B;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,SAAS,GAAG,IAAI,CAMlD"}
|