整理功能代码

This commit is contained in:
JackLee 2025-03-11 16:41:50 +08:00
parent 51778dffbf
commit 742a640c3f
9 changed files with 183 additions and 211 deletions

View File

@ -151,7 +151,6 @@ target_link_libraries(
LaTeX
libcmark-gfm_static
libcmark-gfm-extensions_static
)

View File

@ -1,14 +0,0 @@
cmake_minimum_required(VERSION 3.19)
project(ctai)
#
set_target_properties(sui PROPERTIES VERSION 1.0 SOVERSION 1)
#include dir
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(ctai STATIC ${SRC_LIST})

View File

@ -60,6 +60,7 @@ void ctaiHistoryTextEdit::init_msg_header_layout(msg_type msg_type_mode)
m_msg_header = new QLineEdit();
m_msg_header->setObjectName("m_msg_header");
m_msg_header->setReadOnly(true);
m_msg_tools = new ctaiHistoryTools();
if (msg_type_mode == SYSTEM)
{
// 1.SYSTEM消息头水平左信息区
@ -82,7 +83,6 @@ void ctaiHistoryTextEdit::init_msg_header_layout(msg_type msg_type_mode)
header_info_layout->addWidget(m_restart_to_send);
header_info_layout->addWidget(m_msg_system_del);
// 3.SYSTEM消息头垂直第二排功能区
m_msg_tools = new ctaiHistoryTools();
header_opts_layout->addWidget(m_msg_tools);
// 4.添加到消息头主布局
header_layout->addLayout(header_info_layout);
@ -111,7 +111,7 @@ void ctaiHistoryTextEdit::init_msg_header_layout(msg_type msg_type_mode)
}
void ctaiHistoryTextEdit::set_default_opts()
{
m_msg_history->setFont(QFont(m_font, m_font_size));
m_msg_history->setFont(QFont(m_msg_tools->getFont(), m_msg_tools->getFontSize().toInt()));
}
void ctaiHistoryTextEdit::connect_signals(msg_type msg_type_mode)
{
@ -122,13 +122,9 @@ void ctaiHistoryTextEdit::connect_signals(msg_type msg_type_mode)
connect(m_msg_tools, SIGNAL(on_signals_fold()), this, SLOT(on_fold_slots()));
connect(m_msg_tokens, SIGNAL(clicked()), this, SLOT(on_tokens_slots()));
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)));
connect(m_msg_tools, SIGNAL(on_signals_display_font_size()), this, SLOT(on_display_font_size_changed()));
// 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_save_file(int)), this, SLOT(on_save_file(int)));
// 其他功能菜单
connect(m_msg_tools, SIGNAL(on_signals_menu()), this, SLOT(on_menu_slots()));
}
@ -141,15 +137,9 @@ void ctaiHistoryTextEdit::connect_signals(msg_type msg_type_mode)
void ctaiHistoryTextEdit::on_menu_slots()
{
}
void ctaiHistoryTextEdit::on_display_font_size_changed(QString font_size)
void ctaiHistoryTextEdit::on_display_font_size_changed()
{
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_msg_history->setFont(QFont(m_font, m_font_size));
m_msg_history->setFont(QFont(m_msg_tools->getFont(), m_msg_tools->getFontSize().toInt()));
}
void ctaiHistoryTextEdit::on_delete_slots()
{
@ -164,13 +154,16 @@ void ctaiHistoryTextEdit::on_copy_slots()
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(text);
}
void ctaiHistoryTextEdit::on_save_text()
// 保存文件
void ctaiHistoryTextEdit::on_save_file(int index)
{
QString fileName = QFileDialog::getSaveFileName(this,
tr("保存消息"), m_msg_sned_id + ".txt",
tr("文本文件 (*.txt)"));
QString fileName;
QString temp_current_content;
fileName = QFileDialog::getSaveFileName(this, tr("保存消息"), m_msg_sned_id + save_extend[index], save_extend_str[index]);
if (fileName.isEmpty())
{
return;
}
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
@ -179,57 +172,25 @@ void ctaiHistoryTextEdit::on_save_text()
return;
}
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;
switch(index){
case 0:
temp_current_content=m_msg_history->toPlainText();
break;
case 1:
temp_current_content=m_msg_history->toHtml();
break;
case 2:
temp_current_content=m_msg_history->toMarkdown();
break;
case 3:
break;
}
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;
if(!temp_current_content.isEmpty()){
out << m_current_content << "\n\n";
}
QTextStream out(&file);
out << m_msg_history->toMarkdown();
file.close();
}
void ctaiHistoryTextEdit::on_save_pdf()
{
}
// 实现折叠功能的槽函数
void ctaiHistoryTextEdit::on_fold_slots()
{
@ -252,12 +213,10 @@ void ctaiHistoryTextEdit::on_display_changed(QString mode)
}
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();
m_msg_history->setHtml(m_math_convert->replace_tags_svg(m_current_content, m_msg_tools->getFontSize().toInt()));
}
}
// tokens按钮实现功能的槽函数
void ctaiHistoryTextEdit::on_tokens_slots()
{
@ -343,7 +302,7 @@ 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->setHtml(m_math_convert->replace_tags_svg(disp_data, m_font_size));
m_msg_history->setHtml(m_math_convert->replace_tags_svg(disp_data, m_msg_tools->getFontSize().toInt()));
}
void ctaiHistoryTextEdit::add_system_message(const model_data &message)

