From 51aa93eefbad245096abba89ecc010dfba1c997b Mon Sep 17 00:00:00 2001 From: chakcy <947105045@qq.com> Date: Fri, 21 Aug 2026 14:48:05 +0800 Subject: [PATCH] =?UTF-8?q?modify:=20=E6=B5=81=E5=BC=8F=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/models/__init__.py | 2 ++ example/models/pydantic.py | 9 +++++++-- example/router/__init__.py | 4 +++- example/router/stream_chat.py | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 example/router/stream_chat.py diff --git a/example/models/__init__.py b/example/models/__init__.py index e00d0ba..1d8ba98 100644 --- a/example/models/__init__.py +++ b/example/models/__init__.py @@ -15,6 +15,7 @@ from .pydantic import ExampleResponse from .pydantic import HeartbeatMqttRequest from .pydantic import MultiplyGetRequest from .pydantic import MultiplyGetResponse +from .pydantic import StreamChatPostRequest from .pydantic import SubtractGetRequest from .pydantic import SubtractGetResponse @@ -31,6 +32,7 @@ __all__ = [ "HeartbeatMqttRequest", "MultiplyGetRequest", "MultiplyGetResponse", + "StreamChatPostRequest", "SubtractGetRequest", "SubtractGetResponse", ] diff --git a/example/models/pydantic.py b/example/models/pydantic.py index f4fd602..1e5108b 100644 --- a/example/models/pydantic.py +++ b/example/models/pydantic.py @@ -5,7 +5,7 @@ from __future__ import annotations -from typing import Any, Optional +from typing import Optional from pydantic import BaseModel, Field class AddGetRequest(BaseModel): @@ -67,6 +67,11 @@ class MultiplyGetResponse(BaseModel): operation: str = Field(default='multiply') timestamp: Optional[float] = Field(default=0.0) +class StreamChatPostRequest(BaseModel): + """模拟 AI 流式对话(SSE,逐 token 输出) — 请求体""" + prompt: str = Field(...) + tokens: int = Field(...) + class SubtractGetRequest(BaseModel): """Subtract two numbers — 请求体""" a: float = Field(...) @@ -80,4 +85,4 @@ class SubtractGetResponse(BaseModel): # 所有响应模型的联合类型 -ExampleResponse = AddPostResponse | AddGetResponse | DivideGetResponse | SubtractGetResponse | CountGetResponse | MultiplyGetResponse +ExampleResponse = MultiplyGetResponse | AddPostResponse | CountGetResponse | SubtractGetResponse | DivideGetResponse | AddGetResponse diff --git a/example/router/__init__.py b/example/router/__init__.py index 2679b1a..569d623 100644 --- a/example/router/__init__.py +++ b/example/router/__init__.py @@ -5,6 +5,7 @@ from .subtract import subtract from .multiply import multiply from .divide import divide from .count import count_get +from .stream_chat import stream_chat __all__ = [ @@ -15,5 +16,6 @@ __all__ = [ "subtract", "multiply", "divide", - "count_get" + "count_get", + "stream_chat" ] \ No newline at end of file diff --git a/example/router/stream_chat.py b/example/router/stream_chat.py new file mode 100644 index 0000000..896bebc --- /dev/null +++ b/example/router/stream_chat.py @@ -0,0 +1,34 @@ +""" +流式端点示例 — @rpc_method 返回异步生成器,框架自动逐块多回复推送 + +网关在 TOML 中声明 stream = true 时,该端点以 SSE(text/event-stream)输出: + POST /api/v1/calc/stream_chat {"prompt": "你好", "tokens": 5} + 响应: data: {"token": "..."} ... data: {"done": true} + +约定: + - 插件侧写法:函数返回生成器(yield),框架逐块 query.reply() 推送 + - {"done": true} 是业务结束标记(插件自定义),不是协议哨兵—— + 流式协议以生成器自然结束为流终止信号 + - 中途异常时框架自动发送 {"error": ...} 收尾块 +""" +import asyncio +import logging + +from chongming_worker import rpc_method + +logger = logging.getLogger("plugins.example.stream_chat") + + +@rpc_method( + subject="example.stream_chat", + method="POST", + summary="模拟 AI 流式对话(SSE,逐 token 输出)", + stream=True, +) +async def stream_chat(prompt: str = "你好", tokens: int = 10): + """逐 token 模拟生成:把 return 改成 yield,框架即自动流式推送""" + logger.info("收到流式请求: prompt=%s, tokens=%d", prompt, tokens) + for i in range(tokens): + await asyncio.sleep(0.05) + yield {"token": f"{prompt}·{i + 1}", "index": i} + yield {"done": True}