完善细节

This commit is contained in:
BBIT-Kai
2026-07-17 09:53:02 +08:00
parent a84173066e
commit 89f6944e65
4 changed files with 2835 additions and 86 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ def get_cube_report_settings() -> CubeReportSettings:
"DIFY_DATABASE_ASSISTANT_API_BASE", "https://chat.bbitcn.net/v1"
).rstrip("/"),
dify_api_key=os.getenv(
"DIFY_DATABASE_ASSISTANT_API_KEY", "app-uibWo8ZEpqHCsWXREPTCBDH6"
"DIFY_DATABASE_ASSISTANT_API_KEY", "app-Ojd3zT2wBsO2Bop575ZiHQOD"
),
cube_api_base=os.getenv(
"CUBE_API_BASE_URL", "http://10.10.12.101:4001/cubejs-api/v1"
+31 -10
View File
@@ -138,6 +138,32 @@ function getFetchConfig() {
};
}
async function authorizedFetch(path: string, init: RequestInit) {
const request = () => {
const { authorization, baseURL } = getFetchConfig();
const headers = new Headers(init.headers);
if (authorization) {
headers.set('Authorization', authorization);
} else {
headers.delete('Authorization');
}
return fetch(`${baseURL}${path}`, { ...init, headers });
};
let response = await request();
if (response.status !== 401) return response;
try {
// 标准请求客户端会使用项目现有的 refresh token 机制更新令牌。
await getCubeReportScope();
} catch {
return response;
}
await response.body?.cancel();
response = await request();
return response;
}
async function responseError(response: Response) {
const text = await response.text();
try {
@@ -272,12 +298,10 @@ export async function stopCubeReportTask(taskId: string) {
}
export async function uploadCubeReportFile(file: File) {
const { authorization, baseURL } = getFetchConfig();
const form = new FormData();
form.append('file', file);
const response = await fetch(`${baseURL}/llm/cube-report/files/upload`, {
const response = await authorizedFetch('/llm/cube-report/files/upload', {
method: 'POST',
headers: { Authorization: authorization },
body: form,
});
if (!response.ok) throw new Error(await responseError(response));
@@ -291,14 +315,13 @@ export async function downloadCubeReportFile(
conversationId: string,
file: CubeReportFile,
) {
const { authorization, baseURL } = getFetchConfig();
const params = new URLSearchParams({
conversationId,
asAttachment: 'true',
});
const response = await fetch(
`${baseURL}/llm/cube-report/files/${file.id}/preview?${params}`,
{ headers: { Authorization: authorization } },
const response = await authorizedFetch(
`/llm/cube-report/files/${file.id}/preview?${params}`,
{},
);
if (!response.ok) throw new Error(await responseError(response));
const blob = await response.blob();
@@ -314,12 +337,10 @@ export async function streamCubeReportMessage(
payload: SendCubeReportMessage,
onEvent: (event: CubeReportStreamEvent) => void,
) {
const { authorization, baseURL } = getFetchConfig();
const response = await fetch(`${baseURL}/llm/cube-report/messages/stream`, {
const response = await authorizedFetch('/llm/cube-report/messages/stream', {
method: 'POST',
headers: {
Accept: 'text/event-stream',
Authorization: authorization,
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
@@ -380,6 +380,7 @@ async function sendMessage() {
let completedConversationId = currentSessionId.value;
let completedWithData = false;
try {
try {
await api.streamCubeReportMessage(
{
@@ -424,26 +425,6 @@ async function sendMessage() {
}
},
);
if (!assistantMessage.content) {
assistantMessage.content = stopRequested.value
? '响应已停止。'
: '查询已完成。';
}
if (completedConversationId) {
currentSessionId.value = completedConversationId;
const detail = await api.getCubeReportSession(completedConversationId);
currentSession.value = detail.session;
messages.value = detail.messages;
if (currentReportId.value) {
currentReport.value = await api.getCubeReport(currentReportId.value);
}
await reloadNavigation();
if (completedWithData || detail.session.hasData) {
activeView.value = 'split';
await loadData(1);
}
}
} catch (error) {
const text =
error instanceof Error ? error.message : '请求失败,请稍后重试';
@@ -456,6 +437,34 @@ async function sendMessage() {
pendingFiles.value = sentFiles;
message.error(text);
}
return;
}
if (!assistantMessage.content) {
assistantMessage.content = stopRequested.value
? '响应已停止。'
: '查询已完成。';
}
if (completedConversationId) {
try {
currentSessionId.value = completedConversationId;
const detail = await api.getCubeReportSession(completedConversationId);
currentSession.value = detail.session;
messages.value = detail.messages;
if (currentReportId.value) {
currentReport.value = await api.getCubeReport(currentReportId.value);
}
await reloadNavigation();
if (completedWithData || detail.session.hasData) {
activeView.value = 'split';
await loadData(1);
}
} catch (error) {
const text =
error instanceof Error ? error.message : '会话和数据刷新失败';
message.warning(`回复已完成,但数据刷新失败:${text}`);
}
}
} finally {
sending.value = false;
stopping.value = false;
@@ -465,6 +474,12 @@ async function sendMessage() {
}
}
function sendSuggestedQuestion(question: string) {
if (sending.value) return;
inputMessage.value = question;
void sendMessage();
}
async function stopResponse() {
if (!currentTaskId.value || stopping.value) return;
stopping.value = true;
@@ -1183,17 +1198,14 @@ onBeforeUnmount(() => {
v-for="(question, index) in suggestedQuestions"
:key="question"
type="button"
@click="inputMessage = question"
:disabled="sending"
@click="sendSuggestedQuestion(question)"
>
<IconifyIcon
:icon="suggestionIcons[index % suggestionIcons.length]!"
/>
<span>{{ question }}</span>
</button>
<button type="button" @click="fileInput?.click()">
<IconifyIcon icon="lucide:file-up" />
<span>上传 Excel 辅助分析</span>
</button>
</div>
</div>
</Spin>
File diff suppressed because it is too large Load Diff