dsh-pf-stream 0.2.3 → 0.3.0

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.
Files changed (80) hide show
  1. package/README.en.md +119 -95
  2. package/README.md +119 -96
  3. package/client.js +1156 -0
  4. package/icon.svg +18 -0
  5. package/lib/asr/catalog.d.ts +74 -0
  6. package/lib/asr/catalog.js +168 -0
  7. package/lib/asr/catalog.js.map +1 -0
  8. package/lib/asr/detect.d.ts +33 -0
  9. package/lib/asr/detect.js +117 -0
  10. package/lib/asr/detect.js.map +1 -0
  11. package/lib/asr/engine.d.ts +43 -0
  12. package/lib/asr/engine.js +143 -0
  13. package/lib/asr/engine.js.map +1 -0
  14. package/lib/asr/install.d.ts +56 -0
  15. package/lib/asr/install.js +317 -0
  16. package/lib/asr/install.js.map +1 -0
  17. package/lib/asr/verify.d.ts +22 -0
  18. package/lib/asr/verify.js +174 -0
  19. package/lib/asr/verify.js.map +1 -0
  20. package/lib/audio/acousticVad.d.ts +45 -0
  21. package/lib/audio/acousticVad.js +179 -0
  22. package/lib/audio/acousticVad.js.map +1 -0
  23. package/lib/audio/asrProviders.d.ts +51 -0
  24. package/lib/audio/asrProviders.js +251 -0
  25. package/lib/audio/asrProviders.js.map +1 -0
  26. package/lib/audio/asrRouter.d.ts +30 -0
  27. package/lib/audio/asrRouter.js +187 -0
  28. package/lib/audio/asrRouter.js.map +1 -0
  29. package/lib/audio/hallucinationGuard.d.ts +18 -0
  30. package/lib/audio/hallucinationGuard.js +97 -0
  31. package/lib/audio/hallucinationGuard.js.map +1 -0
  32. package/lib/audio/sidecar.d.ts +76 -0
  33. package/lib/audio/sidecar.js +362 -0
  34. package/lib/audio/sidecar.js.map +1 -0
  35. package/lib/audio/subtitleExtractor.d.ts +36 -0
  36. package/lib/audio/subtitleExtractor.js +218 -0
  37. package/lib/audio/subtitleExtractor.js.map +1 -0
  38. package/lib/audio/transcriptCache.d.ts +33 -0
  39. package/lib/audio/transcriptCache.js +126 -0
  40. package/lib/audio/transcriptCache.js.map +1 -0
  41. package/lib/audio/types.d.ts +136 -0
  42. package/lib/audio/types.js +10 -0
  43. package/lib/audio/types.js.map +1 -0
  44. package/lib/host/api.d.ts +23 -0
  45. package/lib/host/api.js +286 -0
  46. package/lib/host/api.js.map +1 -0
  47. package/lib/host/runtime.d.ts +167 -0
  48. package/lib/host/runtime.js +335 -0
  49. package/lib/host/runtime.js.map +1 -0
  50. package/lib/index.d.ts +229 -1
  51. package/lib/index.js +103 -2
  52. package/lib/index.js.map +1 -1
  53. package/lib/session/state.js +4 -0
  54. package/lib/session/state.js.map +1 -1
  55. package/lib/stage0/decoder.d.ts +1 -9
  56. package/lib/stage0/decoder.js +15 -45
  57. package/lib/stage0/decoder.js.map +1 -1
  58. package/lib/stage2/stateMachine.d.ts +4 -1
  59. package/lib/stage2/stateMachine.js +7 -1
  60. package/lib/stage2/stateMachine.js.map +1 -1
  61. package/lib/stage3/deterministicRouter.js +3 -3
  62. package/lib/stage3/deterministicRouter.js.map +1 -1
  63. package/lib/stage3/streamSampler.d.ts +9 -2
  64. package/lib/stage3/streamSampler.js +37 -16
  65. package/lib/stage3/streamSampler.js.map +1 -1
  66. package/lib/stage6/history.d.ts +2 -1
  67. package/lib/stage6/history.js +4 -1
  68. package/lib/stage6/history.js.map +1 -1
  69. package/lib/tool/handler.d.ts +9 -0
  70. package/lib/tool/handler.js +33 -3
  71. package/lib/tool/handler.js.map +1 -1
  72. package/lib/tool/schema.js +23 -3
  73. package/lib/tool/schema.js.map +1 -1
  74. package/lib/tool/streamCall.d.ts +11 -0
  75. package/lib/tool/streamCall.js +122 -9
  76. package/lib/tool/streamCall.js.map +1 -1
  77. package/lib/types.d.ts +9 -0
  78. package/locale/en.json +6 -0
  79. package/locale/zh.json +6 -0
  80. package/package.json +17 -2
package/README.en.md CHANGED
@@ -1,146 +1,170 @@
1
1
  # dsh-pf-stream
2
2
 