View File

@ -68,13 +68,9 @@ private slots:
void on_fold_slots(); // 折叠按钮
void on_tokens_slots(); // tokens按钮
void on_display_changed(QString); // 显示模式改变
void on_display_font_changed(QString); // 字体大小改变
void on_display_font_size_changed(QString); // 字体大小改变
void on_display_font_size_changed(); // 字体大小改变
void on_sync_text_height();
void on_save_text(); // 保存文本
void on_save_html(); // 保存html
void on_save_markdown(); // 保存markdown
void on_save_pdf(); // 保存pdf
void on_save_file(int); // 保存文本
void on_menu_slots();
signals:
void delete_requested(QString); // 请求删除此消息
@ -121,12 +117,10 @@ private:
QString m_msg_sned_id = {};
// 本次信息
QString m_current_content;
//默认字体跟随软件全局字体
QString m_font = sui_font_table[sui_config.font];//"Arial";
//粗体字
bool m_bold=false;
//字号大小
int m_font_size = 14;
std::vector<QString> save_extend={".txt",".html",".md",".pdf"};
std::vector<QString> save_extend_str={"文本文件 (*.txt)","HTML 文件 (*.html)","Markdown 文件 (*.md)","PDF 文件 (*.pdf)"};
QSpacerItem *bottom_spacer = new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding);
};

View File

