"""Obsidian KB - 知识库内容管理模型""" from enum import Enum from dataclasses import dataclass, field, asdict from typing import Optional, List, Dict, Any from datetime import datetime import uuid import json class ContentType(Enum): """内容类型""" VIDEO = "video" ARTICLE = "article" class ContentStatus(Enum): """内容处理状态""" NEW = "new" # 新发现 SCANNED = "scanned" # 已扫描元数据 CONFIRMED = "confirmed" # 已确认处理 ANALYZED = "analyzed" # 已AI分析 GENERATED = "generated" # 已生成笔记 SKIPPED = "skipped" # 已跳过 @dataclass class ContentChunk: """内容块 - 用于分段处理""" id: str = field(default_factory=lambda: str(uuid.uuid4())[:8]) content: str = "" # 内容文本 start_time: Optional[int] = None # 开始时间(秒) end_time: Optional[int] = None # 结束时间(秒) def to_dict(self) -> Dict[str, Any]: return asdict(self) @classmethod def from_dict(cls, data: Dict[str, Any]) -> "ContentChunk": return cls(**data) @dataclass class ContentAnalysis: """内容分析结果 - 用于模板渲染""" one_liner: str = "" # 一句话摘要 summary: str = "" # 详细摘要 key_points: List[str] = field(default_factory=list) # 关键要点 tags: List[str] = field(default_factory=list) # 标签 quality_score: float = 0.0 # 质量评分 0-100 # 教程视频专用字段 prerequisites: List[str] = field(default_factory=list) # 前置知识 outline: List[Dict[str, Any]] = field(default_factory=list) # 大纲分段 pitfalls: List[str] = field(default_factory=list) # 常见坑点 practice_advice: List[str] = field(default_factory=list) # 实践建议 def to_dict(self) -> Dict[str, Any]: return asdict(self) @classmethod def from_dict(cls, data: Dict[str, Any]) -> "ContentAnalysis": return cls(**data) def is_high_quality(self, threshold: float = 60.0) -> bool: """判断是否高质量内容""" return self.quality_score >= threshold @dataclass class QualityMetrics: """内容质量指标""" overall_score: float = 0.0 # 综合评分 0-1 information_density: float = 0.0 # 信息密度 originality: float = 0.0 # 原创性 practicality: float = 0.0 # 实用性 depth: float = 0.0 # 深度 def to_dict(self) -> Dict[str, Any]: return asdict(self) @classmethod def from_dict(cls, data: Dict[str, Any]) -> "QualityMetrics": return cls(**data) @dataclass class AnalysisResult: """AI深度分析结果""" main_topics: List[str] = field(default_factory=list) # 主要主题 key_insights: List[str] = field(default_factory=list) # 关键洞察 action_items: List[str] = field(default_factory=list) # 行动项 summary: str = "" # 摘要 timeline: List[Dict[str, Any]] = field(default_factory=list) # 时间线 recommended_tags: List[str] = field(default_factory=list) # 推荐标签 full_analysis: str = "" # 完整分析 timeline_summary: List[Dict[str, Any]] = field(default_factory=list) # 时间线摘要(兼容字段) content_structure: str = "" # 内容结构描述 target_audience: str = "" # 目标受众 difficulty_level: str = "intermediate" # 难度级别 def to_dict(self) -> Dict[str, Any]: return asdict(self) @classmethod def from_dict(cls, data: Dict[str, Any]) -> "AnalysisResult": return cls(**data) @dataclass class TimelineEntry: """时间线条目""" timestamp: str title: str description: str def to_dict(self) -> Dict[str, str]: return asdict(self) @classmethod def from_dict(cls, data: Dict[str, str]) -> "TimelineEntry": return cls(**data) @dataclass class Content: """内容数据模型""" # 基本信息 id: str = field(default_factory=lambda: str(uuid.uuid4())[:8]) source: str = "" # 来源: bilibili, youtube, zhihu, local source_id: str = "" # 来源唯一ID url: str = "" title: str = "" author: str = "" description: str = "" duration: Optional[int] = None # 视频时长(秒) # 内容类型与状态 content_type: ContentType = ContentType.VIDEO status: ContentStatus = ContentStatus.NEW # 元数据 created_at: str = field(default_factory=lambda: datetime.now().isoformat()) processed_at: Optional[str] = None # 原始内容 transcript: str = "" # 字幕/原文 # AI分析结果 summary: str = "" # 摘要 one_liner: str = "" # 一句话摘要 key_points: List[str] = field(default_factory=list) # 关键要点 tags: List[str] = field(default_factory=list) # 标签 quality_score: float = 0.0 # 质量评分 analysis: Optional[ContentAnalysis] = None # 详细分析结果 outline: List[str] = field(default_factory=list) # 大纲 timeline: List[TimelineEntry] = field(default_factory=list) # 时间线 quality_metrics: QualityMetrics = field(default_factory=QualityMetrics) # 分类与标签 category: str = "" # 主题分类 # 输出 output_path: Optional[str] = None # 生成的笔记路径 note_path: Optional[str] = None # 别名,用于兼容 def to_dict(self) -> Dict[str, Any]: """序列化为字典""" data = asdict(self) data['content_type'] = self.content_type.value data['status'] = self.status.value data['quality_metrics'] = self.quality_metrics.to_dict() data['timeline'] = [e.to_dict() for e in self.timeline] return data @classmethod def from_dict(cls, data: Dict[str, Any]) -> "Content": """从字典反序列化""" # 处理枚举 data['content_type'] = ContentType(data.get('content_type', 'video')) data['status'] = ContentStatus(data.get('status', 'new')) # 处理嵌套对象 if 'quality_metrics' in data and isinstance(data['quality_metrics'], dict): data['quality_metrics'] = QualityMetrics.from_dict(data['quality_metrics']) else: data['quality_metrics'] = QualityMetrics() if 'timeline' in data and isinstance(data['timeline'], list): data['timeline'] = [TimelineEntry.from_dict(e) for e in data['timeline']] else: data['timeline'] = [] return cls(**{k: v for k, v in data.items() if k in [f.name for f in cls.__dataclass_fields__.values()]}) def to_json(self) -> str: """序列化为JSON字符串""" return json.dumps(self.to_dict(), ensure_ascii=False, indent=2) @classmethod def from_json(cls, json_str: str) -> "Content": """从JSON字符串反序列化""" return cls.from_dict(json.loads(json_str)) def is_high_quality(self, threshold: float = 0.7) -> bool: """判断是否高质量内容""" return self.quality_metrics.overall_score >= threshold def update_status(self, status: ContentStatus): """更新状态""" self.status = status if status == ContentStatus.GENERATED: self.processed_at = datetime.now().isoformat()