Skip to content

Commit f74ff55

Browse files
committed
chore(rust): 删旧直调四命令与死常量
1 parent 978a22d commit f74ff55

4 files changed

Lines changed: 9 additions & 92 deletions

File tree

‎app/src-tauri/src/app_commands.rs‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@ fn anchored<F: Fn(tauri::ipc::Invoke<tauri::Wry>) -> bool>(f: F) -> F {
5050
pub fn handle() -> impl Fn(tauri::ipc::Invoke<tauri::Wry>) -> bool + Send + Sync + 'static {
5151
anchored(tauri::generate_handler![
5252
crate::commands::list_windows,
53-
crate::commands::transcribe_audio,
54-
crate::commands::recognize_image,
55-
crate::commands::build_draft,
56-
crate::commands::save_draft_as_note,
5753
crate::commands::process_to_note,
5854
// v0.11.7(图文会话,ADR-020):图文采集 5 命令
5955
crate::commands_photo::start_photo_session,

‎app/src-tauri/src/commands.rs‎

Lines changed: 4 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::engine::EnginePool;
1515
use crate::live_session::LiveSessionManager;
1616
use crate::model_downloader::ModelDownloader;
1717
use crate::streaming_asr::StreamingAsrModels;
18-
use crate::types::{NewNote, Note, NoteDraft, OcrBlock, TranscriptSegment};
18+
use crate::types::{NewNote, Note};
1919
use crate::video_profile::ProfileMemory;
2020
use crate::windows::{self, CaptureWindow};
2121

@@ -29,13 +29,11 @@ const KEYWORD_MAX_CHARS: usize = 100;
2929
const TAG_MAX_CHARS: usize = 50;
3030
/// 一键流水线最大图片数。
3131
const MAX_IMAGES: usize = 20;
32-
/// 拼接输入段/块数量上限(防恶意超大列表拖垮拼接)。
33-
const MAX_INPUT_ITEMS: usize = 5000;
3432

35-
/// 音频文件扩展名白名单(安全 L1 修复:transcribe_audio 不得接受任意非音频路径,
33+
/// 音频文件扩展名白名单(安全 L1 修复:音频路径不得是任意非音频文件,
3634
/// 与 commands_import::VIDEO_EXTENSIONS 同口径)。
3735
const AUDIO_EXTENSIONS: [&str; 6] = ["mp3", "wav", "m4a", "flac", "ogg", "aac"];
38-
/// 图片文件扩展名白名单(安全 L1 修复:recognize_image 同口径)。
36+
/// 图片文件扩展名白名单(安全 L1 修复:与音频路径校验同口径)。
3937
const IMAGE_EXTENSIONS: [&str; 5] = ["png", "jpg", "jpeg", "webp", "bmp"];
4038

4139
/// 扩展名白名单校验(安全 L1):返回小写扩展名,不在白名单内返回可诊断错误。
@@ -213,78 +211,6 @@ pub async fn list_windows() -> Result<Vec<CaptureWindow>, String> {
213211
.map_err(|e| format!("任务调度失败: {}", e))
214212
}
215213

216-
/// 本地 ASR:转写一个 WAV 文件(REQ-001)。
217-
#[tauri::command]
218-
pub async fn transcribe_audio(state: State<'_, AppState>, path: String) -> Result<TranscriptSegment, String> {
219-
if path.trim().is_empty() {
220-
return Err("音频路径为空".to_string());
221-
}
222-
// 安全 L1 修复:扩展名白名单前置校验(拒绝非音频路径)
223-
require_media_extension(&path, &AUDIO_EXTENSIONS, "音频")?;
224-
let engines = state.engines.clone();
225-
// H2 修复:有界等待变体——引擎卡死时返回可诊断超时错误而非永久阻塞
226-
tauri::async_runtime::spawn_blocking(move || {
227-
engines.transcribe_timeout(&path, crate::engine::ASR_REQUEST_TIMEOUT)
228-
})
229-
.await
230-
.map_err(|e| format!("任务调度失败: {}", e))?
231-
.map_err(|e| e.to_string())
232-
}
233-
234-
/// 本地 OCR:识别一张图片(REQ-002)。
235-
#[tauri::command]
236-
pub async fn recognize_image(state: State<'_, AppState>, path: String) -> Result<Vec<OcrBlock>, String> {
237-
if path.trim().is_empty() {
238-
return Err("图片路径为空".to_string());
239-
}
240-
// 安全 L1 修复:扩展名白名单前置校验(拒绝非图片路径)
241-
require_media_extension(&path, &IMAGE_EXTENSIONS, "图片")?;
242-
let engines = state.engines.clone();
243-
// H2 修复:有界等待变体(同 transcribe_audio)
244-
tauri::async_runtime::spawn_blocking(move || {
245-
engines.recognize_timeout(&path, crate::engine::OCR_REQUEST_TIMEOUT)
246-
})
247-
.await
248-
.map_err(|e| format!("任务调度失败: {}", e))?
249-
.map_err(|e| e.to_string())
250-
}
251-
252-
/// 本地拼接:转写段 + OCR 块 → 笔记初稿(REQ-003,纯本地无 LLM)。
253-
#[tauri::command]
254-
pub async fn build_draft(
255-
title: String,
256-
segments: Vec<TranscriptSegment>,
257-
ocr_blocks: Vec<OcrBlock>,
258-
) -> Result<NoteDraft, String> {
259-
if segments.len() > MAX_INPUT_ITEMS || ocr_blocks.len() > MAX_INPUT_ITEMS {
260-
return Err(format!("拼接输入数量超限(上限 {})", MAX_INPUT_ITEMS));
261-
}
262-
let title = normalize_title(title, "未命名笔记");
263-
tauri::async_runtime::spawn_blocking(move || concat::build_note_draft(&title, &segments, &ocr_blocks))
264-
.await
265-
.map_err(|e| format!("任务调度失败: {}", e))
266-
}
267-
268-
/// 课堂助手 → 笔记联动:把拼接初稿一键存为笔记(REQ-005)。
269-
#[tauri::command]
270-
pub async fn save_draft_as_note(state: State<'_, AppState>, draft: NoteDraft) -> Result<Note, String> {
271-
let new = NewNote {
272-
title: normalize_title(draft.title, "未命名笔记"),
273-
content: truncate_chars(draft.markdown, CONTENT_MAX_CHARS),
274-
source: "classroom".to_string(),
275-
session_id: None,
276-
rule_version: None,
277-
purify_stats: None,
278-
tags: None,
279-
properties: None,
280-
group_id: None,
281-
};
282-
let note = state.db.create_note(&new).map_err(|e| e.to_string())?;
283-
// REQ-278:笔记域变更广播(其它视图即时刷新)
284-
crate::notify::emit_changed(&state.app, crate::notify::DataDomain::Notes);
285-
Ok(note)
286-
}
287-
288214
/// 一键流水线:音频转写 + 多图 OCR → 本地拼接 → 自动存为笔记。
289215
///
290216
/// @ai-context: 这是"课堂助手 → 笔记"的核心体验编排(高价值优化②):用户一次提交素材,
@@ -308,7 +234,7 @@ pub async fn process_to_note(
308234
return Err("音频路径为空".to_string());
309235
}
310236
// 安全 L1 修复(三维复审 #4):直送媒体路径同样套用扩展名白名单,
311-
// 与 transcribe_audio/recognize_image 同口径(此前本 command 是缺口)
237+
// 与音频/图片路径白名单同口径(此前本 command 是缺口)
312238
if let Some(p) = audio_path.as_deref() {
313239
require_media_extension(p, &AUDIO_EXTENSIONS, "音频")?;
314240
}

‎app/src-tauri/src/engine.rs‎

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,9 @@ use crate::ocr::{OcrModels, OcrParams};
2222
use crate::types::{OcrBlock, TranscriptSegment};
2323
use crate::vocab::VocabStore;
2424

25-
/// H2 修复:ASR 单请求默认超时预算。
26-
/// Why 60s:文件导入分窗转写正常在数十秒内完成,但引擎异常(CPU 竞争/
27-
/// 模型卡顿)时不得让调用方裸 recv 永久挂起;特殊长任务可自行传更大 timeout。
28-
pub const ASR_REQUEST_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(60);
29-
3025
/// 三维复审 #3:整文件 WAV 转写(process_to_note 一键流水线)专用超时预算。
31-
/// Why 30 分钟:整文件转写耗时与音频时长线性相关(40 分钟课堂录音远超短请求
32-
/// 60s 预算)——行为契约是"长录音必达",与短请求路径(ASR_REQUEST_TIMEOUT)
26+
/// Why 30 分钟:整文件转写耗时与音频时长线性相关(40 分钟课堂录音远超秒级
27+
/// 预算)——行为契约是"长录音必达",与实时/短请求热路径的秒级预算
3328
/// 语义不同,不得复用同一常量。
3429
pub const ASR_FILE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30 * 60);
3530

‎docs/standards/line-limit-exemptions.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
| 文件 | 行数 | 豁免理由 | 拆分计划 |
2222
|---|---|---|---|
23-
| app/src-tauri/src/commands.rs | 597 | 命令装配域(AppState + 通用命令 + 导入管线编排);登记值 466 过期快照——2026-09-09 实测纠偏(含批 7 delete_note 结果契约 +12;600 硬限内压线) | 若再增长:导入管线命令拆至 commands_import.rs(既有登记计划) |
2423
| app/src/pages/ChatPage.tsx | 593 | AI 对话页编排;批 1(REQ-306/307)active 门控/终态订阅接线净增——2026-09-09 实测纠偏(登记值 529 过期) | 若再增长:任务工具条与发起流拆至 ChatTasksToolbar.tsx |
2524
| app/src-tauri/src/lib.rs | 577 | crate 根 **322 `mod` + 15 `#[cfg]` = 337 行地板**(Task 1 评审实测更正:原写「321 `mod` + 16 `#[cfg]`」,总数 337 不变;322 含本任务新增的 `mod app_commands;`);注册清单已移至 `app_commands.rs`(**数据文件**,同属 300–600 豁免带)—— 结构性下界,非欠账 | 已完成(批 0-C3 Task 1,2026-09-11);余下 161 行模块理由注释 + 装配逻辑,无进一步拆分标的 |
2625
| app/src-tauri/src/db_migrations.rs | 573 | v0.20.11 批 6(REQ-315)再增:note_groups.pin ensure_column + note_group_orders 建表(+21,实测 573——登记值 492 过期;schema 单点收敛理由同左) | 若再增长:kb_* 与 chat_* 表 DDL 拆至 db_migrations_kb.rs |
@@ -30,14 +29,15 @@
3029
| app/src/components/action-center/ActionCenterPanel.tsx | 537 | v0.20.5 行动中心独立页化:原 ActionCenterOverlay.tsx(509 行登记)更名迁移至 action-center/ 并去遮罩/关闭形态(refreshToken 切回重载)——编排内聚(TD-2026-09-06-G 预留目录兑现);2026-09-06 实测登记 | 若再增长:队列/历史/SOP 三区拆至 action-center/ 子组件 |
3130
| app/src-tauri/src/commands_knowledge_core.rs | 529 | v0.13.1(REQ-202~205):知识体系命令域(概念/模型/引用/审计——commands 9-18)内聚;源 commands_knowledge.rs(18 命令 + 校验)超限按规格 §四拆,本文件承接后半;commands 薄壳 + inner 纯函数 + @ai-context 注释内聚于命令域 | 若再增长:引用与审计拆至 commands_knowledge_links.rs |
3231
| app/src-tauri/src/live_frame_process.rs | 529 | v0.6.0 ADR-011 拆分产物:帧处理域(网格差异触发/两级判变/带外事件驱动/UI 面板抑制/字幕落库)内聚;process_frame 上下文参数 20+;H2 修复(OCR 热路径切超时变体)+ L2 修复(score 口径诚实化)行数微增 + v0.11.5 Task 2 新颖度变化区域接线再增 | 若再增长:handle_subtitle_frame 与 persist_voted_subtitle 拆至 live_subtitle_persist.rs |
33-
| app/src-tauri/src/engine.rs | 526 | 引擎池句柄与同步 API(双 worker 编排 + ADR-009 设备状态 + M7 心跳/失败/缓存计数 + 有界等待变体);三维复审 #5 超时排空机制(drain_asr/ocr_backlog)与 #3 ASR_FILE_TIMEOUT 文件级超时常量接入后,worker 主循环与请求协议按登记计划拆至 engine_worker.rs(见文末"已拆分"注记)回归本值 | 若再增长:排空机制与同步 API 变体拆至 engine_request.rs |
3432
| app/src-tauri/src/asr_merge.rs | 524 | v0.5.0 ADR-012 F4-1 语义合并域 + v0.7.0 M2 REQ-119 混排空格(spacing_for/merge_segments_with_spacing);合并决策与切分共用标点常量 | 若再增长:split_sentences/split_timestamps 拆至 asr_merge_split.rs |
33+
| app/src-tauri/src/commands.rs | 523 | 命令装配域(AppState + 通用命令 + 导入管线编排);登记值 466 过期快照——2026-09-09 实测纠偏(含批 7 delete_note 结果契约 +12;600 硬限内压线) | 若再增长:导入管线命令拆至 commands_import.rs(既有登记计划) |
34+
| app/src-tauri/src/engine.rs | 521 | 引擎池句柄与同步 API(双 worker 编排 + ADR-009 设备状态 + M7 心跳/失败/缓存计数 + 有界等待变体);三维复审 #5 超时排空机制(drain_asr/ocr_backlog)与 #3 ASR_FILE_TIMEOUT 文件级超时常量接入后,worker 主循环与请求协议按登记计划拆至 engine_worker.rs(见文末"已拆分"注记)回归本值 | 若再增长:排空机制与同步 API 变体拆至 engine_request.rs |
3535
| app/src/components/GroupSidebar.tsx | 519 | v0.20.12 批 7(REQ-316)拖拽归组/ⓘ 弹层移组清理留痕透传(509→519;登记值过期纠偏) | 若再增长:体系引用拉取与徽标聚合拆至 useGroupSystemLinks.ts hook |
3636
| app/src-tauri/src/video_profile_tests.rs | 518 | 档案测试域(12 档案断言矩阵 + 检测投票 + JSON 校准 + v0.13.6 领域记忆独立通道/旧 JSON 零迁移用例 + 审查回归(烘焙迁移/单字种子守卫))单模块 #[path] 挂载 | 若再增长:档案矩阵拆至 video_profile_data_tests.rs |
3737
| app/src/components/LiveActivityPanel.tsx | 517 | 实时活动面板:会话状态/转录流/OCR 预览/控制区多状态面板内聚(前端审查登记) | 若再增长:转录流与 OCR 预览拆至 LiveTranscriptStream.tsx / LiveOcrPreview.tsx |
3838
| app/src-tauri/src/ai_client.rs | 505 | v0.11.6 M1(AiClient::from_provider / from_settings_with_store / is_fallbackable / fallback_provider_ids)+ 2026-09-11 DeepSeek V4.1 适配(chat_plain 探活路径 / build_plain_payload / json 前置条件兜底接线 / thinking 策略落点 / 4xx 错误体透出——纯策略与提取逻辑已拆至 ai_request_policy.rs)——Provider 解析与错误分类内聚于 AiClient 域,构造入口与降级链纯函数同文件便于单测。**旧登记 322 为过期快照,本次按实测纠偏** | 若再增长:fallback_provider_ids 拆至 ai_fallback.rs;payload 构造族拆至 ai_payload.rs |
39-
| app/src-tauri/src/app_commands.rs | 500 | 宏约束下的**唯一**注册点:334 条 `generate_handler!` 条目是**数据不是逻辑** —— `Invoke` 按值语义使分域组合不可行(见文件头),拆成多份只会在域间新增「命令名 → 域」路由漂移面;一致性由 `scripts/check-command-registry.mjs` 机器门禁守 | 不拆(数据文件);新增命令时同步条目,由门禁强制 |
4039
| app/src/components/GroupSidebar.test.tsx | 497 | 覆盖串组场景——切换 ⓘ 弹层目标组时表单态必须重置(key=group.id修复):组 A 改了判类(未确认)→ 点组 B ⓘ → 弹层显示 B 且判类下拉回到 B.kind(防把 A 的选择误用到 B——路径: 改判误操作)。(自动摘取,待细化) | 若再增长:按职责拆分 |
40+
| app/src-tauri/src/app_commands.rs | 496 | 宏约束下的**唯一**注册点:334 条 `generate_handler!` 条目是**数据不是逻辑** —— `Invoke` 按值语义使分域组合不可行(见文件头),拆成多份只会在域间新增「命令名 → 域」路由漂移面;一致性由 `scripts/check-command-registry.mjs` 机器门禁守 | 不拆(数据文件);新增命令时同步条目,由门禁强制 |
4141
| app/src-tauri/src/db_sop.rs | 490 | v0.20.3(REQ-296/297)SOP 三表数据域(模板/run/步骤/保鲜/聚合)+ 审查加固(保链更新/幂等守卫/步数计数)内聚 | 若再增长:run 执行族拆至 db_sop_run.rs |
4242
| app/src-tauri/src/live_session_persist.rs | 488 | 定稿落库域(persist_final/digest_merged/handle_final_event)+ P2 flush_tail_and_persist(停止/暂停共用尾句落库)内聚 | 若再增长:flush_tail_and_persist 与 digest_merged 拆至 live_session_persist_tail.rs |
4343
| app/src-tauri/src/db_sessions.rs | 482 | 会话仓储;批 4 delete_sessions_batch + 审查修复轮 3(transaction() 改造)——2026-09-09 实测纠偏(登记值 394 过期) | 若再增长:recent_ocr_texts 等建议查询拆至 db_sessions_queries.rs |

0 commit comments

Comments
 (0)