处理渲染和json解析问题
This commit is contained in:
parent
4c03e4d794
commit
6a16887dd8
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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]"))
|
||||||
{
|
{
|
||||||
//更新传入信息
|
//更新传入信息
|
||||||
|
|||||||
@ -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("&", "&");
|
|
||||||
escaped.replace("<", "<");
|
|
||||||
escaped.replace(">", ">");
|
|
||||||
escaped.replace("\"", """);
|
|
||||||
escaped.replace("\n", "<br>");
|
|
||||||
return escaped;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString process_code_blocks(QString html) {
|
QString process_code_blocks(QString html) {
|
||||||
// 添加代码块样式
|
// 添加代码块样式
|
||||||
html.replace(
|
html.replace(
|
||||||
|
|||||||
@ -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
|
||||||
@ -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)
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user