故事板 graph:全部场次与选集共用同一套持久化(无 __all__ 兜底)

目标(已确认)
  • 「全部场次 + 点场次」「选集 + 点同一场次」读写同一 storyboard_graph_state 键:(project_id, episode_id=剧集节点 id, chapter_id=场次节点 id)

  • 不需要兜底、不考虑历史兼容:可删除/收紧依赖 __all__ / STORYBOARD_SCOPE_ALL 的故事板前端路径;遗留库中仅 __all__ 键下的 graph 行可视为可丢弃(不迁移)。

  • 以项目最优解落地:单一解析函数 + 全链路同一 episodeId,避免双轨。

核心结论

推荐实现(最优、改动面收敛)

1. 单一「故事板剧集作用域」解析(前端)

新增小工具(例如 ui/src/domain/storyboardEpisodeScope.ts)或内联 useMemo

// 语义:显式选集 > App 传入的 chapter > 当前场次所属剧集
resolvedStoryboardEpisodeId =
  (activeChapterId?.trim() ||
    chapter?.id?.trim() ||
    activeScene?.chapter_id?.trim() ||
    "");
  • StoryboardTabsceneGraphEpisodeId 改为上述 resolvedStoryboardEpisodeId不再 || STORYBOARD_SCOPE_ALL)。

  • 无场次:不加载 graph(现有逻辑已处理)。

  • 有场次但 resolved 为空:视为数据损坏/孤儿场次 — 不兜底:toast 固定文案(如「场次未关联剧集,无法加载故事板画布」),loadStoryboardGraph / save 不调用;与「不要兼容」一致。

2. 与 graph 键一致的所有调用点(前端)

以下必须使用同一 resolvedStoryboardEpisodeId(从 StoryboardTab 下传或从 App 用相同公式计算,避免分叉):

位置

调整

[useStoryboardSceneGraph](d:/00Dev/bgxiong-ai-story/ui/src/components/storyboard/hooks/useStoryboardSceneGraph.ts)

load/save、cache scope、pendingepisodeId 均用解析结果;sceneGraphCacheScopeKey 中去掉对 STORYBOARD_SCOPE_ALL 的回退拼接(空 episode 时不生成 key 或与「无 scene」一致)

[useChapterSceneBoardGenerate](d:/00Dev/bgxiong-ai-story/ui/src/components/storyboard/hooks/useChapterSceneBoardGenerate.ts)

episodeScopeId / 刷新 graph 的 episodeId 与上一致

[useStoryboardCanvasActions](d:/00Dev/bgxiong-ai-story/ui/src/components/storyboard/hooks/useStoryboardCanvasActions.ts)

cleanupStoryboardGraphAfterSegmentDeleteepisodeScopeId 一致

StoryboardTabcompileClipFrameworkFromStoryboard

episodeId 参数一致

SceneI2iPadSelector chapterId

与垫图/场次上下文一致:传 resolvedStoryboardEpisodeId(若该组件语义为「剧集 id」)

App.tsx refreshStoryboardShots

loadOrderedStoryboardNodesUnderScene 第三参改为 activeChapter?.id ?? activeScene?.chapter_id ?? STORYBOARD_SCOPE_ALL 中的前两项优先;最优:抽共享 resolveEpisodeScopeForStoryboard(activeChapter, activeScene) 与 Tab 同式,删除STORYBOARD_SCOPE_ALL 的默认 — 无解析结果则传空并由 loadOrdered 短路或让 loadOrdered 要求必填

3. [sceneStoryboardChildNodes.ts](d:/00Dev/bgxiong-ai-story/ui/src/domain/sceneStoryboardChildNodes.ts)

  • 删除 episodeId 默认值 STORYBOARD_SCOPE_ALL;改为调用方必传 已解析 的剧集 id。

  • episodeId 为空:直接返回 []throw(二选一;推荐返回 [] + 上层 toast,避免未处理异常)。

