fix(#188): 推理 API 路径规范化,消除双 /v1 前缀对 nginx rewrite 的隐式依赖
问题:infer.ts BASE_URL=/v1,fetchModels/chatCompletion 再拼 /v1/* 导致 /v1/v1 双前缀,当前仅靠 nginx 对 /v1/ rewrite 去前缀巧合耦合才通。 修复(前后端+部署一起改): 1. nginx-fba.conf:新增 location /v1/,proxy_pass http://127.0.0.1:30800/ (带末尾 /,不去前缀直接透传),消除对 rewrite 的隐式依赖。 2. infer.ts:BASE_URL 改为空串,调用方统一写 /v1/models、 /v1/chat/completions、/v1/health(fetchHealth 原误用 /health 已修正)。 3. cockpit/index.vue:健康检查改走 infer.ts 的 fetchHealth 封装, 不再裸 fetch('/v1/health'),路径口径统一。 4. ask() latencyMs 由硬编码 0 改为 performance.now() 实测耗时。 5. README 补充推理通道路径约定说明。 验收:浏览器 Network 确认 /v1/models、/v1/chat/completions、 /v1/health 均 200 且无 /v1/v1 请求。(本环境无 pnpm,构建验证转 bot_qa)
This commit is contained in:
@@ -8,8 +8,12 @@
|
||||
*
|
||||
* 推理服务为 iAOP 独立通道(不要求 FBA JWT),故用原生 fetch 封装,
|
||||
* 统一超时 / 错误信息 / 结果结构;FBA requestClient 仅用于 /fba/* 接口。
|
||||
*
|
||||
* issue #188:推理服务真实路径即 :30800/v1/*,nginx 反代 /v1/ 不去前缀直接透传,
|
||||
* 故 BASE_URL 为空串,调用方统一写 /v1/models、/v1/chat/completions,
|
||||
* 避免出现 /v1/v1 双前缀对 nginx rewrite 的隐式耦合。
|
||||
*/
|
||||
const BASE_URL = '/v1';
|
||||
const BASE_URL = '';
|
||||
const TIMEOUT_MS = 15000;
|
||||
|
||||
export interface InferResult {
|
||||
@@ -61,7 +65,7 @@ async function fetchJson<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
/** 健康巡检(前端徽标展示;失败不抛出,由调用方降级) */
|
||||
export async function fetchHealth(): Promise<Record<string, unknown> | null> {
|
||||
try {
|
||||
return await fetchJson<Record<string, unknown>>('/health');
|
||||
return await fetchJson<Record<string, unknown>>('/v1/health');
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
@@ -92,12 +96,14 @@ export async function chatCompletion(
|
||||
|
||||
/** 便捷:返回纯文本(B 系列页面统一使用) */
|
||||
export async function ask(prompt: string, opts?: Parameters<typeof chatCompletion>[1]): Promise<InferResult> {
|
||||
// issue #188:用 performance.now() 实测耗时,替代原先 latencyMs: 0 硬编码
|
||||
const startedAt = performance.now();
|
||||
const resp = await chatCompletion(prompt, opts);
|
||||
const msg = resp.choices?.[0]?.message?.content || '';
|
||||
return {
|
||||
text: msg,
|
||||
meta: (resp.meta as Record<string, unknown>) || {},
|
||||
backend: String((resp.meta as Record<string, unknown>)?.backend || 'gpu'),
|
||||
latencyMs: 0,
|
||||
latencyMs: Math.round(performance.now() - startedAt),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { onMounted, onUnmounted, ref } from 'vue';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import { fetchHealth } from '#/api/iaop/infer';
|
||||
import { loadCockpitPlan } from '#/api/iaop/templates';
|
||||
|
||||
import AlarmPanel from './components/AlarmPanel.vue';
|
||||
@@ -53,13 +54,10 @@ onUnmounted(() => window.clearInterval(timer));
|
||||
|
||||
const inferOnline = ref(false);
|
||||
async function refreshHealth() {
|
||||
try {
|
||||
const resp = await fetch('/v1/health', { signal: AbortSignal.timeout(3000) });
|
||||
const d = await resp.json();
|
||||
inferOnline.value = d.status === 'ok' || d.status === 'dry-run';
|
||||
} catch {
|
||||
inferOnline.value = false;
|
||||
}
|
||||
// issue #188:健康检查改走 infer.ts 的 fetchHealth 封装,路径口径统一(/v1/health)
|
||||
const d = await fetchHealth();
|
||||
const status = d?.status;
|
||||
inferOnline.value = status === 'ok' || status === 'dry-run';
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user