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

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