- 后端新增豆包(火山引擎Ark)API集成:DoubaoController、ToolDoubaoServiceImpl, 使用OkHttp3 SSE流式对话,兼容OpenAI Chat Completions格式 - 新增DoubaoConfig配置类,读取doubao.api.*配置 - 在eb_system_config表新增ai_chat_model配置项,支持doubao/coze/gemini三种模型切换 - 新增GET /api/front/doubao/ai-model-config接口供前端读取当前模型配置 - 前端ai-nutritionist.vue的sendToAI按系统配置分发到_sendViaDoubao/_sendViaCoze/_sendViaGemini - 前端models-api.js新增doubaoChatStream/doubaoChat/getAiModelConfig函数 - 附带豆包API测试脚本和数据库初始化SQL Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
145 lines
4.4 KiB
Bash
145 lines
4.4 KiB
Bash
#!/bin/bash
|
||
# 豆包 API 连通性测试脚本
|
||
# 用法: bash test-doubao-api.sh
|
||
|
||
API_KEY="18480c26-ebcd-4263-8a6f-48359b8bd65d"
|
||
BASE_URL="https://ark.cn-beijing.volces.com/api/v3"
|
||
MODEL="doubao-seed-2-0-pro-260215"
|
||
|
||
echo "============================================"
|
||
echo " 豆包(火山引擎 Ark)API 测试"
|
||
echo "============================================"
|
||
echo ""
|
||
|
||
# ---- 测试 1: 非流式调用 ----
|
||
echo "【测试 1】非流式调用"
|
||
echo "请求: 你好,请用一句话介绍你自己"
|
||
echo "---"
|
||
|
||
START=$(date +%s%3N 2>/dev/null || python3 -c "import time; print(int(time.time()*1000))")
|
||
|
||
RESPONSE=$(curl -s -w "\n---HTTP_CODE:%{http_code}---" \
|
||
-X POST "${BASE_URL}/chat/completions" \
|
||
-H "Content-Type: application/json" \
|
||
-H "Authorization: Bearer ${API_KEY}" \
|
||
-d "{
|
||
\"model\": \"${MODEL}\",
|
||
\"messages\": [{\"role\": \"user\", \"content\": \"你好,请用一句话介绍你自己\"}],
|
||
\"stream\": false
|
||
}" 2>&1)
|
||
|
||
END=$(date +%s%3N 2>/dev/null || python3 -c "import time; print(int(time.time()*1000))")
|
||
ELAPSED=$((END - START))
|
||
|
||
HTTP_CODE=$(echo "$RESPONSE" | grep -oP '(?<=---HTTP_CODE:)\d+(?=---)')
|
||
BODY=$(echo "$RESPONSE" | sed 's/---HTTP_CODE:[0-9]*---//')
|
||
|
||
echo "HTTP 状态码: ${HTTP_CODE}"
|
||
echo "耗时: ${ELAPSED} ms"
|
||
|
||
if [ "$HTTP_CODE" = "200" ]; then
|
||
# 提取回复内容
|
||
CONTENT=$(echo "$BODY" | python3 -c "
|
||
import sys, json
|
||
data = json.load(sys.stdin)
|
||
choices = data.get('choices', [])
|
||
if choices:
|
||
print('回复:', choices[0].get('message', {}).get('content', '(empty)'))
|
||
usage = data.get('usage', {})
|
||
print(f'Token: prompt={usage.get(\"prompt_tokens\",0)}, completion={usage.get(\"completion_tokens\",0)}, total={usage.get(\"total_tokens\",0)}')
|
||
print(f'模型: {data.get(\"model\", \"?\")}')
|
||
" 2>&1)
|
||
echo "$CONTENT"
|
||
else
|
||
echo "错误响应: $BODY"
|
||
fi
|
||
|
||
echo ""
|
||
echo ""
|
||
|
||
# ---- 测试 2: 流式调用 ----
|
||
echo "【测试 2】流式调用 (SSE)"
|
||
echo "请求: 简单说一下健康饮食的三个要点"
|
||
echo "---"
|
||
|
||
START2=$(date +%s%3N 2>/dev/null || python3 -c "import time; print(int(time.time()*1000))")
|
||
|
||
# 流式请求,逐行输出
|
||
STREAM_OUTPUT=""
|
||
FIRST_CHUNK_TIME=""
|
||
|
||
curl -s -N \
|
||
-X POST "${BASE_URL}/chat/completions" \
|
||
-H "Content-Type: application/json" \
|
||
-H "Authorization: Bearer ${API_KEY}" \
|
||
-d "{
|
||
\"model\": \"${MODEL}\",
|
||
\"messages\": [{\"role\": \"user\", \"content\": \"简单说一下健康饮食的三个要点,每个要点一句话\"}],
|
||
\"stream\": true
|
||
}" 2>/dev/null | while IFS= read -r line; do
|
||
if [[ "$line" == data:* ]]; then
|
||
JSON_DATA="${line#data: }"
|
||
if [ "$JSON_DATA" = "[DONE]" ]; then
|
||
break
|
||
fi
|
||
# 提取 delta content
|
||
DELTA=$(echo "$JSON_DATA" | python3 -c "
|
||
import sys, json
|
||
try:
|
||
d = json.load(sys.stdin)
|
||
c = d.get('choices',[{}])[0].get('delta',{}).get('content','')
|
||
if c: print(c, end='', flush=True)
|
||
except: pass
|
||
" 2>/dev/null)
|
||
if [ -z "$FIRST_CHUNK_TIME" ] && [ -n "$DELTA" ]; then
|
||
FIRST_CHUNK_TIME=$(date +%s%3N 2>/dev/null || python3 -c "import time; print(int(time.time()*1000))")
|
||
fi
|
||
fi
|
||
done
|
||
|
||
END2=$(date +%s%3N 2>/dev/null || python3 -c "import time; print(int(time.time()*1000))")
|
||
ELAPSED2=$((END2 - START2))
|
||
|
||
echo ""
|
||
echo "---"
|
||
echo "流式总耗时: ${ELAPSED2} ms"
|
||
|
||
echo ""
|
||
echo ""
|
||
|
||
# ---- 测试 3: 通过后端接口调用(需先启动后端服务) ----
|
||
echo "【测试 3】通过后端接口调用(需后端服务运行中)"
|
||
echo "请确认后端已启动,默认地址: http://localhost:8081"
|
||
echo "---"
|
||
|
||
BACKEND_URL="http://localhost:8081/api/front/doubao/chat"
|
||
|
||
RESP3=$(curl -s -w "\n---HTTP_CODE:%{http_code}---" \
|
||
-X POST "${BACKEND_URL}" \
|
||
-H "Content-Type: application/json" \
|
||
-d "{
|
||
\"messages\": [{\"role\": \"user\", \"content\": \"你好\"}]
|
||
}" 2>&1)
|
||
|
||
HTTP3=$(echo "$RESP3" | grep -oP '(?<=---HTTP_CODE:)\d+(?=---)')
|
||
BODY3=$(echo "$RESP3" | sed 's/---HTTP_CODE:[0-9]*---//')
|
||
|
||
if [ "$HTTP3" = "200" ]; then
|
||
echo "后端接口调用成功! HTTP $HTTP3"
|
||
echo "$BODY3" | python3 -c "
|
||
import sys, json
|
||
data = json.load(sys.stdin)
|
||
choices = data.get('choices', [])
|
||
if choices:
|
||
print('回复:', choices[0].get('message', {}).get('content', '(empty)')[:100])
|
||
" 2>&1
|
||
else
|
||
echo "后端接口调用失败: HTTP ${HTTP3:-连接失败}"
|
||
echo "(如果后端未启动,这是正常的)"
|
||
fi
|
||
|
||
echo ""
|
||
echo "============================================"
|
||
echo " 测试完成"
|
||
echo "============================================"
|