Initial commit: snapAna 截图智能整理工具
包含 FastAPI 后端、React 前端、队列/OCR/标签/待办等完整功能。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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="标签名列表,自动新建")
|
||||
Reference in New Issue
Block a user