From 8fa0b69c673c128f98b5e83a865d51993215608e Mon Sep 17 00:00:00 2001 From: sabaimran Date: Mon, 20 Nov 2023 15:21:06 -0800 Subject: [PATCH 1/3] Resolve merge issue with adapters methods --- src/database/adapters/__init__.py | 22 +++++ .../migrations/0020_reflectivequestion.py | 36 ++++++++ src/database/models/__init__.py | 5 ++ src/interface/desktop/chat.html | 53 +++++++++++ src/khoj/interface/web/chat.html | 89 +++++++++++++++++++ src/khoj/routers/api.py | 11 +++ 6 files changed, 216 insertions(+) create mode 100644 src/database/migrations/0020_reflectivequestion.py diff --git a/src/database/adapters/__init__.py b/src/database/adapters/__init__.py index 7fae4ac7..53f69bc8 100644 --- a/src/database/adapters/__init__.py +++ b/src/database/adapters/__init__.py @@ -33,8 +33,11 @@ from database.models import ( UserConversationConfig, OpenAIProcessorConversationConfig, OfflineChatProcessorConversationConfig, + ReflectiveQuestion, ) from khoj.utils.helpers import generate_random_name +from khoj.utils import state +from khoj.utils.config import GPT4AllProcessorModel from khoj.search_filter.word_filter import WordFilter from khoj.search_filter.file_filter import FileFilter from khoj.search_filter.date_filter import DateFilter @@ -340,6 +343,25 @@ class ConversationAdapters: async def get_openai_chat_config(): return await OpenAIProcessorConversationConfig.objects.filter().afirst() + @staticmethod + async def aget_conversation_starters(user: KhojUser): + all_questions = [] + if await ReflectiveQuestion.objects.filter(user=user).aexists(): + all_questions = await sync_to_async(ReflectiveQuestion.objects.filter(user=user).values_list)( + "question", flat=True + ) + + all_questions = await sync_to_async(ReflectiveQuestion.objects.filter(user=None).values_list)( + "question", flat=True + ) + + max_results = 3 + all_questions = await sync_to_async(list)(all_questions) + if len(all_questions) < max_results: + return all_questions + + return random.sample(all_questions, max_results) + @staticmethod def get_valid_conversation_config(user: KhojUser): offline_chat_config = ConversationAdapters.get_offline_chat_conversation_config() diff --git a/src/database/migrations/0020_reflectivequestion.py b/src/database/migrations/0020_reflectivequestion.py new file mode 100644 index 00000000..aefb73bf --- /dev/null +++ b/src/database/migrations/0020_reflectivequestion.py @@ -0,0 +1,36 @@ +# Generated by Django 4.2.7 on 2023-11-20 01:13 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + ("database", "0019_alter_googleuser_family_name_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="ReflectiveQuestion", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ("question", models.CharField(max_length=500)), + ( + "user", + models.ForeignKey( + blank=True, + default=None, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/src/database/models/__init__.py b/src/database/models/__init__.py index 92da3e6e..b0463df8 100644 --- a/src/database/models/__init__.py +++ b/src/database/models/__init__.py @@ -141,6 +141,11 @@ class Conversation(BaseModel): conversation_log = models.JSONField(default=dict) +class ReflectiveQuestion(BaseModel): + question = models.CharField(max_length=500) + user = models.ForeignKey(KhojUser, on_delete=models.CASCADE, default=None, null=True, blank=True) + + class Entry(BaseModel): class EntryType(models.TextChoices): IMAGE = "image" diff --git a/src/interface/desktop/chat.html b/src/interface/desktop/chat.html index 21acc4a4..0b50555b 100644 --- a/src/interface/desktop/chat.html +++ b/src/interface/desktop/chat.html @@ -385,6 +385,9 @@ let chatInput = document.getElementById("chat-input"); chatInput.value = chatInput.value.trimStart(); + let questionStarterSuggestions = document.getElementById("question-starters"); + questionStarterSuggestions.style.display = "none"; + if (chatInput.value.startsWith("/") && chatInput.value.split(" ").length === 1) { let chatTooltip = document.getElementById("chat-tooltip"); chatTooltip.style.display = "block"; @@ -467,6 +470,31 @@ return; }); + fetch(`${hostURL}/api/chat/starters?client=desktop`, { headers }) + .then(response => response.json()) + .then(data => { + // Render chat options, if any + if (data) { + let questionStarterSuggestions = document.getElementById("question-starters"); + for (let index in data) { + let questionStarter = data[index]; + let questionStarterButton = document.createElement('button'); + questionStarterButton.innerHTML = questionStarter; + questionStarterButton.classList.add("question-starter"); + questionStarterButton.addEventListener('click', function() { + questionStarterSuggestions.style.display = "none"; + document.getElementById("chat-input").value = questionStarter; + chat(); + }); + questionStarterSuggestions.appendChild(questionStarterButton); + } + questionStarterSuggestions.style.display = "grid"; + } + }) + .catch(err => { + return; + }); + fetch(`${hostURL}/api/chat/options`, { headers }) .then(response => response.json()) .then(data => { @@ -506,6 +534,9 @@
+ + +