dify/api/controllers/common/controller_schemas.py
Stephen Zhou 19838972dc
fix: add service api openapi descriptions (#37595)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-06-17 16:02:43 +00:00

148 lines
4.4 KiB
Python

from copy import deepcopy
from typing import Any, Literal, override
from uuid import UUID
from pydantic import BaseModel, Field, GetJsonSchemaHandler, model_validator
from libs.helper import UUIDStrOrEmpty
# --- Conversation schemas ---
class ConversationRenamePayload(BaseModel):
name: str | None = None
auto_generate: bool = False
@classmethod
@override
def __get_pydantic_json_schema__(cls, core_schema: Any, handler: GetJsonSchemaHandler) -> dict[str, Any]:
schema = handler.resolve_ref_schema(handler(core_schema))
properties = schema.get("properties")
if not isinstance(properties, dict):
return schema
auto_generate_schema = deepcopy(properties.get("auto_generate", {"type": "boolean"}))
name_schema = deepcopy(properties.get("name", {"type": "string"}))
non_blank_name_schema: dict[str, Any] = {"pattern": r".*\S.*", "type": "string"}
if isinstance(name_schema, dict) and isinstance(name_schema.get("title"), str):
non_blank_name_schema["title"] = name_schema["title"]
auto_generate_true_schema = {**auto_generate_schema, "enum": [True]}
auto_generate_true_schema.pop("default", None)
return {
**schema,
"anyOf": [
{
"properties": {
"auto_generate": auto_generate_true_schema,
"name": name_schema,
},
"required": ["auto_generate"],
"type": "object",
},
{
"properties": {
"auto_generate": {**auto_generate_schema, "enum": [False]},
"name": non_blank_name_schema,
},
"required": ["name"],
"type": "object",
},
],
}
@model_validator(mode="after")
def validate_name_requirement(self):
if not self.auto_generate:
if self.name is None or not self.name.strip():
raise ValueError("name is required when auto_generate is false")
return self
# --- Message schemas ---
class MessageListQuery(BaseModel):
conversation_id: UUIDStrOrEmpty = Field(description="Conversation UUID")
first_id: UUIDStrOrEmpty | None = Field(default=None, description="First message ID for pagination")
limit: int = Field(default=20, ge=1, le=100, description="Number of messages to return (1-100)")
class MessageFeedbackPayload(BaseModel):
rating: Literal["like", "dislike"] | None = None
content: str | None = None
# --- Saved message schemas ---
class SavedMessageListQuery(BaseModel):
last_id: UUIDStrOrEmpty | None = None
limit: int = Field(default=20, ge=1, le=100)
class SavedMessageCreatePayload(BaseModel):
message_id: UUIDStrOrEmpty
# --- Workflow schemas ---
class DefaultBlockConfigQuery(BaseModel):
q: str | None = None
class WorkflowListQuery(BaseModel):
page: int = Field(default=1, ge=1, le=99999)
limit: int = Field(default=10, ge=1, le=100)
user_id: str | None = None
named_only: bool = False
class WorkflowRunPayload(BaseModel):
inputs: dict[str, Any]
files: list[dict[str, Any]] | None = Field(default=None)
class WorkflowUpdatePayload(BaseModel):
marked_name: str | None = Field(default=None, max_length=20)
marked_comment: str | None = Field(default=None, max_length=100)
# --- Dataset schemas ---
DOCUMENT_BATCH_DOWNLOAD_ZIP_MAX_DOCS = 100
class ChildChunkCreatePayload(BaseModel):
content: str
class ChildChunkUpdatePayload(BaseModel):
content: str
class DocumentBatchDownloadZipPayload(BaseModel):
"""Request payload for bulk downloading documents as a zip archive."""
document_ids: list[UUID] = Field(..., min_length=1, max_length=DOCUMENT_BATCH_DOWNLOAD_ZIP_MAX_DOCS)
class MetadataUpdatePayload(BaseModel):
name: str
# --- Audio schemas ---
class TextToAudioPayload(BaseModel):
message_id: str | None = Field(default=None, description="Message ID")
voice: str | None = Field(default=None, description="Voice to use for TTS")
text: str | None = Field(default=None, description="Text to convert to audio")
streaming: bool | None = Field(
default=None,
description="Reserved for compatibility; TTS response streaming is determined by the provider output.",
)