dify修正
This commit is contained in:
9
schoolNewsServ/.bin/dify/部署注意点.md
Normal file
9
schoolNewsServ/.bin/dify/部署注意点.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# 1.工作流修改
|
||||||
|
## 动态知识库检索工作流
|
||||||
|
修改dataset的apikey
|
||||||
|
|
||||||
|
## 思政小帮手对话流
|
||||||
|
修改“动态知识库检索”的入参
|
||||||
|
|
||||||
|
# 2. 后端修改
|
||||||
|
修改yaml的配置内容
|
||||||
@@ -111,6 +111,7 @@ school-news:
|
|||||||
- "/public/**"
|
- "/public/**"
|
||||||
- "/static/**"
|
- "/static/**"
|
||||||
- "/file/download/**"
|
- "/file/download/**"
|
||||||
|
- "/ai/chat/stream/**"
|
||||||
|
|
||||||
|
|
||||||
crawler:
|
crawler:
|
||||||
@@ -158,6 +159,10 @@ crontab:
|
|||||||
type: Boolean
|
type: Boolean
|
||||||
value: true
|
value: true
|
||||||
|
|
||||||
|
|
||||||
|
# dify
|
||||||
|
dify:
|
||||||
|
knowledgeApiKey: dataset-nupqKP4LONpzdXmGthIrbjeJ
|
||||||
# 文件存储配置
|
# 文件存储配置
|
||||||
file:
|
file:
|
||||||
storage:
|
storage:
|
||||||
|
|||||||
@@ -514,6 +514,13 @@ public class DifyApiClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 流正常读取完毕,如果没有收到 [DONE] 标记,也当作完成
|
||||||
|
logger.info("SSE流读取完毕");
|
||||||
|
callback.onComplete();
|
||||||
|
} catch (java.io.EOFException e) {
|
||||||
|
// EOFException 通常表示流正常结束(Dify可能没有发送[DONE]标记)
|
||||||
|
logger.info("SSE流已结束(EOF)");
|
||||||
|
callback.onComplete();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("流式响应处理异常", e);
|
logger.error("流式响应处理异常", e);
|
||||||
callback.onError(e);
|
callback.onError(e);
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ public class DifyConfig {
|
|||||||
* Dify API密钥(默认密钥,可被智能体的密钥覆盖)
|
* Dify API密钥(默认密钥,可被智能体的密钥覆盖)
|
||||||
*/
|
*/
|
||||||
// private String apiKey="app-PTHzp2DsLPyiUrDYTXBGxL1f";
|
// private String apiKey="app-PTHzp2DsLPyiUrDYTXBGxL1f";
|
||||||
private String apiKey="app-fwOqGFLTsZtekCQYlOmj9f8x";
|
private String apiKey="app-6VXXDHRC8fiTijeRfnwzOyGn";
|
||||||
|
|
||||||
private String knowledgeApiKey="dataset-HeDK9gHBqPnI4rBZ2q2Hm7rV";
|
private String knowledgeApiKey="dataset-nupqKP4LONpzdXmGthIrbjeJ";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求超时时间(秒)
|
* 请求超时时间(秒)
|
||||||
|
|||||||
@@ -148,7 +148,7 @@
|
|||||||
complete_time = #{completeTime},
|
complete_time = #{completeTime},
|
||||||
</if>
|
</if>
|
||||||
<if test="lastLearnTime != null">
|
<if test="lastLearnTime != null">
|
||||||
last_learn_time = #{lastLearnTime},
|
last_learn_time = #{updateTime},
|
||||||
</if>
|
</if>
|
||||||
<if test="updater != null">
|
<if test="updater != null">
|
||||||
updater = #{updater},
|
updater = #{updater},
|
||||||
@@ -298,8 +298,8 @@
|
|||||||
) current_dept ON user_dept.dept_path LIKE CONCAT(current_dept.dept_path, '%')
|
) current_dept ON user_dept.dept_path LIKE CONCAT(current_dept.dept_path, '%')
|
||||||
</if>
|
</if>
|
||||||
WHERE lr.deleted = 0
|
WHERE lr.deleted = 0
|
||||||
AND lr.last_learn_time >= DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY)
|
AND lr.update_time >= DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY)
|
||||||
AND lr.last_learn_time < DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY), INTERVAL 7 DAY)
|
AND lr.update_time < DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY), INTERVAL 7 DAY)
|
||||||
GROUP BY lr.resource_type
|
GROUP BY lr.resource_type
|
||||||
ORDER BY totalDuration DESC
|
ORDER BY totalDuration DESC
|
||||||
</select>
|
</select>
|
||||||
@@ -326,8 +326,8 @@
|
|||||||
) current_dept ON user_dept.dept_path LIKE CONCAT(current_dept.dept_path, '%')
|
) current_dept ON user_dept.dept_path LIKE CONCAT(current_dept.dept_path, '%')
|
||||||
</if>
|
</if>
|
||||||
WHERE lr.deleted = 0
|
WHERE lr.deleted = 0
|
||||||
AND lr.last_learn_time >= DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY)
|
AND lr.update_time >= DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY)
|
||||||
AND lr.last_learn_time < DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY), INTERVAL 7 DAY)
|
AND lr.update_time < DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY), INTERVAL 7 DAY)
|
||||||
GROUP BY lr.user_id, u.username
|
GROUP BY lr.user_id, u.username
|
||||||
ORDER BY totalDuration DESC
|
ORDER BY totalDuration DESC
|
||||||
LIMIT 10
|
LIMIT 10
|
||||||
@@ -357,8 +357,8 @@
|
|||||||
</if>
|
</if>
|
||||||
WHERE lr.deleted = 0
|
WHERE lr.deleted = 0
|
||||||
AND lr.resource_type = 2
|
AND lr.resource_type = 2
|
||||||
AND lr.last_learn_time >= DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY)
|
AND lr.update_time >= DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY)
|
||||||
AND lr.last_learn_time < DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY), INTERVAL 7 DAY)
|
AND lr.update_time < DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY), INTERVAL 7 DAY)
|
||||||
GROUP BY lr.resource_id, c.name
|
GROUP BY lr.resource_id, c.name
|
||||||
ORDER BY learnerCount DESC, totalDuration DESC
|
ORDER BY learnerCount DESC, totalDuration DESC
|
||||||
LIMIT 10
|
LIMIT 10
|
||||||
@@ -388,8 +388,8 @@
|
|||||||
</if>
|
</if>
|
||||||
WHERE lr.deleted = 0
|
WHERE lr.deleted = 0
|
||||||
AND lr.resource_type = 1
|
AND lr.resource_type = 1
|
||||||
AND lr.last_learn_time >= DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY)
|
AND lr.update_time >= DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY)
|
||||||
AND lr.last_learn_time < DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY), INTERVAL 7 DAY)
|
AND lr.update_time < DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY), INTERVAL 7 DAY)
|
||||||
GROUP BY lr.resource_id, r.title
|
GROUP BY lr.resource_id, r.title
|
||||||
ORDER BY learnerCount DESC, totalDuration DESC
|
ORDER BY learnerCount DESC, totalDuration DESC
|
||||||
LIMIT 10
|
LIMIT 10
|
||||||
@@ -419,7 +419,7 @@
|
|||||||
LEFT JOIN tb_learning_record lr ON tu.user_id = lr.user_id AND tu.task_id = lr.task_id AND lr.deleted = 0
|
LEFT JOIN tb_learning_record lr ON tu.user_id = lr.user_id AND tu.task_id = lr.task_id AND lr.deleted = 0
|
||||||
WHERE tu.deleted = 0
|
WHERE tu.deleted = 0
|
||||||
AND tu.status = 2
|
AND tu.status = 2
|
||||||
AND tu.complete_time >= DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY)
|
AND tu.complete_time >= DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY)
|
||||||
AND tu.complete_time < DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY), INTERVAL 7 DAY)
|
AND tu.complete_time < DATE_ADD(DATE_SUB(CURDATE(), INTERVAL DAYOFWEEK(CURDATE())-1 DAY), INTERVAL 7 DAY)
|
||||||
GROUP BY tu.user_id, u.username
|
GROUP BY tu.user_id, u.username
|
||||||
ORDER BY completedTaskCount DESC, totalDuration DESC
|
ORDER BY completedTaskCount DESC, totalDuration DESC
|
||||||
|
|||||||
@@ -127,7 +127,35 @@ export const chatApi = {
|
|||||||
|
|
||||||
// 监听错误事件
|
// 监听错误事件
|
||||||
eventSource.addEventListener('error', (event: any) => {
|
eventSource.addEventListener('error', (event: any) => {
|
||||||
const error = new Error(event.data || '对话失败');
|
// 如果 data 为空,说明是正常的流结束信号(有些工作流不发送end事件)
|
||||||
|
if (!event.data || event.data.trim() === '') {
|
||||||
|
console.log('[SSE流结束] 收到空error事件,当作正常结束处理');
|
||||||
|
|
||||||
|
// 触发结束回调(如果有的话)
|
||||||
|
callback?.onMessageEnd?.({
|
||||||
|
conversationId: request.conversationId,
|
||||||
|
messageId: '',
|
||||||
|
answer: fullMessage
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
eventSource.close();
|
||||||
|
|
||||||
|
// 正常结束
|
||||||
|
resolve({
|
||||||
|
code: 200,
|
||||||
|
success: true,
|
||||||
|
login: true,
|
||||||
|
auth: true,
|
||||||
|
data: {
|
||||||
|
conversationId: request.conversationId,
|
||||||
|
answer: fullMessage
|
||||||
|
} as any,
|
||||||
|
message: '对话已结束'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const error = new Error(event.data);
|
||||||
callback?.onError?.(error);
|
callback?.onError?.(error);
|
||||||
eventSource.close();
|
eventSource.close();
|
||||||
reject(error);
|
reject(error);
|
||||||
@@ -358,7 +386,34 @@ export const chatApi = {
|
|||||||
|
|
||||||
// 监听错误事件
|
// 监听错误事件
|
||||||
eventSource.addEventListener('error', (event: any) => {
|
eventSource.addEventListener('error', (event: any) => {
|
||||||
const error = new Error(event.data || '重新生成失败');
|
// 如果 data 为空,说明是正常的流结束信号(有些工作流不发送end事件)
|
||||||
|
if (!event.data || event.data.trim() === '') {
|
||||||
|
console.log('[SSE流结束-重新生成] 收到空error事件,当作正常结束处理');
|
||||||
|
|
||||||
|
// 触发结束回调(如果有的话)
|
||||||
|
callback?.onMessageEnd?.({
|
||||||
|
messageId: messageId,
|
||||||
|
answer: fullMessage
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
eventSource.close();
|
||||||
|
|
||||||
|
// 正常结束
|
||||||
|
resolve({
|
||||||
|
code: 200,
|
||||||
|
success: true,
|
||||||
|
login: true,
|
||||||
|
auth: true,
|
||||||
|
data: {
|
||||||
|
messageId: messageId,
|
||||||
|
answer: fullMessage
|
||||||
|
} as any,
|
||||||
|
message: '重新生成已结束'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const error = new Error(event.data);
|
||||||
callback?.onError?.(error);
|
callback?.onError?.(error);
|
||||||
eventSource.close();
|
eventSource.close();
|
||||||
reject(error);
|
reject(error);
|
||||||
|
|||||||
@@ -180,7 +180,14 @@ function initDurationChart(data: any[]) {
|
|||||||
const duration = params.value;
|
const duration = params.value;
|
||||||
const hours = Math.floor(duration / 3600);
|
const hours = Math.floor(duration / 3600);
|
||||||
const minutes = Math.floor((duration % 3600) / 60);
|
const minutes = Math.floor((duration % 3600) / 60);
|
||||||
return `${params.name}<br/>学习时长: ${hours}小时${minutes}分钟<br/>学习人数: ${params.data.userCount}人`;
|
const secs = duration % 60;
|
||||||
|
|
||||||
|
let timeStr = '';
|
||||||
|
if (hours > 0) timeStr += `${hours}小时`;
|
||||||
|
if (minutes > 0) timeStr += `${minutes}分钟`;
|
||||||
|
if (secs > 0 || timeStr === '') timeStr += `${secs}秒`;
|
||||||
|
|
||||||
|
return `${params.name}<br/>学习时长: ${timeStr}<br/>学习人数: ${params.data.userCount}人`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
@@ -204,7 +211,18 @@ function initDurationChart(data: any[]) {
|
|||||||
const duration = params.value;
|
const duration = params.value;
|
||||||
const hours = Math.floor(duration / 3600);
|
const hours = Math.floor(duration / 3600);
|
||||||
const minutes = Math.floor((duration % 3600) / 60);
|
const minutes = Math.floor((duration % 3600) / 60);
|
||||||
return `${params.name}\n${hours}h${minutes}m`;
|
const secs = duration % 60;
|
||||||
|
|
||||||
|
let timeStr = '';
|
||||||
|
if (hours > 0) {
|
||||||
|
timeStr = `${hours}h${minutes}m`;
|
||||||
|
} else if (minutes > 0) {
|
||||||
|
timeStr = `${minutes}m${secs}s`;
|
||||||
|
} else {
|
||||||
|
timeStr = `${secs}s`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${params.name}\n${timeStr}`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emphasis: {
|
emphasis: {
|
||||||
@@ -233,12 +251,26 @@ function initDurationChart(data: any[]) {
|
|||||||
|
|
||||||
// 格式化时长
|
// 格式化时长
|
||||||
function formatDuration(seconds: number): string {
|
function formatDuration(seconds: number): string {
|
||||||
|
if (!seconds || seconds === 0) {
|
||||||
|
return '0秒';
|
||||||
|
}
|
||||||
|
|
||||||
const hours = Math.floor(seconds / 3600);
|
const hours = Math.floor(seconds / 3600);
|
||||||
const minutes = Math.floor((seconds % 3600) / 60);
|
const minutes = Math.floor((seconds % 3600) / 60);
|
||||||
|
const secs = seconds % 60;
|
||||||
|
|
||||||
|
let result = '';
|
||||||
if (hours > 0) {
|
if (hours > 0) {
|
||||||
return `${hours}小时${minutes}分钟`;
|
result += `${hours}小时`;
|
||||||
}
|
}
|
||||||
return `${minutes}分钟`;
|
if (minutes > 0) {
|
||||||
|
result += `${minutes}分钟`;
|
||||||
|
}
|
||||||
|
if (secs > 0 || result === '') {
|
||||||
|
result += `${secs}秒`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取排名样式
|
// 获取排名样式
|
||||||
@@ -294,7 +326,7 @@ function getRankClass(index: number): string {
|
|||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: #e8edf3;
|
background: #e8edf3;
|
||||||
transform: translateX(5px);
|
// transform: translateX(5px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rank {
|
.rank {
|
||||||
|
|||||||
Reference in New Issue
Block a user