4. 常量与类型清理

  • [storyboardGraph.ts](d:/00Dev/bgxiong-ai-story/ui/src/domain/storyboardGraph.ts)STORYBOARD_SCOPE_ALL 若仅故事板 graph 使用,可删除并全量替换;若 片段画布等仍用 __all__(见 [types.ts](d:/00Dev/bgxiong-ai-story/ui/src/components/segment-canvas/types.ts)App Clips),则保留常量故事板模块禁止再引用

  • [useStoryboardSceneGraph](d:/00Dev/bgxiong-ai-story/ui/src/components/storyboard/hooks/useStoryboardSceneGraph.ts):移除仅用于 __all__ 回退的 import/拼接。

5. 后端(可选收紧,与「无兜底」对齐)

  • [storyboard_graph::normalize_scope_id](d:/00Dev/bgxiong-ai-story/src-tauri/src/storyboard_graph.rs):对 load_storyboard_graph_state / upsert_storyboard_graph_state 的入口,若 trim 为空则 Err 而非写入/读取 __all__(需同步改 [commands/storyboard.rs](d:/00Dev/bgxiong-ai-story/src-tauri/src/commands/storyboard.rs) 三处 normalize_scope_id)。

  • 风险:仅当保证前端永远传非空剧集 id 时安全;否则 Tauri 命令会报错(符合「严格」)。

  • 文档注释:chapter_scene_board_pipeline.rs 1388 行附近 更新为「episode_scope_id 必须为剧集节点 id,与前端一致」。

6. 数据(不兼容策略)

  • 不编写迁移合并 __all__ → 真实剧集:旧行自然废弃。

  • 可选(本地开发):手动删 storyboard_graph_stateepisode_id='__all__' 的行;作为代码交付必选项。

验证

  • 选集 A → 选场次 S → 改画布 → 切「全部场次」→ 再点 S:布局与节点与选集时一致

  • 从未选集路径进入:仅点 S(activeScene.chapter_id 有值):同上。

  • 清除场次或孤儿场次:resolved 为空时行为符合预期(不静默读 __all__)。

实施任务清单

  1. 引入 resolvedStoryboardEpisodeId 解析并接入 StoryboardTab + 所有子 hook / API 参数。

  2. 更新 App.refreshStoryboardShotssceneStoryboardChildNodes(去默认 __all__)。

  3. 删除故事板路径上对 STORYBOARD_SCOPE_ALL 的依赖;保留或收缩常量定义。

  4. (可选)后端 normalize_scope_id 对空串改为 Err + cargo check

  5. 手动回归两条路径 + npm run build / 相关 ReadLints

有改名字需求的朋友可以...

到官网去改 https://www.bgxiong.com/user/profile
后期我会把这修改资料加入到客户端
再等等...

在尝试找到把SRT转TEXT+的途径

达芬奇API的某些限制,
让现阶段做动态字幕有点困难!

比格熊v1.2.9马上发布 新功能已调色完毕

### 🆕 新功能
**音效卡片拖拽添加**
- SFX 模块和 Mine 模块均支持拖拽音效卡片到时间轴
- 鼠标按下:抓取手型 + 绿色边框 + 音效名称变绿
- 拖拽出插件窗口外释放:自动添加到达芬奇时间轴
- 使用 Pointer Events (`setPointerCapture`) 技术,支持鼠标移出窗口仍能拖拽
- 拖拽预览标签跟随鼠标,拖出窗口时变亮绿色提示
**搜索框自动聚焦**
- 进入音效模块时,搜索框自动获取焦点,可直接输入搜索
### 🔧 技术改进
**Pointer Events 实现**
- 替换传统的 mouse 事件为 pointer 事件
- `pointerdown` + `setPointerCapture` 捕获指针
- `pointermove``pointerup` 处理拖拽和释放
- 解决鼠标移出 Electron 窗口后事件丢失的问题
**拖拽状态管理**
- 统一的 `dragState` 全局状态管理
- `cleanupDragState()` 统一清理样式和状态
- 支持 `pointerId` 追踪和释放
### 🎨 样式优化
- 波形图自适应卡片宽度
- 卡片内边距优化(padding: 6px 5px)
- 波形图边距统一(margin: 2px 2px 0 0)
### 📝 文件变更
**修改文件**
- `renderer.js` - SFX 模块拖拽功能、搜索框聚焦
- `modules/mine/renderer.js` - Mine 模块拖拽功能
- `css/styles.css` - 波形图和卡片样式

