完善细节
This commit is contained in:
@@ -20,7 +20,7 @@ def get_cube_report_settings() -> CubeReportSettings:
|
|||||||
"DIFY_DATABASE_ASSISTANT_API_BASE", "https://chat.bbitcn.net/v1"
|
"DIFY_DATABASE_ASSISTANT_API_BASE", "https://chat.bbitcn.net/v1"
|
||||||
).rstrip("/"),
|
).rstrip("/"),
|
||||||
dify_api_key=os.getenv(
|
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=os.getenv(
|
||||||
"CUBE_API_BASE_URL", "http://10.10.12.101:4001/cubejs-api/v1"
|
"CUBE_API_BASE_URL", "http://10.10.12.101:4001/cubejs-api/v1"
|
||||||
|
|||||||
@@ -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) {
|
async function responseError(response: Response) {
|
||||||
const text = await response.text();
|
const text = await response.text();
|
||||||
try {
|
try {
|
||||||
@@ -272,12 +298,10 @@ export async function stopCubeReportTask(taskId: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function uploadCubeReportFile(file: File) {
|
export async function uploadCubeReportFile(file: File) {
|
||||||
const { authorization, baseURL } = getFetchConfig();
|
|
||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
form.append('file', file);
|
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',
|
method: 'POST',
|
||||||
headers: { Authorization: authorization },
|
|
||||||
body: form,
|
body: form,
|
||||||
});
|
});
|
||||||
if (!response.ok) throw new Error(await responseError(response));
|
if (!response.ok) throw new Error(await responseError(response));
|
||||||
@@ -291,14 +315,13 @@ export async function downloadCubeReportFile(
|
|||||||
conversationId: string,
|
conversationId: string,
|
||||||
file: CubeReportFile,
|
file: CubeReportFile,
|
||||||
) {
|
) {
|
||||||
const { authorization, baseURL } = getFetchConfig();
|
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
conversationId,
|
conversationId,
|
||||||
asAttachment: 'true',
|
asAttachment: 'true',
|
||||||
});
|
});
|
||||||
const response = await fetch(
|
const response = await authorizedFetch(
|
||||||
`${baseURL}/llm/cube-report/files/${file.id}/preview?${params}`,
|
`/llm/cube-report/files/${file.id}/preview?${params}`,
|
||||||
{ headers: { Authorization: authorization } },
|
{},
|
||||||
);
|
);
|
||||||
if (!response.ok) throw new Error(await responseError(response));
|
if (!response.ok) throw new Error(await responseError(response));
|
||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
@@ -314,12 +337,10 @@ export async function streamCubeReportMessage(
|
|||||||
payload: SendCubeReportMessage,
|
payload: SendCubeReportMessage,
|
||||||
onEvent: (event: CubeReportStreamEvent) => void,
|
onEvent: (event: CubeReportStreamEvent) => void,
|
||||||
) {
|
) {
|
||||||
const { authorization, baseURL } = getFetchConfig();
|
const response = await authorizedFetch('/llm/cube-report/messages/stream', {
|
||||||
const response = await fetch(`${baseURL}/llm/cube-report/messages/stream`, {
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'text/event-stream',
|
Accept: 'text/event-stream',
|
||||||
Authorization: authorization,
|
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify(payload),
|
body: JSON.stringify(payload),
|
||||||
|
|||||||
@@ -380,6 +380,7 @@ async function sendMessage() {
|
|||||||
|
|
||||||
let completedConversationId = currentSessionId.value;
|
let completedConversationId = currentSessionId.value;
|
||||||
let completedWithData = false;
|
let completedWithData = false;
|
||||||
|
try {
|
||||||
try {
|
try {
|
||||||
await api.streamCubeReportMessage(
|
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) {
|
} catch (error) {
|
||||||
const text =
|
const text =
|
||||||
error instanceof Error ? error.message : '请求失败,请稍后重试';
|
error instanceof Error ? error.message : '请求失败,请稍后重试';
|
||||||
@@ -456,6 +437,34 @@ async function sendMessage() {
|
|||||||
pendingFiles.value = sentFiles;
|
pendingFiles.value = sentFiles;
|
||||||
message.error(text);
|
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 {
|
} finally {
|
||||||
sending.value = false;
|
sending.value = false;
|
||||||
stopping.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() {
|
async function stopResponse() {
|
||||||
if (!currentTaskId.value || stopping.value) return;
|
if (!currentTaskId.value || stopping.value) return;
|
||||||
stopping.value = true;
|
stopping.value = true;
|
||||||
@@ -1183,17 +1198,14 @@ onBeforeUnmount(() => {
|
|||||||
v-for="(question, index) in suggestedQuestions"
|
v-for="(question, index) in suggestedQuestions"
|
||||||
:key="question"
|
:key="question"
|
||||||
type="button"
|
type="button"
|
||||||
@click="inputMessage = question"
|
:disabled="sending"
|
||||||
|
@click="sendSuggestedQuestion(question)"
|
||||||
>
|
>
|
||||||
<IconifyIcon
|
<IconifyIcon
|
||||||
:icon="suggestionIcons[index % suggestionIcons.length]!"
|
:icon="suggestionIcons[index % suggestionIcons.length]!"
|
||||||
/>
|
/>
|
||||||
<span>{{ question }}</span>
|
<span>{{ question }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" @click="fileInput?.click()">
|
|
||||||
<IconifyIcon icon="lucide:file-up" />
|
|
||||||
<span>上传 Excel 辅助分析</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Spin>
|
</Spin>
|
||||||
|
|||||||
+2716
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user