")
+ .arg(item.messageId)
+ .arg(item.messageFp)
+ .arg(item.timestamp)
+ .arg(item.isCollapsed ? "
" : item.content);
// 清空并重新显示
clear();
QTextCursor cursor = textCursor();
cursor.movePosition(QTextCursor::End);
cursor.insertHtml(html);
}
+void ctai_textedit::init_stream_display(const QString &messageId)
+{
+ const MessageItem &item = messages[messageId];
+ QString html = QString(
+ "
"
+ ""
+ "
%4
"
+ "
"
+ "prompts tkoens: %5 | completion tokens: %6 | total tokens: %7 | cache hit tokens: %8 | cache miss tokens: %9"
+ "
"
+ "
")
+ .arg(item.messageId)
+ .arg(item.messageFp)
+ .arg(item.timestamp)
+ .arg(item.isCollapsed ? "
[已折叠]
" : item.content)
+ .arg(item.prompts_tkoens)
+ .arg(item.completion_tokens)
+ .arg(item.total_tokens)
+ .arg(item.cache_hit_tokens)
+ .arg(item.cache_miss_tokens);
+ QTextCursor cursor = textCursor();
+ cursor.beginEditBlock();
+ cursor.movePosition(QTextCursor::End);
+ cursor.insertHtml(html);
+ cursor.movePosition(QTextCursor::End);
+ cursor.endEditBlock();
+ // createMessageControls(messageId);
+ verticalScrollBar()->setValue(verticalScrollBar()->maximum());
+}
+void ctai_textedit::append_stream_display(const model_data &data)
+{
+ if (data.postback_model_data != "[DNOE]" && data.postback_model_data != "")
+ {
+ messages[currentStreamingId].content += QSL(data.postback_model_data);
+ // 只更新内容区域
+ QTextCursor cursor = textCursor();
+ cursor.movePosition(QTextCursor::End);
+ cursor.movePosition(QTextCursor::StartOfBlock);
+ cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ const MessageItem &item = messages[currentStreamingId];
+ QString contenthtml = QString("
%1
")
+ .arg(item.isCollapsed ? "
[已折叠]
" : item.content);
+ cursor.insertHtml(contenthtml);
+ cursor.movePosition(QTextCursor::End);
+ }
+ else
+ {
+ createMessageControls(currentStreamingId);
+ const MessageItem &item = messages[currentStreamingId];
+ QString tokensHtml = QString(
+ "
"
+ "prompts tkoens: %1 | completion tokens: %2 | total tokens: %3 | cache hit tokens: %4 | cache miss tokens: %5"
+ "
"
+ "
")
+ .arg(item.prompts_tkoens)
+ .arg(item.completion_tokens)
+ .arg(item.total_tokens)
+ .arg(item.cache_hit_tokens)
+ .arg(item.cache_miss_tokens);
+ QTextCursor cursor = textCursor();
+ cursor.movePosition(QTextCursor::End);
+ cursor.insertHtml(tokensHtml);
+ currentStreamingId.clear();
+ }
+ verticalScrollBar()->setValue(verticalScrollBar()->maximum());
+}
-void ctai_textedit::createMessageControls(const QString& messageId)
+void ctai_textedit::createMessageControls(const QString &messageId)
{
// 删除已存在的控件
- if (messageControls.contains(messageId)) {
+ if (messageControls.contains(messageId))
+ {
delete messageControls[messageId];
messageControls.remove(messageId);
}
-
- QWidget* controlsWidget = new QWidget(this);
- QHBoxLayout* layout = new QHBoxLayout(controlsWidget);
- layout->setContentsMargins(5, 0, 5, 0);
-
+ QWidget *controlsWidget = new QWidget(this);
+ QHBoxLayout *layout = new QHBoxLayout(controlsWidget);
+ layout->setContentsMargins(0, 0, 0, 0);
// 创建按钮并设置样式
- QPushButton* deleteBtn = new QPushButton(tr("删除"), controlsWidget);
- QPushButton* copyBtn = new QPushButton(tr("复制"), controlsWidget);
- QPushButton* saveBtn = new QPushButton(tr("另存"), controlsWidget);
- QPushButton* collapseBtn = new QPushButton(tr("折叠"), controlsWidget);
-
- QString btnStyle = "QPushButton { "
- "padding: 2px 10px; "
- "margin: 0 5px; "
- "border: 1px solid #ccc; "
- "border-radius: 3px; "
- "background: #f8f8f8; "
- "} "
- "QPushButton:hover { "
- "background: #e8e8e8; "
- "}";
-
- deleteBtn->setStyleSheet(btnStyle);
- copyBtn->setStyleSheet(btnStyle);
- saveBtn->setStyleSheet(btnStyle);
- collapseBtn->setStyleSheet(btnStyle);
-
+ QPushButton *deleteBtn = new QPushButton(tr("删除"), controlsWidget);
+ QPushButton *copyBtn = new QPushButton(tr("复制"), controlsWidget);
+ QPushButton *saveBtn = new QPushButton(tr("另存"), controlsWidget);
+ QPushButton *collapseBtn = new QPushButton(tr("折叠"), controlsWidget);
// 连接信号槽
- connect(deleteBtn, &QPushButton::clicked, [this, messageId](){ deleteMessage(messageId); });
- connect(copyBtn, &QPushButton::clicked, [this, messageId](){ copyMessage(messageId); });
- connect(saveBtn, &QPushButton::clicked, [this, messageId](){ saveMessage(messageId); });
- connect(collapseBtn, &QPushButton::clicked, [this, messageId](){ toggleCollapse(messageId); });
-
+ connect(deleteBtn, &QPushButton::clicked, [this, messageId]()
+ { deleteMessage(messageId); });
+ connect(copyBtn, &QPushButton::clicked, [this, messageId]()
+ { copyMessage(messageId); });
+ connect(saveBtn, &QPushButton::clicked, [this, messageId]()
+ { saveMessage(messageId); });
+ connect(collapseBtn, &QPushButton::clicked, [this, messageId]()
+ { toggleCollapse(messageId); });
// 添加按钮到布局
- layout->addStretch(1);
layout->addWidget(deleteBtn);
layout->addWidget(copyBtn);
layout->addWidget(saveBtn);
layout->addWidget(collapseBtn);
- layout->addStretch(1);
-
+ layout->setSpacing(1);
+
controlsWidget->setLayout(layout);
- controlsWidget->setFixedHeight(40);
messageControls[messageId] = controlsWidget;
- // 在文档末尾添加按钮控件
QTextCursor cursor = textCursor();
- cursor.movePosition(QTextCursor::End);
+ cursor.movePosition(QTextCursor::Start);
QRect cursorRect = this->cursorRect(cursor);
- controlsWidget->move(cursorRect.bottomLeft());
+ controlsWidget->move(cursorRect.topRight());
controlsWidget->show();
}
-void ctai_textedit::deleteMessage(const QString& messageId)
+void ctai_textedit::deleteMessage(const QString &messageId)
{
- if (!messages.contains(messageId)) return;
-
+ if (!messages.contains(messageId))
+ return;
+
// 删除控件
- if (messageControls.contains(messageId)) {
+ if (messageControls.contains(messageId))
+ {
delete messageControls[messageId];
messageControls.remove(messageId);
}
-
+
// 删除消息
messages.remove(messageId);
-
+
// 重新渲染所有消息
clear();
- for (const auto& item : messages) {
- messageDisplay(item.messageId);
+ for (const auto &item : messages)
+ {
+ init_framework_display(item.messageId);
}
}
-void ctai_textedit::copyMessage(const QString& messageId)
+void ctai_textedit::copyMessage(const QString &messageId)
{
- if (!messages.contains(messageId)) return;
-
+ if (!messages.contains(messageId))
+ return;
+
// 复制消息内容到剪贴板
- QClipboard* clipboard = QApplication::clipboard();
+ QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(messages[messageId].content);
}
-void ctai_textedit::saveMessage(const QString& messageId)
+void ctai_textedit::saveMessage(const QString &messageId)
{
- if (!messages.contains(messageId)) return;
-
+ if (!messages.contains(messageId))
+ return;
+
QString fileName = QFileDialog::getSaveFileName(this,
- tr("保存消息"),
- QString("message_%1.txt").arg(messageId),
- tr("文本文件 (*.txt);;所有文件 (*.*)"));
-
- if (fileName.isEmpty()) return;
-
+ tr("保存消息"),
+ QString("message_%1.txt").arg(messageId),
+ tr("文本文件 (*.txt);;所有文件 (*.*)"));
+
+ if (fileName.isEmpty())
+ return;
+
QFile file(fileName);
- if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text))
+ {
QTextStream out(&file);
out.setEncoding(QStringConverter::Utf8);
-
- const MessageItem& item = messages[messageId];
+
+ const MessageItem &item = messages[messageId];
out << "Message ID: " << item.messageId << "\n";
out << "Timestamp: " << item.timestamp << "\n";
- out << "Content:\n" << item.content;
-
+ out << "Content:\n"
+ << item.content;
+
file.close();
}
}
-void ctai_textedit::toggleCollapse(const QString& messageId)
+void ctai_textedit::toggleCollapse(const QString &messageId)
{
- if (!messages.contains(messageId)) return;
-
+ if (!messages.contains(messageId))
+ return;
+
// 切换折叠状态
messages[messageId].isCollapsed = !messages[messageId].isCollapsed;
-
+
// 更新显示
clear();
- for (const auto& item : messages) {
- messageDisplay(item.messageId);
+ for (const auto &item : messages)
+ {
+ init_framework_display(item.messageId);
}
-}
-
-void ctai_textedit::insertSeparatorLine()
-{
- QTextCursor cursor = textCursor();
- cursor.movePosition(QTextCursor::End);
- cursor.insertHtml("
");
-}
+}
\ No newline at end of file
diff --git a/src/ctai_textedit.h b/src/ctai_textedit.h
index b171bab..7df601a 100644
--- a/src/ctai_textedit.h
+++ b/src/ctai_textedit.h
@@ -17,6 +17,7 @@ struct MessageItem {
QString total_tokens;
QString cache_hit_tokens;
QString cache_miss_tokens;
+ bool stream_mode;
bool isCollapsed;
};
@@ -25,23 +26,18 @@ class ctai_textedit : public QTextBrowser
Q_OBJECT
public:
explicit ctai_textedit(QWidget *parent = nullptr);
- void appendMessage(const model_data& content);
- void startStreamingMessage(const model_data& messageId);
- void appendStreamContent(const model_data& content);
- void finishStreamingMessage();
-
+ void add_message(const model_data& content);
+ void append_stream_display(const model_data& content);
public slots:
void deleteMessage(const QString& messageId);
void copyMessage(const QString& messageId);
void saveMessage(const QString& messageId);
void toggleCollapse(const QString& messageId);
-
private:
- void createMessageControls(const QString& messageId);
- void messageDisplay(const QString& messageId);
- void streamMessageDisplay(const QString& messageId);
- void insertSeparatorLine();
-
+ void init_stream_display(const QString& messageId);
+ void init_framework_display(const QString& messageId);
+ void init_not_stream_display(const QString& messageId);
+ void createMessageControls(const QString& messageId);
private:
QMap
messages;
QString currentStreamingId;