mirror of
https://github.com/langgenius/dify.git
synced 2026-06-26 06:41:10 +08:00
refactor(api): migrate console app chat endpoints to BaseModel
This commit is contained in:
parent
bb921bcc45
commit
db97c47c5f
@ -1,7 +1,7 @@
|
||||
from typing import Any, Literal
|
||||
from uuid import UUID
|
||||
|
||||
from flask import abort, make_response, request
|
||||
from flask import abort, request
|
||||
from flask_restx import Resource
|
||||
from pydantic import BaseModel, Field, TypeAdapter, field_validator
|
||||
|
||||
@ -26,10 +26,12 @@ from fields.annotation_fields import (
|
||||
AnnotationExportList,
|
||||
AnnotationHitHistory,
|
||||
AnnotationHitHistoryList,
|
||||
AnnotationJobStatusDetailResponse,
|
||||
AnnotationJobStatusResponse,
|
||||
AnnotationList,
|
||||
)
|
||||
from fields.base import ResponseModel
|
||||
from libs.helper import uuid_value
|
||||
from libs.helper import dump_response, uuid_value
|
||||
from libs.login import login_required
|
||||
from services.annotation_service import (
|
||||
AppAnnotationService,
|
||||
@ -99,23 +101,23 @@ class AnnotationFilePayload(BaseModel):
|
||||
return uuid_value(value)
|
||||
|
||||
|
||||
class AnnotationJobStatusResponse(ResponseModel):
|
||||
job_id: str | None = None
|
||||
job_status: str | None = None
|
||||
error_msg: str | None = None
|
||||
record_count: int | None = None
|
||||
|
||||
|
||||
class AnnotationEmbeddingModelResponse(ResponseModel):
|
||||
class AnnotationSettingEmbeddingModelResponse(ResponseModel):
|
||||
embedding_provider_name: str | None = None
|
||||
embedding_model_name: str | None = None
|
||||
|
||||
|
||||
class AnnotationSettingResponse(ResponseModel):
|
||||
id: str | None = None
|
||||
enabled: bool
|
||||
id: str | None = None
|
||||
score_threshold: float | None = None
|
||||
embedding_model: AnnotationEmbeddingModelResponse | None = None
|
||||
embedding_model: AnnotationSettingEmbeddingModelResponse | None = None
|
||||
|
||||
|
||||
class AnnotationBatchImportResponse(ResponseModel):
|
||||
job_id: str | None = None
|
||||
job_status: str | None = None
|
||||
record_count: int | None = None
|
||||
error_msg: str | None = None
|
||||
|
||||
|
||||
register_schema_models(
|
||||
@ -142,7 +144,10 @@ register_response_schema_models(
|
||||
AnnotationHitHistory,
|
||||
AnnotationHitHistoryList,
|
||||
AnnotationJobStatusResponse,
|
||||
AnnotationJobStatusDetailResponse,
|
||||
AnnotationSettingEmbeddingModelResponse,
|
||||
AnnotationSettingResponse,
|
||||
AnnotationBatchImportResponse,
|
||||
)
|
||||
|
||||
|
||||
@ -172,7 +177,7 @@ class AnnotationReplyActionApi(Resource):
|
||||
result = AppAnnotationService.enable_app_annotation(enable_args, str(app_id))
|
||||
case "disable":
|
||||
result = AppAnnotationService.disable_app_annotation(str(app_id))
|
||||
return result, 200
|
||||
return dump_response(AnnotationJobStatusResponse, result), 200
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/annotation-setting")
|
||||
@ -193,7 +198,7 @@ class AppAnnotationSettingDetailApi(Resource):
|
||||
@rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_VIEW_LAYOUT)
|
||||
def get(self, app_id: UUID):
|
||||
result = AppAnnotationService.get_app_annotation_setting_by_app_id(str(app_id))
|
||||
return result, 200
|
||||
return dump_response(AnnotationSettingResponse, result), 200
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/annotation-settings/<uuid:annotation_setting_id>")
|
||||
@ -218,7 +223,7 @@ class AppAnnotationSettingUpdateApi(Resource):
|
||||
result = AppAnnotationService.update_app_annotation_setting(
|
||||
str(app_id), annotation_setting_id_str, setting_args
|
||||
)
|
||||
return result, 200
|
||||
return dump_response(AnnotationSettingResponse, result), 200
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/annotation-reply/<string:action>/status/<uuid:job_id>")
|
||||
@ -227,9 +232,7 @@ class AnnotationReplyActionStatusApi(Resource):
|
||||
@console_ns.doc(description="Get status of annotation reply action job")
|
||||
@console_ns.doc(params={"app_id": "Application ID", "job_id": "Job ID", "action": "Action type"})
|
||||
@console_ns.response(
|
||||
200,
|
||||
"Job status retrieved successfully",
|
||||
console_ns.models[AnnotationJobStatusResponse.__name__],
|
||||
200, "Job status retrieved successfully", console_ns.models[AnnotationJobStatusDetailResponse.__name__]
|
||||
)
|
||||
@console_ns.response(403, "Insufficient permissions")
|
||||
@setup_required
|
||||
@ -251,7 +254,9 @@ class AnnotationReplyActionStatusApi(Resource):
|
||||
app_annotation_error_key = f"{action}_app_annotation_error_{job_id_str}"
|
||||
error_msg = redis_client.get(app_annotation_error_key).decode()
|
||||
|
||||
return {"job_id": job_id_str, "job_status": job_status, "error_msg": error_msg}, 200
|
||||
return AnnotationJobStatusDetailResponse(
|
||||
job_id=job_id_str, job_status=job_status, error_msg=error_msg
|
||||
).model_dump(mode="json"), 200
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/annotations")
|
||||
@ -275,14 +280,9 @@ class AnnotationApi(Resource):
|
||||
|
||||
annotation_list, total = AppAnnotationService.get_annotation_list_by_app_id(str(app_id), page, limit, keyword)
|
||||
annotation_models = TypeAdapter(list[Annotation]).validate_python(annotation_list, from_attributes=True)
|
||||
response = AnnotationList(
|
||||
data=annotation_models,
|
||||
has_more=len(annotation_list) == limit,
|
||||
limit=limit,
|
||||
total=total,
|
||||
page=page,
|
||||
)
|
||||
return response.model_dump(mode="json"), 200
|
||||
return AnnotationList(
|
||||
data=annotation_models, has_more=len(annotation_list) == limit, limit=limit, total=total, page=page
|
||||
).model_dump(mode="json"), 200
|
||||
|
||||
@console_ns.doc("create_annotation")
|
||||
@console_ns.doc(description="Create a new annotation for an app")
|
||||
@ -308,7 +308,7 @@ class AnnotationApi(Resource):
|
||||
if args.question is not None:
|
||||
upsert_args["question"] = args.question
|
||||
annotation = AppAnnotationService.up_insert_app_annotation_from_message(upsert_args, str(app_id))
|
||||
return Annotation.model_validate(annotation, from_attributes=True).model_dump(mode="json")
|
||||
return dump_response(Annotation, annotation), 201
|
||||
|
||||
@setup_required
|
||||
@login_required
|
||||
@ -357,14 +357,14 @@ class AnnotationExportApi(Resource):
|
||||
def get(self, app_id: UUID):
|
||||
annotation_list = AppAnnotationService.export_annotation_list_by_app_id(str(app_id))
|
||||
annotation_models = TypeAdapter(list[Annotation]).validate_python(annotation_list, from_attributes=True)
|
||||
response_data = AnnotationExportList(data=annotation_models).model_dump(mode="json")
|
||||
|
||||
# Create response with secure headers for CSV export
|
||||
response = make_response(response_data, 200)
|
||||
response.headers["Content-Type"] = "application/json; charset=utf-8"
|
||||
response.headers["X-Content-Type-Options"] = "nosniff"
|
||||
|
||||
return response
|
||||
return (
|
||||
AnnotationExportList(data=annotation_models).model_dump(mode="json"),
|
||||
200,
|
||||
{
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"X-Content-Type-Options": "nosniff",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/annotations/<uuid:annotation_id>")
|
||||
@ -392,7 +392,7 @@ class AnnotationUpdateDeleteApi(Resource):
|
||||
annotation = AppAnnotationService.update_app_annotation_directly(
|
||||
update_args, str(app_id), str(annotation_id), db.session
|
||||
)
|
||||
return Annotation.model_validate(annotation, from_attributes=True).model_dump(mode="json")
|
||||
return dump_response(Annotation, annotation)
|
||||
|
||||
@setup_required
|
||||
@login_required
|
||||
@ -411,9 +411,7 @@ class AnnotationBatchImportApi(Resource):
|
||||
@console_ns.doc(description="Batch import annotations from CSV file with rate limiting and security checks")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.response(
|
||||
200,
|
||||
"Batch import started successfully",
|
||||
console_ns.models[AnnotationJobStatusResponse.__name__],
|
||||
200, "Batch import started successfully", console_ns.models[AnnotationBatchImportResponse.__name__]
|
||||
)
|
||||
@console_ns.response(403, "Insufficient permissions")
|
||||
@console_ns.response(400, "No file uploaded or too many files")
|
||||
@ -460,7 +458,10 @@ class AnnotationBatchImportApi(Resource):
|
||||
if file_size == 0:
|
||||
raise ValueError("The uploaded file is empty")
|
||||
|
||||
return AppAnnotationService.batch_import_app_annotations(str(app_id), file)
|
||||
return dump_response(
|
||||
AnnotationBatchImportResponse,
|
||||
AppAnnotationService.batch_import_app_annotations(str(app_id), file),
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/annotations/batch-import-status/<uuid:job_id>")
|
||||
@ -469,9 +470,7 @@ class AnnotationBatchImportStatusApi(Resource):
|
||||
@console_ns.doc(description="Get status of batch import job")
|
||||
@console_ns.doc(params={"app_id": "Application ID", "job_id": "Job ID"})
|
||||
@console_ns.response(
|
||||
200,
|
||||
"Job status retrieved successfully",
|
||||
console_ns.models[AnnotationJobStatusResponse.__name__],
|
||||
200, "Job status retrieved successfully", console_ns.models[AnnotationJobStatusDetailResponse.__name__]
|
||||
)
|
||||
@console_ns.response(403, "Insufficient permissions")
|
||||
@setup_required
|
||||
@ -491,7 +490,9 @@ class AnnotationBatchImportStatusApi(Resource):
|
||||
indexing_error_msg_key = f"app_annotation_batch_import_error_msg_{str(job_id)}"
|
||||
error_msg = redis_client.get(indexing_error_msg_key).decode()
|
||||
|
||||
return {"job_id": job_id, "job_status": job_status, "error_msg": error_msg}, 200
|
||||
return AnnotationJobStatusDetailResponse(
|
||||
job_id=str(job_id), job_status=job_status, error_msg=error_msg
|
||||
).model_dump(mode="json"), 200
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/annotations/<uuid:annotation_id>/hit-histories")
|
||||
@ -520,11 +521,6 @@ class AnnotationHitHistoryListApi(Resource):
|
||||
history_models = TypeAdapter(list[AnnotationHitHistory]).validate_python(
|
||||
annotation_hit_history_list, from_attributes=True
|
||||
)
|
||||
response = AnnotationHitHistoryList(
|
||||
data=history_models,
|
||||
has_more=len(annotation_hit_history_list) == limit,
|
||||
limit=limit,
|
||||
total=total,
|
||||
page=page,
|
||||
)
|
||||
return response.model_dump(mode="json")
|
||||
return AnnotationHitHistoryList(
|
||||
data=history_models, has_more=len(annotation_hit_history_list) == limit, limit=limit, total=total, page=page
|
||||
).model_dump(mode="json")
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from flask import request
|
||||
from flask_restx import Resource
|
||||
@ -7,7 +6,6 @@ from pydantic import BaseModel, Field, RootModel
|
||||
from werkzeug.exceptions import InternalServerError
|
||||
|
||||
import services
|
||||
from controllers.common.fields import AudioBinaryResponse
|
||||
from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models
|
||||
from controllers.console import console_ns
|
||||
from controllers.console.app.error import (
|
||||
@ -31,7 +29,9 @@ from controllers.console.wraps import (
|
||||
)
|
||||
from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError
|
||||
from extensions.ext_database import db
|
||||
from fields.base import ResponseModel
|
||||
from graphon.model_runtime.errors.invoke import InvokeError
|
||||
from libs.helper import dump_response
|
||||
from libs.login import login_required
|
||||
from models import App, AppMode
|
||||
from services.audio_service import AudioService
|
||||
@ -56,16 +56,27 @@ class TextToSpeechVoiceQuery(BaseModel):
|
||||
language: str = Field(..., description="Language code")
|
||||
|
||||
|
||||
class AudioTranscriptResponse(BaseModel):
|
||||
class AudioTranscriptResponse(ResponseModel):
|
||||
text: str = Field(description="Transcribed text from audio")
|
||||
|
||||
|
||||
class TextToSpeechVoiceListResponse(RootModel[list[dict[str, Any]]]):
|
||||
root: list[dict[str, Any]]
|
||||
class TextToSpeechVoiceResponse(ResponseModel):
|
||||
# see api/core/plugin/impl/model.py
|
||||
name: str = Field(description="Voice display name")
|
||||
value: str = Field(description="Voice identifier")
|
||||
|
||||
|
||||
register_schema_models(console_ns, AudioTranscriptResponse, TextToSpeechPayload, TextToSpeechVoiceQuery)
|
||||
register_response_schema_models(console_ns, AudioBinaryResponse, TextToSpeechVoiceListResponse)
|
||||
class TextToSpeechVoiceListResponse(RootModel[list[TextToSpeechVoiceResponse]]):
|
||||
root: list[TextToSpeechVoiceResponse] = Field(description="Available voices")
|
||||
|
||||
|
||||
register_schema_models(console_ns, TextToSpeechPayload, TextToSpeechVoiceQuery)
|
||||
register_response_schema_models(
|
||||
console_ns,
|
||||
AudioTranscriptResponse,
|
||||
TextToSpeechVoiceResponse,
|
||||
TextToSpeechVoiceListResponse,
|
||||
)
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/audio-to-text")
|
||||
@ -94,7 +105,7 @@ class ChatMessageAudioApi(Resource):
|
||||
end_user=None,
|
||||
)
|
||||
|
||||
return response
|
||||
return dump_response(AudioTranscriptResponse, response)
|
||||
except services.errors.app_model_config.AppModelConfigBrokenError:
|
||||
logger.exception("App model config broken.")
|
||||
raise AppUnavailableError()
|
||||
@ -127,11 +138,8 @@ class ChatMessageTextApi(Resource):
|
||||
@console_ns.doc(description="Convert text to speech for chat messages")
|
||||
@console_ns.doc(params={"app_id": "App ID"})
|
||||
@console_ns.expect(console_ns.models[TextToSpeechPayload.__name__])
|
||||
@console_ns.response(
|
||||
200,
|
||||
"Text to speech conversion successful",
|
||||
console_ns.models[AudioBinaryResponse.__name__],
|
||||
)
|
||||
# TTS returns provider audio bytes, so the success response is intentionally schema-less.
|
||||
@console_ns.response(200, "Text to speech conversion successful")
|
||||
@console_ns.response(400, "Bad request - Invalid parameters")
|
||||
@setup_required
|
||||
@login_required
|
||||
@ -141,7 +149,8 @@ class ChatMessageTextApi(Resource):
|
||||
try:
|
||||
payload = TextToSpeechPayload.model_validate(console_ns.payload)
|
||||
|
||||
response = AudioService.transcript_tts(
|
||||
# response-contract:ignore
|
||||
return AudioService.transcript_tts(
|
||||
app_model=app_model,
|
||||
session=db.session,
|
||||
text=payload.text,
|
||||
@ -149,7 +158,6 @@ class ChatMessageTextApi(Resource):
|
||||
message_id=payload.message_id,
|
||||
is_draft=True,
|
||||
)
|
||||
return response
|
||||
except services.errors.app_model_config.AppModelConfigBrokenError:
|
||||
logger.exception("App model config broken.")
|
||||
raise AppUnavailableError()
|
||||
@ -180,8 +188,7 @@ class ChatMessageTextApi(Resource):
|
||||
class TextModesApi(Resource):
|
||||
@console_ns.doc("get_text_to_speech_voices")
|
||||
@console_ns.doc(description="Get available TTS voices for a specific language")
|
||||
@console_ns.doc(params={"app_id": "App ID"})
|
||||
@console_ns.doc(params=query_params_from_model(TextToSpeechVoiceQuery))
|
||||
@console_ns.doc(params={"app_id": "App ID", **query_params_from_model(TextToSpeechVoiceQuery)})
|
||||
@console_ns.response(
|
||||
200,
|
||||
"TTS voices retrieved successfully",
|
||||
@ -202,7 +209,7 @@ class TextModesApi(Resource):
|
||||
language=args.language,
|
||||
)
|
||||
|
||||
return response
|
||||
return dump_response(TextToSpeechVoiceListResponse, response)
|
||||
except services.errors.audio.ProviderNotSupportTextToSpeechLanageServiceError:
|
||||
raise AppUnavailableError("Text to audio voices language parameter loss.")
|
||||
except NoAudioUploadedServiceError:
|
||||
|
||||
@ -8,7 +8,7 @@ from pydantic import BaseModel, Field, field_validator
|
||||
from werkzeug.exceptions import BadRequest, InternalServerError, NotFound
|
||||
|
||||
import services
|
||||
from controllers.common.fields import GeneratedAppResponse, SimpleResultResponse
|
||||
from controllers.common.fields import SimpleResultResponse
|
||||
from controllers.common.schema import register_response_schema_models, register_schema_models
|
||||
from controllers.console import console_ns
|
||||
from controllers.console.agent.app_helpers import resolve_agent_app_model
|
||||
@ -103,7 +103,7 @@ class ChatMessagePayload(BaseMessagePayload):
|
||||
|
||||
|
||||
register_schema_models(console_ns, CompletionMessagePayload, ChatMessagePayload)
|
||||
register_response_schema_models(console_ns, GeneratedAppResponse, SimpleResultResponse)
|
||||
register_response_schema_models(console_ns, SimpleResultResponse)
|
||||
|
||||
|
||||
# define completion message api for user
|
||||
@ -113,7 +113,7 @@ class CompletionMessageApi(Resource):
|
||||
@console_ns.doc(description="Generate completion message for debugging")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.expect(console_ns.models[CompletionMessagePayload.__name__])
|
||||
@console_ns.response(200, "Completion generated successfully", console_ns.models[GeneratedAppResponse.__name__])
|
||||
@console_ns.response(200, "Completion generated successfully")
|
||||
@console_ns.response(400, "Invalid request parameters")
|
||||
@console_ns.response(404, "App not found")
|
||||
@setup_required
|
||||
@ -134,6 +134,7 @@ class CompletionMessageApi(Resource):
|
||||
app_model=app_model, user=current_user, args=args, invoke_from=InvokeFrom.DEBUGGER, streaming=streaming
|
||||
)
|
||||
|
||||
# response-contract:ignore compact_generate_response
|
||||
return helper.compact_generate_response(response)
|
||||
except services.errors.conversation.ConversationNotExistsError:
|
||||
raise NotFound("Conversation Not Exists.")
|
||||
@ -177,7 +178,7 @@ class CompletionMessageStopApi(Resource):
|
||||
app_mode=AppMode.value_of(app_model.mode),
|
||||
)
|
||||
|
||||
return {"result": "success"}, 200
|
||||
return SimpleResultResponse(result="success").model_dump(mode="json"), 200
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/chat-messages")
|
||||
@ -186,7 +187,7 @@ class ChatMessageApi(Resource):
|
||||
@console_ns.doc(description="Generate chat message for debugging")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.expect(console_ns.models[ChatMessagePayload.__name__])
|
||||
@console_ns.response(200, "Chat message generated successfully", console_ns.models[GeneratedAppResponse.__name__])
|
||||
@console_ns.response(200, "Chat message generated successfully")
|
||||
@console_ns.response(400, "Invalid request parameters")
|
||||
@console_ns.response(404, "App or conversation not found")
|
||||
@setup_required
|
||||
@ -207,7 +208,7 @@ class AgentChatMessageApi(Resource):
|
||||
@console_ns.doc(description="Generate an Agent App chat message for debugging")
|
||||
@console_ns.doc(params={"agent_id": "Agent ID"})
|
||||
@console_ns.expect(console_ns.models[ChatMessagePayload.__name__])
|
||||
@console_ns.response(200, "Chat message generated successfully", console_ns.models[GeneratedAppResponse.__name__])
|
||||
@console_ns.response(200, "Chat message generated successfully")
|
||||
@console_ns.response(400, "Invalid request parameters")
|
||||
@console_ns.response(404, "Agent or conversation not found")
|
||||
@setup_required
|
||||
@ -315,6 +316,7 @@ def _create_chat_message(
|
||||
app_model=app_model, user=current_user, args=args, invoke_from=InvokeFrom.DEBUGGER, streaming=streaming
|
||||
)
|
||||
|
||||
# response-contract:ignore compact_generate_response
|
||||
return helper.compact_generate_response(response)
|
||||
except services.errors.conversation.ConversationNotExistsError:
|
||||
raise NotFound("Conversation Not Exists.")
|
||||
@ -348,4 +350,4 @@ def _stop_chat_message(*, current_user_id: str, app_model: App, task_id: str):
|
||||
app_mode=AppMode.value_of(app_model.mode),
|
||||
)
|
||||
|
||||
return {"result": "success"}, 200
|
||||
return SimpleResultResponse(result="success").model_dump(mode="json"), 200
|
||||
|
||||
@ -9,7 +9,7 @@ from sqlalchemy import func, or_
|
||||
from sqlalchemy.orm import selectinload
|
||||
from werkzeug.exceptions import NotFound
|
||||
|
||||
from controllers.common.schema import query_params_from_model, register_schema_models
|
||||
from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models
|
||||
from controllers.console import console_ns
|
||||
from controllers.console.app.wraps import get_app_model
|
||||
from controllers.console.wraps import (
|
||||
@ -39,6 +39,7 @@ from fields.conversation_fields import (
|
||||
ConversationWithSummaryPagination as ConversationWithSummaryPaginationResponse,
|
||||
)
|
||||
from libs.datetime_utils import naive_utc_now, parse_time_range
|
||||
from libs.helper import dump_response
|
||||
from libs.login import login_required
|
||||
from models import Conversation, EndUser, Message, MessageAnnotation
|
||||
from models.account import Account
|
||||
@ -79,13 +80,14 @@ register_schema_models(
|
||||
console_ns,
|
||||
CompletionConversationQuery,
|
||||
ChatConversationQuery,
|
||||
)
|
||||
register_response_schema_models(
|
||||
console_ns,
|
||||
ConversationResponse,
|
||||
ConversationPaginationResponse,
|
||||
ConversationMessageDetailResponse,
|
||||
ConversationWithSummaryPaginationResponse,
|
||||
ConversationDetailResponse,
|
||||
CompletionConversationQuery,
|
||||
ChatConversationQuery,
|
||||
)
|
||||
|
||||
|
||||
@ -93,8 +95,7 @@ register_schema_models(
|
||||
class CompletionConversationApi(Resource):
|
||||
@console_ns.doc("list_completion_conversations")
|
||||
@console_ns.doc(description="Get completion conversations with pagination and filtering")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.doc(params=query_params_from_model(CompletionConversationQuery))
|
||||
@console_ns.doc(params={"app_id": "Application ID", **query_params_from_model(CompletionConversationQuery)})
|
||||
@console_ns.response(200, "Success", console_ns.models[ConversationPaginationResponse.__name__])
|
||||
@console_ns.response(403, "Insufficient permissions")
|
||||
@setup_required
|
||||
@ -157,9 +158,7 @@ class CompletionConversationApi(Resource):
|
||||
|
||||
conversations = db.paginate(query, page=args.page, per_page=args.limit, error_out=False)
|
||||
|
||||
return ConversationPaginationResponse.model_validate(conversations, from_attributes=True).model_dump(
|
||||
mode="json"
|
||||
)
|
||||
return dump_response(ConversationPaginationResponse, conversations)
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/completion-conversations/<uuid:conversation_id>")
|
||||
@ -179,9 +178,9 @@ class CompletionConversationDetailApi(Resource):
|
||||
@get_app_model(mode=AppMode.COMPLETION)
|
||||
def get(self, current_user: Account, app_model: App, conversation_id: UUID):
|
||||
conversation_id_str = str(conversation_id)
|
||||
return ConversationMessageDetailResponse.model_validate(
|
||||
_get_conversation(current_user, app_model, conversation_id_str), from_attributes=True
|
||||
).model_dump(mode="json")
|
||||
return dump_response(
|
||||
ConversationMessageDetailResponse, _get_conversation(current_user, app_model, conversation_id_str)
|
||||
)
|
||||
|
||||
@console_ns.doc("delete_completion_conversation")
|
||||
@console_ns.doc(description="Delete a completion conversation")
|
||||
@ -211,8 +210,7 @@ class CompletionConversationDetailApi(Resource):
|
||||
class ChatConversationApi(Resource):
|
||||
@console_ns.doc("list_chat_conversations")
|
||||
@console_ns.doc(description="Get chat conversations with pagination, filtering and summary")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.doc(params=query_params_from_model(ChatConversationQuery))
|
||||
@console_ns.doc(params={"app_id": "Application ID", **query_params_from_model(ChatConversationQuery)})
|
||||
@console_ns.response(200, "Success", console_ns.models[ConversationWithSummaryPaginationResponse.__name__])
|
||||
@console_ns.response(403, "Insufficient permissions")
|
||||
@setup_required
|
||||
@ -314,9 +312,7 @@ class ChatConversationApi(Resource):
|
||||
|
||||
conversations = db.paginate(query, page=args.page, per_page=args.limit, error_out=False)
|
||||
|
||||
return ConversationWithSummaryPaginationResponse.model_validate(conversations, from_attributes=True).model_dump(
|
||||
mode="json"
|
||||
)
|
||||
return dump_response(ConversationWithSummaryPaginationResponse, conversations)
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/chat-conversations/<uuid:conversation_id>")
|
||||
@ -336,9 +332,9 @@ class ChatConversationDetailApi(Resource):
|
||||
@get_app_model(mode=[AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT, AppMode.AGENT])
|
||||
def get(self, current_user: Account, app_model: App, conversation_id: UUID):
|
||||
conversation_id_str = str(conversation_id)
|
||||
return ConversationDetailResponse.model_validate(
|
||||
_get_conversation(current_user, app_model, conversation_id_str), from_attributes=True
|
||||
).model_dump(mode="json")
|
||||
return dump_response(
|
||||
ConversationDetailResponse, _get_conversation(current_user, app_model, conversation_id_str)
|
||||
)
|
||||
|
||||
@console_ns.doc("delete_chat_conversation")
|
||||
@console_ns.doc(description="Delete a chat conversation")
|
||||
|
||||
@ -22,7 +22,7 @@ from controllers.console.wraps import (
|
||||
from extensions.ext_database import db
|
||||
from fields._value_type_serializer import serialize_value_type
|
||||
from fields.base import ResponseModel
|
||||
from libs.helper import to_timestamp
|
||||
from libs.helper import dump_response, to_timestamp
|
||||
from libs.login import login_required
|
||||
from models import ConversationVariable
|
||||
from models.model import App, AppMode
|
||||
@ -119,7 +119,8 @@ class ConversationVariablesApi(Resource):
|
||||
with sessionmaker(db.engine, expire_on_commit=False).begin() as session:
|
||||
rows = session.scalars(stmt).all()
|
||||
|
||||
response = PaginatedConversationVariableResponse.model_validate(
|
||||
return dump_response(
|
||||
PaginatedConversationVariableResponse,
|
||||
{
|
||||
"page": page,
|
||||
"limit": page_size,
|
||||
@ -135,6 +136,5 @@ class ConversationVariablesApi(Resource):
|
||||
)
|
||||
for row in rows
|
||||
],
|
||||
}
|
||||
},
|
||||
)
|
||||
return response.model_dump(mode="json")
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Literal
|
||||
from uuid import UUID
|
||||
|
||||
@ -38,16 +37,10 @@ from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotIni
|
||||
from extensions.ext_database import db
|
||||
from fields.base import ResponseModel
|
||||
from fields.conversation_fields import (
|
||||
AgentThought,
|
||||
ConversationAnnotation,
|
||||
ConversationAnnotationHitHistory,
|
||||
Feedback,
|
||||
JSONValue,
|
||||
MessageFile,
|
||||
format_files_contained,
|
||||
MessageDetail as BaseMessageDetailResponse,
|
||||
)
|
||||
from graphon.model_runtime.errors.invoke import InvokeError
|
||||
from libs.helper import to_timestamp, uuid_value
|
||||
from libs.helper import dump_response, uuid_value
|
||||
from libs.infinite_scroll_pagination import InfiniteScrollPagination
|
||||
from libs.login import login_required
|
||||
from models.account import Account
|
||||
@ -111,49 +104,16 @@ class FeedbackExportQuery(BaseModel):
|
||||
raise ValueError("has_comment must be a boolean value")
|
||||
|
||||
|
||||
class AnnotationCountResponse(BaseModel):
|
||||
class AnnotationCountResponse(ResponseModel):
|
||||
count: int = Field(description="Number of annotations")
|
||||
|
||||
|
||||
class SuggestedQuestionsResponse(BaseModel):
|
||||
class SuggestedQuestionsResponse(ResponseModel):
|
||||
data: list[str] = Field(description="Suggested question")
|
||||
|
||||
|
||||
class MessageDetailResponse(ResponseModel):
|
||||
id: str
|
||||
conversation_id: str
|
||||
inputs: dict[str, JSONValue]
|
||||
query: str
|
||||
message: JSONValue | None = None
|
||||
message_tokens: int | None = None
|
||||
answer: str = Field(validation_alias="re_sign_file_url_answer")
|
||||
answer_tokens: int | None = None
|
||||
provider_response_latency: float | None = None
|
||||
from_source: str
|
||||
from_end_user_id: str | None = None
|
||||
from_account_id: str | None = None
|
||||
feedbacks: list[Feedback] = Field(default_factory=list)
|
||||
workflow_run_id: str | None = None
|
||||
annotation: ConversationAnnotation | None = None
|
||||
annotation_hit_history: ConversationAnnotationHitHistory | None = None
|
||||
created_at: int | None = None
|
||||
agent_thoughts: list[AgentThought] = Field(default_factory=list)
|
||||
message_files: list[MessageFile] = Field(default_factory=list)
|
||||
class MessageDetailResponse(BaseMessageDetailResponse):
|
||||
extra_contents: list[ExecutionExtraContentDomainModel] = Field(default_factory=list)
|
||||
metadata: JSONValue | None = Field(default=None, validation_alias="message_metadata_dict")
|
||||
status: str
|
||||
error: str | None = None
|
||||
parent_message_id: str | None = None
|
||||
|
||||
@field_validator("inputs", mode="before")
|
||||
@classmethod
|
||||
def _normalize_inputs(cls, value: JSONValue) -> JSONValue:
|
||||
return format_files_contained(value)
|
||||
|
||||
@field_validator("created_at", mode="before")
|
||||
@classmethod
|
||||
def _normalize_created_at(cls, value: datetime | int | None) -> int | None:
|
||||
return to_timestamp(value)
|
||||
|
||||
|
||||
class MessageInfiniteScrollPaginationResponse(ResponseModel):
|
||||
@ -167,20 +127,23 @@ register_schema_models(
|
||||
ChatMessagesQuery,
|
||||
MessageFeedbackPayload,
|
||||
FeedbackExportQuery,
|
||||
)
|
||||
register_response_schema_models(
|
||||
console_ns,
|
||||
AnnotationCountResponse,
|
||||
SuggestedQuestionsResponse,
|
||||
MessageDetailResponse,
|
||||
MessageInfiniteScrollPaginationResponse,
|
||||
SimpleResultResponse,
|
||||
TextFileResponse,
|
||||
)
|
||||
register_response_schema_models(console_ns, SimpleResultResponse, TextFileResponse)
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/chat-messages")
|
||||
class ChatMessageListApi(Resource):
|
||||
@console_ns.doc("list_chat_messages")
|
||||
@console_ns.doc(description="Get chat messages for a conversation with pagination")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.doc(params=query_params_from_model(ChatMessagesQuery))
|
||||
@console_ns.doc(params={"app_id": "Application ID", **query_params_from_model(ChatMessagesQuery)})
|
||||
@console_ns.response(200, "Success", console_ns.models[MessageInfiniteScrollPaginationResponse.__name__])
|
||||
@console_ns.response(404, "Conversation not found")
|
||||
@login_required
|
||||
@ -270,7 +233,7 @@ class MessageAnnotationCountApi(Resource):
|
||||
select(func.count(MessageAnnotation.id)).where(MessageAnnotation.app_id == app_model.id)
|
||||
)
|
||||
|
||||
return {"count": count}
|
||||
return AnnotationCountResponse(count=count or 0).model_dump(mode="json")
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/chat-messages/<uuid:message_id>/suggested-questions")
|
||||
@ -319,13 +282,12 @@ class AgentMessageSuggestedQuestionApi(Resource):
|
||||
class MessageFeedbackExportApi(Resource):
|
||||
@console_ns.doc("export_feedbacks")
|
||||
@console_ns.doc(description="Export user feedback data for Google Sheets")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.doc(params=query_params_from_model(FeedbackExportQuery))
|
||||
@console_ns.response(
|
||||
200,
|
||||
"Feedback data exported successfully",
|
||||
console_ns.models[TextFileResponse.__name__],
|
||||
)
|
||||
@console_ns.doc(params={"app_id": "Application ID", **query_params_from_model(FeedbackExportQuery)})
|
||||
@console_ns.response(400, "Invalid parameters")
|
||||
@console_ns.response(500, "Internal server error")
|
||||
@setup_required
|
||||
@ -350,7 +312,6 @@ class MessageFeedbackExportApi(Resource):
|
||||
end_date=args.end_date,
|
||||
format_type=args.format,
|
||||
)
|
||||
|
||||
return export_data
|
||||
|
||||
except ValueError as e:
|
||||
@ -461,16 +422,16 @@ def _list_chat_messages(*, app_model: App, current_user: Account | None = None):
|
||||
history_messages = list(reversed(history_messages))
|
||||
attach_message_extra_contents(history_messages)
|
||||
|
||||
return MessageInfiniteScrollPaginationResponse.model_validate(
|
||||
return dump_response(
|
||||
MessageInfiniteScrollPaginationResponse,
|
||||
InfiniteScrollPagination(data=history_messages, limit=args.limit, has_more=has_more),
|
||||
from_attributes=True,
|
||||
).model_dump(mode="json")
|
||||
)
|
||||
|
||||
|
||||
def _update_message_feedback(*, current_user: Account, app_model: App):
|
||||
args = MessageFeedbackPayload.model_validate(console_ns.payload)
|
||||
|
||||
message_id = str(args.message_id)
|
||||
message_id = args.message_id
|
||||
|
||||
message = db.session.scalar(
|
||||
select(Message).where(Message.id == message_id, Message.app_id == app_model.id).limit(1)
|
||||
@ -505,7 +466,7 @@ def _update_message_feedback(*, current_user: Account, app_model: App):
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return {"result": "success"}
|
||||
return SimpleResultResponse(result="success").model_dump(mode="json")
|
||||
|
||||
|
||||
def _get_message_suggested_questions(*, current_user: Account, app_model: App, message_id: UUID):
|
||||
@ -533,7 +494,7 @@ def _get_message_suggested_questions(*, current_user: Account, app_model: App, m
|
||||
logger.exception("internal server error.")
|
||||
raise InternalServerError()
|
||||
|
||||
return {"data": questions}
|
||||
return dump_response(SuggestedQuestionsResponse, {"data": questions})
|
||||
|
||||
|
||||
def _get_message_detail(*, app_model: App, message_id: UUID):
|
||||
@ -547,4 +508,4 @@ def _get_message_detail(*, app_model: App, message_id: UUID):
|
||||
raise NotFound("Message Not Exists.")
|
||||
|
||||
attach_message_extra_contents([message])
|
||||
return MessageDetailResponse.model_validate(message, from_attributes=True).model_dump(mode="json")
|
||||
return dump_response(MessageDetailResponse, message)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from decimal import Decimal
|
||||
|
||||
import sqlalchemy as sa
|
||||
from flask import abort, jsonify, request
|
||||
from flask import abort, request
|
||||
from flask_restx import Resource
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
|
||||
@ -20,7 +20,7 @@ from core.app.entities.app_invoke_entities import InvokeFrom
|
||||
from extensions.ext_database import db
|
||||
from fields.base import ResponseModel
|
||||
from libs.datetime_utils import parse_time_range
|
||||
from libs.helper import convert_datetime_to_date
|
||||
from libs.helper import convert_datetime_to_date, dump_response
|
||||
from libs.login import login_required
|
||||
from models import AppMode
|
||||
from models.account import Account
|
||||
@ -44,8 +44,15 @@ class DailyMessageStatisticItem(ResponseModel):
|
||||
message_count: int
|
||||
|
||||
|
||||
class DailyMessageStatisticResponse(ResponseModel):
|
||||
data: list[DailyMessageStatisticItem]
|
||||
register_schema_models(console_ns, StatisticTimeRangeQuery)
|
||||
|
||||
|
||||
class StatisticDataResponse[T](ResponseModel):
|
||||
data: list[T]
|
||||
|
||||
|
||||
class DailyMessageStatisticResponse(StatisticDataResponse[DailyMessageStatisticItem]):
|
||||
pass
|
||||
|
||||
|
||||
class DailyConversationStatisticItem(ResponseModel):
|
||||
@ -53,8 +60,8 @@ class DailyConversationStatisticItem(ResponseModel):
|
||||
conversation_count: int
|
||||
|
||||
|
||||
class DailyConversationStatisticResponse(ResponseModel):
|
||||
data: list[DailyConversationStatisticItem]
|
||||
class DailyConversationStatisticResponse(StatisticDataResponse[DailyConversationStatisticItem]):
|
||||
pass
|
||||
|
||||
|
||||
class DailyTerminalStatisticItem(ResponseModel):
|
||||
@ -62,19 +69,19 @@ class DailyTerminalStatisticItem(ResponseModel):
|
||||
terminal_count: int
|
||||
|
||||
|
||||
class DailyTerminalStatisticResponse(ResponseModel):
|
||||
data: list[DailyTerminalStatisticItem]
|
||||
class DailyTerminalStatisticResponse(StatisticDataResponse[DailyTerminalStatisticItem]):
|
||||
pass
|
||||
|
||||
|
||||
class DailyTokenCostStatisticItem(ResponseModel):
|
||||
date: str
|
||||
token_count: int
|
||||
total_price: str | float
|
||||
currency: str
|
||||
token_count: int | None = None
|
||||
total_price: Decimal | None = None
|
||||
currency: str | None = None
|
||||
|
||||
|
||||
class DailyTokenCostStatisticResponse(ResponseModel):
|
||||
data: list[DailyTokenCostStatisticItem]
|
||||
class DailyTokenCostStatisticResponse(StatisticDataResponse[DailyTokenCostStatisticItem]):
|
||||
pass
|
||||
|
||||
|
||||
class AverageSessionInteractionStatisticItem(ResponseModel):
|
||||
@ -82,8 +89,8 @@ class AverageSessionInteractionStatisticItem(ResponseModel):
|
||||
interactions: float
|
||||
|
||||
|
||||
class AverageSessionInteractionStatisticResponse(ResponseModel):
|
||||
data: list[AverageSessionInteractionStatisticItem]
|
||||
class AverageSessionInteractionStatisticResponse(StatisticDataResponse[AverageSessionInteractionStatisticItem]):
|
||||
pass
|
||||
|
||||
|
||||
class UserSatisfactionRateStatisticItem(ResponseModel):
|
||||
@ -91,8 +98,8 @@ class UserSatisfactionRateStatisticItem(ResponseModel):
|
||||
rate: float
|
||||
|
||||
|
||||
class UserSatisfactionRateStatisticResponse(ResponseModel):
|
||||
data: list[UserSatisfactionRateStatisticItem]
|
||||
class UserSatisfactionRateStatisticResponse(StatisticDataResponse[UserSatisfactionRateStatisticItem]):
|
||||
pass
|
||||
|
||||
|
||||
class AverageResponseTimeStatisticItem(ResponseModel):
|
||||
@ -100,8 +107,8 @@ class AverageResponseTimeStatisticItem(ResponseModel):
|
||||
latency: float
|
||||
|
||||
|
||||
class AverageResponseTimeStatisticResponse(ResponseModel):
|
||||
data: list[AverageResponseTimeStatisticItem]
|
||||
class AverageResponseTimeStatisticResponse(StatisticDataResponse[AverageResponseTimeStatisticItem]):
|
||||
pass
|
||||
|
||||
|
||||
class TokensPerSecondStatisticItem(ResponseModel):
|
||||
@ -109,20 +116,27 @@ class TokensPerSecondStatisticItem(ResponseModel):
|
||||
tps: float
|
||||
|
||||
|
||||
class TokensPerSecondStatisticResponse(ResponseModel):
|
||||
data: list[TokensPerSecondStatisticItem]
|
||||
class TokensPerSecondStatisticResponse(StatisticDataResponse[TokensPerSecondStatisticItem]):
|
||||
pass
|
||||
|
||||
|
||||
register_schema_models(console_ns, StatisticTimeRangeQuery)
|
||||
register_response_schema_models(
|
||||
console_ns,
|
||||
DailyMessageStatisticItem,
|
||||
DailyMessageStatisticResponse,
|
||||
DailyConversationStatisticItem,
|
||||
DailyConversationStatisticResponse,
|
||||
DailyTerminalStatisticItem,
|
||||
DailyTerminalStatisticResponse,
|
||||
DailyTokenCostStatisticItem,
|
||||
DailyTokenCostStatisticResponse,
|
||||
AverageSessionInteractionStatisticItem,
|
||||
AverageSessionInteractionStatisticResponse,
|
||||
UserSatisfactionRateStatisticItem,
|
||||
UserSatisfactionRateStatisticResponse,
|
||||
AverageResponseTimeStatisticItem,
|
||||
AverageResponseTimeStatisticResponse,
|
||||
TokensPerSecondStatisticItem,
|
||||
TokensPerSecondStatisticResponse,
|
||||
)
|
||||
|
||||
@ -131,8 +145,7 @@ register_response_schema_models(
|
||||
class DailyMessageStatistic(Resource):
|
||||
@console_ns.doc("get_daily_message_statistics")
|
||||
@console_ns.doc(description="Get daily message statistics for an application")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery))
|
||||
@console_ns.doc(params={"app_id": "Application ID", **query_params_from_model(StatisticTimeRangeQuery)})
|
||||
@console_ns.response(
|
||||
200,
|
||||
"Daily message statistics retrieved successfully",
|
||||
@ -185,15 +198,14 @@ WHERE
|
||||
for i in rs:
|
||||
response_data.append({"date": str(i.date), "message_count": i.message_count})
|
||||
|
||||
return jsonify({"data": response_data})
|
||||
return dump_response(DailyMessageStatisticResponse, {"data": response_data})
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/statistics/daily-conversations")
|
||||
class DailyConversationStatistic(Resource):
|
||||
@console_ns.doc("get_daily_conversation_statistics")
|
||||
@console_ns.doc(description="Get daily conversation statistics for an application")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery))
|
||||
@console_ns.doc(params={"app_id": "Application ID", **query_params_from_model(StatisticTimeRangeQuery)})
|
||||
@console_ns.response(
|
||||
200,
|
||||
"Daily conversation statistics retrieved successfully",
|
||||
@ -245,15 +257,14 @@ WHERE
|
||||
for i in rs:
|
||||
response_data.append({"date": str(i.date), "conversation_count": i.conversation_count})
|
||||
|
||||
return jsonify({"data": response_data})
|
||||
return dump_response(DailyConversationStatisticResponse, {"data": response_data})
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/statistics/daily-end-users")
|
||||
class DailyTerminalsStatistic(Resource):
|
||||
@console_ns.doc("get_daily_terminals_statistics")
|
||||
@console_ns.doc(description="Get daily terminal/end-user statistics for an application")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery))
|
||||
@console_ns.doc(params={"app_id": "Application ID", **query_params_from_model(StatisticTimeRangeQuery)})
|
||||
@console_ns.response(
|
||||
200,
|
||||
"Daily terminal statistics retrieved successfully",
|
||||
@ -306,15 +317,14 @@ WHERE
|
||||
for i in rs:
|
||||
response_data.append({"date": str(i.date), "terminal_count": i.terminal_count})
|
||||
|
||||
return jsonify({"data": response_data})
|
||||
return dump_response(DailyTerminalStatisticResponse, {"data": response_data})
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/statistics/token-costs")
|
||||
class DailyTokenCostStatistic(Resource):
|
||||
@console_ns.doc("get_daily_token_cost_statistics")
|
||||
@console_ns.doc(description="Get daily token cost statistics for an application")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery))
|
||||
@console_ns.doc(params={"app_id": "Application ID", **query_params_from_model(StatisticTimeRangeQuery)})
|
||||
@console_ns.response(
|
||||
200,
|
||||
"Daily token cost statistics retrieved successfully",
|
||||
@ -370,15 +380,14 @@ WHERE
|
||||
{"date": str(i.date), "token_count": i.token_count, "total_price": i.total_price, "currency": "USD"}
|
||||
)
|
||||
|
||||
return jsonify({"data": response_data})
|
||||
return dump_response(DailyTokenCostStatisticResponse, {"data": response_data})
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/statistics/average-session-interactions")
|
||||
class AverageSessionInteractionStatistic(Resource):
|
||||
@console_ns.doc("get_average_session_interaction_statistics")
|
||||
@console_ns.doc(description="Get average session interaction statistics for an application")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery))
|
||||
@console_ns.doc(params={"app_id": "Application ID", **query_params_from_model(StatisticTimeRangeQuery)})
|
||||
@console_ns.response(
|
||||
200,
|
||||
"Average session interaction statistics retrieved successfully",
|
||||
@ -450,15 +459,14 @@ ORDER BY
|
||||
{"date": str(i.date), "interactions": float(i.interactions.quantize(Decimal("0.01")))}
|
||||
)
|
||||
|
||||
return jsonify({"data": response_data})
|
||||
return dump_response(AverageSessionInteractionStatisticResponse, {"data": response_data})
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/statistics/user-satisfaction-rate")
|
||||
class UserSatisfactionRateStatistic(Resource):
|
||||
@console_ns.doc("get_user_satisfaction_rate_statistics")
|
||||
@console_ns.doc(description="Get user satisfaction rate statistics for an application")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery))
|
||||
@console_ns.doc(params={"app_id": "Application ID", **query_params_from_model(StatisticTimeRangeQuery)})
|
||||
@console_ns.response(
|
||||
200,
|
||||
"User satisfaction rate statistics retrieved successfully",
|
||||
@ -520,15 +528,14 @@ WHERE
|
||||
}
|
||||
)
|
||||
|
||||
return jsonify({"data": response_data})
|
||||
return dump_response(UserSatisfactionRateStatisticResponse, {"data": response_data})
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/statistics/average-response-time")
|
||||
class AverageResponseTimeStatistic(Resource):
|
||||
@console_ns.doc("get_average_response_time_statistics")
|
||||
@console_ns.doc(description="Get average response time statistics for an application")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery))
|
||||
@console_ns.doc(params={"app_id": "Application ID", **query_params_from_model(StatisticTimeRangeQuery)})
|
||||
@console_ns.response(
|
||||
200,
|
||||
"Average response time statistics retrieved successfully",
|
||||
@ -581,15 +588,14 @@ WHERE
|
||||
for i in rs:
|
||||
response_data.append({"date": str(i.date), "latency": round(i.latency * 1000, 4)})
|
||||
|
||||
return jsonify({"data": response_data})
|
||||
return dump_response(AverageResponseTimeStatisticResponse, {"data": response_data})
|
||||
|
||||
|
||||
@console_ns.route("/apps/<uuid:app_id>/statistics/tokens-per-second")
|
||||
class TokensPerSecondStatistic(Resource):
|
||||
@console_ns.doc("get_tokens_per_second_statistics")
|
||||
@console_ns.doc(description="Get tokens per second statistics for an application")
|
||||
@console_ns.doc(params={"app_id": "Application ID"})
|
||||
@console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery))
|
||||
@console_ns.doc(params={"app_id": "Application ID", **query_params_from_model(StatisticTimeRangeQuery)})
|
||||
@console_ns.response(
|
||||
200,
|
||||
"Tokens per second statistics retrieved successfully",
|
||||
@ -645,4 +651,4 @@ WHERE
|
||||
for i in rs:
|
||||
response_data.append({"date": str(i.date), "tps": round(i.tokens_per_second, 4)})
|
||||
|
||||
return jsonify({"data": response_data})
|
||||
return dump_response(TokensPerSecondStatisticResponse, {"data": response_data})
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import Field, field_validator
|
||||
|
||||
@ -29,6 +30,15 @@ class AnnotationList(ResponseModel):
|
||||
page: int
|
||||
|
||||
|
||||
class AnnotationJobStatusResponse(ResponseModel):
|
||||
job_id: str
|
||||
job_status: Literal["waiting", "processing", "completed", "error"] | str
|
||||
|
||||
|
||||
class AnnotationJobStatusDetailResponse(AnnotationJobStatusResponse):
|
||||
error_msg: str = ""
|
||||
|
||||
|
||||
class AnnotationExportList(ResponseModel):
|
||||
data: list[Annotation]
|
||||
|
||||
|
||||
@ -3,25 +3,14 @@ from __future__ import annotations
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from flask_restx import fields
|
||||
from pydantic import field_validator
|
||||
|
||||
from fields.base import ResponseModel
|
||||
from graphon.variables.types import SegmentType
|
||||
from libs.helper import TimestampField, to_timestamp
|
||||
from libs.helper import to_timestamp
|
||||
|
||||
from ._value_type_serializer import serialize_value_type
|
||||
|
||||
conversation_variable_fields = {
|
||||
"id": fields.String,
|
||||
"name": fields.String,
|
||||
"value_type": fields.String(attribute=serialize_value_type),
|
||||
"value": fields.String,
|
||||
"description": fields.String,
|
||||
"created_at": TimestampField,
|
||||
"updated_at": TimestampField,
|
||||
}
|
||||
|
||||
|
||||
class ConversationVariableResponse(ResponseModel):
|
||||
id: str
|
||||
|
||||
@ -1782,7 +1782,7 @@ Get status of annotation reply action job
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Job status retrieved successfully | **application/json**: [AnnotationJobStatusResponse](#annotationjobstatusresponse)<br> |
|
||||
| 200 | Job status retrieved successfully | **application/json**: [AnnotationJobStatusDetailResponse](#annotationjobstatusdetailresponse)<br> |
|
||||
| 403 | Insufficient permissions | |
|
||||
|
||||
### [GET] /apps/{app_id}/annotation-setting
|
||||
@ -1891,7 +1891,7 @@ Batch import annotations from CSV file with rate limiting and security checks
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Batch import started successfully | **application/json**: [AnnotationJobStatusResponse](#annotationjobstatusresponse)<br> |
|
||||
| 200 | Batch import started successfully | **application/json**: [AnnotationBatchImportResponse](#annotationbatchimportresponse)<br> |
|
||||
| 400 | No file uploaded or too many files | |
|
||||
| 403 | Insufficient permissions | |
|
||||
| 413 | File too large | |
|
||||
@ -1911,7 +1911,7 @@ Get status of batch import job
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Job status retrieved successfully | **application/json**: [AnnotationJobStatusResponse](#annotationjobstatusresponse)<br> |
|
||||
| 200 | Job status retrieved successfully | **application/json**: [AnnotationJobStatusDetailResponse](#annotationjobstatusdetailresponse)<br> |
|
||||
| 403 | Insufficient permissions | |
|
||||
|
||||
### [GET] /apps/{app_id}/annotations/count
|
||||
@ -2227,11 +2227,11 @@ Generate completion message for debugging
|
||||
|
||||
#### Responses
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Completion generated successfully | **application/json**: [GeneratedAppResponse](#generatedappresponse)<br> |
|
||||
| 400 | Invalid request parameters | |
|
||||
| 404 | App not found | |
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Completion generated successfully |
|
||||
| 400 | Invalid request parameters |
|
||||
| 404 | App not found |
|
||||
|
||||
### [POST] /apps/{app_id}/completion-messages/{task_id}/stop
|
||||
Stop a running completion message generation
|
||||
@ -2789,10 +2789,10 @@ Convert text to speech for chat messages
|
||||
|
||||
#### Responses
|
||||
|
||||
| Code | Description | Schema |
|
||||
| ---- | ----------- | ------ |
|
||||
| 200 | Text to speech conversion successful | **application/json**: [AudioBinaryResponse](#audiobinaryresponse)<br> |
|
||||
| 400 | Bad request - Invalid parameters | |
|
||||
| Code | Description |
|
||||
| ---- | ----------- |
|
||||
| 200 | Text to speech conversion successful |
|
||||
| 400 | Bad request - Invalid parameters |
|
||||
|
||||
### [GET] /apps/{app_id}/text-to-audio/voices
|
||||
Get available TTS voices for a specific language
|
||||
@ -13429,7 +13429,6 @@ Soft lifecycle state for Agent records.
|
||||
| created_at | integer | | No |
|
||||
| files | [ string ] | | Yes |
|
||||
| id | string | | Yes |
|
||||
| message_chain_id | string | | No |
|
||||
| message_id | string | | Yes |
|
||||
| observation | string | | No |
|
||||
| position | integer | | Yes |
|
||||
@ -13501,19 +13500,21 @@ Soft lifecycle state for Agent records.
|
||||
| id | string | | Yes |
|
||||
| question | string | | No |
|
||||
|
||||
#### AnnotationBatchImportResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| error_msg | string | | No |
|
||||
| job_id | string | | No |
|
||||
| job_status | string | | No |
|
||||
| record_count | integer | | No |
|
||||
|
||||
#### AnnotationCountResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| count | integer | Number of annotations | Yes |
|
||||
|
||||
#### AnnotationEmbeddingModelResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| embedding_model_name | string | | No |
|
||||
| embedding_provider_name | string | | No |
|
||||
|
||||
#### AnnotationExportList
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
@ -13555,14 +13556,20 @@ Soft lifecycle state for Agent records.
|
||||
| limit | integer, <br>**Default:** 20 | Page size | No |
|
||||
| page | integer, <br>**Default:** 1 | Page number | No |
|
||||
|
||||
#### AnnotationJobStatusResponse
|
||||
#### AnnotationJobStatusDetailResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| error_msg | string | | No |
|
||||
| job_id | string | | No |
|
||||
| job_status | string | | No |
|
||||
| record_count | integer | | No |
|
||||
| job_id | string | | Yes |
|
||||
| job_status | string<br>string | | Yes |
|
||||
|
||||
#### AnnotationJobStatusResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| job_id | string | | Yes |
|
||||
| job_status | string<br>string | | Yes |
|
||||
|
||||
#### AnnotationList
|
||||
|
||||
@ -13596,11 +13603,18 @@ Soft lifecycle state for Agent records.
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| action | string, <br>**Available values:** "disable", "enable" | *Enum:* `"disable"`, `"enable"` | Yes |
|
||||
|
||||
#### AnnotationSettingEmbeddingModelResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| embedding_model_name | string | | No |
|
||||
| embedding_provider_name | string | | No |
|
||||
|
||||
#### AnnotationSettingResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| embedding_model | [AnnotationEmbeddingModelResponse](#annotationembeddingmodelresponse) | | No |
|
||||
| embedding_model | [AnnotationSettingEmbeddingModelResponse](#annotationsettingembeddingmodelresponse) | | No |
|
||||
| enabled | boolean | | Yes |
|
||||
| id | string | | No |
|
||||
| score_threshold | number | | No |
|
||||
@ -14512,13 +14526,13 @@ Enum class for configurate method of provider model.
|
||||
| admin_feedback_stats | [FeedbackStat](#feedbackstat) | | No |
|
||||
| annotation | [ConversationAnnotation](#conversationannotation) | | No |
|
||||
| created_at | integer | | No |
|
||||
| first_message | [SimpleMessageDetail](#simplemessagedetail) | | No |
|
||||
| from_account_id | string | | No |
|
||||
| from_account_name | string | | No |
|
||||
| from_end_user_id | string | | No |
|
||||
| from_end_user_session_id | string | | No |
|
||||
| from_source | string | | Yes |
|
||||
| id | string | | Yes |
|
||||
| message | [SimpleMessageDetail](#simplemessagedetail) | | No |
|
||||
| model_config | [SimpleModelConfig](#simplemodelconfig) | | No |
|
||||
| read_at | integer | | No |
|
||||
| status | string | | Yes |
|
||||
@ -14540,8 +14554,8 @@ Enum class for configurate method of provider model.
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| annotation_create_account | [SimpleAccount](#simpleaccount) | | No |
|
||||
| annotation_id | string | | Yes |
|
||||
| created_at | integer | | No |
|
||||
| id | string | | Yes |
|
||||
|
||||
#### ConversationDetail
|
||||
|
||||
@ -14582,11 +14596,11 @@ Enum class for configurate method of provider model.
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| created_at | integer | | No |
|
||||
| first_message | [MessageDetail](#messagedetail) | | No |
|
||||
| from_account_id | string | | No |
|
||||
| from_end_user_id | string | | No |
|
||||
| from_source | string | | Yes |
|
||||
| id | string | | Yes |
|
||||
| message | [MessageDetail](#messagedetail) | | No |
|
||||
| model_config | [ModelConfig](#modelconfig) | | No |
|
||||
| status | string | | Yes |
|
||||
|
||||
@ -14594,10 +14608,10 @@ Enum class for configurate method of provider model.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| has_next | boolean | | Yes |
|
||||
| items | [ [Conversation](#conversation) ] | | Yes |
|
||||
| data | [ [Conversation](#conversation) ] | | Yes |
|
||||
| has_more | boolean | | Yes |
|
||||
| limit | integer | | Yes |
|
||||
| page | integer | | Yes |
|
||||
| per_page | integer | | Yes |
|
||||
| total | integer | | Yes |
|
||||
|
||||
#### ConversationRenamePayload
|
||||
@ -14650,7 +14664,7 @@ Enum class for configurate method of provider model.
|
||||
| read_at | integer | | No |
|
||||
| status | string | | Yes |
|
||||
| status_count | [StatusCount](#statuscount) | | No |
|
||||
| summary_or_query | string | | Yes |
|
||||
| summary | string | | Yes |
|
||||
| updated_at | integer | | No |
|
||||
| user_feedback_stats | [FeedbackStat](#feedbackstat) | | No |
|
||||
|
||||
@ -14658,10 +14672,10 @@ Enum class for configurate method of provider model.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| has_next | boolean | | Yes |
|
||||
| items | [ [ConversationWithSummary](#conversationwithsummary) ] | | Yes |
|
||||
| data | [ [ConversationWithSummary](#conversationwithsummary) ] | | Yes |
|
||||
| has_more | boolean | | Yes |
|
||||
| limit | integer | | Yes |
|
||||
| page | integer | | Yes |
|
||||
| per_page | integer | | Yes |
|
||||
| total | integer | | Yes |
|
||||
|
||||
#### ConvertToWorkflowPayload
|
||||
@ -14834,10 +14848,10 @@ Model class for provider custom model configuration.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| currency | string | | Yes |
|
||||
| currency | string | | No |
|
||||
| date | string | | Yes |
|
||||
| token_count | integer | | Yes |
|
||||
| total_price | string<br>number | | Yes |
|
||||
| token_count | integer | | No |
|
||||
| total_price | string | | No |
|
||||
|
||||
#### DailyTokenCostStatisticResponse
|
||||
|
||||
@ -17051,6 +17065,7 @@ Enum class for large language model mode.
|
||||
| agent_thoughts | [ [AgentThought](#agentthought) ] | | Yes |
|
||||
| annotation | [ConversationAnnotation](#conversationannotation) | | No |
|
||||
| annotation_hit_history | [ConversationAnnotationHitHistory](#conversationannotationhithistory) | | No |
|
||||
| answer | string | | Yes |
|
||||
| answer_tokens | integer | | Yes |
|
||||
| conversation_id | string | | Yes |
|
||||
| created_at | integer | | No |
|
||||
@ -17063,12 +17078,11 @@ Enum class for large language model mode.
|
||||
| inputs | object | | Yes |
|
||||
| message | [JSONValue](#jsonvalue) | | Yes |
|
||||
| message_files | [ [MessageFile](#messagefile) ] | | Yes |
|
||||
| message_metadata_dict | [JSONValue](#jsonvalue) | | Yes |
|
||||
| message_tokens | integer | | Yes |
|
||||
| metadata | [JSONValue](#jsonvalue) | | Yes |
|
||||
| parent_message_id | string | | No |
|
||||
| provider_response_latency | number | | Yes |
|
||||
| query | string | | Yes |
|
||||
| re_sign_file_url_answer | string | | Yes |
|
||||
| status | string | | Yes |
|
||||
| workflow_run_id | string | | No |
|
||||
|
||||
@ -17076,28 +17090,28 @@ Enum class for large language model mode.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| agent_thoughts | [ [AgentThought](#agentthought) ] | | No |
|
||||
| agent_thoughts | [ [AgentThought](#agentthought) ] | | Yes |
|
||||
| annotation | [ConversationAnnotation](#conversationannotation) | | No |
|
||||
| annotation_hit_history | [ConversationAnnotationHitHistory](#conversationannotationhithistory) | | No |
|
||||
| answer_tokens | integer | | No |
|
||||
| answer | string | | Yes |
|
||||
| answer_tokens | integer | | Yes |
|
||||
| conversation_id | string | | Yes |
|
||||
| created_at | integer | | No |
|
||||
| error | string | | No |
|
||||
| extra_contents | [ [HumanInputContent](#humaninputcontent) ] | | No |
|
||||
| feedbacks | [ [Feedback](#feedback) ] | | No |
|
||||
| feedbacks | [ [Feedback](#feedback) ] | | Yes |
|
||||
| from_account_id | string | | No |
|
||||
| from_end_user_id | string | | No |
|
||||
| from_source | string | | Yes |
|
||||
| id | string | | Yes |
|
||||
| inputs | object | | Yes |
|
||||
| message | [JSONValue](#jsonvalue) | | No |
|
||||
| message_files | [ [MessageFile](#messagefile) ] | | No |
|
||||
| message_metadata_dict | [JSONValue](#jsonvalue) | | No |
|
||||
| message_tokens | integer | | No |
|
||||
| message | [JSONValue](#jsonvalue) | | Yes |
|
||||
| message_files | [ [MessageFile](#messagefile) ] | | Yes |
|
||||
| message_tokens | integer | | Yes |
|
||||
| metadata | [JSONValue](#jsonvalue) | | Yes |
|
||||
| parent_message_id | string | | No |
|
||||
| provider_response_latency | number | | No |
|
||||
| provider_response_latency | number | | Yes |
|
||||
| query | string | | Yes |
|
||||
| re_sign_file_url_answer | string | | Yes |
|
||||
| status | string | | Yes |
|
||||
| workflow_run_id | string | | No |
|
||||
|
||||
@ -19203,7 +19217,7 @@ Model class for provider quota configuration.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| model_dict | [JSONValue](#jsonvalue) | | No |
|
||||
| model | [JSONValue](#jsonvalue) | | No |
|
||||
| pre_prompt | string | | No |
|
||||
|
||||
#### SimpleProviderEntityResponse
|
||||
@ -19773,9 +19787,11 @@ Tag type
|
||||
|
||||
#### TextToSpeechVoiceListResponse
|
||||
|
||||
Available voices
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| TextToSpeechVoiceListResponse | array | | |
|
||||
| TextToSpeechVoiceListResponse | array | Available voices | |
|
||||
|
||||
#### TextToSpeechVoiceQuery
|
||||
|
||||
@ -19783,6 +19799,13 @@ Tag type
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| language | string | Language code | Yes |
|
||||
|
||||
#### TextToSpeechVoiceResponse
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| name | string | Voice display name | Yes |
|
||||
| value | string | Voice identifier | Yes |
|
||||
|
||||
#### TokensPerSecondStatisticItem
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|
||||
@ -120,7 +120,8 @@ def test_console_text_api_error_mapping(app: Flask, monkeypatch: pytest.MonkeyPa
|
||||
|
||||
|
||||
def test_console_text_modes_success(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setattr(AudioService, "transcript_tts_voices", lambda **_kwargs: ["voice-1"])
|
||||
expected_voices = [{"name": "Voice 1", "value": "voice-1"}]
|
||||
monkeypatch.setattr(AudioService, "transcript_tts_voices", lambda **_kwargs: expected_voices)
|
||||
|
||||
api = TextModesApi()
|
||||
handler = unwrap(api.get)
|
||||
@ -129,7 +130,7 @@ def test_console_text_modes_success(app: Flask, monkeypatch: pytest.MonkeyPatch)
|
||||
with app.test_request_context("/console/api/apps/app/text-to-audio/voices?language=en", method="GET"):
|
||||
response = handler(api, app_model=app_model)
|
||||
|
||||
assert response == ["voice-1"]
|
||||
assert response == expected_voices
|
||||
|
||||
|
||||
def test_console_text_modes_language_error(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
@ -214,7 +215,8 @@ def test_text_to_audio_voices_success(app: Flask, monkeypatch: pytest.MonkeyPatc
|
||||
api = TextModesApi()
|
||||
method = unwrap(api.get)
|
||||
|
||||
monkeypatch.setattr(AudioService, "transcript_tts_voices", lambda **_kwargs: ["voice-1"])
|
||||
expected_voices = [{"name": "Voice 1", "value": "voice-1"}]
|
||||
monkeypatch.setattr(AudioService, "transcript_tts_voices", lambda **_kwargs: expected_voices)
|
||||
|
||||
app_model = SimpleNamespace(tenant_id="tenant-1")
|
||||
|
||||
@ -225,7 +227,7 @@ def test_text_to_audio_voices_success(app: Flask, monkeypatch: pytest.MonkeyPatc
|
||||
):
|
||||
response = method(api, app_model=app_model)
|
||||
|
||||
assert response == ["voice-1"]
|
||||
assert response == expected_voices
|
||||
|
||||
|
||||
def test_audio_to_text_with_invalid_file(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
@ -272,7 +274,7 @@ def test_text_to_audio_voices_with_language_filter(app: Flask, monkeypatch: pyte
|
||||
monkeypatch.setattr(
|
||||
AudioService,
|
||||
"transcript_tts_voices",
|
||||
lambda **_kwargs: [{"id": "voice-1", "name": "Voice 1"}],
|
||||
lambda **_kwargs: [{"name": "Voice 1", "value": "voice-1"}],
|
||||
)
|
||||
|
||||
app_model = SimpleNamespace(tenant_id="tenant-1")
|
||||
|
||||
@ -1,149 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
from inspect import unwrap
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
from flask import Flask
|
||||
|
||||
from controllers.console.app import audio as audio_module
|
||||
from controllers.console.app.error import AudioTooLargeError
|
||||
from services.errors.audio import AudioTooLargeServiceError
|
||||
|
||||
|
||||
def test_audio_to_text_success(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
api = audio_module.ChatMessageAudioApi()
|
||||
method = unwrap(api.post)
|
||||
|
||||
response_payload = {"text": "hello"}
|
||||
monkeypatch.setattr(audio_module.AudioService, "transcript_asr", lambda **_kwargs: response_payload)
|
||||
|
||||
app_model = SimpleNamespace(id="app-1")
|
||||
|
||||
data = {"file": (io.BytesIO(b"x"), "sample.wav")}
|
||||
with app.test_request_context(
|
||||
"/console/api/apps/app-1/audio-to-text",
|
||||
method="POST",
|
||||
data=data,
|
||||
content_type="multipart/form-data",
|
||||
):
|
||||
response = method(api, app_model=app_model)
|
||||
|
||||
assert response == response_payload
|
||||
|
||||
|
||||
def test_audio_to_text_maps_audio_too_large(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
api = audio_module.ChatMessageAudioApi()
|
||||
method = unwrap(api.post)
|
||||
|
||||
monkeypatch.setattr(
|
||||
audio_module.AudioService,
|
||||
"transcript_asr",
|
||||
lambda **_kwargs: (_ for _ in ()).throw(AudioTooLargeServiceError("too large")),
|
||||
)
|
||||
|
||||
app_model = SimpleNamespace(id="app-1")
|
||||
|
||||
data = {"file": (io.BytesIO(b"x"), "sample.wav")}
|
||||
with app.test_request_context(
|
||||
"/console/api/apps/app-1/audio-to-text",
|
||||
method="POST",
|
||||
data=data,
|
||||
content_type="multipart/form-data",
|
||||
):
|
||||
with pytest.raises(AudioTooLargeError):
|
||||
method(api, app_model=app_model)
|
||||
|
||||
|
||||
def test_text_to_audio_success(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
api = audio_module.ChatMessageTextApi()
|
||||
method = unwrap(api.post)
|
||||
|
||||
monkeypatch.setattr(audio_module.AudioService, "transcript_tts", lambda **_kwargs: {"audio": "ok"})
|
||||
|
||||
app_model = SimpleNamespace(id="app-1")
|
||||
|
||||
with app.test_request_context(
|
||||
"/console/api/apps/app-1/text-to-audio",
|
||||
method="POST",
|
||||
json={"text": "hello"},
|
||||
):
|
||||
response = method(api, app_model=app_model)
|
||||
|
||||
assert response == {"audio": "ok"}
|
||||
|
||||
|
||||
def test_text_to_audio_voices_success(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
api = audio_module.TextModesApi()
|
||||
method = unwrap(api.get)
|
||||
|
||||
monkeypatch.setattr(audio_module.AudioService, "transcript_tts_voices", lambda **_kwargs: ["voice-1"])
|
||||
|
||||
app_model = SimpleNamespace(tenant_id="tenant-1")
|
||||
|
||||
with app.test_request_context(
|
||||
"/console/api/apps/app-1/text-to-audio/voices",
|
||||
method="GET",
|
||||
query_string={"language": "en-US"},
|
||||
):
|
||||
response = method(api, app_model=app_model)
|
||||
|
||||
assert response == ["voice-1"]
|
||||
|
||||
|
||||
def test_audio_to_text_with_invalid_file(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
api = audio_module.ChatMessageAudioApi()
|
||||
method = unwrap(api.post)
|
||||
|
||||
monkeypatch.setattr(audio_module.AudioService, "transcript_asr", lambda **_kwargs: {"text": "test"})
|
||||
|
||||
app_model = SimpleNamespace(id="app-1")
|
||||
|
||||
data = {"file": (io.BytesIO(b"invalid"), "sample.xyz")}
|
||||
with app.test_request_context(
|
||||
"/console/api/apps/app-1/audio-to-text",
|
||||
method="POST",
|
||||
data=data,
|
||||
content_type="multipart/form-data",
|
||||
):
|
||||
# Should not raise, AudioService is mocked
|
||||
response = method(api, app_model=app_model)
|
||||
assert response == {"text": "test"}
|
||||
|
||||
|
||||
def test_text_to_audio_with_language_param(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
api = audio_module.ChatMessageTextApi()
|
||||
method = unwrap(api.post)
|
||||
|
||||
monkeypatch.setattr(audio_module.AudioService, "transcript_tts", lambda **_kwargs: {"audio": "test"})
|
||||
|
||||
app_model = SimpleNamespace(id="app-1")
|
||||
|
||||
with app.test_request_context(
|
||||
"/console/api/apps/app-1/text-to-audio",
|
||||
method="POST",
|
||||
json={"text": "hello", "language": "en-US"},
|
||||
):
|
||||
response = method(api, app_model=app_model)
|
||||
assert response == {"audio": "test"}
|
||||
|
||||
|
||||
def test_text_to_audio_voices_with_language_filter(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
api = audio_module.TextModesApi()
|
||||
method = unwrap(api.get)
|
||||
|
||||
monkeypatch.setattr(
|
||||
audio_module.AudioService,
|
||||
"transcript_tts_voices",
|
||||
lambda **_kwargs: [{"id": "voice-1", "name": "Voice 1"}],
|
||||
)
|
||||
|
||||
app_model = SimpleNamespace(tenant_id="tenant-1")
|
||||
|
||||
with app.test_request_context(
|
||||
"/console/api/apps/app-1/text-to-audio/voices?language=en-US",
|
||||
method="GET",
|
||||
):
|
||||
response = method(api, app_model=app_model)
|
||||
assert isinstance(response, list)
|
||||
@ -125,13 +125,57 @@ def test_message_detail_response_normalizes_aliases_and_timestamp(app: Flask, mo
|
||||
"conversation_id": "550e8400-e29b-41d4-a716-446655440001",
|
||||
"inputs": {"foo": "bar"},
|
||||
"query": "hello",
|
||||
"re_sign_file_url_answer": "world",
|
||||
"message": [{"text": "hello"}],
|
||||
"message_tokens": 7,
|
||||
"answer": "world",
|
||||
"answer_tokens": 11,
|
||||
"provider_response_latency": 1.25,
|
||||
"from_source": "user",
|
||||
"from_end_user_id": None,
|
||||
"from_account_id": "550e8400-e29b-41d4-a716-446655440002",
|
||||
"feedbacks": [],
|
||||
"workflow_run_id": None,
|
||||
"annotation": None,
|
||||
"annotation_hit_history": None,
|
||||
"status": "normal",
|
||||
"created_at": created_at,
|
||||
"agent_thoughts": [],
|
||||
"message_files": [],
|
||||
"message_metadata_dict": {"token_usage": 3},
|
||||
"error": None,
|
||||
"parent_message_id": None,
|
||||
"extra_contents": [],
|
||||
}
|
||||
)
|
||||
assert response.answer == "world"
|
||||
assert response.message_tokens == 7
|
||||
assert response.answer_tokens == 11
|
||||
assert response.provider_response_latency == 1.25
|
||||
assert response.metadata == {"token_usage": 3}
|
||||
assert response.created_at == int(created_at.timestamp())
|
||||
assert response.model_dump(mode="json") == {
|
||||
"id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"conversation_id": "550e8400-e29b-41d4-a716-446655440001",
|
||||
"inputs": {"foo": "bar"},
|
||||
"query": "hello",
|
||||
"message": [{"text": "hello"}],
|
||||
"message_tokens": 7,
|
||||
"answer": "world",
|
||||
"answer_tokens": 11,
|
||||
"provider_response_latency": 1.25,
|
||||
"from_source": "user",
|
||||
"from_end_user_id": None,
|
||||
"from_account_id": "550e8400-e29b-41d4-a716-446655440002",
|
||||
"feedbacks": [],
|
||||
"workflow_run_id": None,
|
||||
"annotation": None,
|
||||
"annotation_hit_history": None,
|
||||
"created_at": int(created_at.timestamp()),
|
||||
"agent_thoughts": [],
|
||||
"message_files": [],
|
||||
"metadata": {"token_usage": 3},
|
||||
"status": "normal",
|
||||
"error": None,
|
||||
"parent_message_id": None,
|
||||
"extra_contents": [],
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
from decimal import Decimal
|
||||
from inspect import unwrap
|
||||
from types import SimpleNamespace
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from flask import Flask
|
||||
@ -39,6 +40,10 @@ def _install_common(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setattr(statistic_module, "convert_datetime_to_date", lambda field: field)
|
||||
|
||||
|
||||
def _json_payload(response: Any) -> dict[str, Any]:
|
||||
return response if isinstance(response, dict) else response.get_json()
|
||||
|
||||
|
||||
def test_daily_message_statistic_returns_rows(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
api = statistic_module.DailyMessageStatistic()
|
||||
method = unwrap(api.get)
|
||||
@ -50,7 +55,7 @@ def test_daily_message_statistic_returns_rows(app: Flask, monkeypatch: pytest.Mo
|
||||
with app.test_request_context("/console/api/apps/app-1/statistics/daily-messages", method="GET"):
|
||||
response = method(api, SimpleNamespace(timezone="UTC"), app_model=SimpleNamespace(id="app-1"))
|
||||
|
||||
assert response.get_json() == {"data": [{"date": "2024-01-01", "message_count": 3}]}
|
||||
assert _json_payload(response) == {"data": [{"date": "2024-01-01", "message_count": 3}]}
|
||||
|
||||
|
||||
def test_daily_conversation_statistic_returns_rows(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
@ -64,7 +69,7 @@ def test_daily_conversation_statistic_returns_rows(app: Flask, monkeypatch: pyte
|
||||
with app.test_request_context("/console/api/apps/app-1/statistics/daily-conversations", method="GET"):
|
||||
response = method(api, SimpleNamespace(timezone="UTC"), app_model=SimpleNamespace(id="app-1"))
|
||||
|
||||
assert response.get_json() == {"data": [{"date": "2024-01-02", "conversation_count": 5}]}
|
||||
assert _json_payload(response) == {"data": [{"date": "2024-01-02", "conversation_count": 5}]}
|
||||
|
||||
|
||||
def test_daily_token_cost_statistic_returns_rows(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
@ -78,11 +83,11 @@ def test_daily_token_cost_statistic_returns_rows(app: Flask, monkeypatch: pytest
|
||||
with app.test_request_context("/console/api/apps/app-1/statistics/token-costs", method="GET"):
|
||||
response = method(api, SimpleNamespace(timezone="UTC"), app_model=SimpleNamespace(id="app-1"))
|
||||
|
||||
data = response.get_json()
|
||||
data = _json_payload(response)
|
||||
assert len(data["data"]) == 1
|
||||
assert data["data"][0]["date"] == "2024-01-03"
|
||||
assert data["data"][0]["token_count"] == 10
|
||||
assert data["data"][0]["total_price"] == 0.25
|
||||
assert Decimal(data["data"][0]["total_price"]) == Decimal("0.25")
|
||||
|
||||
|
||||
def test_daily_terminals_statistic_returns_rows(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
@ -96,7 +101,7 @@ def test_daily_terminals_statistic_returns_rows(app: Flask, monkeypatch: pytest.
|
||||
with app.test_request_context("/console/api/apps/app-1/statistics/daily-end-users", method="GET"):
|
||||
response = method(api, SimpleNamespace(timezone="UTC"), app_model=SimpleNamespace(id="app-1"))
|
||||
|
||||
assert response.get_json() == {"data": [{"date": "2024-01-04", "terminal_count": 7}]}
|
||||
assert _json_payload(response) == {"data": [{"date": "2024-01-04", "terminal_count": 7}]}
|
||||
|
||||
|
||||
def test_average_session_interaction_statistic_requires_chat_mode(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
@ -139,7 +144,7 @@ def test_daily_message_statistic_multiple_rows(app: Flask, monkeypatch: pytest.M
|
||||
with app.test_request_context("/console/api/apps/app-1/statistics/daily-messages", method="GET"):
|
||||
response = method(api, SimpleNamespace(timezone="UTC"), app_model=SimpleNamespace(id="app-1"))
|
||||
|
||||
data = response.get_json()
|
||||
data = _json_payload(response)
|
||||
assert len(data["data"]) == 3
|
||||
|
||||
|
||||
@ -153,7 +158,7 @@ def test_daily_message_statistic_empty_result(app: Flask, monkeypatch: pytest.Mo
|
||||
with app.test_request_context("/console/api/apps/app-1/statistics/daily-messages", method="GET"):
|
||||
response = method(api, SimpleNamespace(timezone="UTC"), app_model=SimpleNamespace(id="app-1"))
|
||||
|
||||
assert response.get_json() == {"data": []}
|
||||
assert _json_payload(response) == {"data": []}
|
||||
|
||||
|
||||
def test_daily_conversation_statistic_with_time_range(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
@ -172,7 +177,7 @@ def test_daily_conversation_statistic_with_time_range(app: Flask, monkeypatch: p
|
||||
with app.test_request_context("/console/api/apps/app-1/statistics/daily-conversations", method="GET"):
|
||||
response = method(api, SimpleNamespace(timezone="UTC"), app_model=SimpleNamespace(id="app-1"))
|
||||
|
||||
assert response.get_json() == {"data": [{"date": "2024-01-02", "conversation_count": 5}]}
|
||||
assert _json_payload(response) == {"data": [{"date": "2024-01-02", "conversation_count": 5}]}
|
||||
|
||||
|
||||
def test_daily_token_cost_with_multiple_currencies(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
@ -189,5 +194,5 @@ def test_daily_token_cost_with_multiple_currencies(app: Flask, monkeypatch: pyte
|
||||
with app.test_request_context("/console/api/apps/app-1/statistics/token-costs", method="GET"):
|
||||
response = method(api, SimpleNamespace(timezone="UTC"), app_model=SimpleNamespace(id="app-1"))
|
||||
|
||||
data = response.get_json()
|
||||
data = _json_payload(response)
|
||||
assert len(data["data"]) == 2
|
||||
|
||||
@ -266,15 +266,16 @@ export type AgentLogMessageListResponse = {
|
||||
}
|
||||
|
||||
export type MessageDetailResponse = {
|
||||
agent_thoughts?: Array<AgentThought>
|
||||
agent_thoughts: Array<AgentThought>
|
||||
annotation?: ConversationAnnotation | null
|
||||
annotation_hit_history?: ConversationAnnotationHitHistory | null
|
||||
answer_tokens?: number | null
|
||||
answer: string
|
||||
answer_tokens: number
|
||||
conversation_id: string
|
||||
created_at?: number | null
|
||||
error?: string | null
|
||||
extra_contents?: Array<HumanInputContent>
|
||||
feedbacks?: Array<Feedback>
|
||||
feedbacks: Array<Feedback>
|
||||
from_account_id?: string | null
|
||||
from_end_user_id?: string | null
|
||||
from_source: string
|
||||
@ -282,14 +283,13 @@ export type MessageDetailResponse = {
|
||||
inputs: {
|
||||
[key: string]: JsonValue
|
||||
}
|
||||
message?: JsonValue | null
|
||||
message_files?: Array<MessageFile>
|
||||
message_metadata_dict?: JsonValue | null
|
||||
message_tokens?: number | null
|
||||
message: JsonValue
|
||||
message_files: Array<MessageFile>
|
||||
message_tokens: number
|
||||
metadata: JsonValue
|
||||
parent_message_id?: string | null
|
||||
provider_response_latency?: number | null
|
||||
provider_response_latency: number
|
||||
query: string
|
||||
re_sign_file_url_answer: string
|
||||
status: string
|
||||
workflow_run_id?: string | null
|
||||
}
|
||||
@ -723,7 +723,6 @@ export type AgentThought = {
|
||||
created_at?: number | null
|
||||
files: Array<string>
|
||||
id: string
|
||||
message_chain_id?: string | null
|
||||
message_id: string
|
||||
observation?: string | null
|
||||
position: number
|
||||
@ -743,8 +742,8 @@ export type ConversationAnnotation = {
|
||||
|
||||
export type ConversationAnnotationHitHistory = {
|
||||
annotation_create_account?: SimpleAccount | null
|
||||
annotation_id: string
|
||||
created_at?: number | null
|
||||
id: string
|
||||
}
|
||||
|
||||
export type HumanInputContent = {
|
||||
|
||||
@ -570,7 +570,6 @@ export const zAgentThought = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
files: z.array(z.string()),
|
||||
id: z.string(),
|
||||
message_chain_id: z.string().nullish(),
|
||||
message_id: z.string(),
|
||||
observation: z.string().nullish(),
|
||||
position: z.int(),
|
||||
@ -1056,8 +1055,8 @@ export const zConversationAnnotation = z.object({
|
||||
*/
|
||||
export const zConversationAnnotationHitHistory = z.object({
|
||||
annotation_create_account: zSimpleAccount.nullish(),
|
||||
annotation_id: z.string(),
|
||||
created_at: z.int().nullish(),
|
||||
id: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
@ -2032,28 +2031,28 @@ export const zHumanInputContent = z.object({
|
||||
* MessageDetailResponse
|
||||
*/
|
||||
export const zMessageDetailResponse = z.object({
|
||||
agent_thoughts: z.array(zAgentThought).optional(),
|
||||
agent_thoughts: z.array(zAgentThought),
|
||||
annotation: zConversationAnnotation.nullish(),
|
||||
annotation_hit_history: zConversationAnnotationHitHistory.nullish(),
|
||||
answer_tokens: z.int().nullish(),
|
||||
answer: z.string(),
|
||||
answer_tokens: z.int(),
|
||||
conversation_id: z.string(),
|
||||
created_at: z.int().nullish(),
|
||||
error: z.string().nullish(),
|
||||
extra_contents: z.array(zHumanInputContent).optional(),
|
||||
feedbacks: z.array(zFeedback).optional(),
|
||||
feedbacks: z.array(zFeedback),
|
||||
from_account_id: z.string().nullish(),
|
||||
from_end_user_id: z.string().nullish(),
|
||||
from_source: z.string(),
|
||||
id: z.string(),
|
||||
inputs: z.record(z.string(), zJsonValue),
|
||||
message: zJsonValue.nullish(),
|
||||
message_files: z.array(zMessageFile).optional(),
|
||||
message_metadata_dict: zJsonValue.nullish(),
|
||||
message_tokens: z.int().nullish(),
|
||||
message: zJsonValue,
|
||||
message_files: z.array(zMessageFile),
|
||||
message_tokens: z.int(),
|
||||
metadata: zJsonValue,
|
||||
parent_message_id: z.string().nullish(),
|
||||
provider_response_latency: z.number().nullish(),
|
||||
provider_response_latency: z.number(),
|
||||
query: z.string(),
|
||||
re_sign_file_url_answer: z.string(),
|
||||
status: z.string(),
|
||||
workflow_run_id: z.string().nullish(),
|
||||
})
|
||||
|
||||
@ -302,11 +302,8 @@ import {
|
||||
zPostAppsByAppIdAudioToTextResponse,
|
||||
zPostAppsByAppIdChatMessagesByTaskIdStopPath,
|
||||
zPostAppsByAppIdChatMessagesByTaskIdStopResponse,
|
||||
zPostAppsByAppIdCompletionMessagesBody,
|
||||
zPostAppsByAppIdCompletionMessagesByTaskIdStopPath,
|
||||
zPostAppsByAppIdCompletionMessagesByTaskIdStopResponse,
|
||||
zPostAppsByAppIdCompletionMessagesPath,
|
||||
zPostAppsByAppIdCompletionMessagesResponse,
|
||||
zPostAppsByAppIdConvertToWorkflowBody,
|
||||
zPostAppsByAppIdConvertToWorkflowPath,
|
||||
zPostAppsByAppIdConvertToWorkflowResponse,
|
||||
@ -340,9 +337,6 @@ import {
|
||||
zPostAppsByAppIdSiteResponse,
|
||||
zPostAppsByAppIdStarPath,
|
||||
zPostAppsByAppIdStarResponse,
|
||||
zPostAppsByAppIdTextToAudioBody,
|
||||
zPostAppsByAppIdTextToAudioPath,
|
||||
zPostAppsByAppIdTextToAudioResponse,
|
||||
zPostAppsByAppIdTraceBody,
|
||||
zPostAppsByAppIdTraceConfigBody,
|
||||
zPostAppsByAppIdTraceConfigPath,
|
||||
@ -1649,28 +1643,7 @@ export const byTaskId2 = {
|
||||
stop: stop2,
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate completion message for debugging
|
||||
*/
|
||||
export const post21 = oc
|
||||
.route({
|
||||
description: 'Generate completion message for debugging',
|
||||
inputStructure: 'detailed',
|
||||
method: 'POST',
|
||||
operationId: 'postAppsByAppIdCompletionMessages',
|
||||
path: '/apps/{app_id}/completion-messages',
|
||||
tags: ['console'],
|
||||
})
|
||||
.input(
|
||||
z.object({
|
||||
body: zPostAppsByAppIdCompletionMessagesBody,
|
||||
params: zPostAppsByAppIdCompletionMessagesPath,
|
||||
}),
|
||||
)
|
||||
.output(zPostAppsByAppIdCompletionMessagesResponse)
|
||||
|
||||
export const completionMessages = {
|
||||
post: post21,
|
||||
byTaskId: byTaskId2,
|
||||
}
|
||||
|
||||
@ -1705,7 +1678,7 @@ export const conversationVariables = {
|
||||
* Convert expert mode of chatbot app to workflow mode
|
||||
* Convert Completion App to Workflow App
|
||||
*/
|
||||
export const post22 = oc
|
||||
export const post21 = oc
|
||||
.route({
|
||||
description:
|
||||
'Convert application to workflow mode\nConvert expert mode of chatbot app to workflow mode\nConvert Completion App to Workflow App',
|
||||
@ -1725,7 +1698,7 @@ export const post22 = oc
|
||||
.output(zPostAppsByAppIdConvertToWorkflowResponse)
|
||||
|
||||
export const convertToWorkflow = {
|
||||
post: post22,
|
||||
post: post21,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1733,7 +1706,7 @@ export const convertToWorkflow = {
|
||||
*
|
||||
* Create a copy of an existing application
|
||||
*/
|
||||
export const post23 = oc
|
||||
export const post22 = oc
|
||||
.route({
|
||||
description: 'Create a copy of an existing application',
|
||||
inputStructure: 'detailed',
|
||||
@ -1748,7 +1721,7 @@ export const post23 = oc
|
||||
.output(zPostAppsByAppIdCopyResponse)
|
||||
|
||||
export const copy = {
|
||||
post: post23,
|
||||
post: post22,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1802,7 +1775,7 @@ export const export3 = {
|
||||
/**
|
||||
* Create or update message feedback (like/dislike)
|
||||
*/
|
||||
export const post24 = oc
|
||||
export const post23 = oc
|
||||
.route({
|
||||
description: 'Create or update message feedback (like/dislike)',
|
||||
inputStructure: 'detailed',
|
||||
@ -1815,14 +1788,14 @@ export const post24 = oc
|
||||
.output(zPostAppsByAppIdFeedbacksResponse)
|
||||
|
||||
export const feedbacks = {
|
||||
post: post24,
|
||||
post: post23,
|
||||
export: export3,
|
||||
}
|
||||
|
||||
/**
|
||||
* Update application icon
|
||||
*/
|
||||
export const post25 = oc
|
||||
export const post24 = oc
|
||||
.route({
|
||||
description: 'Update application icon',
|
||||
inputStructure: 'detailed',
|
||||
@ -1835,7 +1808,7 @@ export const post25 = oc
|
||||
.output(zPostAppsByAppIdIconResponse)
|
||||
|
||||
export const icon = {
|
||||
post: post25,
|
||||
post: post24,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1866,7 +1839,7 @@ export const messages = {
|
||||
*
|
||||
* Update application model configuration
|
||||
*/
|
||||
export const post26 = oc
|
||||
export const post25 = oc
|
||||
.route({
|
||||
description: 'Update application model configuration',
|
||||
inputStructure: 'detailed',
|
||||
@ -1882,13 +1855,13 @@ export const post26 = oc
|
||||
.output(zPostAppsByAppIdModelConfigResponse)
|
||||
|
||||
export const modelConfig = {
|
||||
post: post26,
|
||||
post: post25,
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if app name is available
|
||||
*/
|
||||
export const post27 = oc
|
||||
export const post26 = oc
|
||||
.route({
|
||||
description: 'Check if app name is available',
|
||||
inputStructure: 'detailed',
|
||||
@ -1901,13 +1874,13 @@ export const post27 = oc
|
||||
.output(zPostAppsByAppIdNameResponse)
|
||||
|
||||
export const name = {
|
||||
post: post27,
|
||||
post: post26,
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish app to Creators Platform
|
||||
*/
|
||||
export const post28 = oc
|
||||
export const post27 = oc
|
||||
.route({
|
||||
inputStructure: 'detailed',
|
||||
method: 'POST',
|
||||
@ -1920,7 +1893,7 @@ export const post28 = oc
|
||||
.output(zPostAppsByAppIdPublishToCreatorsPlatformResponse)
|
||||
|
||||
export const publishToCreatorsPlatform = {
|
||||
post: post28,
|
||||
post: post27,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1941,7 +1914,7 @@ export const get28 = oc
|
||||
/**
|
||||
* Create MCP server configuration for an application
|
||||
*/
|
||||
export const post29 = oc
|
||||
export const post28 = oc
|
||||
.route({
|
||||
description: 'Create MCP server configuration for an application',
|
||||
inputStructure: 'detailed',
|
||||
@ -1971,14 +1944,14 @@ export const put = oc
|
||||
|
||||
export const server = {
|
||||
get: get28,
|
||||
post: post29,
|
||||
post: post28,
|
||||
put,
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset access token for application site
|
||||
*/
|
||||
export const post30 = oc
|
||||
export const post29 = oc
|
||||
.route({
|
||||
description: 'Reset access token for application site',
|
||||
inputStructure: 'detailed',
|
||||
@ -1991,13 +1964,13 @@ export const post30 = oc
|
||||
.output(zPostAppsByAppIdSiteAccessTokenResetResponse)
|
||||
|
||||
export const accessTokenReset = {
|
||||
post: post30,
|
||||
post: post29,
|
||||
}
|
||||
|
||||
/**
|
||||
* Update application site configuration
|
||||
*/
|
||||
export const post31 = oc
|
||||
export const post30 = oc
|
||||
.route({
|
||||
description: 'Update application site configuration',
|
||||
inputStructure: 'detailed',
|
||||
@ -2010,14 +1983,14 @@ export const post31 = oc
|
||||
.output(zPostAppsByAppIdSiteResponse)
|
||||
|
||||
export const site = {
|
||||
post: post31,
|
||||
post: post30,
|
||||
accessTokenReset,
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable app site
|
||||
*/
|
||||
export const post32 = oc
|
||||
export const post31 = oc
|
||||
.route({
|
||||
description: 'Enable or disable app site',
|
||||
inputStructure: 'detailed',
|
||||
@ -2030,7 +2003,7 @@ export const post32 = oc
|
||||
.output(zPostAppsByAppIdSiteEnableResponse)
|
||||
|
||||
export const siteEnable = {
|
||||
post: post32,
|
||||
post: post31,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2051,7 +2024,7 @@ export const delete7 = oc
|
||||
/**
|
||||
* Star an application for the current account
|
||||
*/
|
||||
export const post33 = oc
|
||||
export const post32 = oc
|
||||
.route({
|
||||
description: 'Star an application for the current account',
|
||||
inputStructure: 'detailed',
|
||||
@ -2065,7 +2038,7 @@ export const post33 = oc
|
||||
|
||||
export const star = {
|
||||
delete: delete7,
|
||||
post: post33,
|
||||
post: post32,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2295,25 +2268,7 @@ export const voices = {
|
||||
get: get37,
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert text to speech for chat messages
|
||||
*/
|
||||
export const post34 = oc
|
||||
.route({
|
||||
description: 'Convert text to speech for chat messages',
|
||||
inputStructure: 'detailed',
|
||||
method: 'POST',
|
||||
operationId: 'postAppsByAppIdTextToAudio',
|
||||
path: '/apps/{app_id}/text-to-audio',
|
||||
tags: ['console'],
|
||||
})
|
||||
.input(
|
||||
z.object({ body: zPostAppsByAppIdTextToAudioBody, params: zPostAppsByAppIdTextToAudioPath }),
|
||||
)
|
||||
.output(zPostAppsByAppIdTextToAudioResponse)
|
||||
|
||||
export const textToAudio = {
|
||||
post: post34,
|
||||
voices,
|
||||
}
|
||||
|
||||
@ -2338,7 +2293,7 @@ export const get38 = oc
|
||||
/**
|
||||
* Update app tracing configuration
|
||||
*/
|
||||
export const post35 = oc
|
||||
export const post33 = oc
|
||||
.route({
|
||||
description: 'Update app tracing configuration',
|
||||
inputStructure: 'detailed',
|
||||
@ -2352,7 +2307,7 @@ export const post35 = oc
|
||||
|
||||
export const trace = {
|
||||
get: get38,
|
||||
post: post35,
|
||||
post: post33,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2421,7 +2376,7 @@ export const patch = oc
|
||||
*
|
||||
* Create a new tracing configuration for an application
|
||||
*/
|
||||
export const post36 = oc
|
||||
export const post34 = oc
|
||||
.route({
|
||||
description: 'Create a new tracing configuration for an application',
|
||||
inputStructure: 'detailed',
|
||||
@ -2441,13 +2396,13 @@ export const traceConfig = {
|
||||
delete: delete8,
|
||||
get: get39,
|
||||
patch,
|
||||
post: post36,
|
||||
post: post34,
|
||||
}
|
||||
|
||||
/**
|
||||
* Update app trigger (enable/disable)
|
||||
*/
|
||||
export const post37 = oc
|
||||
export const post35 = oc
|
||||
.route({
|
||||
inputStructure: 'detailed',
|
||||
method: 'POST',
|
||||
@ -2465,7 +2420,7 @@ export const post37 = oc
|
||||
.output(zPostAppsByAppIdTriggerEnableResponse)
|
||||
|
||||
export const triggerEnable = {
|
||||
post: post37,
|
||||
post: post35,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2573,7 +2528,7 @@ export const count3 = {
|
||||
*
|
||||
* Stop running workflow task
|
||||
*/
|
||||
export const post38 = oc
|
||||
export const post36 = oc
|
||||
.route({
|
||||
description: 'Stop running workflow task',
|
||||
inputStructure: 'detailed',
|
||||
@ -2587,7 +2542,7 @@ export const post38 = oc
|
||||
.output(zPostAppsByAppIdWorkflowRunsTasksByTaskIdStopResponse)
|
||||
|
||||
export const stop3 = {
|
||||
post: post38,
|
||||
post: post36,
|
||||
}
|
||||
|
||||
export const byTaskId3 = {
|
||||
@ -2690,7 +2645,7 @@ export const read = {
|
||||
/**
|
||||
* Upload one workflow Agent sandbox file as a Dify ToolFile mapping
|
||||
*/
|
||||
export const post39 = oc
|
||||
export const post37 = oc
|
||||
.route({
|
||||
description: 'Upload one workflow Agent sandbox file as a Dify ToolFile mapping',
|
||||
inputStructure: 'detailed',
|
||||
@ -2708,7 +2663,7 @@ export const post39 = oc
|
||||
.output(zPostAppsByAppIdWorkflowRunsByWorkflowRunIdAgentNodesByNodeIdSandboxFilesUploadResponse)
|
||||
|
||||
export const upload2 = {
|
||||
post: post39,
|
||||
post: post37,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2859,7 +2814,7 @@ export const byReplyId = {
|
||||
*
|
||||
* Add a reply to a workflow comment
|
||||
*/
|
||||
export const post40 = oc
|
||||
export const post38 = oc
|
||||
.route({
|
||||
description: 'Add a reply to a workflow comment',
|
||||
inputStructure: 'detailed',
|
||||
@ -2879,7 +2834,7 @@ export const post40 = oc
|
||||
.output(zPostAppsByAppIdWorkflowCommentsByCommentIdRepliesResponse)
|
||||
|
||||
export const replies = {
|
||||
post: post40,
|
||||
post: post38,
|
||||
byReplyId,
|
||||
}
|
||||
|
||||
@ -2888,7 +2843,7 @@ export const replies = {
|
||||
*
|
||||
* Resolve a workflow comment
|
||||
*/
|
||||
export const post41 = oc
|
||||
export const post39 = oc
|
||||
.route({
|
||||
description: 'Resolve a workflow comment',
|
||||
inputStructure: 'detailed',
|
||||
@ -2902,7 +2857,7 @@ export const post41 = oc
|
||||
.output(zPostAppsByAppIdWorkflowCommentsByCommentIdResolveResponse)
|
||||
|
||||
export const resolve = {
|
||||
post: post41,
|
||||
post: post39,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2996,7 +2951,7 @@ export const get52 = oc
|
||||
*
|
||||
* Create a new workflow comment
|
||||
*/
|
||||
export const post42 = oc
|
||||
export const post40 = oc
|
||||
.route({
|
||||
description: 'Create a new workflow comment',
|
||||
inputStructure: 'detailed',
|
||||
@ -3017,7 +2972,7 @@ export const post42 = oc
|
||||
|
||||
export const comments = {
|
||||
get: get52,
|
||||
post: post42,
|
||||
post: post40,
|
||||
mentionUsers,
|
||||
byCommentId,
|
||||
}
|
||||
@ -3198,7 +3153,7 @@ export const get59 = oc
|
||||
/**
|
||||
* Update conversation variables for workflow draft
|
||||
*/
|
||||
export const post43 = oc
|
||||
export const post41 = oc
|
||||
.route({
|
||||
description: 'Update conversation variables for workflow draft',
|
||||
inputStructure: 'detailed',
|
||||
@ -3217,7 +3172,7 @@ export const post43 = oc
|
||||
|
||||
export const conversationVariables2 = {
|
||||
get: get59,
|
||||
post: post43,
|
||||
post: post41,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3241,7 +3196,7 @@ export const get60 = oc
|
||||
/**
|
||||
* Update environment variables for workflow draft
|
||||
*/
|
||||
export const post44 = oc
|
||||
export const post42 = oc
|
||||
.route({
|
||||
description: 'Update environment variables for workflow draft',
|
||||
inputStructure: 'detailed',
|
||||
@ -3260,13 +3215,13 @@ export const post44 = oc
|
||||
|
||||
export const environmentVariables = {
|
||||
get: get60,
|
||||
post: post44,
|
||||
post: post42,
|
||||
}
|
||||
|
||||
/**
|
||||
* Update draft workflow features
|
||||
*/
|
||||
export const post45 = oc
|
||||
export const post43 = oc
|
||||
.route({
|
||||
description: 'Update draft workflow features',
|
||||
inputStructure: 'detailed',
|
||||
@ -3284,7 +3239,7 @@ export const post45 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftFeaturesResponse)
|
||||
|
||||
export const features = {
|
||||
post: post45,
|
||||
post: post43,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3292,7 +3247,7 @@ export const features = {
|
||||
*
|
||||
* Test human input delivery for workflow
|
||||
*/
|
||||
export const post46 = oc
|
||||
export const post44 = oc
|
||||
.route({
|
||||
description: 'Test human input delivery for workflow',
|
||||
inputStructure: 'detailed',
|
||||
@ -3311,7 +3266,7 @@ export const post46 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdDeliveryTestResponse)
|
||||
|
||||
export const deliveryTest = {
|
||||
post: post46,
|
||||
post: post44,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3319,7 +3274,7 @@ export const deliveryTest = {
|
||||
*
|
||||
* Get human input form preview for workflow
|
||||
*/
|
||||
export const post47 = oc
|
||||
export const post45 = oc
|
||||
.route({
|
||||
description: 'Get human input form preview for workflow',
|
||||
inputStructure: 'detailed',
|
||||
@ -3338,7 +3293,7 @@ export const post47 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormPreviewResponse)
|
||||
|
||||
export const preview3 = {
|
||||
post: post47,
|
||||
post: post45,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3346,7 +3301,7 @@ export const preview3 = {
|
||||
*
|
||||
* Submit human input form preview for workflow
|
||||
*/
|
||||
export const post48 = oc
|
||||
export const post46 = oc
|
||||
.route({
|
||||
description: 'Submit human input form preview for workflow',
|
||||
inputStructure: 'detailed',
|
||||
@ -3365,7 +3320,7 @@ export const post48 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftHumanInputNodesByNodeIdFormRunResponse)
|
||||
|
||||
export const run5 = {
|
||||
post: post48,
|
||||
post: post46,
|
||||
}
|
||||
|
||||
export const form2 = {
|
||||
@ -3391,7 +3346,7 @@ export const humanInput2 = {
|
||||
*
|
||||
* Run draft workflow iteration node
|
||||
*/
|
||||
export const post49 = oc
|
||||
export const post47 = oc
|
||||
.route({
|
||||
description: 'Run draft workflow iteration node',
|
||||
inputStructure: 'detailed',
|
||||
@ -3410,7 +3365,7 @@ export const post49 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftIterationNodesByNodeIdRunResponse)
|
||||
|
||||
export const run6 = {
|
||||
post: post49,
|
||||
post: post47,
|
||||
}
|
||||
|
||||
export const byNodeId6 = {
|
||||
@ -3430,7 +3385,7 @@ export const iteration2 = {
|
||||
*
|
||||
* Run draft workflow loop node
|
||||
*/
|
||||
export const post50 = oc
|
||||
export const post48 = oc
|
||||
.route({
|
||||
description: 'Run draft workflow loop node',
|
||||
inputStructure: 'detailed',
|
||||
@ -3449,7 +3404,7 @@ export const post50 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftLoopNodesByNodeIdRunResponse)
|
||||
|
||||
export const run7 = {
|
||||
post: post50,
|
||||
post: post48,
|
||||
}
|
||||
|
||||
export const byNodeId7 = {
|
||||
@ -3481,7 +3436,7 @@ export const candidates = {
|
||||
get: get61,
|
||||
}
|
||||
|
||||
export const post51 = oc
|
||||
export const post49 = oc
|
||||
.route({
|
||||
inputStructure: 'detailed',
|
||||
method: 'POST',
|
||||
@ -3498,10 +3453,10 @@ export const post51 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerCopyFromRosterResponse)
|
||||
|
||||
export const copyFromRoster = {
|
||||
post: post51,
|
||||
post: post49,
|
||||
}
|
||||
|
||||
export const post52 = oc
|
||||
export const post50 = oc
|
||||
.route({
|
||||
inputStructure: 'detailed',
|
||||
method: 'POST',
|
||||
@ -3518,10 +3473,10 @@ export const post52 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerImpactResponse)
|
||||
|
||||
export const impact = {
|
||||
post: post52,
|
||||
post: post50,
|
||||
}
|
||||
|
||||
export const post53 = oc
|
||||
export const post51 = oc
|
||||
.route({
|
||||
inputStructure: 'detailed',
|
||||
method: 'POST',
|
||||
@ -3538,10 +3493,10 @@ export const post53 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerSaveToRosterResponse)
|
||||
|
||||
export const saveToRoster = {
|
||||
post: post53,
|
||||
post: post51,
|
||||
}
|
||||
|
||||
export const post54 = oc
|
||||
export const post52 = oc
|
||||
.route({
|
||||
inputStructure: 'detailed',
|
||||
method: 'POST',
|
||||
@ -3558,7 +3513,7 @@ export const post54 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftNodesByNodeIdAgentComposerValidateResponse)
|
||||
|
||||
export const validate = {
|
||||
post: post54,
|
||||
post: post52,
|
||||
}
|
||||
|
||||
export const get62 = oc
|
||||
@ -3622,7 +3577,7 @@ export const lastRun = {
|
||||
*
|
||||
* Run draft workflow node
|
||||
*/
|
||||
export const post55 = oc
|
||||
export const post53 = oc
|
||||
.route({
|
||||
description: 'Run draft workflow node',
|
||||
inputStructure: 'detailed',
|
||||
@ -3641,7 +3596,7 @@ export const post55 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftNodesByNodeIdRunResponse)
|
||||
|
||||
export const run8 = {
|
||||
post: post55,
|
||||
post: post53,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3649,7 +3604,7 @@ export const run8 = {
|
||||
*
|
||||
* Poll for trigger events and execute single node when event arrives
|
||||
*/
|
||||
export const post56 = oc
|
||||
export const post54 = oc
|
||||
.route({
|
||||
description: 'Poll for trigger events and execute single node when event arrives',
|
||||
inputStructure: 'detailed',
|
||||
@ -3663,7 +3618,7 @@ export const post56 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftNodesByNodeIdTriggerRunResponse)
|
||||
|
||||
export const run9 = {
|
||||
post: post56,
|
||||
post: post54,
|
||||
}
|
||||
|
||||
export const trigger = {
|
||||
@ -3723,7 +3678,7 @@ export const nodes7 = {
|
||||
*
|
||||
* Run draft workflow
|
||||
*/
|
||||
export const post57 = oc
|
||||
export const post55 = oc
|
||||
.route({
|
||||
description: 'Run draft workflow',
|
||||
inputStructure: 'detailed',
|
||||
@ -3742,7 +3697,7 @@ export const post57 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftRunResponse)
|
||||
|
||||
export const run10 = {
|
||||
post: post57,
|
||||
post: post55,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3864,7 +3819,7 @@ export const systemVariables = {
|
||||
*
|
||||
* Poll for trigger events and execute full workflow when event arrives
|
||||
*/
|
||||
export const post58 = oc
|
||||
export const post56 = oc
|
||||
.route({
|
||||
description: 'Poll for trigger events and execute full workflow when event arrives',
|
||||
inputStructure: 'detailed',
|
||||
@ -3883,7 +3838,7 @@ export const post58 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftTriggerRunResponse)
|
||||
|
||||
export const run11 = {
|
||||
post: post58,
|
||||
post: post56,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3891,7 +3846,7 @@ export const run11 = {
|
||||
*
|
||||
* Full workflow debug when the start node is a trigger
|
||||
*/
|
||||
export const post59 = oc
|
||||
export const post57 = oc
|
||||
.route({
|
||||
description: 'Full workflow debug when the start node is a trigger',
|
||||
inputStructure: 'detailed',
|
||||
@ -3910,7 +3865,7 @@ export const post59 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsDraftTriggerRunAllResponse)
|
||||
|
||||
export const runAll = {
|
||||
post: post59,
|
||||
post: post57,
|
||||
}
|
||||
|
||||
export const trigger2 = {
|
||||
@ -4063,7 +4018,7 @@ export const get72 = oc
|
||||
*
|
||||
* Sync draft workflow configuration
|
||||
*/
|
||||
export const post60 = oc
|
||||
export const post58 = oc
|
||||
.route({
|
||||
description: 'Sync draft workflow configuration',
|
||||
inputStructure: 'detailed',
|
||||
@ -4083,7 +4038,7 @@ export const post60 = oc
|
||||
|
||||
export const draft2 = {
|
||||
get: get72,
|
||||
post: post60,
|
||||
post: post58,
|
||||
conversationVariables: conversationVariables2,
|
||||
environmentVariables,
|
||||
features,
|
||||
@ -4119,7 +4074,7 @@ export const get73 = oc
|
||||
/**
|
||||
* Publish workflow
|
||||
*/
|
||||
export const post61 = oc
|
||||
export const post59 = oc
|
||||
.route({
|
||||
inputStructure: 'detailed',
|
||||
method: 'POST',
|
||||
@ -4138,7 +4093,7 @@ export const post61 = oc
|
||||
|
||||
export const publish = {
|
||||
get: get73,
|
||||
post: post61,
|
||||
post: post59,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4275,7 +4230,7 @@ export const triggers2 = {
|
||||
/**
|
||||
* Restore a published workflow version into the draft workflow
|
||||
*/
|
||||
export const post62 = oc
|
||||
export const post60 = oc
|
||||
.route({
|
||||
description: 'Restore a published workflow version into the draft workflow',
|
||||
inputStructure: 'detailed',
|
||||
@ -4288,7 +4243,7 @@ export const post62 = oc
|
||||
.output(zPostAppsByAppIdWorkflowsByWorkflowIdRestoreResponse)
|
||||
|
||||
export const restore = {
|
||||
post: post62,
|
||||
post: post60,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4513,7 +4468,7 @@ export const get81 = oc
|
||||
*
|
||||
* Create a new API key for an app
|
||||
*/
|
||||
export const post63 = oc
|
||||
export const post61 = oc
|
||||
.route({
|
||||
description: 'Create a new API key for an app',
|
||||
inputStructure: 'detailed',
|
||||
@ -4529,7 +4484,7 @@ export const post63 = oc
|
||||
|
||||
export const apiKeys = {
|
||||
get: get81,
|
||||
post: post63,
|
||||
post: post61,
|
||||
byApiKeyId,
|
||||
}
|
||||
|
||||
@ -4587,7 +4542,7 @@ export const get83 = oc
|
||||
*
|
||||
* Create a new application
|
||||
*/
|
||||
export const post64 = oc
|
||||
export const post62 = oc
|
||||
.route({
|
||||
description: 'Create a new application',
|
||||
inputStructure: 'detailed',
|
||||
@ -4603,7 +4558,7 @@ export const post64 = oc
|
||||
|
||||
export const apps = {
|
||||
get: get83,
|
||||
post: post64,
|
||||
post: post62,
|
||||
imports,
|
||||
starred,
|
||||
workflows,
|
||||
|
||||
@ -253,14 +253,18 @@ export type AnnotationReplyPayload = {
|
||||
}
|
||||
|
||||
export type AnnotationJobStatusResponse = {
|
||||
error_msg?: string | null
|
||||
job_id?: string | null
|
||||
job_status?: string | null
|
||||
record_count?: number | null
|
||||
job_id: string
|
||||
job_status: 'completed' | 'error' | 'processing' | 'waiting' | string
|
||||
}
|
||||
|
||||
export type AnnotationJobStatusDetailResponse = {
|
||||
error_msg?: string
|
||||
job_id: string
|
||||
job_status: 'completed' | 'error' | 'processing' | 'waiting' | string
|
||||
}
|
||||
|
||||
export type AnnotationSettingResponse = {
|
||||
embedding_model?: AnnotationEmbeddingModelResponse | null
|
||||
embedding_model?: AnnotationSettingEmbeddingModelResponse | null
|
||||
enabled: boolean
|
||||
id?: string | null
|
||||
score_threshold?: number | null
|
||||
@ -296,6 +300,13 @@ export type Annotation = {
|
||||
question?: string | null
|
||||
}
|
||||
|
||||
export type AnnotationBatchImportResponse = {
|
||||
error_msg?: string | null
|
||||
job_id?: string | null
|
||||
job_status?: string | null
|
||||
record_count?: number | null
|
||||
}
|
||||
|
||||
export type AnnotationCountResponse = {
|
||||
count: number
|
||||
}
|
||||
@ -353,10 +364,10 @@ export type AudioTranscriptResponse = {
|
||||
}
|
||||
|
||||
export type ConversationWithSummaryPagination = {
|
||||
has_next: boolean
|
||||
items: Array<ConversationWithSummary>
|
||||
data: Array<ConversationWithSummary>
|
||||
has_more: boolean
|
||||
limit: number
|
||||
page: number
|
||||
per_page: number
|
||||
total: number
|
||||
}
|
||||
|
||||
@ -391,37 +402,24 @@ export type SimpleResultResponse = {
|
||||
}
|
||||
|
||||
export type ConversationPagination = {
|
||||
has_next: boolean
|
||||
items: Array<Conversation>
|
||||
data: Array<Conversation>
|
||||
has_more: boolean
|
||||
limit: number
|
||||
page: number
|
||||
per_page: number
|
||||
total: number
|
||||
}
|
||||
|
||||
export type ConversationMessageDetail = {
|
||||
created_at?: number | null
|
||||
first_message?: MessageDetail | null
|
||||
from_account_id?: string | null
|
||||
from_end_user_id?: string | null
|
||||
from_source: string
|
||||
id: string
|
||||
message?: MessageDetail | null
|
||||
model_config?: ModelConfig | null
|
||||
status: string
|
||||
}
|
||||
|
||||
export type CompletionMessagePayload = {
|
||||
files?: Array<unknown> | null
|
||||
inputs: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
model_config?: {
|
||||
[key: string]: unknown
|
||||
}
|
||||
query?: string
|
||||
response_mode?: 'blocking' | 'streaming'
|
||||
retriever_from?: string
|
||||
}
|
||||
|
||||
export type PaginatedConversationVariableResponse = {
|
||||
data: Array<ConversationVariableResponse>
|
||||
has_more: boolean
|
||||
@ -469,15 +467,16 @@ export type AppIconPayload = {
|
||||
}
|
||||
|
||||
export type MessageDetailResponse = {
|
||||
agent_thoughts?: Array<AgentThought>
|
||||
agent_thoughts: Array<AgentThought>
|
||||
annotation?: ConversationAnnotation | null
|
||||
annotation_hit_history?: ConversationAnnotationHitHistory | null
|
||||
answer_tokens?: number | null
|
||||
answer: string
|
||||
answer_tokens: number
|
||||
conversation_id: string
|
||||
created_at?: number | null
|
||||
error?: string | null
|
||||
extra_contents?: Array<HumanInputContent>
|
||||
feedbacks?: Array<Feedback>
|
||||
feedbacks: Array<Feedback>
|
||||
from_account_id?: string | null
|
||||
from_end_user_id?: string | null
|
||||
from_source: string
|
||||
@ -485,14 +484,13 @@ export type MessageDetailResponse = {
|
||||
inputs: {
|
||||
[key: string]: JsonValue
|
||||
}
|
||||
message?: JsonValue | null
|
||||
message_files?: Array<MessageFile>
|
||||
message_metadata_dict?: JsonValue | null
|
||||
message_tokens?: number | null
|
||||
message: JsonValue
|
||||
message_files: Array<MessageFile>
|
||||
message_tokens: number
|
||||
metadata: JsonValue
|
||||
parent_message_id?: string | null
|
||||
provider_response_latency?: number | null
|
||||
provider_response_latency: number
|
||||
query: string
|
||||
re_sign_file_url_answer: string
|
||||
status: string
|
||||
workflow_run_id?: string | null
|
||||
}
|
||||
@ -641,18 +639,7 @@ export type UserSatisfactionRateStatisticResponse = {
|
||||
data: Array<UserSatisfactionRateStatisticItem>
|
||||
}
|
||||
|
||||
export type TextToSpeechPayload = {
|
||||
message_id?: string | null
|
||||
streaming?: boolean | null
|
||||
text: string
|
||||
voice?: string | null
|
||||
}
|
||||
|
||||
export type AudioBinaryResponse = Blob | File
|
||||
|
||||
export type TextToSpeechVoiceListResponse = Array<{
|
||||
[key: string]: unknown
|
||||
}>
|
||||
export type TextToSpeechVoiceListResponse = Array<TextToSpeechVoiceResponse>
|
||||
|
||||
export type AppTraceResponse = {
|
||||
enabled: boolean
|
||||
@ -1396,7 +1383,7 @@ export type CliToolSuggestion = {
|
||||
name: string
|
||||
}
|
||||
|
||||
export type AnnotationEmbeddingModelResponse = {
|
||||
export type AnnotationSettingEmbeddingModelResponse = {
|
||||
embedding_model_name?: string | null
|
||||
embedding_provider_name?: string | null
|
||||
}
|
||||
@ -1427,7 +1414,7 @@ export type ConversationWithSummary = {
|
||||
read_at?: number | null
|
||||
status: string
|
||||
status_count?: StatusCount | null
|
||||
summary_or_query: string
|
||||
summary: string
|
||||
updated_at?: number | null
|
||||
user_feedback_stats?: FeedbackStat | null
|
||||
}
|
||||
@ -1441,13 +1428,13 @@ export type Conversation = {
|
||||
admin_feedback_stats?: FeedbackStat | null
|
||||
annotation?: ConversationAnnotation | null
|
||||
created_at?: number | null
|
||||
first_message?: SimpleMessageDetail | null
|
||||
from_account_id?: string | null
|
||||
from_account_name?: string | null
|
||||
from_end_user_id?: string | null
|
||||
from_end_user_session_id?: string | null
|
||||
from_source: string
|
||||
id: string
|
||||
message?: SimpleMessageDetail | null
|
||||
model_config?: SimpleModelConfig | null
|
||||
read_at?: number | null
|
||||
status: string
|
||||
@ -1459,6 +1446,7 @@ export type MessageDetail = {
|
||||
agent_thoughts: Array<AgentThought>
|
||||
annotation?: ConversationAnnotation | null
|
||||
annotation_hit_history?: ConversationAnnotationHitHistory | null
|
||||
answer: string
|
||||
answer_tokens: number
|
||||
conversation_id: string
|
||||
created_at?: number | null
|
||||
@ -1473,12 +1461,11 @@ export type MessageDetail = {
|
||||
}
|
||||
message: JsonValue
|
||||
message_files: Array<MessageFile>
|
||||
message_metadata_dict: JsonValue
|
||||
message_tokens: number
|
||||
metadata: JsonValue
|
||||
parent_message_id?: string | null
|
||||
provider_response_latency: number
|
||||
query: string
|
||||
re_sign_file_url_answer: string
|
||||
status: string
|
||||
workflow_run_id?: string | null
|
||||
}
|
||||
@ -1498,7 +1485,6 @@ export type AgentThought = {
|
||||
created_at?: number | null
|
||||
files: Array<string>
|
||||
id: string
|
||||
message_chain_id?: string | null
|
||||
message_id: string
|
||||
observation?: string | null
|
||||
position: number
|
||||
@ -1518,8 +1504,8 @@ export type ConversationAnnotation = {
|
||||
|
||||
export type ConversationAnnotationHitHistory = {
|
||||
annotation_create_account?: SimpleAccount | null
|
||||
annotation_id: string
|
||||
created_at?: number | null
|
||||
id: string
|
||||
}
|
||||
|
||||
export type HumanInputContent = {
|
||||
@ -1578,10 +1564,10 @@ export type DailyMessageStatisticItem = {
|
||||
}
|
||||
|
||||
export type DailyTokenCostStatisticItem = {
|
||||
currency: string
|
||||
currency?: string | null
|
||||
date: string
|
||||
token_count: number
|
||||
total_price: string | number
|
||||
token_count?: number | null
|
||||
total_price?: string | null
|
||||
}
|
||||
|
||||
export type TokensPerSecondStatisticItem = {
|
||||
@ -1594,6 +1580,11 @@ export type UserSatisfactionRateStatisticItem = {
|
||||
rate: number
|
||||
}
|
||||
|
||||
export type TextToSpeechVoiceResponse = {
|
||||
name: string
|
||||
value: string
|
||||
}
|
||||
|
||||
export type WorkflowAppLogPartialResponse = {
|
||||
created_at?: number | null
|
||||
created_by_account?: SimpleAccount | null
|
||||
@ -2034,7 +2025,7 @@ export type EnvSuggestion = {
|
||||
}
|
||||
|
||||
export type SimpleModelConfig = {
|
||||
model_dict?: JsonValue | null
|
||||
model?: JsonValue | null
|
||||
pre_prompt?: string | null
|
||||
}
|
||||
|
||||
@ -3335,7 +3326,7 @@ export type GetAppsByAppIdAnnotationReplyByActionStatusByJobIdErrors = {
|
||||
}
|
||||
|
||||
export type GetAppsByAppIdAnnotationReplyByActionStatusByJobIdResponses = {
|
||||
200: AnnotationJobStatusResponse
|
||||
200: AnnotationJobStatusDetailResponse
|
||||
}
|
||||
|
||||
export type GetAppsByAppIdAnnotationReplyByActionStatusByJobIdResponse
|
||||
@ -3459,7 +3450,7 @@ export type PostAppsByAppIdAnnotationsBatchImportErrors = {
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdAnnotationsBatchImportResponses = {
|
||||
200: AnnotationJobStatusResponse
|
||||
200: AnnotationBatchImportResponse
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdAnnotationsBatchImportResponse
|
||||
@ -3480,7 +3471,7 @@ export type GetAppsByAppIdAnnotationsBatchImportStatusByJobIdErrors = {
|
||||
}
|
||||
|
||||
export type GetAppsByAppIdAnnotationsBatchImportStatusByJobIdResponses = {
|
||||
200: AnnotationJobStatusResponse
|
||||
200: AnnotationJobStatusDetailResponse
|
||||
}
|
||||
|
||||
export type GetAppsByAppIdAnnotationsBatchImportStatusByJobIdResponse
|
||||
@ -3831,27 +3822,6 @@ export type GetAppsByAppIdCompletionConversationsByConversationIdResponses = {
|
||||
export type GetAppsByAppIdCompletionConversationsByConversationIdResponse
|
||||
= GetAppsByAppIdCompletionConversationsByConversationIdResponses[keyof GetAppsByAppIdCompletionConversationsByConversationIdResponses]
|
||||
|
||||
export type PostAppsByAppIdCompletionMessagesData = {
|
||||
body: CompletionMessagePayload
|
||||
path: {
|
||||
app_id: string
|
||||
}
|
||||
query?: never
|
||||
url: '/apps/{app_id}/completion-messages'
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdCompletionMessagesErrors = {
|
||||
400: unknown
|
||||
404: unknown
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdCompletionMessagesResponses = {
|
||||
200: GeneratedAppResponse
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdCompletionMessagesResponse
|
||||
= PostAppsByAppIdCompletionMessagesResponses[keyof PostAppsByAppIdCompletionMessagesResponses]
|
||||
|
||||
export type PostAppsByAppIdCompletionMessagesByTaskIdStopData = {
|
||||
body?: never
|
||||
path: {
|
||||
@ -4405,26 +4375,6 @@ export type GetAppsByAppIdStatisticsUserSatisfactionRateResponses = {
|
||||
export type GetAppsByAppIdStatisticsUserSatisfactionRateResponse
|
||||
= GetAppsByAppIdStatisticsUserSatisfactionRateResponses[keyof GetAppsByAppIdStatisticsUserSatisfactionRateResponses]
|
||||
|
||||
export type PostAppsByAppIdTextToAudioData = {
|
||||
body: TextToSpeechPayload
|
||||
path: {
|
||||
app_id: string
|
||||
}
|
||||
query?: never
|
||||
url: '/apps/{app_id}/text-to-audio'
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdTextToAudioErrors = {
|
||||
400: unknown
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdTextToAudioResponses = {
|
||||
200: AudioBinaryResponse
|
||||
}
|
||||
|
||||
export type PostAppsByAppIdTextToAudioResponse
|
||||
= PostAppsByAppIdTextToAudioResponses[keyof PostAppsByAppIdTextToAudioResponses]
|
||||
|
||||
export type GetAppsByAppIdTextToAudioVoicesData = {
|
||||
body?: never
|
||||
path: {
|
||||
|
||||
@ -144,10 +144,17 @@ export const zAnnotationReplyPayload = z.object({
|
||||
* AnnotationJobStatusResponse
|
||||
*/
|
||||
export const zAnnotationJobStatusResponse = z.object({
|
||||
error_msg: z.string().nullish(),
|
||||
job_id: z.string().nullish(),
|
||||
job_status: z.string().nullish(),
|
||||
record_count: z.int().nullish(),
|
||||
job_id: z.string(),
|
||||
job_status: z.union([z.enum(['completed', 'error', 'processing', 'waiting']), z.string()]),
|
||||
})
|
||||
|
||||
/**
|
||||
* AnnotationJobStatusDetailResponse
|
||||
*/
|
||||
export const zAnnotationJobStatusDetailResponse = z.object({
|
||||
error_msg: z.string().optional().default(''),
|
||||
job_id: z.string(),
|
||||
job_status: z.union([z.enum(['completed', 'error', 'processing', 'waiting']), z.string()]),
|
||||
})
|
||||
|
||||
/**
|
||||
@ -190,6 +197,16 @@ export const zAnnotationList = z.object({
|
||||
total: z.int(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AnnotationBatchImportResponse
|
||||
*/
|
||||
export const zAnnotationBatchImportResponse = z.object({
|
||||
error_msg: z.string().nullish(),
|
||||
job_id: z.string().nullish(),
|
||||
job_status: z.string().nullish(),
|
||||
record_count: z.int().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AnnotationCountResponse
|
||||
*/
|
||||
@ -242,18 +259,6 @@ export const zSimpleResultResponse = z.object({
|
||||
result: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* CompletionMessagePayload
|
||||
*/
|
||||
export const zCompletionMessagePayload = z.object({
|
||||
files: z.array(z.unknown()).nullish(),
|
||||
inputs: z.record(z.string(), z.unknown()),
|
||||
model_config: z.record(z.string(), z.unknown()).optional(),
|
||||
query: z.string().optional().default(''),
|
||||
response_mode: z.enum(['blocking', 'streaming']).optional().default('blocking'),
|
||||
retriever_from: z.string().optional().default('dev'),
|
||||
})
|
||||
|
||||
/**
|
||||
* ConvertToWorkflowPayload
|
||||
*/
|
||||
@ -393,26 +398,6 @@ export const zAppSiteStatusPayload = z.object({
|
||||
enable_site: z.boolean(),
|
||||
})
|
||||
|
||||
/**
|
||||
* TextToSpeechPayload
|
||||
*/
|
||||
export const zTextToSpeechPayload = z.object({
|
||||
message_id: z.string().nullish(),
|
||||
streaming: z.boolean().nullish(),
|
||||
text: z.string(),
|
||||
voice: z.string().nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
* AudioBinaryResponse
|
||||
*/
|
||||
export const zAudioBinaryResponse = z.custom<Blob | File>()
|
||||
|
||||
/**
|
||||
* TextToSpeechVoiceListResponse
|
||||
*/
|
||||
export const zTextToSpeechVoiceListResponse = z.array(z.record(z.string(), z.unknown()))
|
||||
|
||||
/**
|
||||
* AppTraceResponse
|
||||
*/
|
||||
@ -1069,9 +1054,9 @@ export const zAgentSkillUploadResponse = z.object({
|
||||
})
|
||||
|
||||
/**
|
||||
* AnnotationEmbeddingModelResponse
|
||||
* AnnotationSettingEmbeddingModelResponse
|
||||
*/
|
||||
export const zAnnotationEmbeddingModelResponse = z.object({
|
||||
export const zAnnotationSettingEmbeddingModelResponse = z.object({
|
||||
embedding_model_name: z.string().nullish(),
|
||||
embedding_provider_name: z.string().nullish(),
|
||||
})
|
||||
@ -1080,7 +1065,7 @@ export const zAnnotationEmbeddingModelResponse = z.object({
|
||||
* AnnotationSettingResponse
|
||||
*/
|
||||
export const zAnnotationSettingResponse = z.object({
|
||||
embedding_model: zAnnotationEmbeddingModelResponse.nullish(),
|
||||
embedding_model: zAnnotationSettingEmbeddingModelResponse.nullish(),
|
||||
enabled: z.boolean(),
|
||||
id: z.string().nullish(),
|
||||
score_threshold: z.number().nullish(),
|
||||
@ -1150,7 +1135,6 @@ export const zAgentThought = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
files: z.array(z.string()),
|
||||
id: z.string(),
|
||||
message_chain_id: z.string().nullish(),
|
||||
message_id: z.string(),
|
||||
observation: z.string().nullish(),
|
||||
position: z.int(),
|
||||
@ -1275,10 +1259,13 @@ export const zDailyMessageStatisticResponse = z.object({
|
||||
* DailyTokenCostStatisticItem
|
||||
*/
|
||||
export const zDailyTokenCostStatisticItem = z.object({
|
||||
currency: z.string(),
|
||||
currency: z.string().nullish(),
|
||||
date: z.string(),
|
||||
token_count: z.int(),
|
||||
total_price: z.union([z.string(), z.number()]),
|
||||
token_count: z.int().nullish(),
|
||||
total_price: z
|
||||
.string()
|
||||
.regex(/^(?![-+.]*$)[+-]?\d*(?:\.\d*)?$/)
|
||||
.nullish(),
|
||||
})
|
||||
|
||||
/**
|
||||
@ -1318,6 +1305,21 @@ export const zUserSatisfactionRateStatisticResponse = z.object({
|
||||
data: z.array(zUserSatisfactionRateStatisticItem),
|
||||
})
|
||||
|
||||
/**
|
||||
* TextToSpeechVoiceResponse
|
||||
*/
|
||||
export const zTextToSpeechVoiceResponse = z.object({
|
||||
name: z.string(),
|
||||
value: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
* TextToSpeechVoiceListResponse
|
||||
*
|
||||
* Available voices
|
||||
*/
|
||||
export const zTextToSpeechVoiceListResponse = z.array(zTextToSpeechVoiceResponse)
|
||||
|
||||
/**
|
||||
* SimpleAccount
|
||||
*/
|
||||
@ -1371,8 +1373,8 @@ export const zConversationAnnotation = z.object({
|
||||
*/
|
||||
export const zConversationAnnotationHitHistory = z.object({
|
||||
annotation_create_account: zSimpleAccount.nullish(),
|
||||
annotation_id: z.string(),
|
||||
created_at: z.int().nullish(),
|
||||
id: z.string(),
|
||||
})
|
||||
|
||||
/**
|
||||
@ -1393,6 +1395,7 @@ export const zMessageDetail = z.object({
|
||||
agent_thoughts: z.array(zAgentThought),
|
||||
annotation: zConversationAnnotation.nullish(),
|
||||
annotation_hit_history: zConversationAnnotationHitHistory.nullish(),
|
||||
answer: z.string(),
|
||||
answer_tokens: z.int(),
|
||||
conversation_id: z.string(),
|
||||
created_at: z.int().nullish(),
|
||||
@ -1405,12 +1408,11 @@ export const zMessageDetail = z.object({
|
||||
inputs: z.record(z.string(), zJsonValue),
|
||||
message: zJsonValue,
|
||||
message_files: z.array(zMessageFile),
|
||||
message_metadata_dict: zJsonValue,
|
||||
message_tokens: z.int(),
|
||||
metadata: zJsonValue,
|
||||
parent_message_id: z.string().nullish(),
|
||||
provider_response_latency: z.number(),
|
||||
query: z.string(),
|
||||
re_sign_file_url_answer: z.string(),
|
||||
status: z.string(),
|
||||
workflow_run_id: z.string().nullish(),
|
||||
})
|
||||
@ -2157,11 +2159,11 @@ export const zConversationDetail = z.object({
|
||||
*/
|
||||
export const zConversationMessageDetail = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
first_message: zMessageDetail.nullish(),
|
||||
from_account_id: z.string().nullish(),
|
||||
from_end_user_id: z.string().nullish(),
|
||||
from_source: z.string(),
|
||||
id: z.string(),
|
||||
message: zMessageDetail.nullish(),
|
||||
model_config: zModelConfig.nullish(),
|
||||
status: z.string(),
|
||||
})
|
||||
@ -2307,7 +2309,7 @@ export const zSkillToolInferenceResult = z.object({
|
||||
* SimpleModelConfig
|
||||
*/
|
||||
export const zSimpleModelConfig = z.object({
|
||||
model_dict: zJsonValue.nullish(),
|
||||
model: zJsonValue.nullish(),
|
||||
pre_prompt: z.string().nullish(),
|
||||
})
|
||||
|
||||
@ -2340,7 +2342,7 @@ export const zConversationWithSummary = z.object({
|
||||
read_at: z.int().nullish(),
|
||||
status: z.string(),
|
||||
status_count: zStatusCount.nullish(),
|
||||
summary_or_query: z.string(),
|
||||
summary: z.string(),
|
||||
updated_at: z.int().nullish(),
|
||||
user_feedback_stats: zFeedbackStat.nullish(),
|
||||
})
|
||||
@ -2349,10 +2351,10 @@ export const zConversationWithSummary = z.object({
|
||||
* ConversationWithSummaryPagination
|
||||
*/
|
||||
export const zConversationWithSummaryPagination = z.object({
|
||||
has_next: z.boolean(),
|
||||
items: z.array(zConversationWithSummary),
|
||||
data: z.array(zConversationWithSummary),
|
||||
has_more: z.boolean(),
|
||||
limit: z.int(),
|
||||
page: z.int(),
|
||||
per_page: z.int(),
|
||||
total: z.int(),
|
||||
})
|
||||
|
||||
@ -2373,13 +2375,13 @@ export const zConversation = z.object({
|
||||
admin_feedback_stats: zFeedbackStat.nullish(),
|
||||
annotation: zConversationAnnotation.nullish(),
|
||||
created_at: z.int().nullish(),
|
||||
first_message: zSimpleMessageDetail.nullish(),
|
||||
from_account_id: z.string().nullish(),
|
||||
from_account_name: z.string().nullish(),
|
||||
from_end_user_id: z.string().nullish(),
|
||||
from_end_user_session_id: z.string().nullish(),
|
||||
from_source: z.string(),
|
||||
id: z.string(),
|
||||
message: zSimpleMessageDetail.nullish(),
|
||||
model_config: zSimpleModelConfig.nullish(),
|
||||
read_at: z.int().nullish(),
|
||||
status: z.string(),
|
||||
@ -2391,10 +2393,10 @@ export const zConversation = z.object({
|
||||
* ConversationPagination
|
||||
*/
|
||||
export const zConversationPagination = z.object({
|
||||
has_next: z.boolean(),
|
||||
items: z.array(zConversation),
|
||||
data: z.array(zConversation),
|
||||
has_more: z.boolean(),
|
||||
limit: z.int(),
|
||||
page: z.int(),
|
||||
per_page: z.int(),
|
||||
total: z.int(),
|
||||
})
|
||||
|
||||
@ -3452,28 +3454,28 @@ export const zHumanInputContent = z.object({
|
||||
* MessageDetailResponse
|
||||
*/
|
||||
export const zMessageDetailResponse = z.object({
|
||||
agent_thoughts: z.array(zAgentThought).optional(),
|
||||
agent_thoughts: z.array(zAgentThought),
|
||||
annotation: zConversationAnnotation.nullish(),
|
||||
annotation_hit_history: zConversationAnnotationHitHistory.nullish(),
|
||||
answer_tokens: z.int().nullish(),
|
||||
answer: z.string(),
|
||||
answer_tokens: z.int(),
|
||||
conversation_id: z.string(),
|
||||
created_at: z.int().nullish(),
|
||||
error: z.string().nullish(),
|
||||
extra_contents: z.array(zHumanInputContent).optional(),
|
||||
feedbacks: z.array(zFeedback).optional(),
|
||||
feedbacks: z.array(zFeedback),
|
||||
from_account_id: z.string().nullish(),
|
||||
from_end_user_id: z.string().nullish(),
|
||||
from_source: z.string(),
|
||||
id: z.string(),
|
||||
inputs: z.record(z.string(), zJsonValue),
|
||||
message: zJsonValue.nullish(),
|
||||
message_files: z.array(zMessageFile).optional(),
|
||||
message_metadata_dict: zJsonValue.nullish(),
|
||||
message_tokens: z.int().nullish(),
|
||||
message: zJsonValue,
|
||||
message_files: z.array(zMessageFile),
|
||||
message_tokens: z.int(),
|
||||
metadata: zJsonValue,
|
||||
parent_message_id: z.string().nullish(),
|
||||
provider_response_latency: z.number().nullish(),
|
||||
provider_response_latency: z.number(),
|
||||
query: z.string(),
|
||||
re_sign_file_url_answer: z.string(),
|
||||
status: z.string(),
|
||||
workflow_run_id: z.string().nullish(),
|
||||
})
|
||||
@ -4075,7 +4077,7 @@ export const zGetAppsByAppIdAnnotationReplyByActionStatusByJobIdPath = z.object(
|
||||
* Job status retrieved successfully
|
||||
*/
|
||||
export const zGetAppsByAppIdAnnotationReplyByActionStatusByJobIdResponse
|
||||
= zAnnotationJobStatusResponse
|
||||
= zAnnotationJobStatusDetailResponse
|
||||
|
||||
export const zGetAppsByAppIdAnnotationSettingPath = z.object({
|
||||
app_id: z.uuid(),
|
||||
@ -4142,7 +4144,7 @@ export const zPostAppsByAppIdAnnotationsBatchImportPath = z.object({
|
||||
/**
|
||||
* Batch import started successfully
|
||||
*/
|
||||
export const zPostAppsByAppIdAnnotationsBatchImportResponse = zAnnotationJobStatusResponse
|
||||
export const zPostAppsByAppIdAnnotationsBatchImportResponse = zAnnotationBatchImportResponse
|
||||
|
||||
export const zGetAppsByAppIdAnnotationsBatchImportStatusByJobIdPath = z.object({
|
||||
app_id: z.uuid(),
|
||||
@ -4153,7 +4155,7 @@ export const zGetAppsByAppIdAnnotationsBatchImportStatusByJobIdPath = z.object({
|
||||
* Job status retrieved successfully
|
||||
*/
|
||||
export const zGetAppsByAppIdAnnotationsBatchImportStatusByJobIdResponse
|
||||
= zAnnotationJobStatusResponse
|
||||
= zAnnotationJobStatusDetailResponse
|
||||
|
||||
export const zGetAppsByAppIdAnnotationsCountPath = z.object({
|
||||
app_id: z.uuid(),
|
||||
@ -4345,17 +4347,6 @@ export const zGetAppsByAppIdCompletionConversationsByConversationIdPath = z.obje
|
||||
export const zGetAppsByAppIdCompletionConversationsByConversationIdResponse
|
||||
= zConversationMessageDetail
|
||||
|
||||
export const zPostAppsByAppIdCompletionMessagesBody = zCompletionMessagePayload
|
||||
|
||||
export const zPostAppsByAppIdCompletionMessagesPath = z.object({
|
||||
app_id: z.uuid(),
|
||||
})
|
||||
|
||||
/**
|
||||
* Completion generated successfully
|
||||
*/
|
||||
export const zPostAppsByAppIdCompletionMessagesResponse = zGeneratedAppResponse
|
||||
|
||||
export const zPostAppsByAppIdCompletionMessagesByTaskIdStopPath = z.object({
|
||||
app_id: z.uuid(),
|
||||
task_id: z.string(),
|
||||
@ -4692,17 +4683,6 @@ export const zGetAppsByAppIdStatisticsUserSatisfactionRateQuery = z.object({
|
||||
export const zGetAppsByAppIdStatisticsUserSatisfactionRateResponse
|
||||
= zUserSatisfactionRateStatisticResponse
|
||||
|
||||
export const zPostAppsByAppIdTextToAudioBody = zTextToSpeechPayload
|
||||
|
||||
export const zPostAppsByAppIdTextToAudioPath = z.object({
|
||||
app_id: z.uuid(),
|
||||
})
|
||||
|
||||
/**
|
||||
* Text to speech conversion successful
|
||||
*/
|
||||
export const zPostAppsByAppIdTextToAudioResponse = zAudioBinaryResponse
|
||||
|
||||
export const zGetAppsByAppIdTextToAudioVoicesPath = z.object({
|
||||
app_id: z.uuid(),
|
||||
})
|
||||
|
||||
@ -246,7 +246,6 @@ export type AgentThought = {
|
||||
created_at?: number | null
|
||||
files: Array<string>
|
||||
id: string
|
||||
message_chain_id?: string | null
|
||||
message_id: string
|
||||
observation?: string | null
|
||||
position: number
|
||||
|
||||
@ -266,7 +266,6 @@ export const zAgentThought = z.object({
|
||||
created_at: z.int().nullish(),
|
||||
files: z.array(z.string()),
|
||||
id: z.string(),
|
||||
message_chain_id: z.string().nullish(),
|
||||
message_id: z.string(),
|
||||
observation: z.string().nullish(),
|
||||
position: z.int(),
|
||||
|
||||
@ -10,13 +10,21 @@ type SwaggerSchema = JsonObject & {
|
||||
$ref?: string
|
||||
}
|
||||
|
||||
type OpenApiMediaType = JsonObject & {
|
||||
schema?: SwaggerSchema
|
||||
}
|
||||
|
||||
type OpenApiResponse = JsonObject & {
|
||||
content?: Record<string, OpenApiMediaType>
|
||||
}
|
||||
|
||||
type OpenApiComponents = JsonObject & {
|
||||
schemas?: Record<string, SwaggerSchema>
|
||||
}
|
||||
|
||||
type SwaggerOperation = JsonObject & {
|
||||
operationId?: string
|
||||
responses?: Record<string, unknown>
|
||||
responses?: Record<string, OpenApiResponse>
|
||||
}
|
||||
|
||||
type SwaggerDocument = JsonObject & {
|
||||
@ -52,6 +60,17 @@ const currentDir = path.dirname(fileURLToPath(import.meta.url))
|
||||
const apiOpenApiDir = path.resolve(currentDir, 'openapi')
|
||||
|
||||
const operationMethods = new Set(['delete', 'get', 'patch', 'post', 'put'])
|
||||
const pydanticDecimalStringPattern = '^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$'
|
||||
const codegenSafeDecimalStringPattern = '^(?![-+.]*$)[+-]?0*\\d*\\.?\\d*$'
|
||||
|
||||
const opaqueJsonContent = (): Record<string, OpenApiMediaType> => ({
|
||||
'application/json': {
|
||||
schema: {
|
||||
additionalProperties: true,
|
||||
type: 'object',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const apiSpecs: ApiSpec[] = [
|
||||
{ filename: 'console-openapi.json', name: 'console' },
|
||||
@ -182,6 +201,46 @@ const addOperationIds = (document: SwaggerDocument) => {
|
||||
}
|
||||
}
|
||||
|
||||
const isOpaqueContractResponse = (response: OpenApiResponse) => {
|
||||
const content = response.content
|
||||
if (!isObject(content))
|
||||
return false
|
||||
|
||||
return Object.entries(content).some(([mediaType, media]) => {
|
||||
if (!isObject(media))
|
||||
return false
|
||||
|
||||
return (mediaType === 'application/json' || mediaType === 'text/event-stream') && !('schema' in media)
|
||||
})
|
||||
}
|
||||
|
||||
const hasOpaqueContractSuccessResponse = (operation: SwaggerOperation) => {
|
||||
return Object.entries(operation.responses ?? {}).some(([status, response]) => {
|
||||
return /^2\d\d$/.test(status) && isObject(response) && isOpaqueContractResponse(response)
|
||||
})
|
||||
}
|
||||
|
||||
const normalizeOpaqueContractResponses = (document: SwaggerDocument) => {
|
||||
// Some backend endpoints has no schema (e.g. external) and will trap heyapi here
|
||||
// So we forge an opaque schema here
|
||||
for (const pathItem of Object.values(document.paths ?? {})) {
|
||||
for (const [method, operation] of Object.entries(pathItem)) {
|
||||
if (!operationMethods.has(method) || !isObject(operation))
|
||||
continue
|
||||
|
||||
const swaggerOperation = operation as SwaggerOperation
|
||||
if (!hasOpaqueContractSuccessResponse(swaggerOperation))
|
||||
continue
|
||||
|
||||
Object.values(swaggerOperation.responses ?? {})
|
||||
.filter(response => isObject(response) && isOpaqueContractResponse(response))
|
||||
.forEach((response) => {
|
||||
response.content = opaqueJsonContent()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const hasSuccessResponse = (operation: SwaggerOperation) => {
|
||||
return Object.entries(operation.responses ?? {}).some(([status, response]) => {
|
||||
if (!/^2\d\d$/.test(status))
|
||||
@ -215,6 +274,7 @@ const filterContractOperations = (document: SwaggerDocument) => {
|
||||
}
|
||||
|
||||
const normalizeApiSwagger = (document: SwaggerDocument) => {
|
||||
normalizeOpaqueContractResponses(document)
|
||||
filterContractOperations(document)
|
||||
addOperationIds(document)
|
||||
|
||||
@ -380,10 +440,20 @@ const createApiConfig = (job: ApiJob): UserConfig => ({
|
||||
'name': 'zod',
|
||||
'~resolvers': {
|
||||
string: (ctx) => {
|
||||
if (ctx.schema.format !== 'binary')
|
||||
return undefined
|
||||
if (ctx.schema.format === 'binary')
|
||||
return $(ctx.symbols.z).attr('custom').call().generic($.type.or($.type('Blob'), $.type('File')))
|
||||
|
||||
return $(ctx.symbols.z).attr('custom').call().generic($.type.or($.type('Blob'), $.type('File')))
|
||||
if (ctx.schema.pattern === pydanticDecimalStringPattern) {
|
||||
// the pydantic generated regex will emit error like
|
||||
// regexp/no-useless-assertions, so patch the regex here
|
||||
return $(ctx.symbols.z)
|
||||
.attr('string')
|
||||
.call()
|
||||
.attr('regex')
|
||||
.call($.regexp(codegenSafeDecimalStringPattern))
|
||||
}
|
||||
|
||||
return undefined
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user