feat(chat): markdown formattato nella chat + testo pulito per la voce (v0.5.2)
- src/markdown.{h,cpp}: convertitore minimale, due funzioni:
* toRichText() -> HTML per QML Text.RichText: grassetti (**x**/__x__),
corsivi (*x*/_x_ con confini di parola per non toccare snake_case),
titoli (#), liste (-/1.), citazioni (>), codice (`x` e blocchi ```,
in monospace), link [t](u) -> solo testo, barrato ~~x~~; escape di
< & > contro injection nel rich text
* toSpeech() -> testo piatto per il TTS: via recinti di codice, marcatori
di titoli/liste/citazioni, enfasi, backtick; link/immagini -> testo;
tabelle | a | b | -> "a, b"; righe vuote compattate
- ChatModel: nuovo ruolo contentRich (calcolato in C++, testabile);
incluso nei dataChanged dello streaming
- ChatPage: le bolle dell'assistente usano contentRich con
textFormat: Text.RichText; i messaggi utente restano testo semplice
- ApiClient::speak(): il testo passa da Markdown::toSpeech (niente più
simboli di formattazione letti ad alta voce)
- core-test: 19 casi nuovi per il convertitore (tutti locali, senza device)
Verificato: build zero warning + unit test completi.
This commit is contained in:
+6
-1
@@ -1,4 +1,5 @@
|
||||
#include "chatmodel.h"
|
||||
#include "markdown.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
@@ -35,6 +36,9 @@ QVariant ChatModel::data(const QModelIndex &index, int role) const
|
||||
return m.role;
|
||||
case ContentRole:
|
||||
return m.content;
|
||||
case ContentRichRole:
|
||||
// HTML per il rich text QML (markdown formattato lato C++, testabile).
|
||||
return Markdown::toRichText(m.content);
|
||||
case StreamingRole:
|
||||
return m.streaming;
|
||||
case TimestampRole:
|
||||
@@ -49,6 +53,7 @@ QHash<int, QByteArray> ChatModel::roleNames() const
|
||||
QHash<int, QByteArray> roles;
|
||||
roles.insert(RoleRole, "role");
|
||||
roles.insert(ContentRole, "content");
|
||||
roles.insert(ContentRichRole, "contentRich");
|
||||
roles.insert(StreamingRole, "streaming");
|
||||
roles.insert(TimestampRole, "timestamp");
|
||||
return roles;
|
||||
@@ -167,7 +172,7 @@ void ChatModel::onStreamDelta(const QString &text)
|
||||
}
|
||||
last.content += text;
|
||||
const QModelIndex idx = index(m_msgs.size() - 1, 0);
|
||||
emit dataChanged(idx, idx, QVector<int>() << ContentRole << StreamingRole);
|
||||
emit dataChanged(idx, idx, QVector<int>() << ContentRole << ContentRichRole << StreamingRole);
|
||||
emit streamTick();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user