diff --git a/pyproject.toml b/pyproject.toml index 5a206cce..693415d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,7 +66,7 @@ dependencies = [ "gpt4all >= 2.0.0; platform_system == 'Windows' or platform_system == 'Darwin'", "itsdangerous == 2.1.2", "httpx == 0.25.0", - "pgvector == 0.2.3", + "pgvector == 0.2.4", "psycopg2-binary == 2.9.9", "google-auth == 2.23.3", "python-multipart == 0.0.6", diff --git a/src/khoj/configure.py b/src/khoj/configure.py index 4bb23812..613884ed 100644 --- a/src/khoj/configure.py +++ b/src/khoj/configure.py @@ -25,7 +25,7 @@ from khoj.database.models import KhojUser, Subscription from khoj.database.adapters import ( ConversationAdapters, get_all_users, - get_or_create_search_model, + get_or_create_search_models, aget_user_subscription_state, SubscriptionState, ) @@ -146,8 +146,14 @@ def configure_server( # Initialize Search Models from Config and initialize content try: - state.embeddings_model = EmbeddingsModel(get_or_create_search_model().bi_encoder) - state.cross_encoder_model = CrossEncoderModel(get_or_create_search_model().cross_encoder) + search_models = get_or_create_search_models() + state.embeddings_model = dict() + state.cross_encoder_model = dict() + + for model in search_models: + state.embeddings_model.update({model.name: EmbeddingsModel(model.bi_encoder)}) + state.cross_encoder_model.update({model.name: CrossEncoderModel(model.cross_encoder)}) + state.SearchType = configure_search_types() state.search_models = configure_search(state.search_models, state.config.search_type) initialize_content(regenerate, search_type, init, user) diff --git a/src/khoj/database/adapters/__init__.py b/src/khoj/database/adapters/__init__.py index 31aa1d57..2992ef37 100644 --- a/src/khoj/database/adapters/__init__.py +++ b/src/khoj/database/adapters/__init__.py @@ -32,6 +32,7 @@ from khoj.database.models import ( SpeechToTextModelOptions, Subscription, UserConversationConfig, + UserSearchModelConfig, OpenAIProcessorConversationConfig, OfflineChatProcessorConversationConfig, ReflectiveQuestion, @@ -250,12 +251,33 @@ async def set_user_github_config(user: KhojUser, pat_token: str, repos: list): return config -def get_or_create_search_model(): - search_model = SearchModelConfig.objects.filter().first() - if not search_model: - search_model = SearchModelConfig.objects.create() +def get_user_search_model_or_default(user=None): + if user and UserSearchModelConfig.objects.filter(user=user).exists(): + return UserSearchModelConfig.objects.filter(user=user).first().setting - return search_model + if SearchModelConfig.objects.filter(name="default").exists(): + return SearchModelConfig.objects.filter(name="default").first() + else: + SearchModelConfig.objects.create() + + return SearchModelConfig.objects.first() + + +def get_or_create_search_models(): + search_models = SearchModelConfig.objects.all() + if search_models.count() == 0: + SearchModelConfig.objects.create() + search_models = SearchModelConfig.objects.all() + + return search_models + + +async def aset_user_search_model(user: KhojUser, search_model_config_id: int): + config = await SearchModelConfig.objects.filter(id=search_model_config_id).afirst() + if not config: + return None + new_config, _ = await UserSearchModelConfig.objects.aupdate_or_create(user=user, defaults={"setting": config}) + return new_config class ConversationAdapters: diff --git a/src/khoj/database/admin.py b/src/khoj/database/admin.py index 491eb091..5b5f1006 100644 --- a/src/khoj/database/admin.py +++ b/src/khoj/database/admin.py @@ -16,6 +16,7 @@ from khoj.database.models import ( SpeechToTextModelOptions, Subscription, ReflectiveQuestion, + UserSearchModelConfig, TextToImageModelConfig, Conversation, ) @@ -29,6 +30,7 @@ admin.site.register(OfflineChatProcessorConversationConfig) admin.site.register(SearchModelConfig) admin.site.register(Subscription) admin.site.register(ReflectiveQuestion) +admin.site.register(UserSearchModelConfig) admin.site.register(TextToImageModelConfig) diff --git a/src/khoj/database/migrations/0023_usersearchmodelconfig.py b/src/khoj/database/migrations/0023_usersearchmodelconfig.py new file mode 100644 index 00000000..0aec99f0 --- /dev/null +++ b/src/khoj/database/migrations/0023_usersearchmodelconfig.py @@ -0,0 +1,33 @@ +# Generated by Django 4.2.7 on 2023-12-19 15:44 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + ("database", "0022_texttoimagemodelconfig"), + ] + + operations = [ + migrations.CreateModel( + name="UserSearchModelConfig", + 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)), + ( + "setting", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="database.searchmodelconfig"), + ), + ( + "user", + models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/src/khoj/database/migrations/0024_alter_entry_embeddings.py b/src/khoj/database/migrations/0024_alter_entry_embeddings.py new file mode 100644 index 00000000..a1bbf45d --- /dev/null +++ b/src/khoj/database/migrations/0024_alter_entry_embeddings.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2023-12-20 07:27 + +from django.db import migrations +import pgvector.django + + +class Migration(migrations.Migration): + dependencies = [ + ("database", "0023_usersearchmodelconfig"), + ] + + operations = [ + migrations.AlterField( + model_name="entry", + name="embeddings", + field=pgvector.django.VectorField(), + ), + ] diff --git a/src/khoj/database/models/__init__.py b/src/khoj/database/models/__init__.py index 00700f2f..a9fa38f7 100644 --- a/src/khoj/database/models/__init__.py +++ b/src/khoj/database/models/__init__.py @@ -153,6 +153,11 @@ class UserConversationConfig(BaseModel): setting = models.ForeignKey(ChatModelOptions, on_delete=models.CASCADE, default=None, null=True, blank=True) +class UserSearchModelConfig(BaseModel): + user = models.OneToOneField(KhojUser, on_delete=models.CASCADE) + setting = models.ForeignKey(SearchModelConfig, on_delete=models.CASCADE) + + class Conversation(BaseModel): user = models.ForeignKey(KhojUser, on_delete=models.CASCADE) conversation_log = models.JSONField(default=dict) @@ -180,7 +185,7 @@ class Entry(BaseModel): GITHUB = "github" user = models.ForeignKey(KhojUser, on_delete=models.CASCADE, default=None, null=True, blank=True) - embeddings = VectorField(dimensions=384) + embeddings = VectorField(dimensions=None) raw = models.TextField() compiled = models.TextField() heading = models.CharField(max_length=1000, default=None, null=True, blank=True) diff --git a/src/khoj/interface/web/assets/icons/web.svg b/src/khoj/interface/web/assets/icons/web.svg new file mode 100644 index 00000000..592aa53e --- /dev/null +++ b/src/khoj/interface/web/assets/icons/web.svg @@ -0,0 +1,2 @@ + + diff --git a/src/khoj/interface/web/base_config.html b/src/khoj/interface/web/base_config.html index 723f8aaa..b3a5a3a3 100644 --- a/src/khoj/interface/web/base_config.html +++ b/src/khoj/interface/web/base_config.html @@ -296,6 +296,21 @@ height: 32px; } + div#notification-banner { + background-color: var(--primary); + border: 1px solid var(--primary-hover); + padding: 8px; + box-shadow: 0px 1px 3px 0px rgba(0,0,0,0.1),0px 1px 2px -1px rgba(0,0,0,0.8); + } + + div#notification-banner-parent { + position: fixed; + right: 0; + bottom: 0; + margin: 20px; + } + + select#search-models, select#chat-models { margin-bottom: 0; padding: 8px; diff --git a/src/khoj/interface/web/chat.html b/src/khoj/interface/web/chat.html index c4742b9c..2a813779 100644 --- a/src/khoj/interface/web/chat.html +++ b/src/khoj/interface/web/chat.html @@ -16,6 +16,9 @@ Hi, I am Khoj, your open, personal AI 👋🏽. I can help: - 🧠 Answer general knowledge questions - 💡 Be a sounding board for your ideas - 📜 Chat with your notes & documents +- 🌄 Generate images based on your messages +- 🔎 Search the web for answers to your questions +- 🎙️ Listen to your audio messages Get the Khoj [Desktop](https://khoj.dev/downloads), [Obsidian](https://docs.khoj.dev/#/obsidian?id=setup) or [Emacs](https://docs.khoj.dev/#/emacs?id=setup) app to search, chat with your 🖥️ computer docs. diff --git a/src/khoj/interface/web/config.html b/src/khoj/interface/web/config.html index 3ce9c9cc..4d85e254 100644 --- a/src/khoj/interface/web/config.html +++ b/src/khoj/interface/web/config.html @@ -107,6 +107,26 @@ +
+
+ Language +

+ Language +

+
+
+ +
+
+ +
+
@@ -239,6 +259,10 @@
{% endif %}
+ +
+
+