Skip to content

Commit

Permalink
add search on old conversations
Browse files Browse the repository at this point in the history
  • Loading branch information
sunderme committed Apr 20, 2024
1 parent 6dc29ae commit 5cd4bae
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 30 deletions.
10 changes: 10 additions & 0 deletions images-ng/edit-find.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions images-ng/edit-find_dm.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions images.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@
<file>images-ng/down.svgz</file>
<file>images-ng/edit-copy.svgz</file>
<file>images-ng/edit-cut.svgz</file>
<file>images-ng/edit-find_dm.svg</file>
<file>images-ng/edit-find.svg</file>
<file>images-ng/edit-paste.svgz</file>
<file>images-ng/edit-redo.svg</file>
<file>images-ng/edit-undo.svg</file>
Expand Down
34 changes: 33 additions & 1 deletion src/aichatassistant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,38 @@ AIChatAssistant::AIChatAssistant(QWidget *parent)
{
config=dynamic_cast<ConfigManager *>(ConfigManagerInterface::getInstance());

m_btSearch=new QToolButton();
m_actSearch=new QAction();
m_actSearch->setIcon(getRealIcon("edit-find"));
m_actSearch->setToolTip(tr("Search in previous conversations"));
connect(m_actSearch,&QAction::triggered,this,&AIChatAssistant::slotSearch);
m_btSearch->setDefaultAction(m_actSearch);
m_leSearch=new QLineEdit();
m_leSearch->setPlaceholderText(tr("Search in conversations"));
auto *hlayoutSearch=new QHBoxLayout();
hlayoutSearch->addWidget(m_leSearch);
hlayoutSearch->addWidget(m_btSearch);

AIQueryStorageModel *model=new AIQueryStorageModel(this);
QString path=config->configBaseDir+QString("/ai_conversation");
model->setStoragePath(path);
treeView=new QTreeView();
treeView->setModel(model);
connect(treeView, &QTreeView::clicked, this, &AIChatAssistant::onTreeViewClicked);

auto *vtreeLayout=new QVBoxLayout();
vtreeLayout->addLayout(hlayoutSearch);
vtreeLayout->addWidget(treeView);
QWidget *wdgtTree=new QWidget();
wdgtTree->setLayout(vtreeLayout);

textBrowser=new QTextBrowser();
auto *hlBrowser=new QSplitter();
hlBrowser->addWidget(treeView);
hlBrowser->addWidget(wdgtTree);
hlBrowser->addWidget(textBrowser);

leEntry=new QTextEdit();
leEntry->setPlaceholderText(tr("Enter your query here"));
m_actSend=new QAction();
m_actSend->setIcon(getRealIcon("document-send"));
m_actSend->setToolTip(tr("Send Query to AI provider"));
Expand All @@ -42,6 +61,9 @@ AIChatAssistant::AIChatAssistant(QWidget *parent)
connect(m_actOptions,&QAction::triggered,this,&AIChatAssistant::slotOptions);
m_btOptions=new QToolButton();
m_btOptions->setDefaultAction(m_actOptions);



auto *hlayout=new QHBoxLayout();
hlayout->addWidget(leEntry);
auto *vl=new QVBoxLayout();
Expand Down Expand Up @@ -269,6 +291,15 @@ void AIChatAssistant::slotOptions()
dlg.setLayout(ly);
dlg.exec();
}
/*!
* \brief filter old conversations
*/
void AIChatAssistant::slotSearch()
{
QString text=m_leSearch->text();
AIQueryStorageModel *model=dynamic_cast<AIQueryStorageModel *>(treeView->model());
model->setFilter(text);
}
/*!
* \brief handle communication error with ai provider
*/
Expand Down Expand Up @@ -433,4 +464,5 @@ QString AIChatAssistant::getConversationForBrowser()
* - modeltree for conversations
* + show summary of conversation in titles ?
* - search in questions/answers
* - overlay buttons insert/etc.
*/
4 changes: 4 additions & 0 deletions src/aichatassistant.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ private slots:
void slotSend();
void slotInsert();
void slotOptions();
void slotSearch();
void onRequestError(QNetworkReply::NetworkError code);
void onRequestCompleted(QNetworkReply *nreply);
void onTreeViewClicked(const QModelIndex &index);
Expand All @@ -39,6 +40,9 @@ private slots:
QToolButton *m_btOptions;
QAction *m_actOptions;
QTextEdit *leEntry;
QLineEdit *m_leSearch;
QToolButton *m_btSearch;
QAction *m_actSearch;

QString m_response;
QString m_selectedText;
Expand Down
134 changes: 106 additions & 28 deletions src/aiquerystoragemodel.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#include "aiquerystoragemodel.h"

#include <QJsonDocument>
#include <QJsonArray>

