You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1157 lines
40 KiB
1157 lines
40 KiB
import json
|
|
import io
|
|
import pandas as pd
|
|
import time
|
|
import dash
|
|
from datetime import datetime
|
|
from dash import Patch, set_props, dcc, html,callback_context
|
|
import feffery_antd_components as fac
|
|
from dash.dependencies import Input, Output, State, MATCH, ClientsideFunction,ALL
|
|
import feffery_markdown_components as fmc
|
|
from server import app
|
|
from config import model_config
|
|
from views.dataint.dataquery.components import chat_message_box
|
|
from conversation_cache import conversation_cache
|
|
from feffery_dash_utils.style_utils import style
|
|
|
|
|
|
def get_translation_ct_type(key):
|
|
|
|
translation_dict = {
|
|
"datePicker": "单日筛选",
|
|
"dateRangePicker": "周期筛选",
|
|
"input": "输入框",
|
|
"select": "单项筛选",
|
|
"mselect": "多项筛选",
|
|
"radioGroup": "是否筛选"
|
|
}
|
|
return translation_dict.get(key, "未知") # 如果键不存在,返回 "未知"
|
|
|
|
# 处理策划栏拼接查询语句的情况
|
|
# 处理 default_value 为字典的情况
|
|
def format_default_value(item):
|
|
value = item['default_value']
|
|
if isinstance(value, dict) and 'start_date' in value and 'end_date':
|
|
return f"开始日期{value['start_date']}截止日期为{value['end_date']}"
|
|
elif item['cd_type'] == '输出结果':
|
|
return item['name'] # 使用 name 字段
|
|
return value
|
|
|
|
@app.callback(
|
|
Output({"type": "control-group-store", "index": MATCH}, "data",allow_duplicate=True),
|
|
[
|
|
Input({"type": "edit-widgets-table", "index": MATCH}, "recentlyChangedRow"),
|
|
Input({"type": "edit-widgets-table", "index": MATCH}, "recentlyChangedColumn"),
|
|
],
|
|
State({"type": "control-group-store", "index": MATCH}, "data"),
|
|
prevent_initial_call=True
|
|
)
|
|
def combined_callback(recentlyChangedRow, recentlyChangedColumn, data):
|
|
|
|
new_default_value = recentlyChangedRow.get('条件取值', None)
|
|
param = recentlyChangedRow.get('param', {})
|
|
id = param.get('id', None)
|
|
name = param.get('name', None)
|
|
if new_default_value is not None:
|
|
print("可编辑的表样式1")
|
|
for record in data:
|
|
# 检查是否匹配指定的 id 和 name
|
|
if record['id'] == id and record['name'] == name:
|
|
# 更新 default_value
|
|
record['default_value'] = new_default_value
|
|
break # 假设 id 和 name 组合唯一,找到后可以退出循环
|
|
return data
|
|
|
|
return data
|
|
|
|
@app.callback(
|
|
Output({"type": "control-group-store", "index": MATCH}, "data",allow_duplicate=True),
|
|
Input({"type": "tree-favorites-demo", "index": MATCH}, "favoritedKeys"),
|
|
State({"type": "control-group-store", "index": MATCH}, "data"),
|
|
prevent_initial_call=True
|
|
)
|
|
def tree_favorites_demo(data_change,data):
|
|
|
|
print("选择可用数据收藏")
|
|
max_id = 0
|
|
new_fields = [item.split('|') for item in data_change]
|
|
print("********new_fields"+str(new_fields))
|
|
# 检查并添加新的字段
|
|
for name, d_type in new_fields:
|
|
if not any(item['name'] == name for item in data):
|
|
max_id += 1
|
|
new_field = {
|
|
'cd_type': '', # 根据需要填充
|
|
'ct_type': 'input', # 根据需要填充
|
|
'd_type': d_type,
|
|
'default_value': '', # 根据需要填充
|
|
'id': "t"+str(max_id),
|
|
'name': name,
|
|
'options': [] # 根据需要填充
|
|
}
|
|
print("********insert"+str(new_field))
|
|
data.insert(0, new_field)
|
|
data = [item for item in data if not (str(item['id']).startswith('t') and item['name'] not in [name for name, d_type in new_fields])]
|
|
print(data)
|
|
|
|
return data
|
|
|
|
|
|
@app.callback(Input("listen-unload", "unloaded"), State("conversation-id", "data"))
|
|
def clear_conversation_cache(unloaded, conversation_id):
|
|
"""在页面刷新或关闭时,清除对应的对话缓存数据"""
|
|
|
|
if conversation_cache.get(conversation_id):
|
|
del conversation_cache[conversation_id]
|
|
|
|
|
|
app.clientside_callback(
|
|
# 处理对话框整体的全屏/退出全屏
|
|
ClientsideFunction(
|
|
namespace="clientside", function_name="handleChatContainerFullscreen"
|
|
),
|
|
[
|
|
Output("chat-container-full-screen-icon", "icon"),
|
|
Output("chat-container", "style"),
|
|
],
|
|
Input("chat-container-full-screen", "nClicks"),
|
|
State("chat-container-full-screen-icon", "icon"),
|
|
prevent_initial_call=True,
|
|
)
|
|
|
|
app.clientside_callback(
|
|
# 控制对话消息框的显示/隐藏
|
|
ClientsideFunction(
|
|
namespace="clientside", function_name="handleOperationButtonGroupVisible"
|
|
),
|
|
Output(
|
|
{
|
|
"type": "operation-button-group",
|
|
"index": MATCH,
|
|
},
|
|
"style",
|
|
),
|
|
Input(
|
|
{"type": "chat-message-box-listen-hover", "index": MATCH},
|
|
"isHovering",
|
|
),
|
|
State(
|
|
{
|
|
"type": "operation-button-group",
|
|
"index": MATCH,
|
|
},
|
|
"style",
|
|
),
|
|
prevent_initial_call=True,
|
|
)
|
|
|
|
app.clientside_callback(
|
|
# 控制用户信息输入框内容的发送
|
|
ClientsideFunction(
|
|
namespace="clientside", function_name="handleUserNewMessageSend"
|
|
),
|
|
[Output("newest-user-input", "data", allow_duplicate=True), Output("input-text", "value",allow_duplicate=True)],
|
|
[
|
|
Input("shift-enter-keypress", "pressedCounts"),
|
|
Input("enter-keypress", "pressedCounts"),
|
|
Input("send-input-text", "nClicks"),
|
|
],
|
|
State("input-text", "value"),
|
|
prevent_initial_call=True,
|
|
)
|
|
|
|
|
|
@app.callback(
|
|
[
|
|
Output("chat-area-list", "children"),
|
|
Output("send-input-text", "loading",allow_duplicate=True),
|
|
Output("input-text", "disabled"),
|
|
],
|
|
[
|
|
Input("newest-user-input", "data"),
|
|
Input("chat-area-clear", "nClicks"),
|
|
Input("chat-setting-model", "value"),
|
|
],
|
|
[
|
|
State("conversation-id", "data"),
|
|
State("chat-setting-temperature", "value"),
|
|
State("chat-setting-max-tokens", "value"),
|
|
],
|
|
prevent_initial_call=True,
|
|
)
|
|
def append_new_user_input(
|
|
new_question, nClicks, current_model, conversation_id, temperature, max_tokens
|
|
):
|
|
"""处理新发送问题对话信息框的追加,或清空聊天记录操作"""
|
|
|
|
if dash.ctx.triggered_id == "newest-user-input":
|
|
# 尝试提取有效的模型厂商、子模型名称
|
|
if "|" in current_model:
|
|
model_name = current_model.split("|")[0]
|
|
sub_model_name = current_model.split("|")[1]
|
|
else:
|
|
model_name = None
|
|
sub_model_name = None
|
|
|
|
p = Patch()
|
|
|
|
p.extend(
|
|
[
|
|
chat_message_box.render(
|
|
conversation_id=conversation_id,
|
|
role="user",
|
|
user_input_text=new_question,
|
|
),
|
|
chat_message_box.render(
|
|
conversation_id=conversation_id,
|
|
role="assistant",
|
|
user_input_text=new_question,
|
|
model_name=model_name,
|
|
sub_model_name=sub_model_name,
|
|
temperature=temperature,
|
|
max_tokens=max_tokens,
|
|
),
|
|
]
|
|
)
|
|
set_props("input-text", { "disabled": False })
|
|
set_props("send-input-text", { "loading": False })
|
|
return p, False, False
|
|
|
|
# “清空聊天”按钮被点击,或当前模型发生切换时,均需要重新初始化当前对话缓存
|
|
elif dash.ctx.triggered_id in ["chat-area-clear", "chat-setting-model"]:
|
|
# 初始化当前对话缓存
|
|
conversation_cache.insert(
|
|
conversation_id,
|
|
[],
|
|
)
|
|
|
|
return [
|
|
# 初始化系统提示语
|
|
[
|
|
chat_message_box.render(
|
|
conversation_id=conversation_id,
|
|
role="system",
|
|
system_prompt=config.AppConfig.initial_system_prompt,
|
|
message_uuid="system-initial",
|
|
)
|
|
],
|
|
False,
|
|
False,
|
|
]
|
|
|
|
|
|
app.clientside_callback(
|
|
# 处理流式回复内容更新相关过程
|
|
ClientsideFunction(namespace="clientside", function_name="handleStreamResponse"),
|
|
[
|
|
Output(
|
|
{
|
|
"type": "assistant-output-markdown",
|
|
"index": MATCH,
|
|
},
|
|
"markdownStr",
|
|
),
|
|
Output(
|
|
{
|
|
"type": "assistant-output-markdown",
|
|
"index": MATCH,
|
|
},
|
|
"children",
|
|
),
|
|
],
|
|
Input(
|
|
{
|
|
"type": "assistant-output-sse",
|
|
"index": MATCH,
|
|
},
|
|
"data",
|
|
),
|
|
State(
|
|
{
|
|
"type": "assistant-output-markdown",
|
|
"index": MATCH,
|
|
},
|
|
"markdownStr",
|
|
),
|
|
prevent_initial_call=True,
|
|
)
|
|
|
|
app.clientside_callback(
|
|
# 处理聊天区域的自动滚动策略
|
|
ClientsideFunction(namespace="clientside", function_name="handleChatAreaScroll"),
|
|
Input("listen-chat-area-list-height", "height"),
|
|
State("enable-auto-scroll", "checked"),
|
|
)
|
|
|
|
app.clientside_callback(
|
|
# 处理工具按钮条中的“前往顶部”、“回到底部”操作
|
|
ClientsideFunction(
|
|
namespace="clientside", function_name="handleChatAreaToTopBottom"
|
|
),
|
|
[
|
|
Input("chat-area-to-top", "nClicks"),
|
|
Input("chat-area-to-bottom", "nClicks"),
|
|
],
|
|
)
|
|
|
|
app.clientside_callback(
|
|
# 处理ai回复消息框“中断”按钮操作
|
|
ClientsideFunction(
|
|
namespace="clientside", function_name="handleAssistantOutputStop"
|
|
),
|
|
Output(
|
|
{
|
|
"type": "assistant-output-sse",
|
|
"index": MATCH,
|
|
},
|
|
"operation",
|
|
),
|
|
Input(
|
|
{
|
|
"type": "assistant-output-stop",
|
|
"index": MATCH,
|
|
},
|
|
"nClicks",
|
|
),
|
|
prevent_initial_call=True,
|
|
)
|
|
|
|
app.clientside_callback(
|
|
# 处理ai回复消息框“重试”按钮操作
|
|
ClientsideFunction(
|
|
namespace="clientside", function_name="handleAssistantOutputRetry"
|
|
),
|
|
[
|
|
Output(
|
|
{
|
|
"type": "assistant-output-markdown",
|
|
"index": MATCH,
|
|
},
|
|
"markdownStr",
|
|
allow_duplicate=True,
|
|
),
|
|
Output(
|
|
{
|
|
"type": "assistant-output-markdown",
|
|
"index": MATCH,
|
|
},
|
|
"children",
|
|
allow_duplicate=True,
|
|
),
|
|
Output(
|
|
{
|
|
"type": "assistant-output-sse",
|
|
"index": MATCH,
|
|
},
|
|
"key",
|
|
),
|
|
],
|
|
Input(
|
|
{
|
|
"type": "assistant-output-retry",
|
|
"index": MATCH,
|
|
},
|
|
"nClicks",
|
|
),
|
|
prevent_initial_call=True,
|
|
)
|
|
|
|
|
|
app.clientside_callback(
|
|
# 处理ai回复消息框“赋值 ”按钮操作
|
|
ClientsideFunction(
|
|
namespace="clientside", function_name="handleAssistantOutputCopy"
|
|
),
|
|
Output(
|
|
{
|
|
"type": "assistant-output-copy",
|
|
"index": MATCH,
|
|
},
|
|
"id",
|
|
),
|
|
Input(
|
|
{
|
|
"type": "assistant-output-copy",
|
|
"index": MATCH,
|
|
},
|
|
"nClicks",
|
|
),
|
|
State(
|
|
{
|
|
# "type": "assistant-output-markdown",
|
|
"type": "assistant-output-json",
|
|
"index": MATCH,
|
|
},
|
|
"data",
|
|
),
|
|
prevent_initial_call=True,
|
|
)
|
|
|
|
|
|
@app.callback(
|
|
Output({"type": "assistant-output-json", "index": MATCH}, 'data'),
|
|
Input("input", "input_ids"),
|
|
State("conversation-id", "data"),
|
|
prevent_initial_call=True,
|
|
)
|
|
def update_output(input_ids,filters):
|
|
"开始进行更新回调"
|
|
output = []
|
|
index = 0
|
|
num_values = len(values)
|
|
value_idx = 0
|
|
filter_new = ''
|
|
while index < len(filters) and value_idx < num_values:
|
|
filter = filters[index]
|
|
if filter['type'] == 'date':
|
|
start_date = values[value_idx]
|
|
end_date = values[value_idx + 1]
|
|
output.append(f"{filter['name']}: {start_date} 到 {end_date}")
|
|
value_idx += 2
|
|
new_date_value = {"start_date": start_date, "end_date": end_date}
|
|
# print("*******new"+str(new_date_value))
|
|
updated_filters = update_filters(filters, index, new_date_value)
|
|
# print("*******new")
|
|
# print(filter_new)
|
|
|
|
elif filter['type'] == 'number' and 'equal' in filter['default_value'] and filter['default_value']['equal'] is not None:
|
|
value = values[value_idx]
|
|
output.append(f"{filter['name']}: {value}")
|
|
value_idx += 1
|
|
new_date_value = value
|
|
updated_filters = update_filters(filters, index, new_date_value)
|
|
|
|
elif filter['type'] == 'number':
|
|
min_value = values[value_idx]
|
|
max_value = values[value_idx + 1]
|
|
output.append(f"{filter['name']}: {min_value} to {max_value}")
|
|
value_idx += 2
|
|
new_capital_value = {"min": min_value, "max": max_value}
|
|
updated_filters = update_filters(filters, index, new_capital_value)
|
|
|
|
else:
|
|
value = values[value_idx]
|
|
output.append(f"{filter['name']}: {value}")
|
|
value_idx += 1
|
|
new_value = value
|
|
updated_filters = update_filters(filters, index, new_value)
|
|
index += 1
|
|
|
|
print("*******new")
|
|
print (updated_filters)
|
|
return updated_filters
|
|
|
|
app.clientside_callback(
|
|
# 更新标题栏显示的“当前模型”
|
|
ClientsideFunction(namespace="clientside", function_name="showCurrentModel"),
|
|
Output("header-bar-current-model", "children"),
|
|
Input("chat-setting-model", "value"),
|
|
)
|
|
|
|
app.clientside_callback(
|
|
# 更新标题栏显示的“对话数量”,
|
|
"""(children) => `共 ${children.length} 条对话`""",
|
|
Output("header-bar-chat-message-count", "children"),
|
|
Input("chat-area-list", "children"),
|
|
)
|
|
|
|
# app.clientside_callback(
|
|
# """(nClicks, values, controlParams) => {
|
|
# if (!values) {
|
|
# return window.dash_clientside.no_update;
|
|
# }
|
|
|
|
# // 打印 values
|
|
# console.log("values (formatted as JSON):", JSON.stringify(values, null, 2));
|
|
# console.log("controlParams (formatted as JSON):", JSON.stringify(controlParams, null, 2));
|
|
|
|
# let resultStr = "";
|
|
|
|
# // 日期处理
|
|
# if (values["日期"]) {
|
|
# resultStr += `日期为${values["日期"][0]}到${values["日期"][1]};`;
|
|
# }
|
|
|
|
# // 其他字段处理
|
|
# for (let key in values) {
|
|
# if (key !== "日期") {
|
|
# if (Array.isArray(values[key])) {
|
|
# resultStr += `${key}为${values[key].join("、")};`;
|
|
# } else {
|
|
# resultStr += `${key}为${values[key]};`;
|
|
# }
|
|
# }
|
|
# }
|
|
|
|
# console.log(resultStr);
|
|
|
|
# // 写入当前内容到粘贴板
|
|
# navigator.clipboard.writeText(resultStr);
|
|
# return window.dash_clientside.no_update;
|
|
# }""",
|
|
# Output({"type": "copy-params", "index": MATCH}, "id"),
|
|
# Input({"type": "copy-params", "index": MATCH}, "nClicks"),
|
|
# State({"type": "control-group", "index": MATCH}, "values"),
|
|
# State({"type": "control-group-store", "index": MATCH}, "data"),
|
|
# prevent_initial_call=True,
|
|
# )
|
|
|
|
# app.clientside_callback(
|
|
# """(nClicks, values, controlParams) => {
|
|
# if (!values || !controlParams) {
|
|
# return window.dash_clientside.no_update;
|
|
# }
|
|
|
|
# // 打印 values 和 controlParams
|
|
# console.log("values (formatted as JSON):", JSON.stringify(values, null, 2));
|
|
# console.log("controlParams (formatted as JSON):", JSON.stringify(controlParams, null, 2));
|
|
|
|
# let queryParts = [];
|
|
# let outputParts = [];
|
|
|
|
# // 遍历 controlParams,匹配 values
|
|
# controlParams.forEach(param => {
|
|
# const name = param.name;
|
|
# const cdType = param.cd_type;
|
|
|
|
# if (values.hasOwnProperty(name) && values[name]) {
|
|
# const value = values[name];
|
|
|
|
# // 打印 value 的值
|
|
# console.log(`值 "${name}" 的值为:`, value);
|
|
# if (cdType === "维度筛选") {
|
|
# // 处理维度筛选,生成已知部分
|
|
# queryParts.push(`${name}为${value}`);
|
|
# } else if (cdType === "输出结果") {
|
|
# // 处理输出结果部分
|
|
# outputParts.push(name);
|
|
# }
|
|
# }
|
|
# });
|
|
|
|
# // 构建查询部分的字符串
|
|
# let resultStr = "";
|
|
# if (queryParts.length > 0) {
|
|
# resultStr += `已知${queryParts.join(",")},进行查询`;
|
|
# }
|
|
# // 构建输出结果的字符串
|
|
# if (outputParts.length > 0) {
|
|
# resultStr += `,输出结果为${outputParts.join(",")}。`;
|
|
# }
|
|
|
|
# console.log(resultStr);
|
|
|
|
# // 将结果写入剪贴板
|
|
# navigator.clipboard.writeText(resultStr);
|
|
|
|
# return window.dash_clientside.no_update;
|
|
# }""",
|
|
# Output({"type": "copy-params", "index": MATCH}, "id"),
|
|
# Input({"type": "copy-params", "index": MATCH}, "nClicks"),
|
|
# State({"type": "control-group", "index": MATCH}, "values"),
|
|
# State({"type": "control-group-store", "index": MATCH}, "data"),
|
|
# prevent_initial_call=True,
|
|
# )
|
|
|
|
app.clientside_callback(
|
|
"""
|
|
(nClicks, values, controlParams) => {
|
|
if (!values || !controlParams) {
|
|
console.log("values 或 controlParams 为空,未进行更新");
|
|
return window.dash_clientside.no_update;
|
|
}
|
|
|
|
// 打印初始的 values 和 controlParams
|
|
console.log("初始 values (formatted as JSON):", JSON.stringify(values, null, 2));
|
|
console.log("初始 controlParams (formatted as JSON):", JSON.stringify(controlParams, null, 2));
|
|
|
|
let queryParts = [];
|
|
let outputParts = [];
|
|
|
|
// 遍历 values,匹配 controlParams
|
|
Object.keys(values).forEach(name => {
|
|
const value = values[name];
|
|
console.log(`正在处理值 "${name}", 值为:`, value);
|
|
|
|
// 查找对应的 controlParams
|
|
const param = controlParams.find(p => p.name === name);
|
|
|
|
if (param) {
|
|
const cdType = param.cd_type;
|
|
console.log(`找到参数,cd_type为:`, cdType);
|
|
|
|
if (cdType === "维度筛选" || cdType === "时间筛选" || cdType === "查询其它条件") {
|
|
// 处理维度筛选,生成已知部分
|
|
const queryPart = `${name}为${value}`;
|
|
queryParts.push(queryPart);
|
|
console.log(`添加到查询部分:`, queryPart);
|
|
} else if (cdType === "输出结果") {
|
|
// 处理输出结果部分
|
|
outputParts.push(name);
|
|
console.log(`添加到输出结果部分:`, name);
|
|
}
|
|
} else {
|
|
console.log(`未找到 "${name}" 对应的 controlParams`);
|
|
}
|
|
});
|
|
|
|
// 构建查询部分的字符串
|
|
let resultStr = "";
|
|
if (queryParts.length > 0) {
|
|
resultStr += `已知${queryParts.join(",")},进行查询`;
|
|
console.log(`构建的查询字符串:`, resultStr);
|
|
}
|
|
// 构建输出结果的字符串
|
|
if (outputParts.length > 0) {
|
|
resultStr += `,输出结果为${outputParts.join(",")}。`;
|
|
console.log(`构建的输出结果字符串:`, resultStr);
|
|
}
|
|
|
|
console.log("最终结果字符串:", resultStr);
|
|
|
|
// 将结果写入剪贴板
|
|
navigator.clipboard.writeText(resultStr).then(() => {
|
|
console.log("结果已复制到剪贴板");
|
|
}).catch(err => {
|
|
console.error("复制到剪贴板失败:", err);
|
|
});
|
|
|
|
return window.dash_clientside.no_update;
|
|
}
|
|
""",
|
|
Output({"type": "copy-params", "index": MATCH}, "id"),
|
|
Input({"type": "copy-params", "index": MATCH}, "nClicks"),
|
|
State({"type": "control-group", "index": MATCH}, "values"),
|
|
State({"type": "control-group-store", "index": MATCH}, "data"),
|
|
prevent_initial_call=True
|
|
)
|
|
|
|
@app.callback(
|
|
Output('download-table', 'data'),
|
|
Input('execute-download', 'nClicks'),
|
|
[State('data-table', 'data'),
|
|
State('data-table', 'columns')],
|
|
prevent_initial_call=True
|
|
)
|
|
def download_to_excel(nClicks, data, columns):
|
|
|
|
output = io.BytesIO()
|
|
|
|
(
|
|
pd
|
|
.DataFrame(
|
|
data,
|
|
columns=[column['title'] for column in columns]
|
|
)
|
|
.to_excel(output, index=False)
|
|
)
|
|
|
|
return dcc.send_bytes(output.getvalue(), '数据文件.xlsx')
|
|
|
|
app.clientside_callback(
|
|
# 处理控件组编辑抽屉的打开
|
|
"() => true",
|
|
Output({"type": "edit-widgets-drawer", "index": MATCH}, "visible"),
|
|
Input({"type": "edit-widgets", "index": MATCH}, "nClicks"),
|
|
prevent_initial_call=True,
|
|
)
|
|
|
|
|
|
# 定义回调
|
|
@app.callback(
|
|
Output({'type': 'input-text1', 'index': MATCH}, 'value'),
|
|
Input({"type": "control-group-store", "index": MATCH}, "data"),
|
|
State({"type": "input-text1", "index": MATCH}, "value"),
|
|
prevent_initial_call=True,
|
|
)
|
|
def update_output(data,current_value):
|
|
# ctx = callback_context
|
|
print("进入input-text1的回调函数")
|
|
print(data)
|
|
print(type(data))
|
|
print(type(current_value))
|
|
# result = '查询条件包括' + ', '.join([f"{format_default_value(item)}" if item['cd_type'] == '输出结果' else f"{item['name']}为{format_default_value(item)}" for item in data])
|
|
# if current_value is None:
|
|
# current_value = ""
|
|
# elif isinstance(current_value, (list, dict)):
|
|
# current_value = json.dumps(current_value, ensure_ascii=False, indent=4)
|
|
# else:
|
|
# current_value = str(current_value)
|
|
|
|
# if data is None:
|
|
# data_string = ""
|
|
# else:
|
|
# data_string = json.dumps(data, ensure_ascii=False, indent=4)
|
|
|
|
# result_string = "自动生成:" + data_string + current_value
|
|
# return [result_string] # 返回一个列表
|
|
# 生成字符串并在开始添加"查询"
|
|
output_results = []
|
|
result_list = []
|
|
|
|
for item in data:
|
|
if item['cd_type'] == '输出结果':
|
|
output_results.append(format_default_value(item)) # 收集所有输出结果的name
|
|
else:
|
|
result_list.append(f"{item['name']}为{format_default_value(item)}")
|
|
|
|
# 拼接输出结果
|
|
if output_results:
|
|
result_list.append(f"输出结果为{'和'.join(output_results)}")
|
|
|
|
# 最终结果字符串
|
|
result = '查询' + ', '.join(result_list)
|
|
return result
|
|
|
|
|
|
|
|
@app.callback(
|
|
[
|
|
Output({"type": "edit-widgets-table", "index": MATCH}, "data"),
|
|
# Output({"type": "control-group", "index": MATCH}, "children"),
|
|
],
|
|
Input({"type": "control-group-store", "index": MATCH}, "data"),
|
|
prevent_initial_call=True,
|
|
)
|
|
def update_edit_widgets_table_data(data):
|
|
"""控制对应控件组数据状态更新后,控件组的重新渲染生成"""
|
|
print("!@#***8update_edit_widgets_table_data")
|
|
# print(data)
|
|
# print(param)
|
|
return [
|
|
[
|
|
{
|
|
"字段名称": param["name"],
|
|
"条件类型": param["cd_type"],
|
|
"控件类型": get_translation_ct_type(param["ct_type"]),
|
|
"条件取值": chat_message_box.get_value(param),
|
|
"操作": [
|
|
{"content": "编辑", "type": "link"},
|
|
{"content": "上移", "type": "link"},
|
|
{"content": "下移", "type": "link"},
|
|
{
|
|
"content": "删除",
|
|
"type": "link",
|
|
"danger": True,
|
|
"disabled": len(data) == 1, # 仅有一个控件时不可删除
|
|
},
|
|
],
|
|
"param": param,
|
|
}
|
|
for param in data
|
|
],
|
|
]
|
|
|
|
|
|
@app.callback(
|
|
[
|
|
Output({"type": "edit-widget-modal", "index": MATCH}, "visible"),
|
|
Output({"type": "edit-widget-modal", "index": MATCH}, "children"),
|
|
],
|
|
[
|
|
Input({"type": "edit-widgets-table", "index": MATCH}, "nClicksButton"),
|
|
Input({"type": "edit-widgets-table", "index": MATCH}, "clickedContent"),
|
|
Input(
|
|
{"type": "edit-widgets-table", "index": MATCH}, "recentlyButtonClickedRow"
|
|
),
|
|
],
|
|
State({"type": "control-group-store", "index": MATCH}, "data"),
|
|
prevent_initial_call=True,
|
|
)
|
|
def open_edit_widget_modal(
|
|
nClicksButton, clickedContent, recentlyButtonClickedRow, data
|
|
):
|
|
"""处理控件组编辑表格中的各操作按钮对应操作内容"""
|
|
print("open_edit_widget_modal")
|
|
|
|
if clickedContent == "编辑":
|
|
return [
|
|
True,
|
|
fac.AntdForm(
|
|
[
|
|
fac.AntdRow(
|
|
[
|
|
fac.AntdCol(
|
|
fac.AntdFormItem(
|
|
fac.AntdInput(
|
|
id={
|
|
'type': 'edit-widget-modal-name',
|
|
'index': dash.ctx.triggered_id["index"],
|
|
},
|
|
# readOnly=True,
|
|
value= recentlyButtonClickedRow["param"]["name"],
|
|
style={
|
|
'width': '85%'
|
|
}
|
|
),
|
|
label='字段名称',
|
|
labelCol={
|
|
'offset': 1
|
|
}
|
|
),
|
|
span=12
|
|
),
|
|
fac.AntdCol(
|
|
fac.AntdFormItem(
|
|
fac.AntdInput(
|
|
id={
|
|
'type': 'edit-widget-modal-d_type',
|
|
'index': dash.ctx.triggered_id["index"],
|
|
},
|
|
# readOnly=True,
|
|
value= recentlyButtonClickedRow["param"]["d_type"],
|
|
style={
|
|
'width': '85%'
|
|
}
|
|
),
|
|
label='字段类型',
|
|
labelCol={
|
|
'offset': 1
|
|
}
|
|
),
|
|
span=12
|
|
),
|
|
],
|
|
gutter=5
|
|
),
|
|
fac.AntdRow(
|
|
[
|
|
fac.AntdCol(
|
|
fac.AntdFormItem(
|
|
fac.AntdSelect(
|
|
id={
|
|
'type': 'edit-widget-modal-ct_type',
|
|
'index': dash.ctx.triggered_id["index"]
|
|
},
|
|
placeholder='请选择控件类型',
|
|
options=[
|
|
{
|
|
'label': '单日筛选',
|
|
'value': 'datePicker'
|
|
},
|
|
{
|
|
'label': '周期筛选',
|
|
'value': 'dateRangePicker'
|
|
},
|
|
{
|
|
'label': '输入框',
|
|
'value': 'input'
|
|
},
|
|
{
|
|
'label': '单项筛选',
|
|
'value': 'select'
|
|
},
|
|
{
|
|
'label': '多项筛选',
|
|
'value': 'mselect'
|
|
},
|
|
{
|
|
'label': '是否筛选',
|
|
'value': 'radioGroup'
|
|
}
|
|
],
|
|
# defaultValue = get_translation_ct_type(recentlyButtonClickedRow["param"]["ct_type"]),
|
|
value = recentlyButtonClickedRow["param"]["ct_type"],
|
|
style={
|
|
'width': '85%'
|
|
}
|
|
),
|
|
label='控件类型',
|
|
labelCol={
|
|
'offset': 1
|
|
},
|
|
),
|
|
span=12
|
|
),
|
|
fac.AntdCol(
|
|
fac.AntdFormItem(
|
|
fac.AntdSelect(
|
|
id={
|
|
'type': 'edit-widget-modal-cd_type',
|
|
'index': dash.ctx.triggered_id["index"]
|
|
},
|
|
placeholder='请选择条件类型',
|
|
options=[
|
|
{
|
|
'label': '时间筛选',
|
|
'value': '时间筛选'
|
|
},
|
|
{
|
|
'label': '维度筛选',
|
|
'value': '维度筛选'
|
|
},
|
|
{
|
|
'label': '分组条件',
|
|
'value': '分组条件'
|
|
},
|
|
{
|
|
'label': '查询其它条件',
|
|
'value': '查询其它条件'
|
|
},
|
|
{
|
|
'label': '输出结果',
|
|
'value': '输出结果'
|
|
},
|
|
{
|
|
'label': '输出其它条件',
|
|
'value': '输出其它条件'
|
|
}
|
|
],
|
|
value = recentlyButtonClickedRow["param"]["cd_type"],
|
|
style={
|
|
'width': '85%'
|
|
}
|
|
),
|
|
label='条件类型',
|
|
labelCol={
|
|
'offset': 1
|
|
},
|
|
),
|
|
span=12
|
|
)
|
|
],
|
|
gutter=5
|
|
),
|
|
fac.AntdRow(
|
|
[
|
|
fac.AntdCol(
|
|
fac.AntdFormItem(
|
|
fac.AntdInput(
|
|
id={
|
|
'type': 'edit-widget-modal-value',
|
|
'index': dash.ctx.triggered_id["index"]
|
|
},
|
|
# placeholder='请根据需求输入条件取值内容',
|
|
allowClear=True,
|
|
mode='text-area',
|
|
value = chat_message_box.get_value(recentlyButtonClickedRow["param"]),
|
|
style={
|
|
'width': '370px',
|
|
'height': '60px'
|
|
}
|
|
),
|
|
label='条件取值',
|
|
labelCol={
|
|
'offset': 1
|
|
},
|
|
),
|
|
span=24
|
|
),
|
|
],
|
|
gutter=5
|
|
),
|
|
],
|
|
layout="horizontal",
|
|
),
|
|
]
|
|
elif clickedContent == "删除":
|
|
# 直接操纵数据更新
|
|
# print("dash.ctx.triggered_id["index"]")
|
|
# print(dash.ctx.triggered_id["index"])
|
|
set_props(
|
|
{
|
|
"type": "control-group-store",
|
|
"index": dash.ctx.triggered_id["index"],
|
|
},
|
|
{
|
|
"data": [
|
|
param
|
|
for i, param in enumerate(data)
|
|
if i != int(recentlyButtonClickedRow["key"])
|
|
]
|
|
},
|
|
)
|
|
# 消息提示
|
|
set_props(
|
|
"global-message",
|
|
{"children": fac.AntdMessage(content="删除成功", type="success")},
|
|
)
|
|
|
|
return False, None
|
|
elif clickedContent == "上移":
|
|
new_data = [
|
|
data[i - 1] if i == int(recentlyButtonClickedRow["key"]) else
|
|
data[i + 1] if i == int(recentlyButtonClickedRow["key"]) - 1 else
|
|
param
|
|
for i, param in enumerate(data)
|
|
]
|
|
# print(new_data)
|
|
# 如果点击的是第一个元素,原样返回
|
|
if int(recentlyButtonClickedRow["key"]) == 0:
|
|
new_data = data
|
|
|
|
set_props(
|
|
{
|
|
"type": "control-group-store",
|
|
"index": dash.ctx.triggered_id["index"],
|
|
},
|
|
{
|
|
"data": new_data
|
|
},
|
|
)
|
|
# 消息提示
|
|
set_props(
|
|
"global-message",
|
|
{"children": fac.AntdMessage(content="上移成功", type="success")},
|
|
)
|
|
return False, None
|
|
elif clickedContent == "下移":
|
|
key_index = int(recentlyButtonClickedRow["key"])
|
|
|
|
# 确保 key_index 在有效范围内
|
|
if key_index >= 0 and key_index < len(data) - 1:
|
|
new_data = [
|
|
data[i + 1] if i == key_index else
|
|
data[i - 1] if i == key_index + 1 else
|
|
param
|
|
for i, param in enumerate(data)
|
|
]
|
|
else:
|
|
new_data = data
|
|
|
|
# 如果点击的是最后一个元素,原样返回
|
|
if key_index == len(data) - 1:
|
|
new_data = data
|
|
|
|
set_props(
|
|
{
|
|
"type": "control-group-store",
|
|
"index": dash.ctx.triggered_id["index"],
|
|
},
|
|
{
|
|
"data": new_data
|
|
},
|
|
)
|
|
set_props(
|
|
"global-message",
|
|
{"children": fac.AntdMessage(content="下移成功", type="success")},
|
|
)
|
|
return False, None
|
|
|
|
return True, None
|
|
|
|
@app.callback(
|
|
Output({"type": "control-group-store", "index": MATCH}, "data",allow_duplicate=True),
|
|
Input({"type": "edit-widget-modal", "index": MATCH}, "okCounts"),
|
|
[
|
|
State(
|
|
{
|
|
"type": "edit-widget-modal-cd_type",
|
|
"index": MATCH,
|
|
},
|
|
"value",
|
|
),
|
|
State(
|
|
{
|
|
"type": "edit-widget-modal-ct_type",
|
|
"index": MATCH,
|
|
},
|
|
"value",
|
|
),
|
|
State(
|
|
{
|
|
"type": "edit-widget-modal-value",
|
|
"index": MATCH,
|
|
},
|
|
"value",
|
|
),
|
|
State({"type": "control-group-store", "index": MATCH}, "data"),
|
|
State(
|
|
{"type": "edit-widgets-table", "index": MATCH}, "recentlyButtonClickedRow"
|
|
),
|
|
],
|
|
prevent_initial_call=True,
|
|
)
|
|
def handle_widget_param_update(
|
|
# okCounts, name, cd_type,ct_type,value,origin_data, recentlyButtonClickedRow
|
|
okCounts, cd_type,ct_type,value,origin_data, recentlyButtonClickedRow
|
|
):
|
|
"""控控件编辑模态框点击“确认”按钮后的操作落实"""
|
|
print("handle_widget_param_update")
|
|
|
|
origin_data[int(recentlyButtonClickedRow["key"])] = {
|
|
**origin_data[int(recentlyButtonClickedRow["key"])],
|
|
# "filter_type": filter_type,
|
|
# "name": name,
|
|
"cd_type":cd_type,
|
|
"ct_type":ct_type,
|
|
"default_value":value,
|
|
# "options": options.split("、"),
|
|
}
|
|
|
|
# 消息提示
|
|
set_props(
|
|
"global-message",
|
|
{"children": fac.AntdMessage(content="更新成功", type="success")},
|
|
)
|
|
print("**********")
|
|
print(origin_data)
|
|
return origin_data
|
|
|
|
@app.callback(
|
|
[
|
|
Output("chat-export-download", "data"),
|
|
Output("chat-export-modal", "confirmLoading"),
|
|
],
|
|
Input("chat-export-modal", "okCounts"),
|
|
[State("conversation-id", "data"), State("chat-export-format", "value")],
|
|
prevent_initial_call=True,
|
|
)
|
|
def handle_chat_export(okCounts, conversation_id, export_format):
|
|
"""处理当前聊天记录的导出"""
|
|
|
|
time.sleep(0.5)
|
|
|
|
# 查询当前对话id对应的完整对话记录
|
|
chat_records = conversation_cache.get(conversation_id)
|
|
|
|
if export_format == "json":
|
|
set_props(
|
|
"global-message",
|
|
{"children": fac.AntdMessage(type="success", content="导出成功")},
|
|
)
|
|
return [
|
|
dict(
|
|
content=json.dumps(chat_records, ensure_ascii=False, indent=4),
|
|
filename="对话导出{}.json".format(
|
|
datetime.now().strftime("%Y%m%d%H%M%S")
|
|
),
|
|
),
|
|
False,
|
|
]
|
|
|
|
elif export_format == "markdown":
|
|
markdown_str = ""
|
|
|
|
for record in chat_records:
|
|
markdown_str += "> role: " + record["role"] + "\n\n"
|
|
markdown_str += record.get("content") + "\n\n---\n\n"
|
|
|
|
set_props(
|
|
"global-message",
|
|
{"children": fac.AntdMessage(type="success", content="导出成功")},
|
|
)
|
|
return [
|
|
dict(
|
|
content=markdown_str,
|
|
filename="对话导出{}.md".format(
|
|
datetime.now().strftime("%Y%m%d%H%M%S")
|
|
),
|
|
),
|
|
False,
|
|
]
|
|
|
|
return dash.no_update
|
|
|
|
|
|
# @app.callback(
|
|
# Output('copy-text-output', 'text'),
|
|
# Input('copy-text-input', 'value')
|
|
# )
|
|
@app.callback(
|
|
Output({"type": "copy-text-output", "index": MATCH}, "text"),
|
|
Input({"type": "input-text1", "index": MATCH}, "value"),
|
|
prevent_initial_call=True,
|
|
)
|
|
def copy_text_callback(value):
|
|
return value or '无内容'
|