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] = [
|
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",
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue