@@ -12,15 +12,19 @@ use std::collections::HashSet;
1212use tauri:: State ;
1313
1414use crate :: ai_protocol:: TextFilterDecision ;
15+ use crate :: analysis:: analyze_session_opt;
1516use crate :: commands:: { normalize_title, AppState , TITLE_MAX_CHARS } ;
1617use crate :: db:: Db ;
1718use crate :: db_sessions:: SESSION_STATUS_RECORDING ;
1819use crate :: note_filter:: { apply_ai_decisions, filter_note, NoteFilterResult , PurifyEnv , RULE_VERSION } ;
20+ use crate :: outline:: { detect_outline_smart, OutlineConfig } ;
21+ use crate :: structure_note:: render_note_structure;
1922use crate :: types:: {
2023 BatchNoteResult , ConvertedNote , NewNote , NewSession , NewSessionOcrBlock , NewSessionSegment ,
2124 Note , Session , SessionDetail , SessionListItem , SessionOcrBlock , SessionSegment , SkippedNote ,
2225} ;
2326use crate :: ui_junk:: UiJunkList ;
27+ use crate :: video_profile:: ProfileKind ;
2428
2529/// 会话列表单页上限。
2630const LIST_LIMIT_MAX : u64 = 200 ;
@@ -189,6 +193,47 @@ fn load_note_material(
189193 Ok ( ( session, segments, ocr_blocks) )
190194}
191195
196+ /// 结构渲染接线(v0.7.6 REQ-177/178,双出口共用)。
197+ ///
198+ /// @ai-context: 在 refresh_screen_points 之后调用——净化/配图/警示行先落定,
199+ /// 结构层在其上叠加章节标题与词汇表块;预览与落库同函数同口径
200+ /// (REQ-081 单一管线双出口契约)。
201+ /// @ai-context: 输入为会话原料(segments/ocr_blocks)——章节检测/大纲标题/
202+ /// 术语表均为纯本地规则(analysis/outline/glossary 复用)——
203+ /// 不依赖云端 AI(本地优先铁律);失败不阻断转笔记主链路
204+ /// (分析失败按空结构处理,不抛错)。
205+ fn apply_note_structure (
206+ result : & mut NoteFilterResult ,
207+ db : & Db ,
208+ session : & Session ,
209+ segments : & [ SessionSegment ] ,
210+ ocr_blocks : & [ SessionOcrBlock ] ,
211+ env : & PurifyEnv ,
212+ ) {
213+ // 档案驱动:章节检测/术语表按档案开关(网课开、口播关——analysis 内部门控)
214+ let kind = session
215+ . profile
216+ . as_deref ( )
217+ . map ( ProfileKind :: parse)
218+ . unwrap_or ( ProfileKind :: Lecture ) ;
219+ let detail = SessionDetail {
220+ session : session. clone ( ) ,
221+ segments : segments. to_vec ( ) ,
222+ ocr_blocks : ocr_blocks. to_vec ( ) ,
223+ events : db. list_events ( session. id ) . unwrap_or_default ( ) ,
224+ screens : Vec :: new ( ) ,
225+ } ;
226+ let analysis = analyze_session_opt ( & detail, kind, & env. symbol ) ;
227+ let outline = detect_outline_smart ( ocr_blocks, & result. ocr_screens , & OutlineConfig :: default ( ) ) ;
228+ let _ = render_note_structure (
229+ result,
230+ & analysis. chapters ,
231+ & outline,
232+ & analysis. glossary ,
233+ & env. config . structure ,
234+ ) ;
235+ }
236+
192237/// 会话 → 笔记核心(v0.7.1 提取:单条与批量共用同一管线)。
193238///
194239/// @ai-context: REQ-082:过滤链(UI 垃圾/重复合并/碎片/低置信/口语净化/口头禅
@@ -225,6 +270,9 @@ fn convert_to_note(
225270 // 重建口径一致;警示为正文行,用户可手动删除)
226271 crate :: note_filter:: apply_session_warning ( & mut result, & session. status ) ;
227272 crate :: note_filter:: refresh_screen_points ( & mut result) ;
273+ // v0.7.6(REQ-177/178):结构渲染——章节标题 + 词汇表块(纯本地增强层;
274+ // 无结构数据/分析失败 → 原样输出不阻断,见 apply_note_structure)
275+ apply_note_structure ( & mut result, db, & session, & segments, & ocr_blocks, env) ;
228276 let new = NewNote {
229277 title : result. title . clone ( ) ,
230278 content : result. markdown . clone ( ) ,
@@ -344,28 +392,27 @@ pub async fn batch_session_to_note(
344392/// kept 段),前端展示过滤统计卡/对照复查/一键落库。
345393/// @ai-context: v0.7.3(REQ-160):ocr_screens attach 归档图(预览屏卡配图;
346394/// 目录缺失/无图 → 纯文本降级)。
395+ /// @ai-context: v0.7.6(REQ-177/178):预览与落库同口径——结构渲染(章节
396+ /// 标题 + 词汇表块)在预览即生效。
347397#[ tauri:: command]
348398pub async fn preview_session_note (
349399 state : State < ' _ , AppState > ,
350400 id : i64 ,
351401) -> Result < NoteFilterResult , String > {
352402 let ( session, segments, ocr_blocks) = load_note_material ( & state. db , id) ?;
353- let mut result = filter_note (
354- & session. title ,
355- & segments,
356- & ocr_blocks,
357- & state. ui_junk ,
358- & PurifyEnv {
359- config : state. purify . clone ( ) ,
360- symbol : state. symbol_normalize . clone ( ) ,
361- corrections : state. ocr_corrections . clone ( ) ,
362- } ,
363- ) ;
403+ let env = PurifyEnv {
404+ config : state. purify . clone ( ) ,
405+ symbol : state. symbol_normalize . clone ( ) ,
406+ corrections : state. ocr_corrections . clone ( ) ,
407+ } ;
408+ let mut result = filter_note ( & session. title , & segments, & ocr_blocks, & state. ui_junk , & env) ;
364409 let images_dir = state. data_dir . join ( "session-images" ) . join ( id. to_string ( ) ) ;
365410 crate :: screens:: attach_images ( & mut result. ocr_screens , & images_dir) ;
366411 // v0.7.5(REQ-170):预览与落库同口径——异常会话预览即带警示行
367412 crate :: note_filter:: apply_session_warning ( & mut result, & session. status ) ;
368413 crate :: note_filter:: refresh_screen_points ( & mut result) ;
414+ // v0.7.6(REQ-177/178):结构渲染(与 convert_to_note 同函数同口径)
415+ apply_note_structure ( & mut result, & state. db , & session, & segments, & ocr_blocks, & env) ;
369416 Ok ( result)
370417}
371418
0 commit comments