add first commit
This commit is contained in:
+11
@@ -0,0 +1,11 @@
|
|||||||
|
# Python-generated files
|
||||||
|
__pycache__/
|
||||||
|
*.py[oc]
|
||||||
|
build/
|
||||||
|
build_nuitka/
|
||||||
|
dist/
|
||||||
|
wheels/
|
||||||
|
*.egg-info
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
"""
|
||||||
|
豆包视觉理解 Worker 插件
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from volcenginesdkarkruntime import AsyncArk
|
||||||
|
from chongming_worker import create_workers as _create_workers
|
||||||
|
from chongming_worker import auto_bind_models
|
||||||
|
from .global_var import set_ark_client, cleanup_ark_client
|
||||||
|
from .router import *
|
||||||
|
|
||||||
|
# 自动绑定 gen_models 生成的 Pydantic 模型
|
||||||
|
auto_bind_models("doubao")
|
||||||
|
|
||||||
|
async def create_workers(session, config, count=1, worker_manager=None):
|
||||||
|
"""
|
||||||
|
工厂函数:由 app 生命周期调用,创建 Worker 协程。
|
||||||
|
"""
|
||||||
|
# 从配置或环境变量获取 API Key
|
||||||
|
api_key = config.get("api_key") or os.environ.get("VOLC_ACCESSKEY")
|
||||||
|
if not api_key:
|
||||||
|
raise ValueError("缺少 API_KEY,请在配置中设置 api_key 或环境变量 VOLC_ACCESSKEY")
|
||||||
|
|
||||||
|
base_url = config.get("base_url", "https://ark.cn-beijing.volces.com/api/v3")
|
||||||
|
model = config.get("model", "doubao-seed-evolving")
|
||||||
|
|
||||||
|
# 将模型名存入环境变量,供 router 使用
|
||||||
|
os.environ["DOUBAO_MODEL"] = model
|
||||||
|
|
||||||
|
# 创建全局客户端
|
||||||
|
client = AsyncArk(base_url=base_url, api_key=api_key)
|
||||||
|
set_ark_client(client)
|
||||||
|
|
||||||
|
# 委托给通用运行时创建 Worker 任务
|
||||||
|
return _create_workers(session, config, count, worker_manager)
|
||||||
|
|
||||||
|
async def cleanup(worker_item: str):
|
||||||
|
"""清理资源"""
|
||||||
|
cleanup_ark_client()
|
||||||
|
print(f"{worker_item} 清理完毕")
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
from typing import Optional
|
||||||
|
from volcenginesdkarkruntime import AsyncArk
|
||||||
|
|
||||||
|
_ark_client: Optional[AsyncArk] = None
|
||||||
|
|
||||||
|
def set_ark_client(client: AsyncArk):
|
||||||
|
global _ark_client
|
||||||
|
_ark_client = client
|
||||||
|
|
||||||
|
def get_ark_client() -> Optional[AsyncArk]:
|
||||||
|
return _ark_client
|
||||||
|
|
||||||
|
def cleanup_ark_client():
|
||||||
|
global _ark_client
|
||||||
|
if _ark_client:
|
||||||
|
# AsyncArk 无显式 close,但可设为 None
|
||||||
|
_ark_client = None
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
"""
|
||||||
|
模型导出 — doubao
|
||||||
|
自动生成,请勿手动修改
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .pydantic import AnalyzePostRequest
|
||||||
|
from .pydantic import AnalyzePostResponse
|
||||||
|
from .pydantic import DoubaoResponse
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"AnalyzePostRequest",
|
||||||
|
"AnalyzePostResponse",
|
||||||
|
"DoubaoResponse",
|
||||||
|
]
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
"""
|
||||||
|
自动生成的 Pydantic 模型 — doubao
|
||||||
|
来源: config/workers/doubao/
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any, Optional
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
class AnalyzePostRequest(BaseModel):
|
||||||
|
"""分析图片内容 — 请求体"""
|
||||||
|
image_base64: str = Field(...)
|
||||||
|
prompt: str = Field(...)
|
||||||
|
|
||||||
|
class AnalyzePostResponse(BaseModel):
|
||||||
|
"""分析图片内容 — 响应体"""
|
||||||
|
result: str = Field(...)
|
||||||
|
error: Optional[str] = Field(default='')
|
||||||
|
|
||||||
|
|
||||||
|
# 所有响应模型的联合类型
|
||||||
|
DoubaoResponse = AnalyzePostResponse
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
from .analyze import analyze
|
||||||
|
|
||||||
|
__all__ = ["analyze"]
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import os
|
||||||
|
from chongming_worker import rpc_method
|
||||||
|
from ..models.pydantic import AnalyzePostRequest, AnalyzePostResponse
|
||||||
|
from ..global_var import get_ark_client
|
||||||
|
|
||||||
|
@rpc_method(
|
||||||
|
subject="doubao.analyze",
|
||||||
|
method="POST",
|
||||||
|
summary="Analyze image via Doubao vision model",
|
||||||
|
response_model=AnalyzePostResponse,
|
||||||
|
)
|
||||||
|
async def analyze(request: AnalyzePostRequest) -> AnalyzePostResponse:
|
||||||
|
print(f"[DEBUG] analyze called with prompt={request.prompt}, image_base64 length={len(request.image_base64)}")
|
||||||
|
client = get_ark_client()
|
||||||
|
if client is None:
|
||||||
|
return AnalyzePostResponse(result="", error="客户端未初始化")
|
||||||
|
|
||||||
|
# 获取图片数据
|
||||||
|
image_base64 = request.image_base64
|
||||||
|
|
||||||
|
if not image_base64:
|
||||||
|
return AnalyzePostResponse(result="", error="未提供图片数据(image_base64或image_path)")
|
||||||
|
|
||||||
|
if image_base64.startswith('data:image/'):
|
||||||
|
image_base64 = image_base64.split(',', 1)[1]
|
||||||
|
|
||||||
|
mime_type = "image/png"
|
||||||
|
|
||||||
|
prompt = request.prompt or ""
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = await client.chat.completions.create(
|
||||||
|
model=os.getenv("DOUBAO_MODEL", "doubao-seed-evolving"),
|
||||||
|
messages=[
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": [
|
||||||
|
{"type": "image_url", "image_url": f"data:{mime_type};base64,{image_base64}"},
|
||||||
|
{"type": "text", "text": prompt}
|
||||||
|
]
|
||||||
|
} # type: ignore
|
||||||
|
],
|
||||||
|
thinking={"type": "disabled"}
|
||||||
|
)
|
||||||
|
result = response.choices[0].message.content # type: ignore
|
||||||
|
return AnalyzePostResponse(result=result) # type: ignore
|
||||||
|
except Exception as e:
|
||||||
|
return AnalyzePostResponse(result="", error=f"调用豆包API失败: {str(e)}")
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
"""
|
||||||
|
Example Worker 插件 — 演示 @rpc_method + 显式模型绑定用法
|
||||||
|
|
||||||
|
本插件展示如何使用 chongming_worker 框架定义 RPC 端点。
|
||||||
|
|
||||||
|
核心工作流:
|
||||||
|
1. 编写 config/workers/example/*.toml 配置文件
|
||||||
|
2. 执行 uv run gen_models 生成 Pydantic 模型
|
||||||
|
3. 在 __init__.py 中用 @rpc_method 定义业务函数
|
||||||
|
4. 显式导入模型并绑定到对应端点(替代 auto_bind_models)
|
||||||
|
|
||||||
|
关键约定:
|
||||||
|
- 模型命名: <Operation><Method>{Request|Response}
|
||||||
|
(如 AddGetRequest, AddGetResponse 由 gen_models 自动生成)
|
||||||
|
- 装饰器 subject 中的操作名 → 模型前缀(驼峰)
|
||||||
|
example.add → Add, example.subtract → Subtract
|
||||||
|
"""
|
||||||
|
import modelvault
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from chongming_worker import auto_bind_models
|
||||||
|
from chongming_worker.runtime import create_workers as _create_workers
|
||||||
|
|
||||||
|
from .router import *
|
||||||
|
|
||||||
|
auto_bind_models("example")
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 工厂函数 — 供 app lifespan 动态加载
|
||||||
|
# ============================================================
|
||||||
|
# 框架通过 __import__ + getattr 获取此函数,
|
||||||
|
# 然后调用 create_workers(session, config, count, worker_manager=worker_manager)。
|
||||||
|
# 详见 src/chongming/app/__init__.py 的 lifespan。
|
||||||
|
|
||||||
|
|
||||||
|
async def create_workers(session, config, count=1, worker_manager=None):
|
||||||
|
"""插件入口 — 委托给 chongming_worker 运行时创建 Worker 协程"""
|
||||||
|
from .global_var import set_global_var
|
||||||
|
|
||||||
|
db_path = Path(config.get("data_dir", "./data")) / "example.modelvault"
|
||||||
|
db_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
db = await modelvault.AsyncDatabase.open(str(db_path)) # type: ignore
|
||||||
|
set_global_var("db", db)
|
||||||
|
|
||||||
|
return _create_workers(session, config, count, worker_manager)
|
||||||
|
|
||||||
|
async def cleanup(worker_item: str):
|
||||||
|
print(f"{worker_item}关闭")
|
||||||
|
pass
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import sys
|
||||||
|
from typing import Any, Callable, Awaitable, List
|
||||||
|
import modelvault
|
||||||
|
|
||||||
|
# 初始定义(可以保留 db 作为示例)
|
||||||
|
db: modelvault.AsyncDatabase | None = None # type: ignore
|
||||||
|
|
||||||
|
def set_global_var(name: str, value: Any) -> None:
|
||||||
|
"""
|
||||||
|
设置当前模块的全局变量。
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: 变量名(字符串)
|
||||||
|
value: 任意值
|
||||||
|
"""
|
||||||
|
globals()[name] = value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 但这样会污染导出列表,不推荐自动添加。
|
||||||
|
__all__ = [
|
||||||
|
"db",
|
||||||
|
"set_global_var",
|
||||||
|
]
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
"""
|
||||||
|
模型导出 — example
|
||||||
|
自动生成,请勿手动修改
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .pydantic import AddGetRequest
|
||||||
|
from .pydantic import AddGetResponse
|
||||||
|
from .pydantic import AddPostRequest
|
||||||
|
from .pydantic import AddPostResponse
|
||||||
|
from .pydantic import CountGetResponse
|
||||||
|
from .pydantic import DivideGetRequest
|
||||||
|
from .pydantic import DivideGetResponse
|
||||||
|
from .pydantic import ExampleResponse
|
||||||
|
from .pydantic import MultiplyGetRequest
|
||||||
|
from .pydantic import MultiplyGetResponse
|
||||||
|
from .pydantic import SubtractGetRequest
|
||||||
|
from .pydantic import SubtractGetResponse
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"AddGetRequest",
|
||||||
|
"AddGetResponse",
|
||||||
|
"AddPostRequest",
|
||||||
|
"AddPostResponse",
|
||||||
|
"CountGetResponse",
|
||||||
|
"DivideGetRequest",
|
||||||
|
"DivideGetResponse",
|
||||||
|
"ExampleResponse",
|
||||||
|
"MultiplyGetRequest",
|
||||||
|
"MultiplyGetResponse",
|
||||||
|
"SubtractGetRequest",
|
||||||
|
"SubtractGetResponse",
|
||||||
|
]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# src/plugins/example/models/counter.py
|
||||||
|
from pydantic import BaseModel
|
||||||
|
import modelvault
|
||||||
|
|
||||||
|
class Counter(BaseModel):
|
||||||
|
# 主键字段
|
||||||
|
__modelvault_primary_key__ = "name"
|
||||||
|
# 唯一索引
|
||||||
|
__modelvault_indexes__ = [
|
||||||
|
modelvault.models.unique("name"),
|
||||||
|
]
|
||||||
|
|
||||||
|
name: str # 计数器名称(例如 "visits")
|
||||||
|
value: int = 0
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
"""
|
||||||
|
自动生成的 Pydantic 模型 — example
|
||||||
|
来源: config/workers/example/
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any, Optional
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
class AddGetRequest(BaseModel):
|
||||||
|
"""Add two numbers — 请求体"""
|
||||||
|
a: float = Field(...)
|
||||||
|
b: float = Field(...)
|
||||||
|
|
||||||
|
class AddGetResponse(BaseModel):
|
||||||
|
"""Add two numbers — 响应体"""
|
||||||
|
result: float = Field(...)
|
||||||
|
operation: str = Field(default='add')
|
||||||
|
timestamp: Optional[float] = Field(default=0.0)
|
||||||
|
|
||||||
|
class AddPostRequest(BaseModel):
|
||||||
|
"""Add two numbers (POST) — 请求体"""
|
||||||
|
a: float = Field(...)
|
||||||
|
b: float = Field(...)
|
||||||
|
|
||||||
|
class AddPostResponse(BaseModel):
|
||||||
|
"""Add two numbers (POST) — 响应体"""
|
||||||
|
result: float = Field(...)
|
||||||
|
operation: str = Field(default='add')
|
||||||
|
timestamp: Optional[float] = Field(default=0.0)
|
||||||
|
|
||||||
|
class CountGetResponse(BaseModel):
|
||||||
|
"""Get visit count and increment — 响应体"""
|
||||||
|
name: str = Field(...)
|
||||||
|
value: int = Field(...)
|
||||||
|
|
||||||
|
class DivideGetRequest(BaseModel):
|
||||||
|
"""Divide two numbers — 请求体"""
|
||||||
|
a: float = Field(...)
|
||||||
|
b: float = Field(...)
|
||||||
|
|
||||||
|
class DivideGetResponse(BaseModel):
|
||||||
|
"""Divide two numbers — 响应体"""
|
||||||
|
result: Optional[float] = Field(default=0.0)
|
||||||
|
operation: str = Field(default='divide')
|
||||||
|
timestamp: Optional[float] = Field(default=0.0)
|
||||||
|
error: Optional[str] = Field(default='')
|
||||||
|
|
||||||
|
class MultiplyGetRequest(BaseModel):
|
||||||
|
"""Multiply two numbers — 请求体"""
|
||||||
|
a: float = Field(...)
|
||||||
|
b: float = Field(...)
|
||||||
|
|
||||||
|
class MultiplyGetResponse(BaseModel):
|
||||||
|
"""Multiply two numbers — 响应体"""
|
||||||
|
result: float = Field(...)
|
||||||
|
operation: str = Field(default='multiply')
|
||||||
|
timestamp: Optional[float] = Field(default=0.0)
|
||||||
|
|
||||||
|
class SubtractGetRequest(BaseModel):
|
||||||
|
"""Subtract two numbers — 请求体"""
|
||||||
|
a: float = Field(...)
|
||||||
|
b: float = Field(...)
|
||||||
|
|
||||||
|
class SubtractGetResponse(BaseModel):
|
||||||
|
"""Subtract two numbers — 响应体"""
|
||||||
|
result: float = Field(...)
|
||||||
|
operation: str = Field(default='subtract')
|
||||||
|
timestamp: Optional[float] = Field(default=0.0)
|
||||||
|
|
||||||
|
|
||||||
|
# 所有响应模型的联合类型
|
||||||
|
ExampleResponse = SubtractGetResponse | CountGetResponse | MultiplyGetResponse | AddPostResponse | AddGetResponse | DivideGetResponse
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
from .add import add, add_post
|
||||||
|
from .subtract import subtract
|
||||||
|
from .multiply import multiply
|
||||||
|
from .divide import divide
|
||||||
|
from .count import count_get
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"add",
|
||||||
|
"add_post",
|
||||||
|
"subtract",
|
||||||
|
"multiply",
|
||||||
|
"divide",
|
||||||
|
"count_get"
|
||||||
|
]
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
import zenoh
|
||||||
|
|
||||||
|
from chongming_worker import rpc_method
|
||||||
|
from chongming_request import Client
|
||||||
|
|
||||||
|
from ..models.pydantic import (
|
||||||
|
AddGetRequest,
|
||||||
|
AddGetResponse,
|
||||||
|
AddPostRequest,
|
||||||
|
AddPostResponse
|
||||||
|
)
|
||||||
|
|
||||||
|
@rpc_method(
|
||||||
|
subject="example.add",
|
||||||
|
method="GET",
|
||||||
|
summary="Add two numbers via GET",
|
||||||
|
response_model=AddGetResponse,
|
||||||
|
)
|
||||||
|
async def add(add_get_request:AddGetRequest) -> AddGetResponse:
|
||||||
|
"""加法运算(GET)— 通过查询参数传入 a、b,返回它们的和"""
|
||||||
|
return AddGetResponse(
|
||||||
|
result=add_get_request.a + add_get_request.b,
|
||||||
|
operation="add",
|
||||||
|
timestamp=time.time()
|
||||||
|
)
|
||||||
|
|
||||||
|
@rpc_method(
|
||||||
|
subject="example.add",
|
||||||
|
method="POST",
|
||||||
|
summary="Add two numbers via POST",
|
||||||
|
response_model=AddPostResponse,
|
||||||
|
)
|
||||||
|
async def add_post(add_post_request: AddPostRequest, session: zenoh.Session) -> AddPostResponse:
|
||||||
|
"""加法运算(POST)— 通过 JSON Body 传入 a、b,返回它们的和"""
|
||||||
|
async with Client(session=session) as client:
|
||||||
|
add_result = await client.call(
|
||||||
|
worker_type="example",
|
||||||
|
subject="example.add",
|
||||||
|
payload={
|
||||||
|
"a":add_post_request.a,
|
||||||
|
"b":add_post_request.b
|
||||||
|
},
|
||||||
|
method="GET"
|
||||||
|
)
|
||||||
|
print(add_result)
|
||||||
|
return AddPostResponse(
|
||||||
|
result=add_post_request.a + add_post_request.b,
|
||||||
|
operation="add",
|
||||||
|
timestamp=time.time(),
|
||||||
|
)
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import modelvault
|
||||||
|
|
||||||
|
from chongming_worker import rpc_method
|
||||||
|
|
||||||
|
from ..models.pydantic import CountGetResponse
|
||||||
|
from ..models.counter import Counter
|
||||||
|
|
||||||
|
|
||||||
|
@rpc_method(
|
||||||
|
subject="example.count",
|
||||||
|
method="GET",
|
||||||
|
summary="Increment and get counter value",
|
||||||
|
response_model=CountGetResponse, # 需要定义 CountResponse
|
||||||
|
)
|
||||||
|
async def count_get() -> CountGetResponse:
|
||||||
|
from ..global_var import db
|
||||||
|
|
||||||
|
# 确保数据库已初始化(如果未初始化,则同步初始化,但这里假设已就绪)
|
||||||
|
if db is None:
|
||||||
|
raise RuntimeError("Database not initialized")
|
||||||
|
|
||||||
|
counters = modelvault.models.async_collection(db, Counter) # type: ignore
|
||||||
|
async with db.transaction():
|
||||||
|
counter = await counters.get("visits")
|
||||||
|
if counter is None:
|
||||||
|
counter = Counter(name="visits", value=0)
|
||||||
|
await counters.insert(counter)
|
||||||
|
else:
|
||||||
|
new_value = counter.value + 1
|
||||||
|
await counters.update("visits", {"value": new_value})
|
||||||
|
counter.value = new_value # 更新本地对象以便返回
|
||||||
|
|
||||||
|
return CountGetResponse(name=counter.name, value=counter.value) # type: ignore
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
from chongming_worker import rpc_method
|
||||||
|
|
||||||
|
from ..models.pydantic import (
|
||||||
|
DivideGetResponse,
|
||||||
|
DivideGetRequest,
|
||||||
|
)
|
||||||
|
|
||||||
|
@rpc_method(
|
||||||
|
subject="example.divide",
|
||||||
|
method="GET",
|
||||||
|
summary="Divide two numbers",
|
||||||
|
response_model=DivideGetResponse,
|
||||||
|
)
|
||||||
|
async def divide(divide_get_request: DivideGetRequest) -> DivideGetResponse:
|
||||||
|
"""除法运算:a / b(b 不能为 0)"""
|
||||||
|
if divide_get_request.b == 0:
|
||||||
|
return DivideGetResponse(
|
||||||
|
error="除数不能为零",
|
||||||
|
operation="divide",
|
||||||
|
result=0.0,
|
||||||
|
timestamp=time.time(),
|
||||||
|
)
|
||||||
|
return DivideGetResponse(
|
||||||
|
result=divide_get_request.a / divide_get_request.b,
|
||||||
|
operation="divide",
|
||||||
|
timestamp=time.time(),
|
||||||
|
)
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
from chongming_worker import rpc_method
|
||||||
|
|
||||||
|
from ..models.pydantic import (
|
||||||
|
MultiplyGetRequest,
|
||||||
|
MultiplyGetResponse,
|
||||||
|
)
|
||||||
|
|
||||||
|
@rpc_method(
|
||||||
|
subject="example.multiply",
|
||||||
|
method="GET",
|
||||||
|
summary="Multiply two numbers",
|
||||||
|
response_model=MultiplyGetResponse,
|
||||||
|
)
|
||||||
|
async def multiply(multiply_get_request=MultiplyGetRequest) -> MultiplyGetResponse:
|
||||||
|
"""乘法运算:a * b"""
|
||||||
|
return MultiplyGetResponse(
|
||||||
|
result=multiply_get_request.a * multiply_get_request.b,
|
||||||
|
operation="multiply",
|
||||||
|
timestamp=time.time(),
|
||||||
|
)
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
from chongming_worker import rpc_method
|
||||||
|
|
||||||
|
from ..models.pydantic import (
|
||||||
|
SubtractGetResponse,
|
||||||
|
SubtractGetRequest,
|
||||||
|
)
|
||||||
|
|
||||||
|
@rpc_method(
|
||||||
|
subject="example.subtract",
|
||||||
|
method="GET",
|
||||||
|
summary="Subtract two numbers",
|
||||||
|
response_model=SubtractGetResponse,
|
||||||
|
)
|
||||||
|
async def subtract(subtract_get_request: SubtractGetRequest) -> SubtractGetResponse:
|
||||||
|
"""减法运算:a - b"""
|
||||||
|
return SubtractGetResponse(
|
||||||
|
result=subtract_get_request.a - subtract_get_request.b,
|
||||||
|
operation="subtract",
|
||||||
|
timestamp=time.time(),
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user