置顶 【激活码】20260325新鲜热乎的尝鲜

我这分批放出激活码是为了缓解服务器压力
这是尝鲜测试用激活码不具备长期有效期
J28D-VBZW-44YE-REGJ                             Y8L3-XKU2-U5F4-K6BN
TQ3R-WQVM-6ZTQ-NGG9                         R59Y-JNDL-22S5-QTMT
8LK9-RTTW-2SDM-RSY3                            VLQD-CXVC-69FB-AFJS
83HZ-25DF-562V-Y3DD                              7Q8J-9KRR-5HMD-7BL3
ENMG-GLJM-BU77-7B3J                           SVAQ-PR6P-QH58-HMHT
FAEP-CWME-GEPQ-9RX7

基于 Rust + WebGPU 的技术栈是目前高性能跨平台开发(Native + Web)的最前沿方案。

基于 Rust + WebGPU 的技术栈是目前高性能跨平台开发(Native + Web)的最前沿方案。对于追求性能和系统稳定性的开发者来说,这套组合几乎是“终极形态”。

以下是这套技术栈的核心构成及入门路径:


1. 核心架构:wgpu 生态

在 Rust 社区中,wgpu 是 WebGPU 规范的旗舰级实现。它不仅能让代码运行在浏览器中,还能直接调用 Windows (Direct3D 12)、macOS (Metal) 和 Linux (Vulkan) 的原生驱动。

  • wgpu-rs (核心库): 提供安全的 Rust 绑定。

  • WGSL (WebGPU Shading Language): 官方指定的着色器语言,语法类似 Rust,易于上手,且避开了 GLSL 的历史包袱。

  • naga (着色器翻译器): 负责将 WGSL 翻译为底层 API 能理解的指令。

2. 为什么选择 Rust + WebGPU?

这套方案之所以强大,是因为它解决了两个痛点:内存安全跨平台统一性

3. 入门技术栈建议

如果你准备从零开始构建一个高性能工具(例如 AI 图像处理或视频滤镜引擎),可以参考以下配置:

  • UI 层: eguiiced。这两个库在 Rust 生态中非常流行,且都完美支持 wgpu 后端,适合快速构建跨平台工具界面。

  • 窗口管理: winit。这是 Rust 处理窗口、输入事件的事实标准。

  • 数学运算: nalgebraglam。后者专门为图形学优化,性能极佳。

  • Web 部署: wasm-bindgen。将你的 Rust 逻辑打包成 WebAssembly。

4. 关键应用场景:AI 推理与视频处理

对于本地 AI 推理,你可以利用 WebGPU 的计算着色器 (Compute Shader) 直接对张量进行并行运算。

  • 模型转换: 将模型权重的二进制数据映射到 GPU 的 Storage Buffer

  • 并行计算: 在 WGSL 中编写计算内核(Kernel),实现类似矩阵乘法 (GEMM) 的操作。

  • 零拷贝: 借助 Rust 的高效内存布局,减少 CPU 与 GPU 之间的数据交换延迟。


快速开始建议

  1. 环境配置: 确保 Rust 环境已更新,安装 cargo

  2. 克隆 Demo: 到 GitHub 搜索 gfx-rs/wgpu 仓库,查看其 examples 文件夹。里面有从简单的三角形渲染到复杂的计算着色器应用。

  3. 学习 WGSL: 如果你熟悉 Rust,你会发现 WGSL 的语法非常亲切。

小贴士: 由于你可能处理大量资源或追求极高性能,建议在开发时开启 wgpu 的验证层(Validation Layers),它能帮你捕捉到 90% 以上的非法显存访问错误。

WebGPU 技术了解一下

到 2026 年,WebGPU 已经正式告别了“试验田”阶段,成为了 Web 高性能计算和图形渲染的绝对标准

