From 4c03e4d7942a0dad779688b1035771c80bcac952 Mon Sep 17 00:00:00 2001 From: JackLee <809262979@qq.com> Date: Tue, 4 Mar 2025 15:58:23 +0800 Subject: [PATCH] update --- .vscode/settings.json | 3 +- src/ctai_base.h | 12 +-- src/ctai_history_textedit.cpp | 148 ++++++++++++++-------------------- src/ctai_history_textedit.h | 39 ++++++--- src/ctai_history_widget.cpp | 38 ++++++--- src/ctai_markdown.h | 1 - 6 files changed, 122 insertions(+), 119 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 982f4ed..2b5717f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -101,7 +101,8 @@ "qfiledialog": "cpp", "qtimer": "cpp", "qstring": "cpp", - "qabstracttextdocumentlayout": "cpp" + "qabstracttextdocumentlayout": "cpp", + "qframe": "cpp" }, "editor.gotoLocation.alternativeDeclarationCommand": "editor.action.revealDefinition", "editor.gotoLocation.alternativeDefinitionCommand": "editor.action.revealDefinition", diff --git a/src/ctai_base.h b/src/ctai_base.h index 9950ce2..0f37107 100644 --- a/src/ctai_base.h +++ b/src/ctai_base.h @@ -27,12 +27,12 @@ typedef struct curl_opts } curl_opts; typedef struct model_data{ - std::string api_url = "https://api.deepseek.com/chat/completions"; - std::string api_key = "Authorization: Bearer sk-7e6932ed45674c389dea1cd3481e0ec2"; - std::string user_model = "deepseek-chat"; - //std::string api_url="https://api.siliconflow.cn/v1/chat/completions"; - //std::string api_key="Authorization: Bearer sk-oiphigpzqtmkkcoucyakrfevcvndroywvxhprvscjqhdykdb"; - //std::string user_model = "deepseek-ai/DeepSeek-V3"; + //std::string api_url = "https://api.deepseek.com/chat/completions"; + //std::string api_key = "Authorization: Bearer sk-7e6932ed45674c389dea1cd3481e0ec2"; + //std::string user_model = "deepseek-chat"; + std::string api_url="https://api.siliconflow.cn/v1/chat/completions"; + std::string api_key="Authorization: Bearer sk-oiphigpzqtmkkcoucyakrfevcvndroywvxhprvscjqhdykdb"; + std::string user_model = "deepseek-ai/DeepSeek-V3"; std::string send_content_header = "Content-Type: application/json"; std::string send_accept_header = "Accept: application/json"; std::string send_user_data; diff --git a/src/ctai_history_textedit.cpp b/src/ctai_history_textedit.cpp index e438e5e..b1cd991 100644 --- a/src/ctai_history_textedit.cpp +++ b/src/ctai_history_textedit.cpp @@ -1,8 +1,8 @@ #include "ctai_history_textedit.h" -ctai_history_textedit::ctai_history_textedit(msg_type msg_type_mode) +ctai_history_textedit::ctai_history_textedit(QWidget *parent) + : QWidget(parent) { - init_layout(msg_type_mode); } ctai_history_textedit::~ctai_history_textedit() { @@ -19,9 +19,9 @@ void ctai_history_textedit::init_layout(msg_type msg_type_mode) m_msg_header->setReadOnly(true); if (msg_type_mode == SYSTEM) { - //SYSTEM消息头水平 + // SYSTEM消息头水平 m_msg_system_header_ico = new QPushButton(); - m_msg_system_header_ico->setObjectName("m_msg_system_header_ico"); + m_msg_system_header_ico->setObjectName("m_msg_system_header_ico"); header_info_Layout->addWidget(m_msg_system_header_ico); header_info_Layout->addWidget(m_msg_header); header_info_Layout->setContentsMargins(0, 0, 0, 0); @@ -29,7 +29,7 @@ void ctai_history_textedit::init_layout(msg_type msg_type_mode) // 2.tokens功能按钮 m_msg_tokens = new QPushButton(); m_msg_tokens->setObjectName("m_msg_tokens"); - m_history_to_send=new QPushButton(); + m_history_to_send = new QPushButton(); m_history_to_send->setObjectName("m_history_to_send"); header_info_Layout->addWidget(m_history_to_send); header_info_Layout->addWidget(m_msg_tokens); @@ -41,7 +41,7 @@ void ctai_history_textedit::init_layout(msg_type msg_type_mode) m_msg_save = new QPushButton(); m_msg_menu = new QPushButton(); m_msg_fold = new QPushButton(); - m_restart_to_send= new QPushButton(); + m_restart_to_send = new QPushButton(); m_msg_system_del->setObjectName("m_msg_system_del"); m_restart_to_send->setObjectName("m_restart_to_send"); m_msg_copy->setObjectName("m_msg_copy"); @@ -49,8 +49,8 @@ void ctai_history_textedit::init_layout(msg_type msg_type_mode) m_msg_menu->setObjectName("m_msg_menu"); m_msg_fold->setObjectName("m_msg_fold"); m_msg_fold->setIcon(QIcon(":res/img/btn/btn_info_up.png")); - m_msg_fold->setMinimumSize(QSize(25,25)); - header_opts_Layout->addItem(sparcer_item); + m_msg_fold->setMinimumSize(QSize(25, 25)); + header_opts_Layout->addItem(sparcer_item); header_opts_Layout->addWidget(m_restart_to_send); header_opts_Layout->addWidget(m_msg_system_del); header_opts_Layout->addWidget(m_msg_copy); @@ -63,19 +63,19 @@ void ctai_history_textedit::init_layout(msg_type msg_type_mode) } else { - //SYSTEM MSG ICO + // SYSTEM MSG ICO m_msg_user_header_ico = new QPushButton(); - m_msg_user_header_ico->setObjectName("m_msg_system_header_ico"); + m_msg_user_header_ico->setObjectName("m_msg_system_header_ico"); header_info_Layout->addWidget(m_msg_user_header_ico); header_info_Layout->addWidget(m_msg_header); header_info_Layout->setContentsMargins(0, 0, 0, 0); headerLayout->addLayout(header_info_Layout); - //USER DELETE BUTTON + // USER DELETE BUTTON m_msg_user_del = new QPushButton(); m_msg_user_del->setObjectName("m_msg_user_del"); - m_history_to_send=new QPushButton(); + m_history_to_send = new QPushButton(); m_history_to_send->setObjectName("m_history_to_send"); - m_restart_to_send= new QPushButton(); + m_restart_to_send = new QPushButton(); m_restart_to_send->setObjectName("m_restart_to_send"); header_info_Layout->addWidget(m_restart_to_send); header_info_Layout->addWidget(m_history_to_send); @@ -83,7 +83,7 @@ void ctai_history_textedit::init_layout(msg_type msg_type_mode) } // 4.分割线区域 hLine = new QFrame; - hLine->setFrameShape(QFrame::HLine); // 关键属性 + hLine->setFrameShape(QFrame::HLine); // 关键属性 hLine->setFrameShadow(QFrame::Sunken); // 凹陷效果 hLine->setLineWidth(2); // 线宽 // 5. 历史信息QTextEdit @@ -92,6 +92,7 @@ void ctai_history_textedit::init_layout(msg_type msg_type_mode) m_msg_history->setAcceptRichText(true); m_msg_history->setLineWrapMode(QTextEdit::WidgetWidth); m_msg_history->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_msg_history->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); // 添加性能优化设置 m_msg_history->setUndoRedoEnabled(false); // 禁用撤销重做 m_msg_history->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); @@ -129,68 +130,7 @@ void ctai_history_textedit::connect_signals(msg_type msg_type_mode) } connect(m_msg_history->document(), SIGNAL(contentsChanged()), this, SLOT(on_text_height())); } -void ctai_history_textedit::on_text_height() -{ - // 防抖动处理:如果上次更新在100ms内,则延迟处理 - static QTimer debounceTimer; - debounceTimer.setSingleShot(true); - if (debounceTimer.isActive()) - { - return; - } - - // 使用viewport宽度作为缓存 - static int lastWidth = 0; - int currentWidth = m_msg_history->viewport()->width(); - - // 只在宽度变化时才重新计算 - if (lastWidth != currentWidth) - { - m_msg_history->document()->setTextWidth(currentWidth); - lastWidth = currentWidth; - } - - // 直接使用documentLayout获取高度,避免多次计算 - int textHeight = m_msg_history->document()->documentLayout()->documentSize().height(); - - if (textHeight > 0) - { - // 计算实际需要的高度 (包含边距和视口边框) - int newHeight = textHeight + - m_msg_history->document()->documentMargin() * 2 + - m_msg_history->frameWidth() * 2; - - // 添加高度阈值判断,避免微小变化触发更新 - static const int HEIGHT_THRESHOLD = 5; // 5像素的阈值 - if (abs(m_msg_history->height() - newHeight) > HEIGHT_THRESHOLD) - { - m_original_height = newHeight; - - // 批量更新布局 - bool wasBlocked = m_msg_history->signalsBlocked(); - m_msg_history->blockSignals(true); - - m_msg_history->setFixedHeight(newHeight); - updateGeometry(); - - m_msg_history->blockSignals(wasBlocked); - emit height_changed(); - - // 延迟发送布局更新请求 - if (QWidget *parent = parentWidget()) - { - QTimer::singleShot(100, [parent]() - { - QEvent e(QEvent::LayoutRequest); - QApplication::sendEvent(parent, &e); }); - } - } - } - - // 设置下一次检查的延迟 - debounceTimer.start(100); -} // tokens按钮实现功能的槽函数 void ctai_history_textedit::on_tokens_clicked() { @@ -267,31 +207,65 @@ void ctai_history_textedit::on_fold_clicked() m_msg_fold->setIcon(QIcon(m_is_folded ? ":res/img/btn/btn_info_down.png" : ":res/img/btn/btn_info_up.png")); updateGeometry(); + emit height_changed(); } -void ctai_history_textedit::add_message(const model_data &message) +void ctai_history_textedit::on_text_height() +{ + +} +void ctai_history_textedit::add_user_message(const model_data &message) { - std::lock_guard lock(m_mutex); QString disp_data; - QString disp_header; + disp_data = ctai_markdown::md_to_html(QSL(message.send_user_data)); + m_msg_sned_id = QSL(message.send_user_id); + m_msg_history->setHtml(disp_data); +} + +void ctai_history_textedit::add_system_message(const model_data &message) +{ + QString disp_data; + m_msg_sned_id = QSL(message.send_user_id); + std::lock_guard lock(m_mutex); + + if (message.postback_stream_mode) + { + // 流式模式下追加内容 + m_current_content += message.postback_model_data; + m_msg_history->setHtml(ctai_markdown::md_to_html(m_current_content)); + } + else + { + // 非流式模式直接设置全部内容 + disp_data = ctai_markdown::md_to_html(QSL(message.postback_model_data)); + m_msg_history->setHtml(disp_data); + m_current_content = QSL(message.postback_model_data); + } +} +// 增加tokens信息 +void ctai_history_textedit::update_tokens_message(const model_data &message) +{ if (message.msg_type_mode == SYSTEM) { - disp_header = "ID:" + QSL(message.postback_send_id) + " | FP:" + QSL(message.postback_system_fingerprint) + " | 时间:" + QSL(message.postback_time); m_tokens_data.prompt_tokens = "提示词消耗tokens:" + QSN(message.postback_prompt_tokens); m_tokens_data.completion_tokens = "生成信息消耗:tokens:" + QSN(message.postback_completion_tokens); m_tokens_data.total_tokens = "总消耗tokens:" + QSN(message.postback_total_tokens); m_tokens_data.cache_hit_tokens = "提示词缓存命中消耗tokens:" + QSN(message.postback_prompt_cache_hit_tokens); m_tokens_data.cache_miss_tokens = "提示词缓存未命中消耗tokens:" + QSN(message.postback_prompt_cache_miss_tokens); - disp_data =ctai_markdown::md_to_html(QSL(message.postback_model_data)); - m_msg_sned_id = QSL(message.postback_send_id); + } +} +// 增加头信息 +void ctai_history_textedit::add_header_message(const model_data &message) +{ + QString disp_header; + if (message.msg_type_mode == SYSTEM) + { + disp_header = "ID:" + QSL(message.postback_send_id) + " | FP:" + QSL(message.postback_system_fingerprint) + " | 时间:" + QSL(message.postback_time); } else { disp_header = "ID:" + QSL(message.send_user_id) + " | Time:" + QSL(message.send_user_time); - disp_data = ctai_markdown::md_to_html(QSL(message.send_user_data)); - m_msg_sned_id = QSL(message.send_user_id); } - m_msg_header->setText(disp_header); - m_msg_history->setHtml(disp_data); + m_msg_header->setText(disp_header); } void ctai_history_textedit::on_delete_clicked() { @@ -359,7 +333,7 @@ void ctai_history_textedit::on_menu_clicked() { on_copy_clicked(); } - else if (act == actSave) + else if (actSave) { on_save_clicked(); } @@ -367,4 +341,4 @@ void ctai_history_textedit::on_menu_clicked() { on_delete_clicked(); } -} +} \ No newline at end of file diff --git a/src/ctai_history_textedit.h b/src/ctai_history_textedit.h index bbfa8b4..cf97d09 100644 --- a/src/ctai_history_textedit.h +++ b/src/ctai_history_textedit.h @@ -2,24 +2,32 @@ #ifndef CTAI_HISTORY_TEXTEDIT_H #define CTAI_HISTORY_TEXTEDIT_H +// Qt核心组件 #include +#include +#include +#include +// Qt布局相关 #include #include -#include +#include + +// Qt控件相关 #include #include #include -#include -#include -#include -#include -#include +#include #include +#include +#include +// Qt对话框 #include #include -#include + +// 系统相关 #include -#include + +// 项目相关头文件 #include "ctai_base.h" #include "ctai_markdown.h" @@ -37,9 +45,13 @@ class ctai_history_textedit : public QWidget { Q_OBJECT public: - ctai_history_textedit(msg_type msg_type_mode); + ctai_history_textedit(QWidget *parent = nullptr); ~ctai_history_textedit(); - void add_message(const model_data &message); + void init_layout(msg_type msg_type_mode); + void add_user_message(const model_data &message); + void add_system_message(const model_data &message); + void update_tokens_message(const model_data &message); + void add_header_message(const model_data &message); private slots: void on_delete_clicked(); // 删除按钮 void on_copy_clicked(); // 复制按钮 @@ -55,8 +67,7 @@ private slots: signals: void delete_requested(QString); // 请求删除此消息 void height_changed(); // 新增高度变化信号 -private: - void init_layout(msg_type msg_type_mode); +private: void connect_signals(msg_type msg_type_mode); // 连接信号和槽 private: QFrame *hLine; @@ -100,7 +111,9 @@ private: //本次会话的tokens消耗信息 tokens_data m_tokens_data; //本次信息ID - QString m_msg_sned_id={}; + QString m_msg_sned_id={}; + //本次信息 + QString m_current_content; QSpacerItem *bottom_spacer = new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding); }; diff --git a/src/ctai_history_widget.cpp b/src/ctai_history_widget.cpp index b636054..2e713b2 100644 --- a/src/ctai_history_widget.cpp +++ b/src/ctai_history_widget.cpp @@ -48,29 +48,45 @@ void ctai_history_widget::add_message(const model_data &message) model_data *stored_data = it->second.first; int row = it->second.second; + //如果传入的对象属性为null或者[DONE]表示传输完毕或者其他情况 + //此时需要将tokens更新掉所有其他属性不更新传输数据 + QWidget *widget = cellWidget(row, 0); if (!QSL(message.postback_model_data).isEmpty() || - !QSL(message.postback_model_data).contains("[]")) + !QSL(message.postback_model_data).contains("[DONE]")) { + //更新传入信息 stored_data->postback_model_data += message.postback_model_data; + if (auto message_widget = qobject_cast(widget)) + { + message_widget->add_system_message(message); + } } else { + //更新tokens信息 update_stored_data(stored_data, message); - } - - // 更新显示 - QWidget *widget = cellWidget(row, 0); - if (auto message_widget = qobject_cast(widget)) - { - message_widget->add_message(*stored_data); - } + if (auto message_widget = qobject_cast(widget)) + { + message_widget->update_tokens_message(message); + } + } } else { // 添加新消息 model_data *new_data = new model_data(message); - ctai_history_textedit *message_widget = new ctai_history_textedit(new_data->msg_type_mode); - message_widget->add_message(*new_data); + ctai_history_textedit *message_widget = new ctai_history_textedit(this); + message_widget->init_layout(new_data->msg_type_mode); + message_widget->show(); + if(new_data->msg_type_mode==SYSTEM){ + message_widget->add_header_message(*new_data); + message_widget->update_tokens_message(*new_data); + message_widget->add_system_message(*new_data); + }else{ + message_widget->add_header_message(*new_data); + message_widget->add_user_message(*new_data); + } + // 创建新行 int row = rowCount(); insertRow(row); diff --git a/src/ctai_markdown.h b/src/ctai_markdown.h index 7fa0f6a..3c3d1bc 100644 --- a/src/ctai_markdown.h +++ b/src/ctai_markdown.h @@ -15,5 +15,4 @@ namespace ctai_markdown { void savePDF(QString fileName); } - #endif // CTAI_PARSESTRING_H \ No newline at end of file