feat(embedding): 支持 OpenAI 兼容 API 并增强错误处理
- 更新 OpenAI 提供商描述以支持兼容 API 服务商 - 前端添加兼容 API 使用引导说明 - 后端 QwenEmbedding 添加 API 密钥验证和错误处理
This commit is contained in:
parent
9eddef589a
commit
4d7abae245
|
|
@ -76,8 +76,8 @@ class TestEmbeddingResponse(BaseModel):
|
|||
EMBEDDING_PROVIDERS: List[EmbeddingProvider] = [
|
||||
EmbeddingProvider(
|
||||
id="openai",
|
||||
name="OpenAI",
|
||||
description="OpenAI 官方嵌入模型,高质量、稳定",
|
||||
name="OpenAI (兼容 DeepSeek/Moonshot/智谱 等)",
|
||||
description="OpenAI 官方或兼容 API,填写自定义端点可接入其他服务商",
|
||||
models=[
|
||||
"text-embedding-3-small",
|
||||
"text-embedding-3-large",
|
||||
|
|
|
|||
|
|
@ -486,6 +486,12 @@ class QwenEmbedding(EmbeddingProvider):
|
|||
or getattr(settings, "QWEN_API_KEY", None)
|
||||
or settings.LLM_API_KEY
|
||||
)
|
||||
# 🔥 API 密钥验证
|
||||
if not self.api_key:
|
||||
raise ValueError(
|
||||
"Qwen embedding requires API key. "
|
||||
"Set EMBEDDING_API_KEY, QWEN_API_KEY or LLM_API_KEY environment variable."
|
||||
)
|
||||
# DashScope 兼容 OpenAI 的 embeddings 端点
|
||||
self.base_url = base_url or "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||
self.model = model
|
||||
|
|
@ -520,23 +526,33 @@ class QwenEmbedding(EmbeddingProvider):
|
|||
|
||||
url = f"{self.base_url.rstrip('/')}/embeddings"
|
||||
|
||||
async with httpx.AsyncClient(timeout=60) as client:
|
||||
response = await client.post(url, headers=headers, json=payload)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=60) as client:
|
||||
response = await client.post(url, headers=headers, json=payload)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
usage = data.get("usage", {}) or {}
|
||||
total_tokens = usage.get("total_tokens") or usage.get("prompt_tokens") or 0
|
||||
usage = data.get("usage", {}) or {}
|
||||
total_tokens = usage.get("total_tokens") or usage.get("prompt_tokens") or 0
|
||||
|
||||
results: List[EmbeddingResult] = []
|
||||
for item in data.get("data", []):
|
||||
results.append(EmbeddingResult(
|
||||
embedding=item["embedding"],
|
||||
tokens_used=total_tokens // max(len(texts), 1),
|
||||
model=self.model,
|
||||
))
|
||||
results: List[EmbeddingResult] = []
|
||||
for item in data.get("data", []):
|
||||
results.append(EmbeddingResult(
|
||||
embedding=item["embedding"],
|
||||
tokens_used=total_tokens // max(len(texts), 1),
|
||||
model=self.model,
|
||||
))
|
||||
|
||||
return results
|
||||
return results
|
||||
except httpx.HTTPStatusError as e:
|
||||
logger.error(f"Qwen embedding API error: {e.response.status_code} - {e.response.text}")
|
||||
raise RuntimeError(f"Qwen embedding API failed: {e.response.status_code}") from e
|
||||
except httpx.RequestError as e:
|
||||
logger.error(f"Qwen embedding network error: {e}")
|
||||
raise RuntimeError(f"Qwen embedding network error: {e}") from e
|
||||
except Exception as e:
|
||||
logger.error(f"Qwen embedding unexpected error: {e}")
|
||||
raise RuntimeError(f"Qwen embedding failed: {e}") from e
|
||||
|
||||
|
||||
class EmbeddingService:
|
||||
|
|
|
|||
|
|
@ -434,7 +434,7 @@ export default function EmbeddingConfigPanel() {
|
|||
</div>
|
||||
|
||||
{/* 说明 */}
|
||||
<div className="bg-muted border border-border p-4 rounded-lg text-xs space-y-2">
|
||||
<div className="bg-muted border border-border p-4 rounded-lg text-xs space-y-3">
|
||||
<p className="font-bold uppercase text-muted-foreground flex items-center gap-2">
|
||||
<Info className="w-4 h-4 text-sky-400" />
|
||||
关于嵌入模型
|
||||
|
|
@ -445,6 +445,25 @@ export default function EmbeddingConfigPanel() {
|
|||
<li>• 推荐使用 <span className="text-foreground">OpenAI text-embedding-3-small</span> 或本地 <span className="text-foreground">Ollama</span></li>
|
||||
<li>• 向量维度影响存储空间和检索精度</li>
|
||||
</ul>
|
||||
|
||||
{/* OpenAI 兼容 API 引导 */}
|
||||
<div className="mt-3 pt-3 border-t border-border/50">
|
||||
<p className="font-bold text-amber-400 flex items-center gap-2 mb-2">
|
||||
<Zap className="w-4 h-4" />
|
||||
使用 OpenAI 兼容 API
|
||||
</p>
|
||||
<p className="text-muted-foreground mb-2">
|
||||
许多服务商提供 OpenAI 兼容的 API,可以直接使用 <span className="text-foreground">openai</span> 作为提供商:
|
||||
</p>
|
||||
<ul className="text-muted-foreground space-y-1 ml-4">
|
||||
<li>• <span className="text-foreground">DeepSeek</span>: 端点填写 <code className="text-primary bg-primary/10 px-1 rounded">https://api.deepseek.com/v1</code></li>
|
||||
<li>• <span className="text-foreground">Moonshot</span>: 端点填写 <code className="text-primary bg-primary/10 px-1 rounded">https://api.moonshot.cn/v1</code></li>
|
||||
<li>• <span className="text-foreground">智谱 GLM</span>: 端点填写 <code className="text-primary bg-primary/10 px-1 rounded">https://open.bigmodel.cn/api/paas/v4</code></li>
|
||||
</ul>
|
||||
<p className="text-muted-foreground mt-2 text-[11px]">
|
||||
提示:选择 openai 提供商,填入对应服务的 API Key 和自定义端点即可
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue