处理渲染和json解析问题
This commit is contained in:
parent
4c03e4d794
commit
6a16887dd8
@ -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();
|
||||
}
|
||||
@ -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:
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QTimer>
|
||||
// Qt对话框
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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("&", "&");
|
||||
escaped.replace("<", "<");
|
||||
escaped.replace(">", ">");
|
||||
escaped.replace("\"", """);
|
||||
escaped.replace("\n", "<br>");
|
||||
return escaped;
|
||||
}
|
||||
|
||||
QString process_code_blocks(QString html) {
|
||||
// 添加代码块样式
|
||||
html.replace(
|
||||
|
||||
@ -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
|
||||
@ -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)
|
||||
|
||||
@ -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();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user