@ -63,7 +63,7 @@ void ctaiHistoryTools::initDisplayMode()
for(auto str:sui_font_table){
m_msg_display_font_combobox->addItem(str);
}
m_msg_display_font_size_combobox->setCurrentIndex(5);
m_msg_display_font_size_combobox->setCurrentIndex(3);
m_msg_display_font_combobox->setCurrentIndex(sui_config.font);
}
void ctaiHistoryTools::initConnect()
@ -73,8 +73,8 @@ void ctaiHistoryTools::initConnect()
connect(m_msg_menu, SIGNAL(clicked()), this, SLOT(on_opts_menu_slots()));
connect(m_msg_fold, SIGNAL(clicked()), this, SIGNAL(on_signals_fold()));
connect(m_msg_display_combobox, SIGNAL(currentTextChanged(QString)), this, SIGNAL(on_signals_display_mode(QString)));
connect(m_msg_display_font_size_combobox, SIGNAL(currentTextChanged(QString)), this, SIGNAL(on_signals_display_font_size(QString)));
connect(m_msg_display_font_combobox, SIGNAL(currentTextChanged(QString)), this, SIGNAL(on_signals_display_font(QString)));
connect(m_msg_display_font_size_combobox, SIGNAL(currentTextChanged(QString)), this, SIGNAL(on_signals_display_font_size()));
connect(m_msg_display_font_combobox, SIGNAL(currentTextChanged(QString)), this, SIGNAL(on_signals_display_font_size()));
}
void ctaiHistoryTools::setFoldIco(QIcon ico)
{
@ -86,33 +86,20 @@ void ctaiHistoryTools::on_save_menu_slots()
if (!m_msg_save_menu)
{
m_msg_save_menu = new QMenu();
for(int i=0;i<=ds_save_menu.count()-1;i++){
QAction* action=new QAction(ds_save_menu[i]);
action->setObjectName(QString::number(i));
connect(action, SIGNAL(triggered(bool)), this, SLOT(on_save_action_slots()));
save_ver.push_back(action);
m_msg_save_menu->addAction(action);
}
if (!m_msg_save_text)
{
m_msg_save_text = new QAction(tr("另存为文本"));
connect(m_msg_save_text, SIGNAL(triggered(bool)), this, SIGNAL(on_signals_save_text()));
}
if (!m_msg_save_html)
{
m_msg_save_html = new QAction(tr("另存为HTML"));
connect(m_msg_save_html, SIGNAL(triggered(bool)), this, SIGNAL(on_signals_save_html()));
}
if (!m_msg_save_markdown)
{
m_msg_save_markdown = new QAction(tr("另存为Markdown"));
connect(m_msg_save_markdown, SIGNAL(triggered(bool)), this, SIGNAL(on_signals_save_markdown()));
}
if (!m_msg_save_pdf)
{
m_msg_save_pdf = new QAction(tr("另存为PDF"));
connect(m_msg_save_pdf, SIGNAL(triggered(bool)), this, SIGNAL(on_signals_save_pdf()));
}
m_msg_save_menu->addAction(m_msg_save_text);
m_msg_save_menu->addAction(m_msg_save_html);
m_msg_save_menu->addAction(m_msg_save_markdown);
m_msg_save_menu->addAction(m_msg_save_pdf);
m_msg_save_menu->exec(QCursor::pos());
}
void ctaiHistoryTools::on_save_action_slots(){
save_index=sender()->objectName().toInt();
emit on_signals_save_file(save_index);
}
void ctaiHistoryTools::on_opts_menu_slots()
{
QMenu menu(this);
@ -127,3 +114,9 @@ void ctaiHistoryTools::on_opts_menu_slots()
QPoint pos = m_msg_menu->mapToGlobal(m_msg_menu->rect().bottomRight());
QAction *act = menu.exec(pos);
}
QString ctaiHistoryTools::getFontSize(){
return m_msg_display_font_size_combobox->currentText();
}
QString ctaiHistoryTools::getFont(){
return m_msg_display_font_combobox->currentText();
}

View File

@ -18,6 +18,8 @@ public:
void initLayout();
void initConnect();
void setFoldIco(QIcon ico);
QString getFontSize();
QString getFont();
private:
QHBoxLayout *header_opts_Layout = {};
QPushButton *m_msg_copy = {};
@ -35,28 +37,23 @@ private:
QComboBox *m_msg_display_font_combobox = {};
// save保存菜单
QMenu *m_msg_save_menu = {};
QAction *m_msg_save_text = {};
QAction *m_msg_save_html = {};
QAction *m_msg_save_markdown = {};
QAction *m_msg_save_pdf = {};
QSpacerItem *sparcer_item = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed);
QStringList ds_mode_str={"原始文本","HTML源码","HTML渲染","Markdown源码","Markdown渲染"};
QStringList ds_font_size_str={"4","6","8","10","12","14","16","18","20"};
QStringList ds_save_menu={"另存为文本","另存为HTML","另存为Markdown","另存为PDF"};
std::vector<QAction*> save_ver;
int save_index;
private:
void initDisplayMode();
signals:
void on_signals_copy();
void on_signals_fold();
void on_signals_display_mode(QString);
void on_signals_display_font_size(QString);
void on_signals_display_font(QString);
void on_signals_save_text();
void on_signals_save_html();
void on_signals_save_markdown();
void on_signals_save_pdf();
void on_signals_display_font_size();
void on_signals_save_file(int);
public slots:
void on_save_menu_slots();
void on_opts_menu_slots();
void on_save_action_slots();
};
#endif