AIQueryStorageModel::AIQueryStorageModel(QObject *parent)
: QAbstractItemModel{parent}
{}
Expand All @@ -20,9 +23,9 @@ QVariant AIQueryStorageModel::data(const QModelIndex &index, int role) const
previous=m_segments.at(parent_row-2).index;
}
int r=index.row();
return m_files.value(previous+r);
return m_shownFiles.value(previous+r);
}
return m_files.at(index.row());
return m_shownFiles.at(index.row());
}
}
return QVariant{};
Expand Down Expand Up @@ -67,7 +70,7 @@ int AIQueryStorageModel::rowCount(const QModelIndex &parent) const
return m_segments.at(row).index;
}
}
return m_files.size();
return m_shownFiles.size();
}
return 0;
}
Expand All @@ -93,29 +96,8 @@ void AIQueryStorageModel::setStoragePath(const QString &path)
if(m_files.isEmpty()) {
return;
}
auto lst_names = std::vector{tr("Today"),tr("Last Week"),tr("Last Month")};
auto lst_date = std::vector{QDate::currentDate(),QDate::currentDate().addDays(-7),QDate::currentDate().addMonths(-1)};
auto last_it=m_files.cbegin();
for(size_t i=0;i<lst_date.size();++i){
QString date = lst_date.at(i).toString("yyyyMMdd");
auto it=std::upper_bound(m_files.constBegin(),m_files.constEnd(),date,std::greater<QString>());
if (it-last_it > 0) {
TimeFrame tf;
tf.name=lst_names.at(i);
tf.index=it-m_files.constBegin();
m_segments.append(tf);
last_it=it;
}
if(it==m_files.cend()){
break;
}
}
if(last_it!=m_files.cend()){
TimeFrame tf;
tf.name=tr("Older");
tf.index=last_it-m_files.constBegin();
m_segments.append(tf);
}
m_shownFiles=m_files;
generateSegments();
}

QString AIQueryStorageModel::getFileName(const QModelIndex &index) const
Expand All @@ -124,15 +106,27 @@ QString AIQueryStorageModel::getFileName(const QModelIndex &index) const
if (row == 0) {
return QString{};
}
QString fn;
if(m_segments.size()>0){
int previous=0;
if(row>1 && row<=m_segments.size()){
previous=m_segments.at(row-2).index;
}
int r=index.row();
return m_storageDirectory.absoluteFilePath(m_files.value(previous+r));
if(m_filterActive){
fn=m_filteredFiles.value(previous+r);
}else{
fn=m_files.value(previous+r);
}
}
if(fn.isEmpty()){
if(m_filterActive){
fn=m_filteredFiles.at(index.row());
}else{
fn=m_files.at(index.row());
}
}
return m_storageDirectory.absoluteFilePath(m_files.at(index.row()));
return m_storageDirectory.absoluteFilePath(fn);
}

void AIQueryStorageModel::addFileName(const QString &name)
Expand All @@ -152,3 +146,87 @@ void AIQueryStorageModel::addFileName(const QString &name)
}
endInsertRows();
}

void AIQueryStorageModel::setFilter(const QString &filter)
{
beginResetModel();
if(filter.isEmpty()){
m_shownFiles=m_files;
generateSegments();
endResetModel();
m_filterActive=false;
return;
}
m_filteredFiles.clear();
for (auto &elem : m_files) {
if (fileContains(m_storageDirectory.absoluteFilePath(elem), filter)) {
m_filteredFiles.append(elem);
}
}
if (m_filteredFiles.isEmpty()) {
m_shownFiles=m_files;
m_filterActive=false;
} else {
m_shownFiles=m_filteredFiles;
m_filterActive=true;
}
generateSegments();
endResetModel();
}
/*!
* \brief segment files by date
*/
void AIQueryStorageModel::generateSegments()
{
m_segments.clear();
auto lst_names = std::vector{tr("Today"),tr("Last Week"),tr("Last Month")};
auto lst_date = std::vector{QDate::currentDate(),QDate::currentDate().addDays(-7),QDate::currentDate().addMonths(-1)};
auto last_it=m_shownFiles.cbegin();
for(size_t i=0;i<lst_date.size();++i){
QString date = lst_date.at(i).toString("yyyyMMdd");
auto it=std::upper_bound(m_shownFiles.constBegin(),m_shownFiles.constEnd(),date,std::greater<QString>());
if (it-last_it > 0) {
TimeFrame tf;
tf.name=lst_names.at(i);
tf.index=it-m_shownFiles.constBegin();
m_segments.append(tf);
last_it=it;
}
if(it==m_shownFiles.cend()){
break;
}
}
if(last_it!=m_shownFiles.cend()){
TimeFrame tf;
tf.name=tr("Older");
tf.index=last_it-m_files.constBegin();
m_segments.append(tf);
}
}
/*!
* \brief open json file and check if user query or response contains filter
* \param filename
* \param filter
* \return
*/
bool AIQueryStorageModel::fileContains(const QString &filename, const QString &filter) const
{
QFile file{filename};
if (!file.open(QIODevice::ReadOnly)) {
return false;
}
QJsonDocument doc{QJsonDocument::fromJson(file.readAll())};
file.close();
if (doc.isNull()) {
return false;
}
auto obj = doc.object();
QJsonArray ja = obj["messages"].toArray();
for (auto elem : ja) {
auto msg = elem.toObject();
if (msg.contains("content") && msg["content"].toString().contains(filter)) {
return true;
}
}
return false;
}
8 changes: 7 additions & 1 deletion src/aiquerystoragemodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@ class AIQueryStorageModel : public QAbstractItemModel
void setStoragePath(const QString &path);
QString getFileName(const QModelIndex &index) const;
void addFileName(const QString &name);
void setFilter(const QString &filter);
private:
QDir m_storageDirectory;
QStringList m_files;
QStringList m_filteredFiles;
QStringList m_shownFiles;
bool m_filterActive=false;


struct TimeFrame
{
Expand All @@ -31,7 +36,8 @@ class AIQueryStorageModel : public QAbstractItemModel
};
QList<TimeFrame>m_segments;


void generateSegments();
bool fileContains(const QString &filename, const QString &filter) const;
// QAbstractItemModel interface
};

Expand Down

0 comments on commit 5cd4bae

Please sign in to comment.