feat(embedding): 支持 OpenAI 兼容 API 并增强错误处理

- 更新 OpenAI 提供商描述以支持兼容 API 服务商
- 前端添加兼容 API 使用引导说明
- 后端 QwenEmbedding 添加 API 密钥验证和错误处理
This commit is contained in:
lintsinghua 2025-12-19 16:37:39 +08:00
parent 9eddef589a
commit 4d7abae245
3 changed files with 60 additions and 25 deletions

View File

@ -76,8 +76,8 @@ class TestEmbeddingResponse(BaseModel):
EMBEDDING_PROVIDERS: List[EmbeddingProvider] = [ EMBEDDING_PROVIDERS: List[EmbeddingProvider] = [
EmbeddingProvider( EmbeddingProvider(
id="openai", id="openai",
name="OpenAI", name="OpenAI (兼容 DeepSeek/Moonshot/智谱 等)",
description="OpenAI 官方嵌入模型,高质量、稳定", description="OpenAI 官方或兼容 API填写自定义端点可接入其他服务商",
models=[ models=[
"text-embedding-3-small", "text-embedding-3-small",
"text-embedding-3-large", "text-embedding-3-large",

View File

@ -486,6 +486,12 @@ class QwenEmbedding(EmbeddingProvider):
or getattr(settings, "QWEN_API_KEY", None) or getattr(settings, "QWEN_API_KEY", None)
or settings.LLM_API_KEY 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 端点 # DashScope 兼容 OpenAI 的 embeddings 端点
self.base_url = base_url or "https://dashscope.aliyuncs.com/compatible-mode/v1" self.base_url = base_url or "https://dashscope.aliyuncs.com/compatible-mode/v1"
self.model = model self.model = model
@ -520,6 +526,7 @@ class QwenEmbedding(EmbeddingProvider):
url = f"{self.base_url.rstrip('/')}/embeddings" url = f"{self.base_url.rstrip('/')}/embeddings"
try:
async with httpx.AsyncClient(timeout=60) as client: async with httpx.AsyncClient(timeout=60) as client:
response = await client.post(url, headers=headers, json=payload) response = await client.post(url, headers=headers, json=payload)
response.raise_for_status() response.raise_for_status()
@ -537,6 +544,15 @@ class QwenEmbedding(EmbeddingProvider):
)) ))
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: class EmbeddingService:

View File

@ -434,7 +434,7 @@ export default function EmbeddingConfigPanel() {
</div> </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"> <p className="font-bold uppercase text-muted-foreground flex items-center gap-2">
<Info className="w-4 h-4 text-sky-400" /> <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> 使 <span className="text-foreground">OpenAI text-embedding-3-small</span> <span className="text-foreground">Ollama</span></li>
<li> </li> <li> </li>
</ul> </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>
</div> </div>
); );