Files
prop-ai-hr/mobile-uni/src/services/web-ai.ts
T

89 lines
2.5 KiB
TypeScript

import type { KnowledgeMediaSelectedFile, WebAiCapabilities, WebAiResponse } from '@/types/api';
import { apiRequest, apiUrl, authHeaders, readTextPayload } from './api';
type RawCapabilities = {
enabled: boolean;
supportsImage?: boolean;
provider: string;
requiresConsent: boolean;
maxQuestionLength: number;
notice: string;
};
type RawWebAiResponse = {
mode: string;
status: string;
answer: string;
sources?: Array<{ title: string; url: string; snippet: string; score?: number }>;
provider: string;
notice: string;
redacted: boolean;
requiresConsent: boolean;
};
const domainOf = (value: string) => {
try { return new URL(value).hostname; } catch { return ''; }
};
const normalizeResponse = (raw: RawWebAiResponse): WebAiResponse => ({
requestId: `web:${Date.now()}`,
status: raw.status,
provider: raw.provider,
answer: raw.answer || '',
citations: (raw.sources || []).map((source) => ({
title: source.title,
url: source.url,
domain: domainOf(source.url),
snippet: source.snippet
})),
noEvidence: raw.status !== 'OK',
warning: raw.notice,
redacted: raw.redacted
});
export const getWebAiCapabilities = async (): Promise<WebAiCapabilities> => {
const raw = await apiRequest<RawCapabilities>({
url: '/api/aihr/web-ai/capabilities',
method: 'GET',
timeout: 15000
});
return {
enabled: raw.enabled,
supportsImage: raw.supportsImage,
requiresConsent: raw.requiresConsent,
providerName: raw.provider,
maxQuestionLength: raw.maxQuestionLength,
notice: raw.notice
};
};
export const queryWebAi = async (question: string, consent: boolean): Promise<WebAiResponse> => {
const raw = await apiRequest<RawWebAiResponse>({
url: '/api/aihr/web-ai/query',
method: 'POST',
data: { question, consent },
timeout: 45000
});
return normalizeResponse(raw);
};
export const queryWebAiWithImage = (file: KnowledgeMediaSelectedFile, question: string, consent: boolean) =>
new Promise<WebAiResponse>((resolve, reject) => {
uni.uploadFile({
url: apiUrl('/api/aihr/web-ai/query-image'),
filePath: file.path,
name: 'file',
header: authHeaders(false),
formData: { question, consent: String(consent) },
timeout: 60000,
success: (response) => {
try {
resolve(normalizeResponse(readTextPayload<RawWebAiResponse>(response.statusCode, response.data)));
} catch (error) {
reject(error);
}
},
fail: () => reject(new Error('图片上传或联网识图失败'))
});
});