142 lines
5.0 KiB
Python
142 lines
5.0 KiB
Python
"""RAG / 知识库 / QA 记录请求模型。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from typing import ClassVar, Optional
|
|
|
|
from pydantic import BaseModel, Field, field_validator
|
|
|
|
|
|
class RAGAskRequest(BaseModel):
|
|
_ALLOWED_ASKED_VIA: ClassVar[set[str]] = {
|
|
"pmflow",
|
|
"feishu",
|
|
"lark",
|
|
"feishu_group",
|
|
"feishu_dm",
|
|
"pmflow_manual",
|
|
"/ai-pmo/process-text",
|
|
"ai-pmo-process-text",
|
|
"ai_pmo",
|
|
"ai_pmo_ui",
|
|
}
|
|
_ASKED_VIA_ALIAS: ClassVar[dict[str, str]] = {
|
|
"ai-pmo-process-text": "/ai-pmo/process-text",
|
|
}
|
|
question: str = Field(..., min_length=1, max_length=4000)
|
|
project_id: Optional[int] = Field(default=None)
|
|
asked_via: str = Field(default="pmflow", min_length=1, max_length=32)
|
|
source_chat_id: Optional[str] = Field(default=None, max_length=128)
|
|
session_id: Optional[int] = Field(default=None, ge=1)
|
|
new_session: bool = Field(default=False)
|
|
thinking_mode: str = Field(default="deep", pattern="^(normal|deep)$")
|
|
action_mode: str = Field(default="auto", pattern="^(auto|read|write|read_write)$")
|
|
sync_requirement: bool = Field(default=True)
|
|
message_intent: Optional[str] = Field(default=None, max_length=32)
|
|
mixed_signal_part: Optional[str] = Field(default=None, max_length=2000)
|
|
|
|
@field_validator("asked_via", mode="before")
|
|
@classmethod
|
|
def _normalize_asked_via(cls, value: object) -> str:
|
|
text = str(value or "pmflow").strip().lower()
|
|
text = cls._ASKED_VIA_ALIAS.get(text, text)
|
|
if text not in cls._ALLOWED_ASKED_VIA:
|
|
allowed = ", ".join(sorted(cls._ALLOWED_ASKED_VIA))
|
|
raise ValueError(f"asked_via must be one of: {allowed}")
|
|
return text
|
|
|
|
@field_validator("message_intent", mode="before")
|
|
@classmethod
|
|
def _normalize_message_intent(cls, value: object) -> Optional[str]:
|
|
if value is None:
|
|
return None
|
|
text = str(value).strip().lower()
|
|
if not text:
|
|
return None
|
|
return text
|
|
|
|
@field_validator("mixed_signal_part", mode="before")
|
|
@classmethod
|
|
def _normalize_mixed_signal_part(cls, value: object) -> Optional[str]:
|
|
if value is None:
|
|
return None
|
|
text = str(value).strip()
|
|
return text or None
|
|
|
|
|
|
class KnowledgeDocCreateRequest(BaseModel):
|
|
title: str = Field(..., min_length=1, max_length=255)
|
|
file_type: str = Field(default="txt", max_length=32)
|
|
content: str = Field(..., min_length=1, max_length=200000)
|
|
source_type: str = Field(default="file", max_length=32)
|
|
file_url: Optional[str] = Field(default=None, max_length=1024)
|
|
project_id: Optional[int] = Field(default=None)
|
|
|
|
|
|
class KnowledgeURLCreateRequest(BaseModel):
|
|
url: str = Field(..., min_length=5, max_length=1024)
|
|
title: Optional[str] = Field(default=None, max_length=255)
|
|
project_id: Optional[int] = Field(default=None)
|
|
|
|
|
|
class QAFeedbackCreateRequest(BaseModel):
|
|
rating: str = Field(..., pattern="^(positive|negative)$")
|
|
helpfulness: Optional[str] = Field(default=None, pattern="^(fully|partially|could_be_better)$")
|
|
error_types: list[str] = Field(default_factory=list)
|
|
correct_answer: Optional[str] = Field(default=None, max_length=4000)
|
|
|
|
|
|
class QAListQuery(BaseModel):
|
|
project_id: Optional[int] = None
|
|
date_from: Optional[datetime] = None
|
|
date_to: Optional[datetime] = None
|
|
rating: Optional[str] = Field(default=None, pattern="^(positive|negative)$")
|
|
page: int = Field(default=1, ge=1)
|
|
page_size: int = Field(default=20, ge=1, le=100)
|
|
|
|
|
|
class QAExportQuery(BaseModel):
|
|
include_unrated: bool = False
|
|
project_id: Optional[int] = None
|
|
rating: Optional[str] = Field(default=None, pattern="^(positive|negative|unrated)$")
|
|
domain: Optional[str] = None
|
|
date_from: Optional[datetime] = None
|
|
date_to: Optional[datetime] = None
|
|
|
|
|
|
class QASessionListQuery(BaseModel):
|
|
date_from: Optional[datetime] = None
|
|
date_to: Optional[datetime] = None
|
|
page: int = Field(default=1, ge=1)
|
|
page_size: int = Field(default=20, ge=1, le=100)
|
|
|
|
|
|
class QASessionRenameRequest(BaseModel):
|
|
title: str = Field(..., min_length=1, max_length=120)
|
|
|
|
|
|
class EntityResolutionRequest(BaseModel):
|
|
question: str = Field(..., min_length=1, max_length=4000)
|
|
project_id: Optional[int] = Field(default=None)
|
|
limit: int = Field(default=10, ge=1, le=50)
|
|
|
|
|
|
class MultiStepSearchRequest(BaseModel):
|
|
question: str = Field(..., min_length=1, max_length=4000)
|
|
project_id: Optional[int] = Field(default=None)
|
|
source_chat_id: Optional[str] = Field(default=None, max_length=128)
|
|
|
|
|
|
class SymbolSyncRequest(BaseModel):
|
|
base_dir: Optional[str] = Field(default=None, max_length=500)
|
|
max_files: int = Field(default=500, ge=1, le=3000)
|
|
force_reindex: bool = Field(default=False)
|
|
|
|
|
|
class SymbolSearchRequest(BaseModel):
|
|
query: str = Field(..., min_length=1, max_length=255)
|
|
language: Optional[str] = Field(default=None, max_length=20)
|
|
symbol_type: Optional[str] = Field(default=None, max_length=32)
|
|
limit: int = Field(default=30, ge=1, le=200)
|