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

1 month ago
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 '无内容'