如果说 WebGL 是在浏览器里“画图”,那么 WebGPU 则是在浏览器里“直接操控 GPU”。

以下是 WebGPU 当前发展的关键维度:

1. 核心生态:从“尝鲜”转向“默认”

WebGPU 1.0 在 2023 年发布后,经历了两年的高速迭代。

  • 引擎全面转向: Three.jsBabylon.js 等主流 Web 图形引擎已经将 WebGPU 作为首选后端。相比 WebGL,WebGPU 在处理复杂场景(如数万个独立对象的渲染)时,CPU 开销降低了约 80%。

  • 原生级性能: 借助 WebAssembly (Wasm) 和 WebGPU 的深度集成,现在的 Web 应用可以实现接近原生桌面软件的图形表现。这使得云端视频剪辑、高级调色工具和复杂的 3D 设计软件(如 Web 版 CAD)在性能上几乎没有短板。

2. AI 浪潮下的“杀手锏”:计算着色器 (Compute Shaders)

WebGPU 与 WebGL 最大的区别在于其强大的通用计算能力

  • 端侧 AI (On-device AI): 这是 WebGPU 发展最迅猛的领域。由于其提供了对现代 GPU 特性(如共享内存、原子操作)的访问,诸如 WebLLMTransformers.js 等项目可以让大语言模型(LLM)和 Stable Diffusion 直接在用户的本地 GPU 上运行,无需上传数据到服务器。

  • 视频处理加速: 对于视频后期从业者而言,WebGPU 允许在浏览器内进行实时的 4K 视频滤镜处理、AI 降噪和自动抠图,其效率是传统 JavaScript 或 WebGL 无法比拟的。

3. 浏览器与硬件兼容性

  • 多端统一: 截至 2026 年,Chrome、Edge、Safari 和 Firefox 的稳定版均已全面支持 WebGPU。它在底层完美映射了系统的原生 API(如 Windows 的 Direct3D 12、macOS 的 Metal、Linux 的 Vulkan)。

  • 移动端爆发: 随着高性能移动芯片的普及,手机端的 WebGPU 支持也已趋于成熟,网页端手游的品质已经开始向主机级画质靠拢。

4. 技术特性演进

  • FP16 与精度优化: 现在的 WebGPU 已经广泛支持 半精度浮点数 (FP16),这对 AI 推理至关重要,能在减少显存占用的同时提升一倍的运算速度。

  • 子组操作 (Subgroups): 这一高级特性的加入,使得开发者可以更精细地控制 GPU 线程间的通信,进一步压榨硬件性能。


总结:对开发者的影响

对于开发者(尤其是熟悉 RustC++ 这种底层语言的人)来说,WebGPU 极大地拓宽了 Web 的边界。你不再受限于简单的网页交互,而是可以直接开发高性能的跨平台桌面应用(通过 Electron 加速)或高性能的 Web AI 工具。

我的问题以及GEMINI给我的答案

win10和mac兼容系比较好的客户端架构有哪些,最好能基于web视图技术,因为对CSS和HTML结构比较熟悉,但是也需要一些其他的高级语言处理逻辑,操作文件,加载本地大模型之类的,你有什么比较成熟稳定的技术方案吗?

既然你对 HTML/CSS 非常熟悉,同时又有处理复杂逻辑、文件系统操作以及加载本地大模型 (LLM) 这种高负载需求,目前的跨平台客户端架构主要集中在以下三个“黄金方案”上。

针对你的需求,我按照性能、成熟度技术栈匹配度进行了排序:


1. Tauri (首选推荐:极致性能与轻量化)

Tauri 是目前增长最快、最受开发者青睐的方案。它将 UI 交给系统原生的 WebView(Win10 用 Edge/WebView2,Mac 用 WebKit),而后台逻辑则交给 Rust

  • 为什么适合你:

    • Web 前端: 你可以用任何喜欢的 Web 框架(React, Vue, 或纯 HTML/CSS)构建 UI。

    • 本地大模型: Rust 是目前处理本地 AI 推理最理想的语言之一。你可以直接调用 llama-cpp-rscandle 等 Rust 库,效率远高于 Node.js。

    • 安全性与体积: 它的安装包极小(通常只有几 MB),且由于 Rust 的特性,内存安全管理非常出色。

  • 挑战: 你需要学习一点 Rust 语法来编写后端逻辑(操作文件、调用模型)。

