Initial commit: snapAna 截图智能整理工具

包含 FastAPI 后端、React 前端、队列/OCR/标签/待办等完整功能。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wjl
2026-05-27 15:45:50 +08:00
commit 5c028d7952
76 changed files with 10467 additions and 0 deletions
View File
+76
View File
@@ -0,0 +1,76 @@
"""通用 Schema:状态、统计、设置。"""
from __future__ import annotations
from typing import Any, Optional
from pydantic import BaseModel
class StatsResp(BaseModel):
total: int
pending_ocr: int
pending_ai: int
failed: int
by_category: list[dict[str, Any]]
by_date: list[dict[str, Any]]
class WatchFolderIn(BaseModel):
path: str
enabled: bool = True
recursive: bool = True
is_sensitive: bool = False
class WatchFolderOut(WatchFolderIn):
id: int
class Config:
from_attributes = True
class CategoryIn(BaseModel):
name: str
color: Optional[str] = None
prompt_hint: Optional[str] = None
class ProviderConfig(BaseModel):
"""OCR/VLM Provider 配置。
type: openai_compat / tesseract / anthropic / none
base_url、api_key、model 等都是可选的,按 provider 类型决定。
"""
type: str
base_url: Optional[str] = None
api_key: Optional[str] = None
model: Optional[str] = None
extra: dict[str, Any] = {}
class ProviderConfigOut(ProviderConfig):
"""读取用:api_key 永远为空,只通过 api_key_mask 暴露提示。"""
api_key_mask: Optional[str] = None
class RecognitionModeIn(BaseModel):
"""文字识别策略:传统 OCR / 视觉 AI / 混合。"""
mode: str # ocr | vision | hybrid
class ProviderTestResult(BaseModel):
"""Provider 连通性测试结果。"""
ok: bool
message: str
detail: Optional[str] = None
latency_ms: Optional[int] = None
class TodoUpdate(BaseModel):
status: Optional[str] = None
title: Optional[str] = None
note: Optional[str] = None
+79
View File
@@ -0,0 +1,79 @@
"""分析任务队列的请求/响应模型。"""
from __future__ import annotations
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
class JobOut(BaseModel):
"""单条任务详情,含关联截图摘要。"""
id: int
screenshot_id: int
kind: str
status: str
retries: int
last_error: Optional[str] = None
created_at: datetime
started_at: Optional[datetime] = None
finished_at: Optional[datetime] = None
thumb_url: Optional[str] = None
path: Optional[str] = None
ai_title: Optional[str] = None
ai_status: Optional[str] = None
ocr_status: Optional[str] = None
class JobListResp(BaseModel):
items: list[JobOut]
total: int
page: int
size: int
class JobRetryIn(BaseModel):
"""可选:仅重试指定 job id;不传则重试全部 failed。"""
job_ids: Optional[list[int]] = None
+90
View File
@@ -0,0 +1,90 @@
"""截图相关的请求/响应模型。"""
from __future__ import annotations
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, Field
class TagOut(BaseModel):
id: int
name: str
color: Optional[str] = None
class Config:
from_attributes = True
class CategoryOut(BaseModel):
id: int
name: str
color: Optional[str] = None
class Config:
from_attributes = True
class ScreenshotBrief(BaseModel):
"""卡片列表用:尽量精简。"""
id: int
path: str
width: int
height: int
captured_at: datetime
thumb_url: Optional[str] = None
ai_title: Optional[str] = None
ai_status: str
ocr_status: str
is_favorite: bool = False
category: Optional[CategoryOut] = None
tags: list[TagOut] = []
class TodoBrief(BaseModel):
id: int
title: str
note: Optional[str] = None
kind: Optional[str] = None
status: str
created_at: datetime
completed_at: Optional[datetime] = None
screenshot_id: int
class Config:
from_attributes = True
class TodoListResp(BaseModel):
items: list[TodoBrief]
total: int
page: int
size: int
class ScreenshotDetail(ScreenshotBrief):
"""详情页用:含 OCR 与 AI 文本。"""
file_url: str
size: int
ocr_text: Optional[str] = None
ai_summary: Optional[str] = None
ai_suggestion: Optional[str] = None
todos: list[TodoBrief] = []
class ScreenshotListResp(BaseModel):
items: list[ScreenshotBrief]
total: int
page: int
size: int
class ScreenshotUpdate(BaseModel):
"""前端更新可写字段。"""
category_id: Optional[int] = None
is_favorite: Optional[bool] = None
is_hidden: Optional[bool] = None
tags: Optional[list[str]] = Field(default=None, description="标签名列表,自动新建")