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