增加文本内容对齐

This commit is contained in:
JackLee 2025-03-10 17:09:01 +08:00
parent 2dde514696
commit 51778dffbf
6 changed files with 115 additions and 42 deletions

View File

@ -69,10 +69,6 @@ QLineEdit#m_msg_header{
border:none;
background-color: #FFFFFF;
}
QTextEdit#m_msg_history{
border:none;
background-color: #FFFFFF;
}
QPushButton#m_msg_system_header_ico,
QPushButton#m_msg_user_header_ico{

View File

@ -11,11 +11,11 @@ ctaiHistoryTextEdit::~ctaiHistoryTextEdit()
void ctaiHistoryTextEdit::init_layout(msg_type msg_type_mode)
{
// 主垂直布局
main_layout = new QVBoxLayout();
main_layout = new QVBoxLayout();
init_msg_line();
init_msg_header_layout(msg_type_mode);
init_msg_history_layout();
//主布局
// 主布局
main_layout->addLayout(header_layout);
main_layout->addLayout(history_layout);
main_layout->addItem(bottom_spacer);
@ -28,7 +28,7 @@ void ctaiHistoryTextEdit::init_layout(msg_type msg_type_mode)
}
void ctaiHistoryTextEdit::init_msg_line()
{
//分割线区域
// 分割线区域
msg_line = new QFrame;
msg_line->setFrameShape(QFrame::HLine); // 关键属性
msg_line->setFrameShadow(QFrame::Sunken); // 凹陷效果
@ -52,11 +52,11 @@ void ctaiHistoryTextEdit::init_msg_history_layout()
}
void ctaiHistoryTextEdit::init_msg_header_layout(msg_type msg_type_mode)
{
//消息头左区域布局,ico,id,fp,time
// 消息头左区域布局,ico,id,fp,time
header_info_layout = new QHBoxLayout();
//消息区头整体垂直
// 消息区头整体垂直
header_layout = new QVBoxLayout();
header_opts_layout=new QHBoxLayout();
header_opts_layout = new QHBoxLayout();
m_msg_header = new QLineEdit();
m_msg_header->setObjectName("m_msg_header");
m_msg_header->setReadOnly(true);
@ -95,7 +95,7 @@ void ctaiHistoryTextEdit::init_msg_header_layout(msg_type msg_type_mode)
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);
header_info_layout->setContentsMargins(0, 0, 0, 0);
// USER DELETE BUTTON
m_msg_user_del = new QPushButton();
m_msg_user_del->setObjectName("m_msg_user_del");
@ -109,8 +109,9 @@ void ctaiHistoryTextEdit::init_msg_header_layout(msg_type msg_type_mode)
header_layout->addLayout(header_info_layout);
}
}
void ctaiHistoryTextEdit::set_default_opts(){
m_msg_history->setFont(QFont(m_font,m_font_size));
void ctaiHistoryTextEdit::set_default_opts()
{
m_msg_history->setFont(QFont(m_font, m_font_size));
}
void ctaiHistoryTextEdit::connect_signals(msg_type msg_type_mode)
{
@ -123,12 +124,12 @@ void ctaiHistoryTextEdit::connect_signals(msg_type msg_type_mode)
connect(m_msg_tools, SIGNAL(on_signals_display_mode(QString)), this, SLOT(on_display_changed(QString)));
connect(m_msg_tools, SIGNAL(on_signals_display_font(QString)), this, SLOT(on_display_font_changed(QString)));
connect(m_msg_tools, SIGNAL(on_signals_display_font_size(QString)), this, SLOT(on_display_font_size_changed(QString)));
//save菜单功能
// save菜单功能
connect(m_msg_tools, SIGNAL(on_signals_save_text()), this, SLOT(on_save_text()));
connect(m_msg_tools, SIGNAL(on_signals_save_html()), this, SLOT(on_save_html()));
connect(m_msg_tools, SIGNAL(on_signals_save_pdf()), this, SLOT(on_save_pdf()));
connect(m_msg_tools, SIGNAL(on_signals_save_markdown()), this, SLOT(on_save_markdown()));
//其他功能菜单
// 其他功能菜单
connect(m_msg_tools, SIGNAL(on_signals_menu()), this, SLOT(on_menu_slots()));
}
else
@ -139,16 +140,15 @@ void ctaiHistoryTextEdit::connect_signals(msg_type msg_type_mode)
}
void ctaiHistoryTextEdit::on_menu_slots()
{
}
void ctaiHistoryTextEdit::on_display_font_size_changed(QString font_size)
{
m_font_size=font_size.toInt();
m_font_size = font_size.toInt();
m_msg_history->setFont(QFont(m_font, m_font_size));
}
void ctaiHistoryTextEdit::on_display_font_changed(QString font)
{
m_font=font;
m_font = font;
m_msg_history->setFont(QFont(m_font, m_font_size));
}
void ctaiHistoryTextEdit::on_delete_slots()
@ -180,13 +180,50 @@ void ctaiHistoryTextEdit::on_save_text()
}
QTextStream out(&file);
out << m_msg_history->toPlainText() << "\n\n";
file.close();
}
void ctaiHistoryTextEdit::on_save_html()
{
QString fileName = QFileDialog::getSaveFileName(this,
tr("保存HTML"),
m_msg_sned_id + ".html",
tr("HTML 文件 (*.html)"));
if (fileName.isEmpty())
return;
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
QMessageBox::warning(this, tr("保存失败"),
tr("无法保存文件 %1:\n%2").arg(fileName).arg(file.errorString()));
return;
}
QTextStream out(&file);
out << m_msg_history->toHtml();
file.close();
}
void ctaiHistoryTextEdit::on_save_markdown()
{
QString fileName = QFileDialog::getSaveFileName(this,
tr("保存 Markdown"),
m_msg_sned_id + ".md",
tr("Markdown 文件 (*.md)"));
if (fileName.isEmpty())
return;
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
QMessageBox::warning(this, tr("保存失败"),
tr("无法保存文件 %1:\n%2").arg(fileName).arg(file.errorString()));
return;
}
QTextStream out(&file);
out << m_msg_history->toMarkdown();
file.close();
}
void ctaiHistoryTextEdit::on_save_pdf()
@ -212,14 +249,13 @@ void ctaiHistoryTextEdit::on_display_changed(QString mode)
}
else if (mode == "HTML源码")
{
}else if(mode == "HTML渲染"){
}else if(mode == "Markdown源码"){
}else if(mode == "Markdown渲染"){
m_msg_history->setMarkdown(m_math_convert->replace_tags_svg(m_current_content,m_font_size));
}
else if (mode == "HTML渲染" || mode == "Markdown渲染")
{
m_msg_history->setHtml(m_math_convert->replace_tags_svg(m_current_content, m_font_size));
qDebug() << "LaTeX Markdown:" << m_msg_history->toMarkdown();
on_save_html();
on_save_markdown();
}
}
// tokens按钮实现功能的槽函数
@ -307,27 +343,24 @@ void ctaiHistoryTextEdit::add_user_message(const model_data &message)
QString disp_data;
disp_data = QSL(message.send_user_data);
m_msg_sned_id = QSL(message.send_user_id);
m_msg_history->setMarkdown(disp_data);
m_msg_history->setHtml(m_math_convert->replace_tags_svg(disp_data, m_font_size));
}
void ctaiHistoryTextEdit::add_system_message(const model_data &message)
{
m_msg_sned_id = QSL(message.postback_send_id);
std::lock_guard<std::mutex> lock(m_mutex);
if (message.postback_stream_mode)
{
// 流式模式下追加内容
m_current_content += message.postback_model_data;
m_msg_history->setMarkdown(m_current_content);
// m_msg_history->setHtml(m_math_convert->replace_tags_svg(m_current_content));
}
else
{
// 非流式模式直接设置全部内容
m_current_content = QSL(message.postback_model_data);
m_msg_history->setMarkdown(m_current_content);
}
m_msg_history->setMarkdown(m_current_content);
}
// 增加tokens信息
void ctaiHistoryTextEdit::update_tokens_message(const model_data &message)