3
- [中文](README.md) | **English**
3
+ [中文](https://github.com/Weilv-D/dsh-pf-stream/blob/main/README.md) | **English**
4
4
 
5
- Video perception plugin for DeepSeek Harness (DSH). One tool lets the model "see" local video files:
5
+ Let the agent watch videos: adaptive sampling, plus the spoken lines.
6
6
 
7
- - **Continuous events** → adaptive streaming sampling. During motion, the sampler emits low-token process units by displacement integration. On settle or sharpness peaks, it freezes a high-resolution focus unit.
8
- - **Suspicious time points** → deterministic inspection: metadata probe, frame extraction at given timestamps, uniform slicing, and local RoI zoom-in.
7
+ ## What it does
9
8
 
10
- Every canvas aligns with the DeepSeek-V4.1-Flash vision pipeline: 42-px superpixel grid, billing `r×(c+1)+2`. All four forms bill ≤530 tokens, within the 1024-token per-image limit. The server encodes each canvas at its original resolution.
9
+ - **See**: motion is recorded as it happens; the moment it settles, detail is captured. Any timestamp can be inspected at full resolution.
10
+ - **Hear**: subtitles are used when present; otherwise a transcription engine produces the speech and mounts it on the matching frames.
11
+ - **Optional setup**: video works without transcription; with it, videos that only have a voice track also work.
11
12
 
12
- ## Capability routing
13
+ ## Install
13
14
 
14
- One tool, `dsh-pf-stream`, routes through `intent.action`:
15
+ ### 1. Install ffmpeg
15
16
 
16
- | action | engine | use |
17
- | --- | --- | --- |
18
- | `pf_stream` (default) | adaptive streaming | 336² process units (P) during motion; 672² focus units (F) on settle/peak. Schmitt four-state machine + two-layer adaptation (intent baseline + content feedback R1-R4) |
19
- | `timestamps` | deterministic inspection | high-resolution frames at given timestamps; `roi_hint` zoom-in |
20
- | `uniform` | deterministic inspection | uniform slicing by step or target frame count |
21
- | `probe` | deterministic inspection | metadata only (display size, rotation, last-frame PTS, stream summary); zero vision tokens |
17
+ The plugin decodes video with ffmpeg. Check that it runs:
22
18
 
23
- ## Install
19
+ ```bash
20
+ ffmpeg -version
21
+ ffprobe -version
22
+ ```
24
23
 
25
- ### 1. Install the plugin
24
+ Both must print output. If not:
26
25
 
27
- - Open the DSH plugin manager, search for `dsh-pf-stream`, and install the latest version.
28
- - Or tell the agent "install the plugin dsh-pf-stream"; the agent runs the same flow through plugin_manager.
26
+ | OS | Command |
27
+ | --- | --- |
28
+ | Windows | `winget install Gyan.FFmpeg` |
29
+ | macOS | `brew install ffmpeg` |
30
+ | Ubuntu / Debian | `sudo apt install ffmpeg` |
29
31
 
30
- The host performs the install: it adds the package through pnpm and mounts the plugin from `cordis.patch.yml`. Peer dependencies `@deepseek-ai/cordis` and `@deepseek-ai/schemastery` resolve in the host runtime. The only runtime dependency is `pngjs`; canvas PNG encoding uses fixed parameters, so output bytes are deterministic.
32
+ Open a new terminal and check again. To keep it out of PATH, set `ffmpegPath` and `ffprobePath` in the plugin config.
31
33
 
32
- ### 2. Prepare ffmpeg and ffprobe
34
+ ### 2. Install the plugin in DSH
33
35
 
34
- Pick one install method:
36
+ 1. Open DSH and click **Plugins** in the left sidebar.
37
+ 2. Find **Video understanding** (package `dsh-pf-stream`).
38
+ 3. Open its detail page and switch it on (top right).
39
+ 4. On first enable, a setup card appears on the detail page.
35
40
 
36
- ```bash
37
- winget install Gyan.FFmpeg # Windows
38
- brew install ffmpeg # macOS
39
- sudo apt install ffmpeg # Debian / Ubuntu
41
+ If it is not listed, use the install entry on the Plugins page to install `dsh-pf-stream` from npm, then return here.
42
+
43
+ You can also hand the install to the agent:
44
+
45
+ ```text
46
+ Install the DSH plugin dsh-pf-stream:
47
+ 1. Install the latest version from npm with the plugin manager; success means result applied;
48
+ 2. Check ffmpeg and ffprobe; install them if missing (Windows: winget install Gyan.FFmpeg / macOS: brew install ffmpeg / Linux: sudo apt install ffmpeg);
49
+ 3. Call probe on a local video; duration and resolution in the result means success;
50
+ 4. Report the plugin version, ffmpeg location, and check results.
40
51
  ```
41
52
 
42
- You can also download from [ffmpeg.org](https://ffmpeg.org/download.html), unpack, and point an environment variable at the `bin` directory. Executable search order: plugin config `ffmpegPath` / `ffprobePath` → `DSH_FFMPEG_PATH` / `FFMPEG_PATH` → `DSH_FFMPEG_DIR` → `~/.dsh/tools/ffmpeg/bin` → `~/.dsh/bin` → `PATH`.
53
+ ## First run: configure transcription
43
54
 
44
- ### 3. Verify the installation
55
+ The transcription engine decides whether videos without subtitles get speech text. Without it, video still works; only the transcript is missing.
45
56
 
46
- After installation the model-side tool `dsh-pf-stream` appears. Probe any local video:
57
+ To open the settings: **Plugins in the left sidebar → Video understanding → the panel below the description**. Use the same path later to change settings.
47
58
 
48
- ```json
49
- { "video_path": "D:/videos/demo.mp4", "intent": { "action": "probe" } }
50
- ```
59
+ Three cards at the top report video decode (ffmpeg), local transcription, and cloud transcription. Pick one path:
51
60
 
52
- A response with display size, duration, and frame rate confirms a working installation.
61
+ | Path | Best for | What to do |
62
+ | --- | --- | --- |
63
+ | Local (recommended) | Free, offline, no API key | Click "Download local model" (~190 MB), then "Test transcription" |
64
+ | Cloud | You have a key, or the machine is slow | Pick OpenAI / Groq / a custom compatible endpoint, paste the key, save, then test |
65
+ | Skip for now | Videos have subtitles | Use it as is; speech-only videos get no transcript |
53
66
 
54
- ## Usage
67
+ Local model steps:
55
68
 
56
- Streaming perception ("what text is on screen"):
69
+ 1. Click "Download local model". The progress bar shows bytes received; cancel at any time.
70
+ 2. Clicking again after an interruption resumes the download.
71
+ 3. When done, the card reads "Ready · whisper.cpp".
72
+ 4. Click "Test transcription". "Local engine available" means it works.
57
73
 
58
- ```json
59
- {
60
- "video_path": "D:/videos/demo.mp4",
61
- "intent": { "action": "pf_stream", "focus": "detail", "mode": "dense" }
62
- }
63
- ```
74
+ Cloud key steps:
75
+
76
+ 1. Choose a provider under "Cloud transcription key".
77
+ 2. Paste the API key and click "Save". After saving, only "Configured" is shown; the key is never echoed back.
78
+ 3. Click "Test transcription" to verify the key and network.
64
79
 
65
- Point inspection (text found at 12.9 s in a streaming result):
66
-
67
- ```json
68
- {
69
- "video_path": "D:/videos/demo.mp4",
70
- "intent": {
71
- "action": "timestamps",
72
- "timestamps_ms": [12900],
73
- "roi_hint": { "x": 0.2, "y": 0.3, "w": 0.4, "h": 0.4 }
74
- }
75
- }
80
+ The default policy is `auto`: use a cloud key when configured, otherwise the local engine. Under "Advanced" you can switch to local only, cloud only, or off.
81
+
82
+ One-click install currently supports Windows x64. On other systems, install whisper.cpp and set `audio.asr.local.binPath` in the config file, or use cloud transcription.
83
+
84
+ ## Use it
85
+
86
+ Give the agent a video path and ask:
87
+
88
+ - "What happens in this video?"
89
+ - "What does the text at 12.9 seconds say?"
90
+ - "Take one frame every 5 seconds and describe how it changes."
91
+ - "Transcribe this interview with timestamps."
92
+
93
+ Example output (excerpt):
94
+
95
+ ```text
96
+ [Packet #42 | Anchor: #105 | #101(P, 12.1s, Left-Top) → #105(F, 13.4s, Center)]
97
+ Audio @Packet #42: [12.1s-12.9s] "we prepared this for three years" | [13.0s-13.4s] "today we can finally say it"
76
98
  ```
77
99
 
78
- The top level also accepts common convenience fields from the video-inspection domain: `start_time`, `end_time`, `timestamps`, `fps`, `interval`, `num_frames`, `crop`, `probe_only`. The entry adapter normalizes them into the standard `intent` structure.
100
+ The text block is structured metadata: each canvas packet reports time, form, anchor, and unit positions; the audio part reports status, source, and per-line timings. The image block is one canvas per packet.
79
101
 
80
- ## Returned content
102
+ Four ways to look, by question:
81
103
 
82
- Each call returns one or more canvas packets:
104
+ | Goal | Ask |
105
+ | --- | --- |
106
+ | Overview first | "Look at this video" — streaming sampling; motion as process, settle as detail |
107
+ | One exact moment | "What is written at 12.9s" — deterministic high-resolution frame |
108
+ | Even coverage | "One frame every 5 seconds" — uniform sampling |
109
+ | A region | "Zoom into the bottom right" — crop by area, then look |
83
110
 
84
- - **PNG canvas**: one of four forms (table below). Two-tone separator lines block edge-feature crosstalk between units; an optional superpixel badge renders unit IDs.
85
- - **Structured metadata**: `packet_id`, per-unit PTS, token-grid bbox, source-sampling bbox, dual-carrier SHA-256.
86
- - **Timeline hint line**: a model-readable P/F timeline, for example `[Packet #42 | Anchor: #105 | #101(P, 12.1s, Left-Top) → …]`.
111
+ ## Design
87
112
 
88
- Session capabilities:
113
+ ### Dual-scale streaming perception
89
114
 
90
- - Intent persists across calls.
91
- - Streaming cursor resume: the next call on the same video continues from the last position.
92
- - Two-tier history reference: the hot tier reuses the latest 2 full strips; the cold tier reuses up to 4 independent F-anchor carriers.
93
- - Epoch compaction: hot-to-cold conversion in batches of 6 packets, keeping the multi-turn Prefix KV-Cache prefix stable.
115
+ Video is not sampled at a fixed rate. While the picture moves, low-resolution process units (P) record change; when it settles, high-resolution freeze units (F) keep detail. A single canvas packet carries both process and result, so the model does not need to re-watch a clip to recover one detail.
94
116
 
95
- ## Canvas and billing
117
+ The sampling cadence follows the picture: fast change lowers density to avoid duplicates; slow change waits for a settle before freezing. Long static stretches keep a heartbeat instead of repeating images.
96
118
 
97
- | form | layout | tokens |
98
- | --- | --- | --- |
99
- | `FORM_1_STANDARD_STRIP` | 4P + 1F, 1344×672 | 530 |
100
- | `FORM_2_COMPACT_4P` | 4P, 672×672 | 274 |
101
- | `FORM_3_COMPACT_1F` | 1F, 672×672 | 274 |
102
- | `FORM_4_PARTIAL_STRIP` | 1-3P + 1F, 1344×672 | 530 |
119
+ ### Canvas packing and metering
103
120
 
104
- ## Canvas samples
121
+ A frame is divided into 42 px superpixel-aligned units. P or F units are taken as needed and packed into one canvas. One call can carry several packets; each packet holds only the units that are new, and older packets collapse into reference hashes instead of resending images. Metering follows the canvas grid (`r × (c + 1) + 2`).
105
122
 
106
- `FORM_1` standard strip: four process units (P) on the left, one focus unit (F) on the right.
123
+ ### Deterministic inspection
107
124
 
108
- ![FORM_1 standard strip](https://raw.githubusercontent.com/Weilv-D/dsh-pf-stream/main/assets/screenshot-1.png)
125
+ Besides streaming, three paths are deterministic: `probe` reads metadata only; `timestamps` returns exact frames in milliseconds; `uniform` samples at a fixed interval; `roi_hint` crops a region. These do not depend on motion detection, so results are reproducible and suited to reading text, numbers, and small objects.
109
126
 
110
- `FORM_2` process-only: four process units.
127
+ ### Three sources for speech
111
128
 
112
- ![FORM_2 process-only](https://raw.githubusercontent.com/Weilv-D/dsh-pf-stream/main/assets/screenshot-2.png)
129
+ 1. **Subtitles**: a sidecar `.srt` / `.vtt` with the same name first, then embedded soft subtitles.
130
+ 2. **Acoustic check**: without subtitles, silence detection and a speech-ratio estimate run first; an all-silent video skips transcription.
131
+ 3. **Transcription**: local whisper.cpp, or OpenAI / Groq / a custom compatible endpoint. Segments are mounted on packets by PTS and stitched across block boundaries with a ±300 ms tolerance.
113
132
 
114
- `FORM_3` single focus: RoI zoom review via `roi_hint`.
133
+ The default is "picture first, speech later": when the soft deadline (`graceMs`, 8 s by default) passes, the visual result returns and transcription continues in the background; the next call on the same video hits the disk cache.
115
134
 
116
- ![FORM_3 single focus RoI zoom](https://raw.githubusercontent.com/Weilv-D/dsh-pf-stream/main/assets/screenshot-3.png)
135
+ ### Old regions
117
136
 
118
- ## Configuration
137
+ Canvas packets outside the window collapse into references (anchor hash, time, and transcript text) instead of resending images. A timestamp call brings the detail back when needed.
119
138
 
120
- | option | default | description |
121
- | --- | --- | --- |
122
- | `renderVisualId` | `true` | superpixel inverse badge at each unit corner |
123
- | `maxPacketsPerCall` | `64` | packet count limit per call |
124
- | `maxFramesPerCall` | `128` | deterministic frame target limit per call (clamps `frame_count`) |
125
- | `maxTokensBudgetPerCall` | `65536` | vision-token budget per call |
126
- | `maxRequestBytes` | `56 MiB` | request byte watermark, Base64-inclusive |
127
- | `maxColdRefs` | `4` | cold-tier reference limit |
128
- | `defaultStreamWindowMs` | `10000` | window length in ms when `pts_window` is absent |
129
- | `streamWorkMaxEdge` | `2048` | working-resolution long edge for streaming decode; deterministic inspection always uses full resolution |
130
- | `epochCompactionWindow` | `6` | hot-to-cold batch window, in packets |
131
- | `meteringProfile.imageCountTiersEnabled` | `false` | gate for the ≥15-image 4096-px rule |
132
-
133
- ## Testing
139
+ ## Troubleshooting
140
+
141
+ | Symptom | Read |
142
+ | --- | --- |
143
+ | ffmpeg not found | [ffmpeg](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/排障.md#找不到-ffmpeg) |
144
+ | Speech but no transcript | [No transcript](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/排障.md#有声音但没有台词) |
145
+ | Model download fails or is slow | [Download](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/排障.md#下载失败) |
146
+ | Transcription is slow or times out | [Slow transcription](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/排障.md#转写很慢或超时) |
147
+ | Settings page is read-only | [Read-only config](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/排障.md#设置页只读) |
148
+
149
+ ## Docs
150
+
151
+ - [Usage Guide](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/usage-guide.md) (English)
152
+ - [使用指南](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/使用指南.md) (Chinese)
153
+ - [排障](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/排障.md) (Chinese)
154
+ - [开发者指南](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/开发者指南.md) (Chinese): architecture, host contracts, tests, release
155
+
156
+ ## Development
134
157
 
135
158
  ```bash
136
- pnpm test # boundary (pure logic) + e2e (fixture-driven), 20 boundary cases
137
- pnpm run build # TypeScript compile
138
- pnpm verify:host # host-contract self-check (schema shape, keyword subset, dependency boundary)
159
+ pnpm build
160
+ pnpm test
161
+ pnpm verify:host
162
+ pnpm check:package
139
163
  ```
140
164
 
141
- ## Release
165
+ The host half provides the `dsh-pf-stream` tool (`probe` / `pf_stream` / `timestamps` / `uniform`), the audio sidecar, the local engine installer, and the settings API. The client half is `client.js`, which registers the config panel and the setup card on the plugin detail page. The only runtime dependency is `pngjs`.
142
166
 
143
- npm releases run automatically through GitHub Actions. Process and version policy: [docs/发布规范.md](docs/发布规范.md) (Chinese).
167
+ Configuration is written through `ctx.configEditor.edit()`, which keeps fields the user did not touch; keys live in `ctx.credentials`, and the config file only holds a reference.
144
168
 
145
169
  ## License
146
170
 
package/README.md CHANGED
@@ -1,147 +1,170 @@
1
1
  # dsh-pf-stream
2
2
 
3
- **中文** | [English](README.en.md)
3
+ **中文** | [English](https://github.com/Weilv-D/dsh-pf-stream/blob/main/README.en.md)
4
4
 
5
- DeepSeek Harness(DSH)视频感知插件。模型用一个工具即可「看」本地视频:
5
+ 让智能体看懂视频:动态抽帧,加上台词。
6
6
 
7
- - **连续事件** → 自适应流式采样。运动时按位移积分抽低 token 过程单元;停稳与顿挫波峰时定格高清焦点单元。
8
- - **可疑时间点** → 确定性检视。能力:元数据探测、指定时间戳抽帧、均匀切片、局部 RoI 放大复核。
7
+ ## 能做什么
9
8
 
10
- 全部画布对齐 DeepSeek-V4.1-Flash 视觉编码管线:42px 超像素网格,计费 `r×(c+1)+2`。四种形态计费均 ≤530 token,满足单图 1024 token 上限。服务端按画布原始分辨率计量。
9
+ - **看画面**:画面运动时记录过程,停稳时定格细节;指定时间点可以高清复核。
10
+ - **听声音**:有字幕就用字幕;没有字幕时,配置转写引擎后生成台词,并按时间挂到对应画面。
11
+ - **按需配置**:不配置转写也能处理画面;配置后可以处理带音轨的视频。
11
12
 
12
- ## 能力路由
13
+ ## 安装
13
14
 
14
- 一个主工具 `dsh-pf-stream`,统一 `intent.action` 路由:
15
+ ### 第一步:安装 ffmpeg
15
16
 
16
- | action | 引擎 | 用途 |
17
- | --- | --- | --- |
18
- | `pf_stream`(默认) | 动态流式采样 | 运动中抽 336² 过程单元(P);停稳/波峰定格 672² 焦点单元(F)。施密特四状态机 + 双层自适应调节(意图基准 + 内容自闭环 R1-R4) |
19
- | `timestamps` | 确定性检视 | 指定时间戳单帧/组合高清检视,支持 `roi_hint` 局部放大 |
20
- | `uniform` | 确定性检视 | 固定步长或目标帧数均匀切片 |
21
- | `probe` | 确定性检视 | 仅元数据(显示宽高/旋转/末帧 PTS/流摘要),零视觉 token |
17
+ 插件用 ffmpeg 解码视频。先确认它能运行:
22
18
 
23
- ## 安装
19
+ ```bash
20
+ ffmpeg -version
21
+ ffprobe -version
22
+ ```
24
23
 
25
- ### 1. 安装插件
24
+ 两条都要有输出。没有的话:
26
25
 
27
- - 在 DSH 插件管理器中搜索 `dsh-pf-stream`,安装最新版本。
28
- - 或直接对智能体说「安装插件 dsh-pf-stream」,智能体经 plugin_manager 完成同一流程。
26
+ | 系统 | 安装命令 |
27
+ | --- | --- |
28
+ | Windows | `winget install Gyan.FFmpeg` |
29
+ | macOS | `brew install ffmpeg` |
30
+ | Ubuntu / Debian | `sudo apt install ffmpeg` |
29
31
 
30
- 安装由宿主执行:宿主经 pnpm 安装包,读取 `cordis.patch.yml` 挂载插件。peer 依赖 `@deepseek-ai/cordis` 与 `@deepseek-ai/schemastery` 由宿主运行时解析;运行时直接依赖仅 `pngjs`,画布 PNG 编码参数固定,输出字节幂等。
32
+ 装完新开一个终端再验证。不想放进 PATH,可以在插件配置里写 `ffmpegPath` 与 `ffprobePath` 的绝对路径。
31
33
 
32
- ### 2. 准备 ffmpeg 与 ffprobe
34
+ ### 第二步:在 DSH 里安装插件
33
35
 
34
- 任选一种安装方式:
36
+ 1. 打开 DSH,点左侧栏的「插件」。
37
+ 2. 在列表里找「视频理解」(包名 `dsh-pf-stream`)。
38
+ 3. 点进详情页,把右上角的开关打开。
39
+ 4. 第一次开启后,详情页会出现引导卡片。
35
40
 
36
- ```bash
37
- winget install Gyan.FFmpeg # Windows
38
- brew install ffmpeg # macOS
39
- sudo apt install ffmpeg # Debian / Ubuntu
41
+ 列表里没有时,用插件页的安装入口从 npm 安装 `dsh-pf-stream`,装完再回到这一步。
42
+
43
+ 也可以把安装交给智能体:
44
+
45
+ ```text
46
+ 安装 DSH 插件 dsh-pf-stream:
47
+ 1. 用插件管理器从 npm 安装最新版本,结果为 applied 才算成功;
48
+ 2. 检查 ffmpeg 与 ffprobe;缺失时安装(Windows: winget install Gyan.FFmpeg / macOS: brew install ffmpeg / Linux: sudo apt install ffmpeg);
49
+ 3. 对一个本地视频调用 probe;返回时长与分辨率即成功;
50
+ 4. 汇报插件版本、ffmpeg 位置与检查结果。
40
51
  ```
41
52
 
42
- 也可从 [ffmpeg.org](https://ffmpeg.org/download.html) 下载解压,用环境变量指向 `bin` 目录。可执行文件定位顺序:插件配置 `ffmpegPath` / `ffprobePath` → `DSH_FFMPEG_PATH` / `FFMPEG_PATH` → `DSH_FFMPEG_DIR` → `~/.dsh/tools/ffmpeg/bin` → `~/.dsh/bin` → `PATH`。
53
+ ## 第一次配置转写
43
54
 
44
- ### 3. 验证安装
55
+ 转写引擎决定「没有字幕的视频能不能拿到台词」。不配置也能看画面,只是不会生成转写文本。
45
56
 
46
- 安装成功后,模型侧出现工具 `dsh-pf-stream`。用任一本地视频探测元数据:
57
+ 进入配置页:**左侧栏「插件」→ 点「视频理解」→ 详情页描述下方的面板**。以后要改设置,走同一条路。
47
58
 
48
- ```json
49
- { "video_path": "D:/videos/demo.mp4", "intent": { "action": "probe" } }
50
- ```
59
+ 面板顶部有三张状态卡:视频解码(ffmpeg)、本地转写、云端转写。按需要选一条路线:
51
60
 
52
- 返回显示宽高、时长、帧率,即安装成功。
61
+ | 路线 | 适合 | 操作 |
62
+ | --- | --- | --- |
63
+ | 本地转写(推荐) | 免费、离线、不填密钥 | 点「下载本地模型」,约 190 MB;下载完点「测试转写」 |
64
+ | 云端转写 | 已有 API Key,或机器性能较弱 | 选 OpenAI / Groq / 自定义兼容端点,填 Key,保存后点「测试转写」 |
65
+ | 暂不配置 | 视频都有字幕 | 直接使用;无字幕的语音视频不会生成转写文本 |
53
66
 
54
- ## 使用
67
+ 本地模型的下载步骤:
55
68
 
56
- 流式感知(问「画面里写了什么」):
69
+ 1. 点「下载本地模型」。进度条显示已下载大小,可随时取消。
70
+ 2. 下载中断后再次点击会续传,不用从头开始。
71
+ 3. 完成后状态卡显示「已就绪 · whisper.cpp」。
72
+ 4. 点「测试转写」。返回「本地引擎可用」即配置成功。
57
73
 
58
- ```json
59
- {
60
- "video_path": "D:/videos/demo.mp4",
61
- "intent": { "action": "pf_stream", "focus": "detail", "mode": "dense" }
62
- }
63
- ```
74
+ 云端密钥的保存步骤:
75
+
76
+ 1. 在「云端转写密钥」里选服务商。
77
+ 2. 粘贴 API Key,点「保存」。保存后只显示「已配置」,不再回显密钥。
78
+ 3. 点「测试转写」验证密钥与网络。
64
79
 
65
- 定点复核(流式结果中 12.9s 处发现文字):
66
-
67
- ```json
68
- {
69
- "video_path": "D:/videos/demo.mp4",
70
- "intent": {
71
- "action": "timestamps",
72
- "timestamps_ms": [12900],
73
- "roi_hint": { "x": 0.2, "y": 0.3, "w": 0.4, "h": 0.4 }
74
- }
75
- }
80
+ 默认策略是 `auto`:云端密钥、端点、模型都齐时用云端(更快,按量计费);否则用本地引擎。面板标题旁会显示当前实际使用的引擎,如「转写可用 · 云端」。可以在「高级」里改成仅本地、仅云端或不转写。
81
+
82
+ 一键安装当前支持 Windows x64。其他系统请先安装 whisper.cpp,在配置文件 `audio.asr.local.binPath` 填写可执行文件路径,或改用云端转写。
83
+
84
+ ## 开始使用
85
+
86
+ 在对话里直接给视频路径并提问:
87
+
88
+ - 「这个视频里发生了什么?」
89
+ - 「第 12.9 秒的文字写的是什么?」
90
+ - 「每 5 秒抽一帧,看画面怎么变化。」
91
+ - 「把这段访谈里说的话按时间整理出来。」
92
+
93
+ 返回示例(节选):
94
+
95
+ ```text
96
+ [Packet #42 | Anchor: #105 | #101(P, 12.1s, Left-Top) → #105(F, 13.4s, Center)]
97
+ Audio @Packet #42: [12.1s-12.9s] "这件事我们准备了三年" | [13.0s-13.4s] "今天终于可以说了"
76
98
  ```
77
99
 
78
- 顶层同时接受视频检视领域常见便捷字段:`start_time` / `end_time` / `timestamps` / `fps` / `interval` / `num_frames` / `crop` / `probe_only`。入口适配器将其归一化为标准 `intent` 结构。
100
+ 文本块是结构化元数据:每个画布包给出时间、形态、锚点与单元位置;音频部分给出状态、来源与逐句时间。图像块是每个画布包一张画布。
79
101
 
80
- ## 返回内容
102
+ 常用问法对应四种取帧方式:
81
103
 
82
- 每次调用返回一个或多个画布包:
104
+ | 想要 | 说法 |
105
+ | --- | --- |
106
+ | 先看整体 | 「看看这个视频」——流式采样,运动记过程、停稳给细节 |
107
+ | 只看某一秒 | 「第 12.9 秒写了什么」——定点高清帧 |
108
+ | 均匀看一遍 | 「每 5 秒抽一帧」——等间隔抽帧 |
109
+ | 看局部 | 「放大右下角」——按区域裁剪后再看 |
83
110
 
84
- - **PNG 画布**:四形态之一(见下表)。单元间双色隔离线阻断相邻边缘特征串扰;可选超像素角标渲染单元编号。画布 PNG 同时作为图像内容块进入模型上下文(单次调用至多 `maxImagesPerCall` 张)。
85
- - **结构化元数据**:`packet_id`、每单元 PTS、token 网格 bbox、源采样 bbox、双载体 SHA-256。
86
- - **时序提示行**:模型可读的 P/F 单元时间轴(如 `[Packet #42 | Anchor: #105 | #101(P, 12.1s, Left-Top) → …]`)。
111
+ ## 特点
87
112
 
88
- 会话级能力:
113
+ ### 双尺度流式感知
89
114
 
90
- - 意图跨调用持久化。
91
- - 流式游标续窗:同视频下次调用从上次位置继续。
92
- - 两级历史引用:热区最近 2 包整条带复用;冷区至多 4 个 F 锚点独立载体复用。
93
- - Epoch Compaction:默认 6 包窗口批量热转冷,保持多轮对话 Prefix KV-Cache 前缀稳定。
115
+ 视频不再平均抽帧。画面运动时,插件用低分辨率的过程单元(P)记录变化;画面停稳后,用高分辨率的定格单元(F)保留细节。同一个画布包里既有过程也有结果,模型不用为了一个细节反复回看整段视频。
94
116
 
95
- ## 画布与计费
117
+ 采样节奏由画面变化驱动:变化快时降低采样密度、避免重复帧;变化慢时等待停稳再定格。长静止画面用心跳保持时间感,不重复发图。
96
118
 
97
- | 形态 | 布局 | Token |
98
- | --- | --- | --- |
99
- | `FORM_1_STANDARD_STRIP` | 4P + 1F,1344×672 | 530 |
100
- | `FORM_2_COMPACT_4P` | 4P,672×672 | 274 |
101
- | `FORM_3_COMPACT_1F` | 1F,672×672 | 274 |
102
- | `FORM_4_PARTIAL_STRIP` | 1-3P + 1F,1344×672 | 530 |
119
+ ### 画布打包与计费
103
120
 
104
- ## 画布样例
121
+ 一帧画面被切成 42px 超像素对齐的单元,按需取 P 或 F,再拼成一张画布。一次调用可以带多个画布包;每个包只包含当前新增的单元,历史包以引用哈希折叠,不重复传图。计费按画布网格计算(`r × (c + 1) + 2`)。
105
122
 
106
- `FORM_1` 标准条带:左半 4 个过程单元(P),右半 1 个焦点单元(F)。
123
+ ### 确定性检视
107
124
 
108
- ![FORM_1 标准条带](https://raw.githubusercontent.com/Weilv-D/dsh-pf-stream/main/assets/screenshot-1.png)
125
+ 流式采样之外,另外三条路径是确定性的:`probe` 只读元数据;`timestamps` 按毫秒取指定帧;`uniform` 按固定间隔取帧;`roi_hint` 裁剪指定区域。这几种不依赖运动检测,结果可复现,适合核对文字、数字与小目标。
109
126
 
110
- `FORM_2` 纯过程:4 个过程单元。
127
+ ### 台词的三级来源
111
128
 
112
- ![FORM_2 纯过程](https://raw.githubusercontent.com/Weilv-D/dsh-pf-stream/main/assets/screenshot-2.png)
129
+ 1. **字幕**:优先用外挂同名 `.srt` / `.vtt`,其次内嵌软字幕。
130
+ 2. **声学判断**:没有字幕时先做静音检测与语音占比估计;全程静音的视频直接跳过转写。
131
+ 3. **语音转写**:本地 whisper.cpp,或 OpenAI / Groq / 自定义兼容端点。转写结果按 PTS 挂到对应画布包,跨块边界按 ±300ms 缝合。
113
132
 
114
- `FORM_3` 单焦点:`roi_hint` 局部放大检视。
133
+ 默认「先回画面、后台补台词」:首次调用超过软截止(`graceMs`,默认 8 秒)就先返回视觉结果,转写在后台继续;同一视频再调用时直接命中磁盘缓存。
115
134
 
116
- ![FORM_3 单焦点 RoI 放大](https://raw.githubusercontent.com/Weilv-D/dsh-pf-stream/main/assets/screenshot-3.png)
135
+ ### 长视频的冷区
117
136
 
118
- ## 配置
137
+ 超出窗口的历史画布包会折叠成引用(锚点哈希 + 时间 + 台词文本),不重复传图。需要回看时再按时间点取帧。
119
138
 
120
- | 配置项 | 默认 | 说明 |
121
- | --- | --- | --- |
122
- | `renderVisualId` | `true` | 单元左上角超像素反色角标 |
123
- | `maxPacketsPerCall` | `64` | 单次调用返回包数上限 |
124
- | `maxFramesPerCall` | `128` | 确定性抽帧单次目标帧数上限(`frame_count` 受此钳制) |
125
- | `maxImagesPerCall` | `20` | 单次调用回传图像上限(宿主单条消息图像上限 20) |
126
- | `maxTokensBudgetPerCall` | `65536` | 单次调用视觉 token 预算 |
127
- | `maxRequestBytes` | `56 MiB` | 请求字节软水位(Base64 后口径) |
128
- | `maxColdRefs` | `4` | 冷区引用上限 |
129
- | `defaultStreamWindowMs` | `10000` | `pts_window` 缺省时窗口长度(毫秒) |
130
- | `streamWorkMaxEdge` | `2048` | 流式解码工作分辨率长边上限(定点检视恒全分辨率) |
131
- | `epochCompactionWindow` | `6` | 热转冷批量收敛窗口(包数) |
132
- | `meteringProfile.imageCountTiersEnabled` | `false` | ≥15 图单边 4096px 规则门控 |
133
-
134
- ## 测试
139
+ ## 遇到问题
140
+
141
+ | 现象 | 先看这里 |
142
+ | --- | --- |
143
+ | 提示找不到 ffmpeg | [排障:ffmpeg](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/排障.md#找不到-ffmpeg) |
144
+ | 有声音,但没有台词 | [排障:没有台词](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/排障.md#有声音但没有台词) |
145
+ | 下载模型失败或很慢 | [排障:下载失败](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/排障.md#下载失败) |
146
+ | 转写很慢、超时 | [排障:转写慢](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/排障.md#转写很慢或超时) |
147
+ | 设置页显示「只读」 | [排障:配置只读](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/排障.md#设置页只读) |
148
+
149
+ ## 文档
150
+
151
+ - [使用指南](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/使用指南.md):用法、参数、返回内容、计费、全部配置项
152
+ - [排障](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/排障.md):按现象查原因
153
+ - [开发者指南](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/开发者指南.md):架构、宿主契约、测试与发布
154
+ - [Usage Guide](https://github.com/Weilv-D/dsh-pf-stream/blob/main/docs/usage-guide.md)(English)
155
+
156
+ ## 本地开发
135
157
 
136
158
  ```bash
137
- pnpm test # boundary(纯逻辑)+ e2e(fixture 驱动),20 项边界用例
138
- pnpm run build # TypeScript 编译
139
- pnpm verify:host # 宿主契约自检(Schema 形状/关键字子集/依赖边界)
159
+ pnpm build
160
+ pnpm test
161
+ pnpm verify:host
162
+ pnpm check:package
140
163
  ```
141
164
 
142
- ## 发布
165
+ Host 半提供工具 `dsh-pf-stream`(`probe` / `pf_stream` / `timestamps` / `uniform`)、音频边车、本地引擎安装器与设置接口;Client 半是 `client.js`,在插件详情页注册配置面板与引导卡片。运行时依赖只有 `pngjs`。
143
166
 
144
- npm 发布由 GitHub Actions 自动执行。流程与版本策略见 [docs/发布规范.md](docs/发布规范.md)。
167
+ 配置通过 `ctx.configEditor.edit()` 写入,保留用户未触碰的字段;密钥通过 `ctx.credentials` 存取,配置文件只保留引用。
145
168
 
146
169
  ## 许可证
147
170