View File

@ -28,15 +28,14 @@ QByteArray ctaiMathConvert::svg_to_base64(QPixmap &pix)
}
QString ctaiMathConvert::math_convert_svg(const QString &math)
{
QString res=QDir::currentPath() + "/res/";
QString res = QDir::currentPath() + "/res/";
auto render = LaTeX::parse(math.toStdWString(), m_render_width, m_text_size, m_lineSpace, m_color);
qDebug() << render->getWidth() << render->getHeight();
QPixmap pix(render->getWidth()+m_padding*2, render->getHeight()+m_padding*2);
QPixmap pix(render->getWidth() + m_padding * 2, render->getHeight() + m_padding * 2);
pix.fill(Qt::white);
QPainter painter(&pix);
painter.setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing);
Graphics2D_qt g2(&painter);
render->draw(g2,m_padding,m_padding);
render->draw(g2, m_padding, m_padding);
save_svg(pix);
return QString::fromUtf8(svg_to_base64(pix));
}
@ -66,11 +65,10 @@ QString ctaiMathConvert::clean_latex_for_mula(const QString &formula)
return result;
}
QString ctaiMathConvert::replace_tags_svg(const QString &text,int font_size)
QString ctaiMathConvert::replace_tags_svg(const QString &text, int font_size)
{
m_text_size=font_size;
//QString result("4566545646\\[\n f'(a) = \\lim_{h \\to 0} \\frac{f(a + h) - f(a)}{h}\n \\]654564646");
QString result=text;
m_text_size = font_size*1.5;
QString result = text;
// 使用改进的正则表达式模式
QRegularExpression latexPattern(
QString(R"(\\[(](.*?)\\[)]|\\[{](.*?)\\[}]|\\[[](.*?)\\])"),
@ -84,7 +82,7 @@ QString ctaiMathConvert::replace_tags_svg(const QString &text,int font_size)
QRegularExpressionMatchIterator iterator = latexPattern.globalMatch(result);
//收集所有替换操作
// 收集所有替换操作
QList<QPair<int, int>> replacements;
QStringList svgResults;
// 定义基础图片标签
@ -93,8 +91,10 @@ QString ctaiMathConvert::replace_tags_svg(const QString &text,int font_size)
{
QRegularExpressionMatch match = iterator.next();
QString matchedText = match.captured(0);
// 调试输出
if (debug_node_print)
{
debug_latex_match(result, match);
}
// 清理和转换公式
QString cleanFormula = clean_latex_for_mula(matchedText);
QString svg_markdown = markdown_base + math_convert_svg(cleanFormula) + ")";
@ -111,7 +111,8 @@ QString ctaiMathConvert::replace_tags_svg(const QString &text,int font_size)
}
return markdown_to_html(result);
}
QString ctaiMathConvert::markdown_to_html(const QString& text){
QString ctaiMathConvert::markdown_to_html(const QString &text)
{
// 转换为UTF-8编码的字符串
QByteArray markdown = text.toUtf8();
@ -121,36 +122,69 @@ QString ctaiMathConvert::markdown_to_html(const QString& text){
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_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);
// 解析Markdown为AST
cmark_node *doc = cmark_parse_document(markdown.constData(), markdown.size(), options);
if (debug_node_print)
{
// 递归打印AST节点
print_ast_node(doc, 0);
}
// 转换为HTML
char *html = cmark_render_html(doc, options, NULL);
// 转换回QString并处理代码块
QString result = QString::fromUtf8(html);
replace_symbol(result);
// 释放内存
cmark_node_free(doc);
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))
void ctaiMathConvert::replace_symbol(QString &context)
{
// 执行转换符号为半角
for (auto it = fullToHalfMap.begin(); it != fullToHalfMap.end(); ++it)
{
context.replace(it.key(), it.value());
}
QTextStream out(&file);
out << html << "\n\n";
file.close();
}
// 添加新的辅助方法用于打印AST节点
void ctaiMathConvert::print_ast_node(cmark_node *node, int level)
{
if (!node)
return;
// 获取节点类型
const char *type_str = cmark_node_get_type_string(node);
// 打印缩进和节点类型
QString indent = QString(" ").repeated(level * 2);
qDebug() << indent << "Node Type:" << type_str;
// 获取并打印节点内容(如果有)
const char *literal = cmark_node_get_literal(node);
if (literal)
{
qDebug() << indent << "Content:" << literal;
}
// 递归处理子节点
cmark_node *child = cmark_node_first_child(node);
while (child)
{
print_ast_node(child, level + 1);
child = cmark_node_next(child);
}
}
QString ctaiMathConvert::fix_img_str_line_height(QString html)
{
// 修正图片样式,使其与文本在同一行显示
html.replace("<img ", "<img style='vertical-align: middle ;'");
return html;
}

View File

@ -48,7 +48,6 @@ public:
QString replace_tags_svg(const QString &text,int font_size);
void set_convert_opts();
void save_svg(QPixmap& img);
private:
void debug_latex_match(const QString &text, const QRegularExpressionMatch &match);
QString clean_latex_for_mula(const QString &formula);
@ -56,6 +55,8 @@ private:
QByteArray svg_to_base64(QPixmap& pix);
QString markdown_to_html(const QString& text);
QString fix_img_str_line_height(QString html);
void print_ast_node(cmark_node *node, int level);
void replace_symbol(QString& context);
TexGuard texGuard;
//宽度
int m_render_width=600;
@ -70,7 +71,8 @@ private:
int m_padding=3;
//处理后保存模式
bool save_mode=false;
//print node str debug
bool debug_node_print=true;
};
#endif

