modify: aibox_sophon_adapter plugins
This commit is contained in:
+62
-21
@@ -1,38 +1,79 @@
|
||||
# Doubao Worker 插件
|
||||
|
||||
火山引擎豆包(Doubao)视觉理解模型集成,支持图像分析。
|
||||
火山引擎豆包(Doubao)视觉理解模型集成,支持图像分析与描述生成。
|
||||
|
||||
---
|
||||
|
||||
## 功能
|
||||
|
||||
- 接收 base64 编码的图片和提示词
|
||||
- 调用火山引擎豆包视觉模型(支持思考模式)
|
||||
- 返回模型描述结果
|
||||
- 接收 **base64 编码**的图片和**提示词**(prompt)
|
||||
- 调用火山引擎豆包视觉模型 API
|
||||
- 支持**思考模式**(thinking mode),模型会先推理再输出结果
|
||||
- 返回模型生成的图像描述文本
|
||||
|
||||
---
|
||||
|
||||
## 配置
|
||||
|
||||
在 `config/workers/doubao/config.toml` 中设置:
|
||||
在 `config/workers/doubao/config.toml` 和 `config/workers/config.toml` 中设置:
|
||||
|
||||
- `api_key`:火山引擎 API Key(也可通过环境变量 `VOLC_ACCESSKEY` 提供)
|
||||
- `base_url`:API 端点(默认 `https://ark.cn-beijing.volces.com/api/v3`)
|
||||
- `model`:模型名称(如 `doubao-seed-evolving`)
|
||||
|
||||
## 调用示例
|
||||
|
||||
```http
|
||||
POST /api/v1/doubao/analyze
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"image_base64": "data:image/png;base64,iVBORw0KG...",
|
||||
"prompt": "描述这个图片的内容"
|
||||
}
|
||||
```toml
|
||||
[workers.config]
|
||||
type = "doubao"
|
||||
api_key = "<your-api-key>" # 火山引擎 API Key(也可通过环境变量 VOLC_ACCESSKEY 提供)
|
||||
base_url = "https://ark.cn-beijing.volces.com/api/v3" # API 端点
|
||||
model = "doubao-seed-evolving" # 模型名称
|
||||
```
|
||||
|
||||
响应示例:
|
||||
---
|
||||
|
||||
## API 端点
|
||||
|
||||
### `POST /doubao/analyze` — 图像分析
|
||||
|
||||
```json
|
||||
// 请求
|
||||
{
|
||||
"result": "图片中是一只猫坐在沙发上...",
|
||||
"image_base64": "data:image/png;base64,iVBORw0KGgoAAAANS...",
|
||||
"prompt": "描述这张图片的内容"
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
"result": "图片中是一只橘猫坐在米色沙发上,阳光从窗户照进来...",
|
||||
"error": ""
|
||||
}
|
||||
```
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| -------------- | ----- | ---- | ----------------------------------------------------------- |
|
||||
| `image_base64` | `str` | ✅ | Base64 编码的图片数据(可含 `data:image/...;base64,` 前缀) |
|
||||
| `prompt` | `str` | ✅ | 给模型的提示词,描述期望的分析内容 |
|
||||
|
||||
---
|
||||
|
||||
## 支持的模型
|
||||
|
||||
| 模型 | 说明 |
|
||||
| ---------------------- | ---------------------------- |
|
||||
| `doubao-seed-evolving` | 豆包视觉理解旗舰模型(默认) |
|
||||
|
||||
可根据火山引擎最新文档更换 `model` 配置项。
|
||||
|
||||
---
|
||||
|
||||
## 实现细节
|
||||
|
||||
- 使用 `httpx` 异步 HTTP 客户端调用火山引擎 API
|
||||
- 支持流式响应(streaming)中的思考模式 token
|
||||
- API Key 优先从环境变量 `VOLC_ACCESSKEY` 读取
|
||||
- 超时时间默认 30 秒,在 `config.toml` 的 `defaults.timeout` 中配置
|
||||
|
||||
---
|
||||
|
||||
## 依赖
|
||||
|
||||
| 工具包 | 用途 |
|
||||
| ------------------ | ------------------------------------ |
|
||||
| `httpx` | 异步 HTTP 客户端 |
|
||||
| `chongming-worker` | `@rpc_method` 装饰器 + Worker 运行时 |
|
||||
|
||||
+30
-9
@@ -2,10 +2,14 @@
|
||||
豆包视觉理解 Worker 插件
|
||||
"""
|
||||
import os
|
||||
from openai import AsyncOpenAI
|
||||
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 .global_var import (
|
||||
set_ark_client, set_aicc_client, set_is_aicc,
|
||||
cleanup_all,
|
||||
)
|
||||
from .router import *
|
||||
|
||||
# 自动绑定 gen_models 生成的 Pydantic 模型
|
||||
@@ -15,25 +19,42 @@ async def create_workers(session, config, count=1, worker_manager=None):
|
||||
"""
|
||||
工厂函数:由 app 生命周期调用,创建 Worker 协程。
|
||||
"""
|
||||
# 从配置或环境变量获取 API Key
|
||||
is_aicc = config.get("is_aicc", False)
|
||||
set_is_aicc(is_aicc)
|
||||
|
||||
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)
|
||||
if is_aicc:
|
||||
# AICC 模式:懒加载,避免非 AICC 环境导入失败
|
||||
from bytedance.volcengine_aicc_sdk.secure_http_client import (
|
||||
AICCConfig, AsyncSecureHttpClient,
|
||||
)
|
||||
|
||||
base_url = config.get("base_url", "https://ark.cn-beijing.volces.com/api/v3")
|
||||
os.environ["DOUBAO_BASE_URL"] = base_url
|
||||
|
||||
aicc_config = AICCConfig(ra_url=base_url, auth_token=api_key)
|
||||
client = AsyncOpenAI(
|
||||
api_key=api_key,
|
||||
base_url=base_url,
|
||||
http_client=AsyncSecureHttpClient(aicc_config=aicc_config),
|
||||
)
|
||||
set_aicc_client(client)
|
||||
else:
|
||||
# Ark 模式:使用 AsyncArk
|
||||
base_url = config.get("base_url", "https://ark.cn-beijing.volces.com/api/v3")
|
||||
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()
|
||||
cleanup_all()
|
||||
print(f"{worker_item} 清理完毕")
|
||||
+34
-3
@@ -1,7 +1,10 @@
|
||||
from typing import Optional
|
||||
from typing import Optional, Union
|
||||
from volcenginesdkarkruntime import AsyncArk
|
||||
from openai import AsyncOpenAI
|
||||
|
||||
_ark_client: Optional[AsyncArk] = None
|
||||
_aicc_client: Optional[AsyncOpenAI] = None
|
||||
_is_aicc: bool = False
|
||||
|
||||
def set_ark_client(client: AsyncArk):
|
||||
global _ark_client
|
||||
@@ -10,8 +13,36 @@ def set_ark_client(client: AsyncArk):
|
||||
def get_ark_client() -> Optional[AsyncArk]:
|
||||
return _ark_client
|
||||
|
||||
def set_aicc_client(client: AsyncOpenAI):
|
||||
global _aicc_client
|
||||
_aicc_client = client
|
||||
|
||||
def get_aicc_client() -> Optional[AsyncOpenAI]:
|
||||
return _aicc_client
|
||||
|
||||
def set_is_aicc(value: bool):
|
||||
global _is_aicc
|
||||
_is_aicc = value
|
||||
|
||||
def get_is_aicc() -> bool:
|
||||
return _is_aicc
|
||||
|
||||
def get_client() -> Union[AsyncArk, AsyncOpenAI, None]:
|
||||
"""返回当前活跃的客户端(AICC 或 Ark)"""
|
||||
if _is_aicc:
|
||||
return _aicc_client
|
||||
return _ark_client
|
||||
|
||||
def cleanup_ark_client():
|
||||
global _ark_client
|
||||
if _ark_client:
|
||||
# AsyncArk 无显式 close,但可设为 None
|
||||
_ark_client = None
|
||||
_ark_client = None
|
||||
|
||||
def cleanup_aicc_client():
|
||||
global _aicc_client
|
||||
if _aicc_client:
|
||||
_aicc_client = None
|
||||
|
||||
def cleanup_all():
|
||||
cleanup_ark_client()
|
||||
cleanup_aicc_client()
|
||||
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
from chongming_worker import rpc_method
|
||||
from ..models.pydantic import AnalyzePostRequest, AnalyzePostResponse
|
||||
from ..global_var import get_ark_client
|
||||
from ..global_var import get_client, get_is_aicc
|
||||
|
||||
@rpc_method(
|
||||
subject="doubao.analyze",
|
||||
@@ -11,7 +11,7 @@ from ..global_var import get_ark_client
|
||||
)
|
||||
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()
|
||||
client = get_client()
|
||||
if client is None:
|
||||
return AnalyzePostResponse(result="", error="客户端未初始化")
|
||||
|
||||
@@ -29,6 +29,12 @@ async def analyze(request: AnalyzePostRequest) -> AnalyzePostResponse:
|
||||
prompt = request.prompt or ""
|
||||
|
||||
try:
|
||||
# AICC 模式的 AsyncOpenAI 不支持 thinking 参数,需通过 extra_body 传递
|
||||
if get_is_aicc():
|
||||
create_kwargs = {"extra_body": {"thinking": {"type": "disabled"}}}
|
||||
else:
|
||||
create_kwargs = {"thinking": {"type": "disabled"}}
|
||||
|
||||
response = await client.chat.completions.create(
|
||||
model=os.getenv("DOUBAO_MODEL", "doubao-seed-evolving"),
|
||||
messages=[
|
||||
@@ -40,7 +46,7 @@ async def analyze(request: AnalyzePostRequest) -> AnalyzePostResponse:
|
||||
]
|
||||
} # type: ignore
|
||||
],
|
||||
thinking={"type": "disabled"}
|
||||
**create_kwargs # type: ignore
|
||||
)
|
||||
result = response.choices[0].message.content # type: ignore
|
||||
return AnalyzePostResponse(result=result) # type: ignore
|
||||
|
||||
Reference in New Issue
Block a user