View File

@ -24,6 +24,8 @@
#include <QTimer>
#include <QLabel>
#include <QComboBox>
#include <QTextBlock>
#include <QChar>
// Qt对话框
#include <QFileDialog>
#include <QMessageBox>

View File

@ -19,11 +19,9 @@ void ctaiMathConvert::save_svg(QPixmap &img)
}
QByteArray ctaiMathConvert::svg_to_base64(QPixmap &pix)
{
QByteArray data;
QBuffer buffer(&data);
QImage img = pix.toImage();
img.save(&buffer, "PNG");
data = data.toBase64();
return data;
@ -49,7 +47,6 @@ void ctaiMathConvert::debug_latex_match(const QString &text, const QRegularExpre
qDebug() << "匹配位置:" << match.capturedStart() << "-" << match.capturedEnd();
qDebug() << "匹配文本:" << match.captured(0);
qDebug() << "数学内容:" << match.captured(1);
// 显示匹配位置的上下文
int contextSize = 20;
int start = qMax(0, match.capturedStart() - contextSize);
@ -91,7 +88,6 @@ QString ctaiMathConvert::replace_tags_svg(const QString &text,int font_size)
QList<QPair<int, int>> replacements;
QStringList svgResults;
// 定义基础图片标签
const QString html_base = "<img src=\"data:image/png;base64,";
const QString markdown_base = "![math](data:image/png;base64,";
while (iterator.hasNext())
{
@ -100,13 +96,11 @@ QString ctaiMathConvert::replace_tags_svg(const QString &text,int font_size)
// 调试输出
debug_latex_match(result, match);
// 清理和转换公式
//QString cleanFormula = clean_latex_for_mula(matchedText);
QString svg_markdown = markdown_base + math_convert_svg(matchedText) + ")";
//QString svg_html = html_base + math_convert_svg(matchedText) + "/>";
QString cleanFormula = clean_latex_for_mula(matchedText);
QString svg_markdown = markdown_base + math_convert_svg(cleanFormula) + ")";
// 保存替换信息
replacements.prepend({match.capturedStart(), match.capturedLength()});
svgResults.prepend(svg_markdown);
//svgResults.prepend(svg_html);
}
// 从后向前执行替换,避免位置改变影响
@ -115,7 +109,48 @@ QString ctaiMathConvert::replace_tags_svg(const QString &text,int font_size)
const auto &rep = replacements[i];
result.replace(rep.first, rep.second, svgResults[i]);
}
return result;
return markdown_to_html(result);
}
QString ctaiMathConvert::markdown_to_html(const QString& text){
// 转换为UTF-8编码的字符串
QByteArray markdown = text.toUtf8();
// 启用所有 GFM 扩展选项
int options = CMARK_OPT_SOURCEPOS |
CMARK_OPT_VALIDATE_UTF8 |
CMARK_OPT_SMART |
CMARK_OPT_GITHUB_PRE_LANG |
CMARK_OPT_LIBERAL_HTML_TAG |
CMARK_OPT_FOOTNOTES|
CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE|
CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES|
CMARK_OPT_FULL_INFO_STRING;
// 使用cmark-gfm解析Markdown
char *html = cmark_markdown_to_html(
markdown.constData(),
markdown.size(),
options);
// 转换回QString并处理代码块
QString result = QString::fromUtf8(html);
free(html);
return fix_img_str_line_height(result.toUtf8());
}
QString ctaiMathConvert::fix_img_str_line_height(QString html) {
// 修正图片样式,使其与文本在同一行显示
html.replace("<li ", "<li style='vertical-align: middle ;' ");
html.replace("<p ", "<p style='vertical-align: middle ;' ");
html.replace("<img ", "<img style='vertical-align: middle ;' ");
QString fileName = QDir::currentPath() + "/"+QUuid::createUuid().toString(QUuid::WithoutBraces) + ".html";
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
}
QTextStream out(&file);
out << html << "\n\n";
file.close();
return html;
}

View File

@ -12,6 +12,8 @@
#include <QPainter>
#include <QPixmap>
#include <QDir>
#include <QFile>
#include <QMessageBox>
#include <QBuffer>
#include <QUuid>
#include <QRegularExpression>
@ -36,6 +38,7 @@ class TexGuard {
};
using namespace tex;
class ctaiMathConvert :public QObject
{
Q_OBJECT
@ -51,14 +54,16 @@ private:
QString clean_latex_for_mula(const QString &formula);
QString math_convert_svg(const QString& text);
QByteArray svg_to_base64(QPixmap& pix);
QString markdown_to_html(const QString& text);
QString fix_img_str_line_height(QString html);
TexGuard texGuard;
//宽度
int m_render_width=600;
int m_render_height=64;
//文本大小
int m_text_size=20;
int m_text_size=16;
//行距
float m_lineSpace=20 / 3.f;
float m_lineSpace=1.5f;
//颜色
tex::color m_color=0xff424242;
//边距

View File

@ -88,4 +88,6 @@ const QStringList latex_symbols = {
"\\Psi",
"\\Omega"
};
#endif // CTAI_BASE_H