diff --git a/README.md b/README.md index c6f909e2..213abd95 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,9 @@ Also check our sibling project, [OllamaHub](https://ollamahub.com/), where you c - ✒️🔢 **Full Markdown and LaTeX Support**: Elevate your LLM experience with comprehensive Markdown and LaTeX capabilities for enriched interaction. -- 📚 **Local RAG Integration**: Dive into the future of chat interactions with the groundbreaking Retrieval Augmented Generation (RAG) support. This feature seamlessly integrates document interactions into your chat experience. You can load documents directly into the chat or add files to your document library, effortlessly accessing them using '#' command in the prompt. In its alpha phase, occasional issues may arise as we actively refine and enhance this feature to ensure optimal performance and reliability. +- 📚 **Local RAG Integration**: Dive into the future of chat interactions with the groundbreaking Retrieval Augmented Generation (RAG) support. This feature seamlessly integrates document interactions into your chat experience. You can load documents directly into the chat or add files to your document library, effortlessly accessing them using **'#'** command in the prompt. In its alpha phase, occasional issues may arise as we actively refine and enhance this feature to ensure optimal performance and reliability. -- 📜 **Prompt Preset Support**: Instantly access preset prompts using the '/' command in the chat input. Load predefined conversation starters effortlessly and expedite your interactions. Effortlessly import prompts through [OllamaHub](https://ollamahub.com/) integration. +- 📜 **Prompt Preset Support**: Instantly access preset prompts using the **'/'** command in the chat input. Load predefined conversation starters effortlessly and expedite your interactions. Effortlessly import prompts through [OllamaHub](https://ollamahub.com/) integration. - 👍👎 **RLHF Annotation**: Empower your messages by rating them with thumbs up and thumbs down, facilitating the creation of datasets for Reinforcement Learning from Human Feedback (RLHF). Utilize your messages to train or fine-tune models, all while ensuring the confidentiality of locally saved data. @@ -51,6 +51,8 @@ Also check our sibling project, [OllamaHub](https://ollamahub.com/), where you c - ⚙️ **Many Models Conversations**: Effortlessly engage with various models simultaneously, harnessing their unique strengths for optimal responses. Enhance your experience by leveraging a diverse set of models in parallel. +- 💬 **Collaborative Chat**: Harness the collective intelligence of multiple models by seamlessly orchestrating group conversations. Use the **'@'** command to specify the model, enabling dynamic and diverse dialogues within your chat interface. Immerse yourself in the collective intelligence woven into your chat environment. + - 🤝 **OpenAI API Integration**: Effortlessly integrate OpenAI-compatible API for versatile conversations alongside Ollama models. Customize the API Base URL to link with **LMStudio, Mistral, OpenRouter, and more**. - 🔄 **Regeneration History Access**: Easily revisit and explore your entire regeneration history. @@ -92,6 +94,7 @@ Don't forget to explore our sibling project, [OllamaHub](https://ollamahub.com/) 1. **Installing Docker:** - **For Windows and Mac Users:** + - Download Docker Desktop from [Docker's official website](https://www.docker.com/products/docker-desktop). - Follow the installation instructions provided on the website. After installation, open Docker Desktop to ensure it's running properly. @@ -112,6 +115,7 @@ Don't forget to explore our sibling project, [OllamaHub](https://ollamahub.com/) This command downloads a test image and runs it in a container, which prints an informational message. 2. **Ensure You Have the Latest Version of Ollama:** + - Download the latest version from [https://ollama.ai/](https://ollama.ai/). 3. **Verify Ollama Installation:** @@ -264,7 +268,6 @@ See [TROUBLESHOOTING.md](/TROUBLESHOOTING.md) for information on how to troubles Here are some exciting tasks on our roadmap: -- 💬 **Group Conversations**: Witness the dynamic synergy of multiple Language Models engaging in collaborative discussions. In this unique feature, you can orchestrate interactions between various models, opening up avenues for diverse and intriguing dialogues. Experience the power of collective intelligence within your chat environment. - 🌐 **Web Browsing Capability**: Experience the convenience of seamlessly integrating web content directly into your chat. Easily browse and share information without leaving the conversation. - 🔄 **Function Calling**: Empower your interactions by running code directly within the chat. Execute functions and commands effortlessly, enhancing the functionality of your conversations. - ⚙️ **Custom Python Backend Actions**: Empower your Ollama Web UI by creating or downloading custom Python backend actions. Unleash the full potential of your web interface with tailored actions that suit your specific needs, enhancing functionality and versatility. diff --git a/src/lib/apis/ollama/index.ts b/src/lib/apis/ollama/index.ts index 10eddc1c..65386606 100644 --- a/src/lib/apis/ollama/index.ts +++ b/src/lib/apis/ollama/index.ts @@ -167,6 +167,44 @@ export const generateTitle = async (token: string = '', model: string, prompt: s return res?.response ?? 'New Chat'; }; +export const generatePrompt = async (token: string = '', model: string, conversation: string) => { + let error = null; + + if (conversation === '') { + conversation = '[no existing conversation]'; + } + + const res = await fetch(`${OLLAMA_API_BASE_URL}/generate`, { + method: 'POST', + headers: { + 'Content-Type': 'text/event-stream', + Authorization: `Bearer ${token}` + }, + body: JSON.stringify({ + model: model, + prompt: `Conversation: + ${conversation} + + As USER in the conversation above, your task is to continue the conversation. Remember, Your responses should be crafted as if you're a human conversing in a natural, realistic manner, keeping in mind the context and flow of the dialogue. Please generate a fitting response to the last message in the conversation, or if there is no existing conversation, initiate one as a normal person would. + + Response: + ` + }) + }).catch((err) => { + console.log(err); + if ('detail' in err) { + error = err.detail; + } + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + export const generateChatCompletion = async (token: string = '', body: object) => { let error = null; diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index 4df0ebb1..3fae5a76 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -10,6 +10,7 @@ import AddFilesPlaceholder from '../AddFilesPlaceholder.svelte'; import { SUPPORTED_FILE_TYPE } from '$lib/constants'; import Documents from './MessageInput/Documents.svelte'; + import Models from './MessageInput/Models.svelte'; export let submitPrompt: Function; export let stopResponse: Function; @@ -18,12 +19,17 @@ export let autoScroll = true; let filesInputElement; + let promptsElement; let documentsElement; + let modelsElement; let inputFiles; let dragged = false; + let user = null; + let chatInputPlaceholder = ''; + export let files = []; export let fileUploadEnabled = true; @@ -35,6 +41,15 @@ let speechRecognition; + $: if (prompt) { + const chatInput = document.getElementById('chat-textarea'); + + if (chatInput) { + chatInput.style.height = ''; + chatInput.style.height = Math.min(chatInput.scrollHeight, 200) + 'px'; + } + } + const speechRecognitionHandler = () => { // Check if SpeechRecognition is supported @@ -79,7 +94,7 @@ console.log('recognition ended'); speechRecognitionListening = false; if (prompt !== '' && $settings?.speechAutoSend === true) { - submitPrompt(prompt); + submitPrompt(prompt, user); } }; @@ -246,6 +261,14 @@ ]; }} /> + {:else if prompt.charAt(0) === '@'} + {:else if messages.length == 0 && suggestionPrompts.length !== 0} {/if} @@ -293,7 +316,7 @@
{ - submitPrompt(prompt); + submitPrompt(prompt, user); }} > {#if files.length > 0} @@ -435,14 +458,18 @@ class=" dark:bg-gray-800 dark:text-gray-100 outline-none w-full py-3 px-2 {fileUploadEnabled ? '' : ' pl-4'} rounded-xl resize-none h-[48px]" - placeholder={speechRecognitionListening ? 'Listening...' : 'Send a message'} + placeholder={chatInputPlaceholder !== '' + ? chatInputPlaceholder + : speechRecognitionListening + ? 'Listening...' + : 'Send a message'} bind:value={prompt} on:keypress={(e) => { if (e.keyCode == 13 && !e.shiftKey) { e.preventDefault(); } if (prompt !== '' && e.keyCode == 13 && !e.shiftKey) { - submitPrompt(prompt); + submitPrompt(prompt, user); } }} on:keydown={async (e) => { @@ -477,10 +504,10 @@ editButton?.click(); } - if (['/', '#'].includes(prompt.charAt(0)) && e.key === 'ArrowUp') { + if (['/', '#', '@'].includes(prompt.charAt(0)) && e.key === 'ArrowUp') { e.preventDefault(); - (promptsElement || documentsElement).selectUp(); + (promptsElement || documentsElement || modelsElement).selectUp(); const commandOptionButton = [ ...document.getElementsByClassName('selected-command-option-button') @@ -488,10 +515,10 @@ commandOptionButton.scrollIntoView({ block: 'center' }); } - if (['/', '#'].includes(prompt.charAt(0)) && e.key === 'ArrowDown') { + if (['/', '#', '@'].includes(prompt.charAt(0)) && e.key === 'ArrowDown') { e.preventDefault(); - (promptsElement || documentsElement).selectDown(); + (promptsElement || documentsElement || modelsElement).selectDown(); const commandOptionButton = [ ...document.getElementsByClassName('selected-command-option-button') @@ -499,7 +526,7 @@ commandOptionButton.scrollIntoView({ block: 'center' }); } - if (['/', '#'].includes(prompt.charAt(0)) && e.key === 'Enter') { + if (['/', '#', '@'].includes(prompt.charAt(0)) && e.key === 'Enter') { e.preventDefault(); const commandOptionButton = [ @@ -509,7 +536,7 @@ commandOptionButton?.click(); } - if (['/', '#'].includes(prompt.charAt(0)) && e.key === 'Tab') { + if (['/', '#', '@'].includes(prompt.charAt(0)) && e.key === 'Tab') { e.preventDefault(); const commandOptionButton = [ @@ -540,6 +567,7 @@ on:input={(e) => { e.target.style.height = ''; e.target.style.height = Math.min(e.target.scrollHeight, 200) + 'px'; + user = null; }} on:paste={(e) => { const clipboardData = e.clipboardData || window.clipboardData; diff --git a/src/lib/components/chat/MessageInput/Models.svelte b/src/lib/components/chat/MessageInput/Models.svelte new file mode 100644 index 00000000..0dbb71c8 --- /dev/null +++ b/src/lib/components/chat/MessageInput/Models.svelte @@ -0,0 +1,158 @@ + + +{#if filteredModels.length > 0} +
+
+
+
@
+
+ +
+
+ {#each filteredModels as model, modelIdx} + + {/each} +
+
+
+
+{/if} diff --git a/src/lib/components/chat/Messages/UserMessage.svelte b/src/lib/components/chat/Messages/UserMessage.svelte index 64904bf8..ade2ae18 100644 --- a/src/lib/components/chat/Messages/UserMessage.svelte +++ b/src/lib/components/chat/Messages/UserMessage.svelte @@ -2,6 +2,7 @@ import { tick } from 'svelte'; import Name from './Name.svelte'; import ProfileImage from './ProfileImage.svelte'; + import { modelfiles } from '$lib/stores'; export let user; export let message; @@ -42,11 +43,25 @@
- + modelfile.tagName === message.user)?.imageUrl ?? '/user.png' + : user?.profile_image_url ?? '/user.png'} + />
- You + + {#if message.user} + {#if $modelfiles.map((modelfile) => modelfile.tagName).includes(message.user)} + {$modelfiles.find((modelfile) => modelfile.tagName === message.user)?.title} + {:else} + You {message?.user ?? ''} + {/if} + {:else} + You + {/if} +
{ + const submitPrompt = async (userPrompt, _user = null) => { console.log('submitPrompt', $chatId); if (selectedModels.includes('')) { @@ -143,6 +143,7 @@ parentId: messages.length !== 0 ? messages.at(-1).id : null, childrenIds: [], role: 'user', + user: _user ?? undefined, content: userPrompt, files: files.length > 0 ? files : undefined }; diff --git a/src/routes/(app)/c/[id]/+page.svelte b/src/routes/(app)/c/[id]/+page.svelte index aeffa000..7fb82955 100644 --- a/src/routes/(app)/c/[id]/+page.svelte +++ b/src/routes/(app)/c/[id]/+page.svelte @@ -135,7 +135,8 @@ // Ollama functions ////////////////////////// - const submitPrompt = async (userPrompt) => { + const submitPrompt = async (userPrompt, user) => { + console.log(userPrompt, user); console.log('submitPrompt', $chatId); if (selectedModels.includes('')) { @@ -143,6 +144,14 @@ } else if (messages.length != 0 && messages.at(-1).done != true) { // Response not done console.log('wait'); + } else if ( + files.length > 0 && + files.filter((file) => file.upload_status === false).length > 0 + ) { + // Upload not done + toast.error( + `Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.` + ); } else { // Reset chat message textarea height document.getElementById('chat-textarea').style.height = '';