处理渲染和json解析问题

This commit is contained in:
JackLee 2025-03-04 19:10:32 +08:00
parent 4c03e4d794
commit 6a16887dd8
9 changed files with 112 additions and 78 deletions

View File

@ -135,38 +135,19 @@ std::string ctai_curl::send_timestamp_to_time(time_t timestamp)
void ctai_curl::send_stream(model_data &data, std::string response_data) void ctai_curl::send_stream(model_data &data, std::string response_data)
{ {
std::vector<std::string> _info_data = steam_extract(response_data); std::vector<std::string> _info_data = steam_extract(response_data);
qDebug() << "response_data:" << response_data;
if (!_info_data.empty()) if (!_info_data.empty())
{ {
for (auto str : _info_data) for (auto str : _info_data)
{ {
if(str == "[DONE]"){ if (str == "[DONE]")
{
data.postback_model_data = str; data.postback_model_data = str;
emit send_post_out_data(data); emit send_post_out_data(data);
return; return;
} }
if (str != "") if (str != "")
{ {
json response = json::parse(str); send_not_stream(data, str);
if (response.contains("choices") && !response["choices"].empty())
{
data.postback_model_data = response["choices"][0]["delta"]["content"];
}
// 获取时间戳自动转换为时间
if (response.contains("created") && !response["created"].empty())
{
data.postback_time = send_timestamp_to_time(response["created"]);
}
// 任务ID
if (response.contains("id") && !response["id"].empty())
{
data.postback_send_id = response["id"];
}
// 任务指纹
if (response.contains("system_fingerprint") && !response["system_fingerprint"].empty())
{
data.postback_system_fingerprint = response["system_fingerprint"];
}
emit send_post_out_data(data); emit send_post_out_data(data);
} }
qDebug() << "send_stream:" << str; qDebug() << "send_stream:" << str;
@ -176,11 +157,21 @@ void ctai_curl::send_stream(model_data &data, std::string response_data)
void ctai_curl::send_not_stream(model_data &data, std::string response_data) void ctai_curl::send_not_stream(model_data &data, std::string response_data)
{ {
json response = json::parse(response_data); json response = json::parse(response_data);
// 获取返回内容 qDebug()<<"msg_type_mode:"<<data.msg_type_mode;
if (data.postback_stream_mode)
{
if (response.contains("choices") && !response["choices"].empty())
{
data.postback_model_data = response["choices"][0]["delta"]["content"];
}
}
else
{
if (response.contains("choices") && !response["choices"].empty()) if (response.contains("choices") && !response["choices"].empty())
{ {
data.postback_model_data = response["choices"][0]["message"]["content"]; data.postback_model_data = response["choices"][0]["message"]["content"];
} }
}
// 获取时间戳自动转换为时间 // 获取时间戳自动转换为时间
if (response.contains("created") && !response["created"].empty()) if (response.contains("created") && !response["created"].empty())
{ {
@ -225,7 +216,6 @@ void ctai_curl::send_not_stream(model_data &data, std::string response_data)
data.postback_prompt_cache_hit_tokens = response["usage"]["prompt_cache_miss_tokens"]; data.postback_prompt_cache_hit_tokens = response["usage"]["prompt_cache_miss_tokens"];
} }
} }
qDebug() << "send_not_stream:" << response_data;
} }
std::string ctai_curl::send_send_body(model_data m_data) std::string ctai_curl::send_send_body(model_data m_data)
{ {
@ -258,17 +248,20 @@ void ctai_curl::set_send_post_option()
void ctai_curl::set_send_post_opts_reset() void ctai_curl::set_send_post_opts_reset()
{ {
// 先清理 headers // 先清理 headers
if (m_headers) { if (m_headers)
{
curl_slist_free_all(m_headers); curl_slist_free_all(m_headers);
m_headers = nullptr; m_headers = nullptr;
} }
if (m_curl) { if (m_curl)
{
// 完全清理旧的 handle // 完全清理旧的 handle
curl_easy_cleanup(m_curl); curl_easy_cleanup(m_curl);
// 创建新的 handle // 创建新的 handle
m_curl = curl_easy_init(); m_curl = curl_easy_init();
if (m_curl) { if (m_curl)
{
// 设置基本选项 // 设置基本选项
curl_easy_setopt(m_curl, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt(m_curl, CURLOPT_NOSIGNAL, 1L);
} }
@ -276,23 +269,27 @@ void ctai_curl::set_send_post_opts_reset()
} }
void ctai_curl::curl_init() void ctai_curl::curl_init()
{ {
if (!m_initialized) { if (!m_initialized)
{
curl_global_init(CURL_GLOBAL_ALL); curl_global_init(CURL_GLOBAL_ALL);
m_initialized = true; m_initialized = true;
} }
// 每次都创建新的 handle // 每次都创建新的 handle
if (m_curl) { if (m_curl)
{
curl_easy_cleanup(m_curl); curl_easy_cleanup(m_curl);
} }
m_curl = curl_easy_init(); m_curl = curl_easy_init();
if (!m_curl) { if (!m_curl)
{
throw std::runtime_error("Failed to initialize CURL handle"); throw std::runtime_error("Failed to initialize CURL handle");
} }
} }
void ctai_curl::send_post_response(model_data m_data, curl_opts opts) void ctai_curl::send_post_response(model_data m_data, curl_opts opts)
{ {
if (!m_curl) { if (!m_curl)
{
emit send_post_out_error("CURL handle is null"); emit send_post_out_error("CURL handle is null");
return; return;
} }
@ -301,30 +298,38 @@ void ctai_curl::send_post_response(model_data m_data, curl_opts opts)
c_opts = opts; c_opts = opts;
c_data.request_body = send_send_body(c_data); c_data.request_body = send_send_body(c_data);
try { try
{
std::string response_data; std::string response_data;
call_back_context ctx{this, c_data}; // 使用列表初始化 call_back_context ctx{this, c_data}; // 使用列表初始化
set_send_post_option(); set_send_post_option();
if (c_data.postback_stream_mode) { if (c_data.postback_stream_mode)
{
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, stream_callback); curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, stream_callback);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &ctx); curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &ctx);
} else { }
else
{
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, not_stream_callback); curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, not_stream_callback);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &response_data); curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &response_data);
} }
m_error = curl_easy_perform(m_curl); m_error = curl_easy_perform(m_curl);
if (m_error != CURLE_OK) { if (m_error != CURLE_OK)
{
emit send_post_out_error(curl_easy_strerror(m_error)); emit send_post_out_error(curl_easy_strerror(m_error));
} else if (!c_data.postback_stream_mode) { }
else if (!c_data.postback_stream_mode)
{
send_not_stream(c_data, response_data); send_not_stream(c_data, response_data);
emit send_post_out_data(c_data); emit send_post_out_data(c_data);
} }
} }
catch (const std::exception& e) { catch (const std::exception &e)
{
emit send_post_out_error(e.what()); emit send_post_out_error(e.what());
} }

View File

@ -25,7 +25,6 @@ public:
void send_post_response(model_data,curl_opts); void send_post_response(model_data,curl_opts);
void send_stream(model_data &, std::string response_data); void send_stream(model_data &, std::string response_data);
void send_not_stream(model_data &, std::string response_data); void send_not_stream(model_data &, std::string response_data);
public: public:
std::mutex m_mutex; std::mutex m_mutex;
private: private:

View File

@ -90,7 +90,6 @@ void ctai_history_textedit::init_layout(msg_type msg_type_mode)
historyLayout = new QVBoxLayout(); historyLayout = new QVBoxLayout();
m_msg_history = new QTextEdit(); m_msg_history = new QTextEdit();
m_msg_history->setAcceptRichText(true); m_msg_history->setAcceptRichText(true);
m_msg_history->setLineWrapMode(QTextEdit::WidgetWidth);
m_msg_history->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_msg_history->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_msg_history->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); m_msg_history->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
// 添加性能优化设置 // 添加性能优化设置
@ -211,7 +210,52 @@ void ctai_history_textedit::on_fold_clicked()
} }
void ctai_history_textedit::on_text_height() void ctai_history_textedit::on_text_height()
{ {
// 防抖动处理如果上次更新在100ms内则延迟处理
static QTimer debounceTimer;
debounceTimer.setSingleShot(true);
if (debounceTimer.isActive())
{
return;
}
// 直接使用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);
} }
void ctai_history_textedit::add_user_message(const model_data &message) void ctai_history_textedit::add_user_message(const model_data &message)
{ {

View File

@ -20,6 +20,7 @@
#include <QMenu> #include <QMenu>
#include <QAction> #include <QAction>
#include <QAbstractTextDocumentLayout> #include <QAbstractTextDocumentLayout>
#include <QTimer>
// Qt对话框 // Qt对话框
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>

View File

@ -51,7 +51,7 @@ void ctai_history_widget::add_message(const model_data &message)
//如果传入的对象属性为null或者[DONE]表示传输完毕或者其他情况 //如果传入的对象属性为null或者[DONE]表示传输完毕或者其他情况
//此时需要将tokens更新掉所有其他属性不更新传输数据 //此时需要将tokens更新掉所有其他属性不更新传输数据
QWidget *widget = cellWidget(row, 0); QWidget *widget = cellWidget(row, 0);
if (!QSL(message.postback_model_data).isEmpty() || if (!QSL(message.postback_model_data).isEmpty() &&
!QSL(message.postback_model_data).contains("[DONE]")) !QSL(message.postback_model_data).contains("[DONE]"))
{ {
//更新传入信息 //更新传入信息

View File

@ -18,17 +18,6 @@ QString md_to_html(const QString& text) {
qDebug()<<"处理的块:"<<result; qDebug()<<"处理的块:"<<result;
return process_code_blocks(result.toUtf8()); return process_code_blocks(result.toUtf8());
} }
QString escape_html(const QString& text) {
QString escaped = text;
escaped.replace("&", "&amp;");
escaped.replace("<", "&lt;");
escaped.replace(">", "&gt;");
escaped.replace("\"", "&quot;");
escaped.replace("\n", "<br>");
return escaped;
}
QString process_code_blocks(QString html) { QString process_code_blocks(QString html) {
// 添加代码块样式 // 添加代码块样式
html.replace( html.replace(

View File

@ -8,11 +8,7 @@
namespace ctai_markdown { namespace ctai_markdown {
// Markdown 转 HTML // Markdown 转 HTML
QString md_to_html(const QString& text); QString md_to_html(const QString& text);
// 纯文本转义
QString escape_html(const QString& text);
// 处理代码块样式 // 处理代码块样式
QString process_code_blocks(QString html); QString process_code_blocks(QString html);
void savePDF(QString fileName);
} }
#endif // CTAI_PARSESTRING_H #endif // CTAI_PARSESTRING_H

View File

@ -125,20 +125,20 @@ void ctai_session_info::btn_disable_enable(bool state)
void ctai_session_info::ctai_session_postback_info(model_data resp_data) void ctai_session_info::ctai_session_postback_info(model_data resp_data)
{ {
if (resp_data.postback_time != current_info_time) if (resp_data.postback_send_id != current_info_id)
{ {
current_info_time = resp_data.postback_time; current_info_id = resp_data.postback_send_id;
m_session_systeam_info->add_message(resp_data); m_session_systeam_info->add_message(resp_data);
} }
else else
{ {
m_session_systeam_info->add_message(resp_data); m_session_systeam_info->add_message(resp_data);
} }
if (resp_data.postback_model_data == "" || resp_data.postback_model_data == "[DONE]") if (QSL(resp_data.postback_model_data).contains("[DONE]"))
{ {
current_info_time = {}; current_info_id = {};
}
btn_disable_enable(true); btn_disable_enable(true);
}
ctai_session_curl_state_tips(""); ctai_session_curl_state_tips("");
} }
void ctai_session_info::ctai_session_curl_state_tips(std::string state_str) void ctai_session_info::ctai_session_curl_state_tips(std::string state_str)

View File

@ -71,7 +71,7 @@ private:
ctai_curl *m_curl; ctai_curl *m_curl;
model_data user_model_data; model_data user_model_data;
curl_opts curl_opt; curl_opts curl_opt;
std::string current_info_time; std::string current_info_id;
bool m_stream_mode = false; bool m_stream_mode = false;
private slots: private slots:
void ctai_session_user_sending(); void ctai_session_user_sending();