@@ -157,26 +157,35 @@ fn convert_to_note(
157157}
158158
159159/// 会话 → 笔记:转写段 + OCR 块经 note_filter 净化管线,一键落库(REQ-010 闭环)。
160+ ///
161+ /// @ai-context: TD-2026-08-20-A 清偿:主体迁 spawn_blocking——v0.7.6 起管线叠加
162+ /// analyze_session_opt 全量分析(章节/术语/重点等),千段长会话
163+ /// 可达秒级,不得占用异步运行时线程(review_text_filter 先例)。
160164#[ tauri:: command]
161165pub async fn session_to_note (
162166 state : State < ' _ , AppState > ,
163167 id : i64 ,
164168 title : Option < String > ,
165169 ai_decisions : Option < Vec < TextFilterDecision > > ,
166170) -> Result < Note , String > {
167- convert_to_note (
168- & state. db ,
169- & state. ui_junk ,
170- & PurifyEnv {
171- config : state. purify . clone ( ) ,
172- symbol : state. symbol_normalize . clone ( ) ,
173- corrections : state. ocr_corrections . clone ( ) ,
174- } ,
175- & state. data_dir ,
176- id,
177- title,
178- ai_decisions,
179- )
171+ let state: AppState = ( * state) . clone ( ) ;
172+ tauri:: async_runtime:: spawn_blocking ( move || {
173+ convert_to_note (
174+ & state. db ,
175+ & state. ui_junk ,
176+ & PurifyEnv {
177+ config : state. purify . clone ( ) ,
178+ symbol : state. symbol_normalize . clone ( ) ,
179+ corrections : state. ocr_corrections . clone ( ) ,
180+ } ,
181+ & state. data_dir ,
182+ id,
183+ title,
184+ ai_decisions,
185+ )
186+ } )
187+ . await
188+ . map_err ( |e| format ! ( "转笔记任务失败: {}" , e) ) ?
180189}
181190
182191/// 批量转笔记核心编排(v0.7.1:部分成功语义——单条失败不阻塞其他)。
@@ -238,22 +247,29 @@ pub fn run_batch_conversion(
238247}
239248
240249/// 批量转笔记(v0.7.1 会话体验:列表勾选批量转化)。
250+ /// @ai-context: TD-2026-08-20-A 清偿:迁 spawn_blocking(≤50 条 × 全量分析,
251+ /// 长会话批量可达数十秒——不得阻塞异步运行时线程)。
241252#[ tauri:: command]
242253pub async fn batch_session_to_note (
243254 state : State < ' _ , AppState > ,
244255 ids : Vec < i64 > ,
245256) -> Result < BatchNoteResult , String > {
246- run_batch_conversion (
247- & state. db ,
248- & state. ui_junk ,
249- & PurifyEnv {
250- config : state. purify . clone ( ) ,
251- symbol : state. symbol_normalize . clone ( ) ,
252- corrections : state. ocr_corrections . clone ( ) ,
253- } ,
254- & state. data_dir ,
255- ids,
256- )
257+ let state: AppState = ( * state) . clone ( ) ;
258+ tauri:: async_runtime:: spawn_blocking ( move || {
259+ run_batch_conversion (
260+ & state. db ,
261+ & state. ui_junk ,
262+ & PurifyEnv {
263+ config : state. purify . clone ( ) ,
264+ symbol : state. symbol_normalize . clone ( ) ,
265+ corrections : state. ocr_corrections . clone ( ) ,
266+ } ,
267+ & state. data_dir ,
268+ ids,
269+ )
270+ } )
271+ . await
272+ . map_err ( |e| format ! ( "批量转笔记任务失败: {}" , e) ) ?
257273}
258274
259275/// 会话笔记预览(REQ-081):过滤后只读预览——不落库、不改库。
@@ -270,19 +286,26 @@ pub async fn preview_session_note(
270286 state : State < ' _ , AppState > ,
271287 id : i64 ,
272288) -> Result < NoteFilterResult , String > {
273- let ( session, segments, ocr_blocks) = load_note_material ( & state. db , id) ?;
274- let env = PurifyEnv {
275- config : state. purify . clone ( ) ,
276- symbol : state. symbol_normalize . clone ( ) ,
277- corrections : state. ocr_corrections . clone ( ) ,
278- } ;
279- let mut result = filter_note ( & session. title , & segments, & ocr_blocks, & state. ui_junk , & env) ;
280- let images_dir = state. data_dir . join ( "session-images" ) . join ( id. to_string ( ) ) ;
281- crate :: screens:: attach_images ( & mut result. ocr_screens , & images_dir) ;
282- // v0.7.5(REQ-170):预览与落库同口径——异常会话预览即带警示行
283- crate :: note_filter:: apply_session_warning ( & mut result, & session. status ) ;
284- crate :: note_filter:: refresh_screen_points ( & mut result) ;
285- // v0.7.6(REQ-177/178):结构渲染(与 convert_to_note 同函数同口径)
286- apply_note_structure ( & mut result, & state. db , & session, & segments, & ocr_blocks, & env) ;
287- Ok ( result)
289+ // TD-2026-08-20-A 清偿:迁 spawn_blocking(预览与落库同口径——全量分析
290+ // 同样耗时;数据所有权移入闭包,消除 segments/ocr_blocks 二次拷贝——观察 1)
291+ let state: AppState = ( * state) . clone ( ) ;
292+ tauri:: async_runtime:: spawn_blocking ( move || {
293+ let ( session, segments, ocr_blocks) = load_note_material ( & state. db , id) ?;
294+ let env = PurifyEnv {
295+ config : state. purify . clone ( ) ,
296+ symbol : state. symbol_normalize . clone ( ) ,
297+ corrections : state. ocr_corrections . clone ( ) ,
298+ } ;
299+ let mut result = filter_note ( & session. title , & segments, & ocr_blocks, & state. ui_junk , & env) ;
300+ let images_dir = state. data_dir . join ( "session-images" ) . join ( id. to_string ( ) ) ;
301+ crate :: screens:: attach_images ( & mut result. ocr_screens , & images_dir) ;
302+ // v0.7.5(REQ-170):预览与落库同口径——异常会话预览即带警示行
303+ crate :: note_filter:: apply_session_warning ( & mut result, & session. status ) ;
304+ crate :: note_filter:: refresh_screen_points ( & mut result) ;
305+ // v0.7.6(REQ-177/178):结构渲染(与 convert_to_note 同函数同口径)
306+ apply_note_structure ( & mut result, & state. db , & session, & segments, & ocr_blocks, & env) ;
307+ Ok ( result)
308+ } )
309+ . await
310+ . map_err ( |e| format ! ( "笔记预览任务失败: {}" , e) ) ?
288311}
0 commit comments