2. Electron (最成熟:生态之王)

Electron 是 VS Code、Discord 和 Slack 的底层架构。它将 Chromium 浏览器和 Node.js 打包在一起。

  • 为什么适合你:

    • 上手难度最低: 前端 UI 和后端逻辑(Node.js)全部使用 JavaScript/TypeScript。

    • 生态极其丰富: 对于加载大模型,你可以直接使用 node-llama-cpp 或者 onnxruntime-node 等成熟的 NPM 包。

    • 文件操作: Node.js 的 fs 模块处理本地文件非常简单直观。

  • 挑战: 资源占用大(内存怪兽)。由于它自带了一个完整的 Chromium,加载本地大模型时,GPU/内存压力会比 Tauri 大得多。

3. Wails (平衡之选:Go 语言后端)

如果觉得 Rust 太难,又觉得 Electron 太重,Wails 是一个绝佳的中间地带。它使用 Go 语言作为后端。

  • 为什么适合你:

    • Go 语言逻辑: Go 的语法比 Rust 简单得多,且处理并发和系统 API(文件操作)非常高效。

    • 轻量: 和 Tauri 一样,它使用系统原生的 WebView,不打包 Chromium。

    • 模型支持: 通过 Go 的 CGO 调用 llama.cpp 的 C++ 接口非常成熟。

  • 挑战: 在三者中,Wails 的社区插件生态相对较小。


技术方案对比表


针对“加载本地大模型”的深度建议

无论你选择哪种架构,加载大模型(如 Llama 3 或 Qwen)通常有两条路径:

  1. 侧边进程 (Sidecar) 模式: 不要在 Electron/Tauri 的主进程里直接运行推理。可以打包一个编译好的 llama.cpp 二进制文件作为“侧边服务”,你的 Web 视图通过本地端口(如 localhost:11434)与其通信。这是目前最稳定、解耦最好的方式。

  2. WebGPU (未来趋势): 如果你希望完全在 Web 视图内处理,可以关注 WebLLM 项目。它利用 WebGPU 接口,让 HTML 页面直接调用显卡进行推理,不需要编写复杂的后端 C++/Rust 代码,直接在 JS 里写逻辑。

如果你希望现在就开始一个稳定且高性能的项目,我建议: 先尝试 Tauri。虽然 Rust 有学习成本,但它处理文件和本地模型的能力是目前跨平台方案的天花板。

您是否需要我为您整理一份基于 Tauri 运行本地 LLM 的基础项目结构示例?

云端更新记录0324

