Add Vue user H5 client
This commit is contained in:
79
ai_knowledge_base_v2/apps/user-client/src/services/api.ts
Normal file
79
ai_knowledge_base_v2/apps/user-client/src/services/api.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import type { ApiResponse, ChatMessage, ChatSession, LoginResult, UserProfile } from "../types/api";
|
||||
|
||||
const API_BASE = import.meta.env.VITE_API_BASE_URL ?? "http://127.0.0.1:8100/api";
|
||||
const TOKEN_KEY = "ai-kb-user-token";
|
||||
|
||||
export function getToken() {
|
||||
return window.localStorage.getItem(TOKEN_KEY);
|
||||
}
|
||||
|
||||
export function saveToken(token: string) {
|
||||
window.localStorage.setItem(TOKEN_KEY, token);
|
||||
}
|
||||
|
||||
export function clearToken() {
|
||||
window.localStorage.removeItem(TOKEN_KEY);
|
||||
}
|
||||
|
||||
async function request<T>(path: string, init: RequestInit = {}): Promise<T> {
|
||||
const headers = new Headers(init.headers);
|
||||
headers.set("Content-Type", "application/json");
|
||||
const token = getToken();
|
||||
if (token) {
|
||||
headers.set("Authorization", `Bearer ${token}`);
|
||||
}
|
||||
const response = await fetch(`${API_BASE}${path}`, { ...init, headers });
|
||||
const body = (await response.json()) as ApiResponse<T>;
|
||||
if (!response.ok || body.code !== 0) {
|
||||
throw new Error(body.message || `${response.status} ${response.statusText}`);
|
||||
}
|
||||
return body.data;
|
||||
}
|
||||
|
||||
export const api = {
|
||||
sendSms: (phone: string) => request<null>("/auth/sms/send", { method: "POST", body: JSON.stringify({ phone }) }),
|
||||
login: (phone: string, code: string) =>
|
||||
request<LoginResult>("/auth/login", { method: "POST", body: JSON.stringify({ phone, code }) }),
|
||||
logout: () => request<null>("/auth/logout", { method: "POST", body: JSON.stringify({}) }),
|
||||
profile: () => request<UserProfile>("/user/profile"),
|
||||
createSession: () => request<{ sessionId: number }>("/chat/session", { method: "POST", body: JSON.stringify({}) }),
|
||||
listSessions: () => request<ChatSession[]>("/chat/session/list"),
|
||||
history: (sessionId: number) => request<ChatMessage[]>(`/chat/history?sessionId=${sessionId}`),
|
||||
renameSession: (sessionId: number, title: string) =>
|
||||
request<ChatSession>("/chat/session/title", { method: "PUT", body: JSON.stringify({ sessionId, title }) }),
|
||||
deleteSession: (sessionId: number) => request<null>(`/chat/session/${sessionId}`, { method: "DELETE" }),
|
||||
stop: (sessionId: number) => request<null>("/chat/stop", { method: "POST", body: JSON.stringify({ sessionId }) }),
|
||||
};
|
||||
|
||||
export async function streamChat(sessionId: number, message: string, onChunk: (chunk: string) => void) {
|
||||
const token = getToken();
|
||||
const response = await fetch(`${API_BASE}/chat/completions`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify({ sessionId, message }),
|
||||
});
|
||||
if (!response.ok || !response.body) {
|
||||
throw new Error("AI 回复连接失败");
|
||||
}
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
let buffer = "";
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
buffer += decoder.decode(value, { stream: true });
|
||||
const parts = buffer.split("\n\n");
|
||||
buffer = parts.pop() ?? "";
|
||||
for (const part of parts) {
|
||||
const line = part.trim();
|
||||
if (!line.startsWith("data:")) continue;
|
||||
const payload = line.slice(5).trim();
|
||||
if (payload === "[DONE]") return;
|
||||
const parsed = JSON.parse(payload) as { content?: string };
|
||||
if (parsed.content) onChunk(parsed.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user