refactor(service_api): dep-inject app payloads with @model_validate (#41491)

This commit is contained in:
Eddy ZHANG authored and GitHub committed 2026-08-30 12:51:50 +00:00
1 parent 02f9b3ca7c
commit 8b3c2ee274
4 files changed
+31 -14

No files matched your search

+3 -3
View File
@@ -8,6 +8,7 @@ import services
from controllers.common.controller_schemas import TextToAudioPayload
from controllers.common.fields import AudioBinaryResponse, AudioTranscriptResponse
from controllers.common.schema import register_response_schema_models, register_schema_model
from controllers.console.wraps import model_validate
from controllers.service_api import service_api_ns
from controllers.service_api.app.error import (
AppUnavailableError,
@@ -181,14 +182,13 @@ class TextApi(Resource):
# TTS returns provider audio bytes, so the success response is intentionally schema-less.
@service_api_ns.response(200, "Text successfully converted to audio")
@validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON))
def post(self, app_model: App, end_user: EndUser):
@model_validate(TextToAudioPayload)
def post(self, payload: TextToAudioPayload, app_model: App, end_user: EndUser):
"""Convert text to audio using text-to-speech.
Converts the provided text to audio using the specified voice.
"""
try:
payload = TextToAudioPayload.model_validate(service_api_ns.payload or {})
message_id = payload.message_id
text = payload.text
voice = payload.voice
@@ -11,6 +11,7 @@ from werkzeug.exceptions import BadRequest, NotFound
import services
from controllers.common.controller_schemas import ConversationRenamePayload
from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models
from controllers.console.wraps import model_validate
from controllers.service_api import service_api_ns
from controllers.service_api.app.error import NotChatAppError
from controllers.service_api.schema import expect_user_json, expect_with_user
@@ -293,7 +294,8 @@ class ConversationRenameApi(Resource):
service_api_ns.models[SimpleConversation.__name__],
)
@validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON))
def post(self, app_model: App, end_user: EndUser, conversation_id: UUID):
@model_validate(ConversationRenamePayload)
def post(self, payload: ConversationRenamePayload, app_model: App, end_user: EndUser, conversation_id: UUID):
"""Rename a conversation or auto-generate a name."""
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT, AppMode.AGENT}:
@@ -301,8 +303,6 @@ class ConversationRenameApi(Resource):
conversation_id_str = str(conversation_id)
payload = ConversationRenamePayload.model_validate(service_api_ns.payload or {})
try:
session = db.session()
conversation = ConversationService.rename(
@@ -408,7 +408,15 @@ class ConversationVariableDetailApi(Resource):
service_api_ns.models[ConversationVariableResponse.__name__],
)
@validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON))
def put(self, app_model: App, end_user: EndUser, conversation_id: UUID, variable_id: UUID):
@model_validate(ConversationVariableUpdatePayload)
def put(
self,
payload: ConversationVariableUpdatePayload,
app_model: App,
end_user: EndUser,
conversation_id: UUID,
variable_id: UUID,
):
"""Update a conversation variable's value.
Allows updating the value of a specific conversation variable.
@@ -421,8 +429,6 @@ class ConversationVariableDetailApi(Resource):
conversation_id_str = str(conversation_id)
variable_id_str = str(variable_id)
payload = ConversationVariableUpdatePayload.model_validate(service_api_ns.payload or {})
try:
variable = ConversationService.update_conversation_variable(
app_model, conversation_id_str, variable_id_str, end_user, payload.value, session=db.session()
@@ -13,7 +13,7 @@ from inspect import unwrap
from unittest.mock import Mock, patch
import pytest
from flask import Flask
from flask import Flask, request
from sqlalchemy.orm import Session
from werkzeug.datastructures import FileStorage
from werkzeug.exceptions import InternalServerError
@@ -285,7 +285,8 @@ class TestTextApi:
method="POST",
json={"text": "hello", "voice": "v"},
):
response = handler(api, app_model=app_model, end_user=end_user)
payload = TextToAudioPayload.model_validate(request.get_json() or {})
response = handler(api, payload, app_model=app_model, end_user=end_user)
assert response == {"audio": "ok"}
@@ -308,7 +309,8 @@ class TestTextApi:
method="POST",
json={"text": "hello", "message_id": "message-1"},
):
response = handler(api, app_model=app_model, end_user=end_user)
payload = TextToAudioPayload.model_validate(request.get_json() or {})
response = handler(api, payload, app_model=app_model, end_user=end_user)
assert response == {"audio": "ok"}
assert calls["message_ref"] == MessageRef(AppRef("tenant-1", "a1"), "message-1", end_user_id="end-user-1")
@@ -324,5 +326,6 @@ class TestTextApi:
end_user = _end_user(end_user_id="end-user-1", external_user_id="ext")
with app.test_request_context("/text-to-audio", method="POST", json={"text": "hello"}):
payload = TextToAudioPayload.model_validate(request.get_json() or {})
with pytest.raises(ProviderQuotaExceededError):
handler(api, app_model=app_model, end_user=end_user)
handler(api, payload, app_model=app_model, end_user=end_user)
@@ -21,7 +21,7 @@ from types import SimpleNamespace
from unittest.mock import Mock, patch
import pytest
from flask import Flask
from flask import Flask, request
from sqlalchemy.engine import Engine
from sqlalchemy.orm import Session
from werkzeug.exceptions import BadRequest, NotFound
@@ -625,9 +625,11 @@ class TestConversationRenameApiController:
method="POST",
json={"auto_generate": True},
):
payload = ConversationRenamePayload.model_validate(request.get_json() or {})
with pytest.raises(NotFound):
handler(
api,
payload,
app_model=app_model,
end_user=end_user,
conversation_id="00000000-0000-0000-0000-000000000001",
@@ -736,9 +738,11 @@ class TestConversationVariableDetailApiController:
method="PUT",
json={"value": "x"},
):
payload = ConversationVariableUpdatePayload.model_validate(request.get_json() or {})
with pytest.raises(BadRequest):
handler(
api,
payload,
app_model=app_model,
end_user=end_user,
conversation_id="00000000-0000-0000-0000-000000000001",
@@ -762,9 +766,11 @@ class TestConversationVariableDetailApiController:
method="PUT",
json={"value": "x"},
):
payload = ConversationVariableUpdatePayload.model_validate(request.get_json() or {})
with pytest.raises(NotFound):
handler(
api,
payload,
app_model=app_model,
end_user=end_user,
conversation_id="00000000-0000-0000-0000-000000000001",
@@ -796,8 +802,10 @@ class TestConversationVariableDetailApiController:
method="PUT",
json={"value": 1},
):
payload = ConversationVariableUpdatePayload.model_validate(request.get_json() or {})
result = handler(
api,
payload,
app_model=app_model,
end_user=end_user,
conversation_id="00000000-0000-0000-0000-000000000001",