处理渲染和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

@ -2,7 +2,7 @@
ctai_curl::ctai_curl() : m_curl(nullptr),
m_headers(nullptr),
m_initialized(false) // 初始化标志
m_initialized(false) // 初始化标志
{
}
ctai_curl::~ctai_curl()
@ -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)
{
std::vector<std::string> _info_data = steam_extract(response_data);
qDebug() << "response_data:" << response_data;
if (!_info_data.empty())
{
for (auto str : _info_data)
{
if(str == "[DONE]"){
if (str == "[DONE]")
{
data.postback_model_data = str;
emit send_post_out_data(data);
return;
}
if (str != "")
{
json response = json::parse(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"];
}
{
send_not_stream(data, str);
emit send_post_out_data(data);
}
qDebug() << "send_stream:" << str;
@ -176,10 +157,20 @@ 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)
{
json response = json::parse(response_data);
// 获取返回内容
if (response.contains("choices") && !response["choices"].empty())
qDebug()<<"msg_type_mode:"<<data.msg_type_mode;
if (data.postback_stream_mode)
{
data.postback_model_data = response["choices"][0]["message"]["content"];
if (response.contains("choices") && !response["choices"].empty())
{
data.postback_model_data = response["choices"][0]["delta"]["content"];
}
}
else
{
if (response.contains("choices") && !response["choices"].empty())
{
data.postback_model_data = response["choices"][0]["message"]["content"];
}
}
// 获取时间戳自动转换为时间
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"];
}
}
qDebug() << "send_not_stream:" << response_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()
{
// 先清理 headers
if (m_headers) {
if (m_headers)
{
curl_slist_free_all(m_headers);
m_headers = nullptr;
}
if (m_curl) {
if (m_curl)
{
// 完全清理旧的 handle
curl_easy_cleanup(m_curl);
// 创建新的 handle
m_curl = curl_easy_init();
if (m_curl) {
if (m_curl)
{
// 设置基本选项
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()
{
if (!m_initialized) {
if (!m_initialized)
{
curl_global_init(CURL_GLOBAL_ALL);
m_initialized = true;
}
// 每次都创建新的 handle
if (m_curl) {
if (m_curl)
{
curl_easy_cleanup(m_curl);
}
m_curl = curl_easy_init();
if (!m_curl) {
if (!m_curl)
{
throw std::runtime_error("Failed to initialize CURL handle");
}
}
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");
return;
}
@ -300,34 +297,42 @@ void ctai_curl::send_post_response(model_data m_data, curl_opts opts)
c_data = m_data;
c_opts = opts;
c_data.request_body = send_send_body(c_data);
try {
try
{
std::string response_data;
call_back_context ctx{this, c_data}; // 使用列表初始化
call_back_context ctx{this, c_data}; // 使用列表初始化
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_WRITEDATA, &ctx);
} else {
}
else
{
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, not_stream_callback);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &response_data);
}
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));
} else if (!c_data.postback_stream_mode) {
}
else if (!c_data.postback_stream_mode)
{
send_not_stream(c_data, response_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());
}
// 请求完成后重置
set_send_post_opts_reset();
}

View File

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

View File

@ -90,7 +90,6 @@ void ctai_history_textedit::init_layout(msg_type msg_type_mode)
historyLayout = new QVBoxLayout();
m_msg_history = new QTextEdit();
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);
// 添加性能优化设置
@ -211,7 +210,52 @@ void ctai_history_textedit::on_fold_clicked()
}
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)
{

View File

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

View File

@ -51,7 +51,7 @@ void ctai_history_widget::add_message(const model_data &message)
//如果传入的对象属性为null或者[DONE]表示传输完毕或者其他情况
//此时需要将tokens更新掉所有其他属性不更新传输数据
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]"))
{
//更新传入信息
@ -69,7 +69,7 @@ void ctai_history_widget::add_message(const model_data &message)
{
message_widget->update_tokens_message(message);
}
}
}
}
else
{

View File

@ -18,17 +18,6 @@ QString md_to_html(const QString& text) {
qDebug()<<"处理的块:"<<result;
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) {
// 添加代码块样式
html.replace(

View File

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

View File

@ -124,21 +124,21 @@ void ctai_session_info::btn_disable_enable(bool state)
}
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);
}
else
{
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 = {};
}
btn_disable_enable(true);
current_info_id = {};
btn_disable_enable(true);
}
ctai_session_curl_state_tips("");
}
void ctai_session_info::ctai_session_curl_state_tips(std::string state_str)

View File

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