### 状态
- 创建时间: 2026-03-23
- 完成时间: 2026-03-23
- 数据库脚本: `update-mysql/update0323-user-sfx-behavior.sql`
---
## 2026-03-24 客户端下载历史功能修复
### 问题描述
客户端下载音效后,历史记录列表显示异常,部分功能返回错误。
### 修复内容
#### 1. 下载历史列表查询条件不一致
**问题**: `findUserDownloadHistory``download_count > 0` 条件,但 `countUserDownloadHistory` 没有,导致 list 和 total 数量不匹配。
**修复**: 移除 `download_count > 0` 条件,两边统一只过滤 `deleted = 0`
#### 2. downloadJSON 未记录下载历史
**问题**: `ClientSfxController.downloadJSON()` 获取下载链接时未调用 `behaviorLogService.recordBehavior()`
**修复**:
- 恢复 `BehaviorLogService` 注入(之前被注释)
- 在返回下载链接前调用 `recordBehavior()` 记录下载行为
#### 3. downloadProxy 未从 URL 参数获取 token
**问题**: `downloadjson` 返回的 URL 没有带 token,客户端请求时无法识别用户。
**修复**:
- URL 添加 token 参数: `&token=xxx`
- `downloadProxy` 支持 `tokenParam` 参数
#### 4. PageViewInterceptor 无法识别客户端用户
**问题**: 拦截器只从 Spring Security 上下文获取用户,客户端 API 使用自定义 token 解析,导致 `user=null`
**修复**: `getCurrentUserId()` 增加从请求头/参数解析 token 的逻辑。
#### 5. upsertUserSfxBehavior 未重置 deleted 字段
**问题**: 用户删除历史后重新下载同一音效,`ON DUPLICATE KEY UPDATE` 未重置 `deleted=0`,导致记录仍然不显示。
**修复**: UPDATE 语句添加 `deleted = 0`
#### 6. Map.of() 不支持 null 值
**问题**: 取消置顶时 `pinnedTime=null``Map.of("pinned", pinned, "pinnedTime", null)` 抛出 NPE,返回 500。
**修复**: 改用 `HashMap` 代替 `Map.of()`
---
### 修改文件
| 文件 | 修改内容 |
|------|----------|
| `UserBehaviorMapper.java` | 移除 download_count 条件,UPDATE 添加 deleted=0 |
| `ClientSfxController.java` | 恢复 BehaviorLogService 注入,添加记录调用,URL 带 token |
| `ClientUserResourceController.java` | Map.of() 改 HashMap |
| `PageViewInterceptor.java` | 增加 token 解析逻辑 |
---
### 状态
- 修复时间: 2026-03-24

## 最近更新 新版本即将发布 ###

## 最近更新
### 2026-03-23: Mine 模块(我的下载)正式发布
**功能概述**:用户下载记录管理模块,支持音效试听、批量操作、本地文件管理
**核心功能**
1. 下载记录列表展示(分页、两列布局)
2. 音频波形图试听播放(鼠标悬停自动播放、点击跳转进度)
3. 置顶/取消置顶下载记录
4. 1-5星评分功能
5. 删除记录(同时删除本地缓存文件)
6. 批量操作:全选、反选、批量删除、清空所有
7. 打开本地缓存目录
8. 添加到 DaVinci Resolve 媒体池
**新增文件**
- `modules/mine/index.html` - 容器结构
- `modules/mine/renderer.js` - 核心逻辑(约1100行)
- `modules/mine/styles.css` - 样式文件
**修改文件**
- `main.js` - 新增 `shell:openFolder``shell:deleteLocalFile` IPC handler
- `preload.js` - 暴露 `window.shellAPI.openFolder()``window.shellAPI.deleteLocalFile()`
- `config.json` - 新增 4 个接口端点配置
- `index.html` - 侧边栏"我的"菜单项指向 mine 模块
- `network_client.js` - 添加调试日志、支持 code: 200 成功状态
**API 接口**(云端 ClientUserResourceController):
- `GET /user/downloads` - 下载记录列表(page, size 参数)
- `POST /user/downloads/pin` - 置顶/取消置顶(sfxId, pinned 参数)
- `POST /user/downloads/delete` - 删除记录(sfxId 参数)
- `POST /user/downloads/rate` - 评分(sfxId, rating 参数)
**关键实现**
- 波形图绘制:使用 Canvas API,支持进度显示
- 播放控制:HTML5 Audio API,支持悬停播放、点击跳转
- 多选功能:使用 Set 存储选中状态,支持点击名称切换选中
- 批量删除:遍历选中项,先删除本地文件再删除后端记录
- 清空所有:分页遍历删除,避免内存溢出
- 失效记录标记:后端返回 `isValid: false` 标记已删除的音效
**UI 布局**
- 顶部工具栏:左侧统计信息,右侧操作按钮
- 两列卡片布局:名称、波形图、评分、操作按钮
- 底部分页:居中显示
- Toast 提示:替代 alert 弹窗
### 2025-03-14: v1.2.4 版本发布 - 代码清理
**变更内容**
1. 移除 Rough Cut(粗剪)模块 - 整个 `modules/rough_cut/` 目录
2. 清理 10000+ 行废弃代码