View File

@ -62,31 +62,39 @@ typedef struct model_data{
std::string request_body;
}model_data;
const QStringList latex_symbols = {
"\\Alpha",
"\\Beta",
"\\Gamma",
"\\Delta",
"\\Epsilon",
"\\Zeta",
"\\Eta",
"\\Theta",
"\\Iota",
"\\Kappa",
"\\Lambda",
"\\Mu",
"\\Nu",
"\\Xi",
"\\Omicron",
"\\Pi",
"\\Rho",
"\\Sigma",
"\\Tau",
"\\Upsilon",
"\\Phi",
"\\Chi",
"\\Psi",
"\\Omega"
// 将全角符号转换为半角符号的映射
const QMap<QString, QString> fullToHalfMap = {
{"", ","},
{"", "."},
{"", "!"},
{"", "?"},
{"", ":"},
{"", ";"},
{"", "("},
{"", ")"},
{"", "["},
{"", "]"},
{"", "["},
{"", "]"},
{"", "{"},
{"", "}"},
{"", "|"},
{"", "\""},
{"", "'"},
{"", "~"},
{"", "<"},
{"", ">"},
{"", "="},
{"", "+"},
{"", "-"},
{"", "*"},
{"", "/"},
{"", "%"},
{"", "#"},
{"", "&"},
{"", "@"},
{"", "`"},
{" ", " "} // 全角空格转换为半角空格
};