forked from open-webui/open-webui
Merge pull request #30 from ollama-webui/dev
feat: server url edit & markdown styling added
This commit is contained in:
commit
886c19246f
7 changed files with 316 additions and 51 deletions
28
README.md
28
README.md
|
@ -117,6 +117,34 @@ docker run -d -p 3000:8080 --name ollama-webui --restart always ollama-webui
|
|||
caddy run --envfile .env --config ./Caddyfile.localhost
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Errors
|
||||
|
||||
If you encounter difficulties connecting to the Ollama server, please follow these steps to diagnose and resolve the issue:
|
||||
|
||||
**1. Verify Ollama Server Configuration**
|
||||
|
||||
Ensure that the Ollama server is properly configured to accept incoming connections from all origins. To do this, make sure the server is launched with the `OLLAMA_ORIGINS=*` environment variable, as shown in the following command:
|
||||
|
||||
```bash
|
||||
OLLAMA_HOST=0.0.0.0 OLLAMA_ORIGINS=* ollama serve
|
||||
```
|
||||
|
||||
This configuration allows Ollama to accept connections from any source.
|
||||
|
||||
**2. Check Ollama URL Format**
|
||||
|
||||
Ensure that the Ollama URL is correctly formatted in the application settings. Follow these steps:
|
||||
|
||||
- Go to "Settings" within the Ollama WebUI.
|
||||
- Navigate to the "General" section.
|
||||
- Verify that the Ollama URL is in the following format: `http://localhost:11434/api`.
|
||||
|
||||
It is crucial to include the `/api` at the end of the URL to ensure that the Ollama Web UI can communicate with the server.
|
||||
|
||||
By following these troubleshooting steps, you should be able to identify and resolve connection issues with your Ollama server configuration. If you require further assistance or have additional questions, please don't hesitate to reach out or refer to our documentation for comprehensive guidance.
|
||||
|
||||
## What's Next? 🚀
|
||||
|
||||
### To-Do List 📝
|
||||
|
|
77
package-lock.json
generated
77
package-lock.json
generated
|
@ -21,6 +21,7 @@
|
|||
"@sveltejs/adapter-auto": "^2.0.0",
|
||||
"@sveltejs/adapter-static": "^2.0.3",
|
||||
"@sveltejs/kit": "^1.20.4",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
"@typescript-eslint/parser": "^6.0.0",
|
||||
"autoprefixer": "^10.4.16",
|
||||
|
@ -838,6 +839,34 @@
|
|||
"vite": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/typography": {
|
||||
"version": "0.5.10",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.10.tgz",
|
||||
"integrity": "sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lodash.castarray": "^4.4.0",
|
||||
"lodash.isplainobject": "^4.0.6",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"postcss-selector-parser": "6.0.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"tailwindcss": ">=3.0.0 || insiders"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": {
|
||||
"version": "6.0.10",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
|
||||
"integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cookie": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.2.tgz",
|
||||
|
@ -2603,6 +2632,18 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash.castarray": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
|
||||
"integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
|
@ -4670,6 +4711,30 @@
|
|||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"@tailwindcss/typography": {
|
||||
"version": "0.5.10",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.10.tgz",
|
||||
"integrity": "sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash.castarray": "^4.4.0",
|
||||
"lodash.isplainobject": "^4.0.6",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"postcss-selector-parser": "6.0.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"postcss-selector-parser": {
|
||||
"version": "6.0.10",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
|
||||
"integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/cookie": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.2.tgz",
|
||||
|
@ -5909,6 +5974,18 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"lodash.castarray": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
|
||||
"integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"@sveltejs/adapter-auto": "^2.0.0",
|
||||
"@sveltejs/adapter-static": "^2.0.3",
|
||||
"@sveltejs/kit": "^1.20.4",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
"@typescript-eslint/parser": "^6.0.0",
|
||||
"autoprefixer": "^10.4.16",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
<script lang="ts">
|
||||
import Modal from '../common/Modal.svelte';
|
||||
|
||||
import { API_BASE_URL } from '$lib/constants';
|
||||
import { API_BASE_URL as BUILD_TIME_API_BASE_URL } from '$lib/constants';
|
||||
import toast from 'svelte-french-toast';
|
||||
|
||||
export let show = false;
|
||||
export let saveSettings: Function;
|
||||
export let getModelTags: Function;
|
||||
|
||||
let API_BASE_URL = BUILD_TIME_API_BASE_URL;
|
||||
let system = '';
|
||||
let temperature = 0.8;
|
||||
|
||||
|
@ -33,6 +34,22 @@
|
|||
});
|
||||
};
|
||||
|
||||
const checkOllamaConnection = async () => {
|
||||
if (API_BASE_URL === '') {
|
||||
API_BASE_URL = BUILD_TIME_API_BASE_URL;
|
||||
}
|
||||
const res = await getModelTags(API_BASE_URL);
|
||||
|
||||
if (res) {
|
||||
toast.success('Server connection verified');
|
||||
saveSettings(
|
||||
API_BASE_URL,
|
||||
system != '' ? system : null,
|
||||
temperature != 0.8 ? temperature : null
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const pullModelHandler = async () => {
|
||||
const res = await fetch(`${API_BASE_URL}/pull`, {
|
||||
method: 'POST',
|
||||
|
@ -139,6 +156,7 @@
|
|||
|
||||
$: if (show) {
|
||||
let settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
|
||||
API_BASE_URL = settings.API_BASE_URL ?? BUILD_TIME_API_BASE_URL;
|
||||
system = settings.system ?? '';
|
||||
temperature = settings.temperature ?? 0.8;
|
||||
}
|
||||
|
@ -227,6 +245,50 @@
|
|||
<div class="flex-1 md:min-h-[300px]">
|
||||
{#if selectedMenu === 'general'}
|
||||
<div class="flex flex-col space-y-3">
|
||||
<div>
|
||||
<div class=" mb-2.5 text-sm font-medium">Ollama Server URL</div>
|
||||
<div class="flex w-full">
|
||||
<div class="flex-1 mr-2">
|
||||
<input
|
||||
class="w-full rounded py-2 px-4 text-sm text-gray-300 bg-gray-800 outline-none"
|
||||
placeholder="Enter URL (e.g. http://localhost:11434/api)"
|
||||
bind:value={API_BASE_URL}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
class="px-3 bg-gray-600 hover:bg-gray-700 rounded transition"
|
||||
on:click={() => {
|
||||
checkOllamaConnection();
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M15.312 11.424a5.5 5.5 0 01-9.201 2.466l-.312-.311h2.433a.75.75 0 000-1.5H3.989a.75.75 0 00-.75.75v4.242a.75.75 0 001.5 0v-2.43l.31.31a7 7 0 0011.712-3.138.75.75 0 00-1.449-.39zm1.23-3.723a.75.75 0 00.219-.53V2.929a.75.75 0 00-1.5 0V5.36l-.31-.31A7 7 0 003.239 8.188a.75.75 0 101.448.389A5.5 5.5 0 0113.89 6.11l.311.31h-2.432a.75.75 0 000 1.5h4.243a.75.75 0 00.53-.219z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mt-2 text-xs text-gray-500">
|
||||
Trouble accessing Ollama? <a
|
||||
class=" text-gray-300 font-medium"
|
||||
href="https://github.com/ollama-webui/ollama-webui#troubleshooting"
|
||||
target="_blank"
|
||||
>
|
||||
Click here for help.
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class=" border-gray-700" />
|
||||
|
||||
<div>
|
||||
<div class=" mb-2.5 text-sm font-medium">System Prompt</div>
|
||||
<textarea
|
||||
|
@ -260,6 +322,7 @@
|
|||
class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 transition rounded"
|
||||
on:click={() => {
|
||||
saveSettings(
|
||||
API_BASE_URL === '' ? BUILD_TIME_API_BASE_URL : API_BASE_URL,
|
||||
system != '' ? system : null,
|
||||
temperature != 0.8 ? temperature : null
|
||||
);
|
||||
|
@ -305,11 +368,11 @@
|
|||
</div>
|
||||
|
||||
<div class="mt-2 text-xs text-gray-500">
|
||||
To access the available model names for downloading, click <a
|
||||
To access the available model names for downloading, <a
|
||||
class=" text-gray-300 font-medium"
|
||||
href="https://ollama.ai/library"
|
||||
target="_blank">here</a
|
||||
>.
|
||||
target="_blank">click here.</a
|
||||
>
|
||||
</div>
|
||||
|
||||
{#if pullProgress !== ''}
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
import fileSaver from 'file-saver';
|
||||
const { saveAs } = fileSaver;
|
||||
import hljs from 'highlight.js';
|
||||
import 'highlight.js/styles/dark.min.css';
|
||||
import { API_BASE_URL } from '$lib/constants';
|
||||
import 'highlight.js/styles/github-dark.min.css';
|
||||
import { API_BASE_URL as BUILD_TIME_API_BASE_URL } from '$lib/constants';
|
||||
import { onMount, tick } from 'svelte';
|
||||
|
||||
import Navbar from '$lib/components/layout/Navbar.svelte';
|
||||
import SettingsModal from '$lib/components/chat/SettingsModal.svelte';
|
||||
|
||||
let API_BASE_URL = BUILD_TIME_API_BASE_URL;
|
||||
let suggestions = ''; // $page.url.searchParams.get('suggestions');
|
||||
|
||||
let models = [];
|
||||
|
@ -26,26 +27,24 @@
|
|||
|
||||
let chats = [];
|
||||
let chatId = uuidv4();
|
||||
let title = ``;
|
||||
let title = '';
|
||||
let prompt = '';
|
||||
let messages = [];
|
||||
|
||||
onMount(async () => {
|
||||
let settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
|
||||
|
||||
API_BASE_URL = settings.API_BASE_URL ?? BUILD_TIME_API_BASE_URL;
|
||||
console.log(API_BASE_URL);
|
||||
system = settings.system ?? null;
|
||||
temperature = settings.temperature ?? null;
|
||||
|
||||
await getModelTags();
|
||||
|
||||
let settings = localStorage.getItem('settings');
|
||||
if (settings) {
|
||||
settings = JSON.parse(settings);
|
||||
console.log(settings);
|
||||
|
||||
selectedModel =
|
||||
settings.model && models.map((model) => model.name).includes(settings.model)
|
||||
? settings.model
|
||||
: '';
|
||||
system = settings.system ?? null;
|
||||
temperature = settings.temperature ?? null;
|
||||
}
|
||||
selectedModel =
|
||||
settings.model && models.map((model) => model.name).includes(settings.model)
|
||||
? settings.model
|
||||
: '';
|
||||
|
||||
db = await openDB('Chats', 1, {
|
||||
upgrade(db) {
|
||||
|
@ -117,6 +116,41 @@
|
|||
);
|
||||
};
|
||||
|
||||
const createCopyCodeBlockButton = () => {
|
||||
// use a class selector if available
|
||||
let blocks = document.querySelectorAll('pre');
|
||||
console.log(blocks);
|
||||
|
||||
blocks.forEach((block) => {
|
||||
// only add button if browser supports Clipboard API
|
||||
|
||||
if (navigator.clipboard && block.childNodes.length < 2) {
|
||||
let button = document.createElement('button');
|
||||
|
||||
button.innerText = 'Copy Code';
|
||||
block.appendChild(button);
|
||||
|
||||
button.addEventListener('click', async () => {
|
||||
await copyCode(block, button);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
async function copyCode(block, button) {
|
||||
let code = block.querySelector('code');
|
||||
let text = code.innerText;
|
||||
|
||||
await navigator.clipboard.writeText(text);
|
||||
|
||||
// visual feedback that task is completed
|
||||
button.innerText = 'Code Copied';
|
||||
|
||||
setTimeout(() => {
|
||||
button.innerText = 'Copy Code';
|
||||
}, 700);
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////
|
||||
// Web functions
|
||||
//////////////////////////
|
||||
|
@ -133,21 +167,23 @@
|
|||
toast.success('Default model updated');
|
||||
};
|
||||
|
||||
const saveSettings = (_system, _temperature) => {
|
||||
const saveSettings = async (_api_base_url, _system, _temperature) => {
|
||||
API_BASE_URL = _api_base_url;
|
||||
system = _system;
|
||||
temperature = _temperature;
|
||||
|
||||
let settings = localStorage.getItem('settings') ?? '{}';
|
||||
if (settings) {
|
||||
settings = JSON.parse(settings);
|
||||
|
||||
settings.API_BASE_URL = API_BASE_URL;
|
||||
settings.system = system;
|
||||
settings.temperature = temperature;
|
||||
localStorage.setItem('settings', JSON.stringify(settings));
|
||||
}
|
||||
|
||||
console.log(settings);
|
||||
|
||||
console.log('saved');
|
||||
await getModelTags();
|
||||
};
|
||||
|
||||
const createNewChat = () => {
|
||||
|
@ -163,7 +199,10 @@
|
|||
settings = JSON.parse(settings);
|
||||
console.log(settings);
|
||||
|
||||
selectedModel = settings.model ?? selectedModel;
|
||||
selectedModel =
|
||||
settings.model && models.map((model) => model.name).includes(settings.model)
|
||||
? settings.model
|
||||
: '';
|
||||
system = settings.system ?? system;
|
||||
temperature = settings.temperature ?? temperature;
|
||||
}
|
||||
|
@ -172,12 +211,18 @@
|
|||
|
||||
const loadChat = async (id) => {
|
||||
const chat = await db.get('chats', id);
|
||||
messages = chat.messages;
|
||||
title = chat.title;
|
||||
chatId = chat.id;
|
||||
selectedModel = chat.model ?? selectedModel;
|
||||
system = chat.system ?? system;
|
||||
temperature = chat.temperature ?? temperature;
|
||||
if (chatId !== chat.id) {
|
||||
messages = chat.messages;
|
||||
title = chat.title;
|
||||
chatId = chat.id;
|
||||
selectedModel = chat.model ?? selectedModel;
|
||||
system = chat.system ?? system;
|
||||
temperature = chat.temperature ?? temperature;
|
||||
|
||||
await tick();
|
||||
hljs.highlightAll();
|
||||
createCopyCodeBlockButton();
|
||||
}
|
||||
};
|
||||
|
||||
const deleteChatHistory = async () => {
|
||||
|
@ -219,8 +264,8 @@
|
|||
// Ollama functions
|
||||
//////////////////////////
|
||||
|
||||
const getModelTags = async () => {
|
||||
const res = await fetch(`${API_BASE_URL}/tags`, {
|
||||
const getModelTags = async (url = null) => {
|
||||
const res = await fetch(`${url === null ? API_BASE_URL : url}/tags`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
|
@ -233,11 +278,13 @@
|
|||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
return { models: [] };
|
||||
toast.error('Server connection failed');
|
||||
return null;
|
||||
});
|
||||
|
||||
console.log(res);
|
||||
models = res.models ?? [];
|
||||
models = res?.models ?? [];
|
||||
return res;
|
||||
};
|
||||
|
||||
const submitPrompt = async (user_prompt) => {
|
||||
|
@ -334,6 +381,7 @@
|
|||
responseMessage.context = data.context;
|
||||
messages = messages;
|
||||
hljs.highlightAll();
|
||||
createCopyCodeBlockButton();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -341,24 +389,25 @@
|
|||
console.log(error);
|
||||
}
|
||||
window.scrollTo({ top: document.body.scrollHeight });
|
||||
|
||||
await db.put('chats', {
|
||||
id: chatId,
|
||||
title: title === '' ? 'New Chat' : title,
|
||||
model: selectedModel,
|
||||
system: system,
|
||||
options: {
|
||||
temperature: temperature
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
messages: messages
|
||||
});
|
||||
}
|
||||
|
||||
window.scrollTo({ top: document.body.scrollHeight });
|
||||
|
||||
if (messages.length == 2) {
|
||||
await generateTitle(user_prompt);
|
||||
await generateTitle(chatId, user_prompt);
|
||||
}
|
||||
await db.put('chats', {
|
||||
id: chatId,
|
||||
title: title,
|
||||
model: selectedModel,
|
||||
system: system,
|
||||
options: {
|
||||
temperature: temperature
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
messages: messages
|
||||
});
|
||||
chats = await db.getAllFromIndex('chats', 'timestamp');
|
||||
}
|
||||
};
|
||||
|
@ -430,6 +479,7 @@
|
|||
responseMessage.context = data.context;
|
||||
messages = messages;
|
||||
hljs.highlightAll();
|
||||
createCopyCodeBlockButton();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -442,7 +492,7 @@
|
|||
window.scrollTo({ top: document.body.scrollHeight });
|
||||
await db.put('chats', {
|
||||
id: chatId,
|
||||
title: title,
|
||||
title: title === '' ? 'New Chat' : title,
|
||||
model: selectedModel,
|
||||
system: system,
|
||||
options: {
|
||||
|
@ -457,7 +507,7 @@
|
|||
console.log(messages);
|
||||
};
|
||||
|
||||
const generateTitle = async (user_prompt) => {
|
||||
const generateTitle = async (_chatId, user_prompt) => {
|
||||
console.log('generateTitle');
|
||||
|
||||
const res = await fetch(`${API_BASE_URL}/generate`, {
|
||||
|
@ -482,7 +532,11 @@
|
|||
|
||||
if (res) {
|
||||
console.log(res);
|
||||
title = res.response;
|
||||
const chat = await db.get('chats', _chatId);
|
||||
await db.put('chats', { ...chat, title: res.response === '' ? 'New Chat' : res.response });
|
||||
if (chat.id === chatId) {
|
||||
title = res.response;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -609,7 +663,9 @@
|
|||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="markdown-body whitespace-pre-line">
|
||||
<div
|
||||
class="prose max-w-full prose-invert prose-headings:my-0 prose-p:my-0 prose-pre:my-0 prose-table:my-0 prose-blockquote:my-0 prose-img:my-0 prose-ul:-my-2 prose-ol:-my-2 prose-li:-my-2 whitespace-pre-line"
|
||||
>
|
||||
{@html marked.parse(message.content)}
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -863,4 +919,33 @@
|
|||
clip-path: inset(0 -1ch 0 0);
|
||||
}
|
||||
}
|
||||
|
||||
pre[class*='language-'] {
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
|
||||
/* make space */
|
||||
margin: 5px 0;
|
||||
padding: 1.75rem 0 1.75rem 1rem;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
pre[class*='language-'] button {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
|
||||
font-size: 0.9rem;
|
||||
padding: 0.15rem;
|
||||
background-color: #828282;
|
||||
|
||||
border: ridge 1px #7b7b7c;
|
||||
border-radius: 5px;
|
||||
text-shadow: #c4c4c4 0 0 2px;
|
||||
}
|
||||
|
||||
pre[class*='language-'] button:hover {
|
||||
cursor: pointer;
|
||||
background-color: #bcbabb;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -17,8 +17,19 @@ export default {
|
|||
900: '#202123',
|
||||
950: '#050509'
|
||||
}
|
||||
},
|
||||
typography: {
|
||||
DEFAULT: {
|
||||
css: {
|
||||
pre: false,
|
||||
code: false,
|
||||
'pre code': false,
|
||||
'code::before': false,
|
||||
'code::after': false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: []
|
||||
plugins: [require('@tailwindcss/typography')]
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue