f26d4d8f7f
- Multi-source content aggregation (Bilibili/YouTube/Zhihu) - Smart inbox management with AI quality scoring - Long video chunking analysis (30min+ auto-segmentation) - Topic-based organization - Git auto-sync to Obsidian - Template system with Jinja2 and fallback rendering - CLI commands: subscribe, inbox, process, skip, status, search - Comprehensive test suite with unit and integration tests - Documentation: README.md and SKILL.md Checkpoint 7-8 completed by Agent E
58 lines
1.7 KiB
Python
58 lines
1.7 KiB
Python
"""Obsidian KB - 本地文件源"""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
from .base import BaseSource
|
|
from ..models import Content, ContentType
|
|
|
|
|
|
class LocalSource(BaseSource):
|
|
"""本地文件源"""
|
|
|
|
name = "local"
|
|
|
|
SUPPORTED_EXTENSIONS = ['.txt', '.md', '.pdf', '.docx']
|
|
|
|
def can_handle(self, url: str) -> bool:
|
|
"""检查是否为本地文件路径"""
|
|
if url.startswith('http'):
|
|
return False
|
|
path = Path(url)
|
|
return path.exists() and path.suffix.lower() in self.SUPPORTED_EXTENSIONS
|
|
|
|
def extract_id(self, url: str) -> Optional[str]:
|
|
"""使用文件路径作为ID"""
|
|
return os.path.basename(url)
|
|
|
|
def fetch(self, url: str) -> Optional[Content]:
|
|
"""获取文件元数据"""
|
|
path = Path(url)
|
|
if not path.exists():
|
|
return None
|
|
|
|
content_type = ContentType.ARTICLE
|
|
if path.suffix.lower() == '.txt':
|
|
content_type = ContentType.ARTICLE
|
|
|
|
return Content(
|
|
source=self.name,
|
|
source_id=str(path),
|
|
url=str(path.absolute()),
|
|
title=path.stem,
|
|
author='',
|
|
content_type=content_type
|
|
)
|
|
|
|
def get_transcript(self, content: Content) -> Optional[str]:
|
|
"""读取文件内容"""
|
|
try:
|
|
path = Path(content.url)
|
|
if path.suffix.lower() in ['.txt', '.md']:
|
|
return path.read_text(encoding='utf-8')
|
|
# TODO: 支持 PDF 和 DOCX
|
|
return None
|
|
except Exception as e:
|
|
print(f"Error reading local file: {e}")
|
|
return None
|