Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
chenpangpang
open-webui
Commits
b8d7fdf1
Unverified
Commit
b8d7fdf1
authored
May 08, 2024
by
Timothy Jaeryang Baek
Committed by
GitHub
May 08, 2024
Browse files
Merge pull request #1965 from open-webui/dev
0.1.124
parents
30b05311
b44ae536
Changes
106
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
456 additions
and
190 deletions
+456
-190
src/lib/apis/streaming/index.ts
src/lib/apis/streaming/index.ts
+11
-0
src/lib/components/ChangelogModal.svelte
src/lib/components/ChangelogModal.svelte
+2
-4
src/lib/components/admin/AddUserModal.svelte
src/lib/components/admin/AddUserModal.svelte
+1
-1
src/lib/components/chat/MessageInput/Documents.svelte
src/lib/components/chat/MessageInput/Documents.svelte
+1
-1
src/lib/components/chat/MessageInput/Suggestions.svelte
src/lib/components/chat/MessageInput/Suggestions.svelte
+5
-3
src/lib/components/chat/Messages/CitationsModal.svelte
src/lib/components/chat/Messages/CitationsModal.svelte
+77
-0
src/lib/components/chat/Messages/RateComment.svelte
src/lib/components/chat/Messages/RateComment.svelte
+1
-1
src/lib/components/chat/Messages/ResponseMessage.svelte
src/lib/components/chat/Messages/ResponseMessage.svelte
+200
-156
src/lib/components/chat/Messages/Skeleton.svelte
src/lib/components/chat/Messages/Skeleton.svelte
+1
-1
src/lib/components/chat/ModelSelector.svelte
src/lib/components/chat/ModelSelector.svelte
+1
-1
src/lib/components/chat/ModelSelector/Selector.svelte
src/lib/components/chat/ModelSelector/Selector.svelte
+4
-4
src/lib/components/chat/Settings/Account.svelte
src/lib/components/chat/Settings/Account.svelte
+2
-2
src/lib/components/chat/Settings/Audio.svelte
src/lib/components/chat/Settings/Audio.svelte
+37
-2
src/lib/components/chat/Settings/Connections.svelte
src/lib/components/chat/Settings/Connections.svelte
+1
-1
src/lib/components/chat/Settings/Models.svelte
src/lib/components/chat/Settings/Models.svelte
+2
-2
src/lib/components/chat/ShareChatModal.svelte
src/lib/components/chat/ShareChatModal.svelte
+10
-6
src/lib/components/chat/ShortcutsModal.svelte
src/lib/components/chat/ShortcutsModal.svelte
+52
-0
src/lib/components/chat/Tags.svelte
src/lib/components/chat/Tags.svelte
+21
-3
src/lib/components/common/ImagePreview.svelte
src/lib/components/common/ImagePreview.svelte
+26
-1
src/lib/components/common/Tags/TagInput.svelte
src/lib/components/common/Tags/TagInput.svelte
+1
-1
No files found.
src/lib/apis/streaming/index.ts
View file @
b8d7fdf1
...
@@ -4,6 +4,8 @@ import type { ParsedEvent } from 'eventsource-parser';
...
@@ -4,6 +4,8 @@ import type { ParsedEvent } from 'eventsource-parser';
type
TextStreamUpdate
=
{
type
TextStreamUpdate
=
{
done
:
boolean
;
done
:
boolean
;
value
:
string
;
value
:
string
;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
citations
?:
any
;
};
};
// createOpenAITextStream takes a responseBody with a SSE response,
// createOpenAITextStream takes a responseBody with a SSE response,
...
@@ -45,6 +47,11 @@ async function* openAIStreamToIterator(
...
@@ -45,6 +47,11 @@ async function* openAIStreamToIterator(
const
parsedData
=
JSON
.
parse
(
data
);
const
parsedData
=
JSON
.
parse
(
data
);
console
.
log
(
parsedData
);
console
.
log
(
parsedData
);
if
(
parsedData
.
citations
)
{
yield
{
done
:
false
,
value
:
''
,
citations
:
parsedData
.
citations
};
continue
;
}
yield
{
done
:
false
,
value
:
parsedData
.
choices
?.[
0
]?.
delta
?.
content
??
''
};
yield
{
done
:
false
,
value
:
parsedData
.
choices
?.[
0
]?.
delta
?.
content
??
''
};
}
catch
(
e
)
{
}
catch
(
e
)
{
console
.
error
(
'
Error extracting delta from SSE event:
'
,
e
);
console
.
error
(
'
Error extracting delta from SSE event:
'
,
e
);
...
@@ -62,6 +69,10 @@ async function* streamLargeDeltasAsRandomChunks(
...
@@ -62,6 +69,10 @@ async function* streamLargeDeltasAsRandomChunks(
yield
textStreamUpdate
;
yield
textStreamUpdate
;
return
;
return
;
}
}
if
(
textStreamUpdate
.
citations
)
{
yield
textStreamUpdate
;
continue
;
}
let
content
=
textStreamUpdate
.
value
;
let
content
=
textStreamUpdate
.
value
;
if
(
content
.
length
<
5
)
{
if
(
content
.
length
<
5
)
{
yield
{
done
:
false
,
value
:
content
};
yield
{
done
:
false
,
value
:
content
};
...
...
src/lib/components/ChangelogModal.svelte
View file @
b8d7fdf1
...
@@ -22,7 +22,7 @@
...
@@ -22,7 +22,7 @@
</script>
</script>
<Modal bind:show>
<Modal bind:show>
<div class="px-5 p
y
-4 dark:text-gray-300 text-gray-700">
<div class="px-5 p
t
-4 dark:text-gray-300 text-gray-700">
<div class="flex justify-between items-start">
<div class="flex justify-between items-start">
<div class="text-xl font-bold">
<div class="text-xl font-bold">
{$i18n.t('What’s New in')}
{$i18n.t('What’s New in')}
...
@@ -57,10 +57,8 @@
...
@@ -57,10 +57,8 @@
</div>
</div>
</div>
</div>
<hr class=" dark:border-gray-800" />
<div class=" w-full p-4 px-5 text-gray-700 dark:text-gray-100">
<div class=" w-full p-4 px-5 text-gray-700 dark:text-gray-100">
<div class=" overflow-y-scroll max-h-80">
<div class=" overflow-y-scroll max-h-80
scrollbar-none
">
<div class="mb-3">
<div class="mb-3">
{#if changelog}
{#if changelog}
{#each Object.keys(changelog) as version}
{#each Object.keys(changelog) as version}
...
...
src/lib/components/admin/AddUserModal.svelte
View file @
b8d7fdf1
...
@@ -107,7 +107,7 @@
...
@@ -107,7 +107,7 @@
reader.readAsText(file);
reader.readAsText(file);
} else {
} else {
toast.error(
`
File not found.
`
);
toast.error(
$i18n.t('
File not found.
')
);
}
}
}
}
};
};
...
...
src/lib/components/chat/MessageInput/Documents.svelte
View file @
b8d7fdf1
...
@@ -24,7 +24,7 @@
...
@@ -24,7 +24,7 @@
{
{
name: 'All Documents',
name: 'All Documents',
type: 'collection',
type: 'collection',
title: 'All Documents',
title:
$i18n.t(
'All Documents'
)
,
collection_names: $documents.map((doc) => doc.collection_name)
collection_names: $documents.map((doc) => doc.collection_name)
}
}
]
]
...
...
src/lib/components/chat/MessageInput/Suggestions.svelte
View file @
b8d7fdf1
<script lang="ts">
<script lang="ts">
import Bolt from '$lib/components/icons/Bolt.svelte';
import Bolt from '$lib/components/icons/Bolt.svelte';
import { onMount } from 'svelte';
import { onMount, getContext } from 'svelte';
const i18n = getContext('i18n');
export let submitPrompt: Function;
export let submitPrompt: Function;
export let suggestionPrompts = [];
export let suggestionPrompts = [];
...
@@ -33,7 +35,7 @@
...
@@ -33,7 +35,7 @@
{#if prompts.length > 0}
{#if prompts.length > 0}
<div class="mb-2 flex gap-1 text-sm font-medium items-center text-gray-400 dark:text-gray-600">
<div class="mb-2 flex gap-1 text-sm font-medium items-center text-gray-400 dark:text-gray-600">
<Bolt />
<Bolt />
Suggested
{$i18n.t('
Suggested
')}
</div>
</div>
{/if}
{/if}
...
@@ -71,7 +73,7 @@
...
@@ -71,7 +73,7 @@
<div
<div
class="text-xs text-gray-400 group-hover:text-gray-500 dark:text-gray-600 dark:group-hover:text-gray-500 transition self-center"
class="text-xs text-gray-400 group-hover:text-gray-500 dark:text-gray-600 dark:group-hover:text-gray-500 transition self-center"
>
>
Prompt
{$i18n.t('
Prompt
')}
</div>
</div>
<div
<div
...
...
src/lib/components/chat/Messages/CitationsModal.svelte
0 → 100644
View file @
b8d7fdf1
<script lang="ts">
import { getContext, onMount, tick } from 'svelte';
import Modal from '$lib/components/common/Modal.svelte';
const i18n = getContext('i18n');
export let show = false;
export let citation;
let mergedDocuments = [];
$: if (citation) {
mergedDocuments = citation.document?.map((c, i) => {
return {
source: citation.source,
document: c,
metadata: citation.metadata?.[i]
};
});
}
</script>
<Modal size="lg" bind:show>
<div>
<div class=" flex justify-between dark:text-gray-300 px-5 pt-4 pb-2">
<div class=" text-lg font-medium self-center capitalize">
{$i18n.t('Citation')}
</div>
<button
class="self-center"
on:click={() => {
show = false;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-5 h-5"
>
<path
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
/>
</svg>
</button>
</div>
<div class="flex flex-col md:flex-row w-full px-6 pb-5 md:space-x-4">
<div
class="flex flex-col w-full dark:text-gray-200 overflow-y-scroll max-h-[22rem] scrollbar-none"
>
{#each mergedDocuments as document, documentIdx}
<div class="flex flex-col w-full">
<div class="text-sm font-medium dark:text-gray-300">
{$i18n.t('Source')}
</div>
<div class="text-sm dark:text-gray-400">
{document.source?.name ?? $i18n.t('No source available')}
</div>
</div>
<div class="flex flex-col w-full">
<div class=" text-sm font-medium dark:text-gray-300">
{$i18n.t('Content')}
</div>
<pre class="text-sm dark:text-gray-400 whitespace-pre-line">
{document.document}
</pre>
</div>
{#if documentIdx !== mergedDocuments.length - 1}
<hr class=" dark:border-gray-850 my-3" />
{/if}
{/each}
</div>
</div>
</div>
</Modal>
src/lib/components/chat/Messages/RateComment.svelte
View file @
b8d7fdf1
...
@@ -123,7 +123,7 @@
...
@@ -123,7 +123,7 @@
submitHandler();
submitHandler();
}}
}}
>
>
Submit
{$i18n.t('
Submit
')}
</button>
</button>
</div>
</div>
</div>
</div>
src/lib/components/chat/Messages/ResponseMessage.svelte
View file @
b8d7fdf1
...
@@ -23,15 +23,16 @@
...
@@ -23,15 +23,16 @@
revertSanitizedResponseContent,
revertSanitizedResponseContent,
sanitizeResponseContent
sanitizeResponseContent
} from '$lib/utils';
} from '$lib/utils';
import { WEBUI_BASE_URL } from '$lib/constants';
import Name from './Name.svelte';
import Name from './Name.svelte';
import ProfileImage from './ProfileImage.svelte';
import ProfileImage from './ProfileImage.svelte';
import Skeleton from './Skeleton.svelte';
import Skeleton from './Skeleton.svelte';
import CodeBlock from './CodeBlock.svelte';
import CodeBlock from './CodeBlock.svelte';
import Image from '$lib/components/common/Image.svelte';
import Image from '$lib/components/common/Image.svelte';
import { WEBUI_BASE_URL } from '$lib/constants';
import Tooltip from '$lib/components/common/Tooltip.svelte';
import Tooltip from '$lib/components/common/Tooltip.svelte';
import RateComment from './RateComment.svelte';
import RateComment from './RateComment.svelte';
import CitationsModal from '$lib/components/chat/Messages/CitationsModal.svelte';
export let modelfiles = [];
export let modelfiles = [];
export let message;
export let message;
...
@@ -65,6 +66,9 @@
...
@@ -65,6 +66,9 @@
let showRateComment = false;
let showRateComment = false;
let showCitationModal = false;
let selectedCitation = null;
$: tokens = marked.lexer(sanitizeResponseContent(message.content));
$: tokens = marked.lexer(sanitizeResponseContent(message.content));
const renderer = new marked.Renderer();
const renderer = new marked.Renderer();
...
@@ -223,7 +227,8 @@
...
@@ -223,7 +227,8 @@
const res = await synthesizeOpenAISpeech(
const res = await synthesizeOpenAISpeech(
localStorage.token,
localStorage.token,
$settings?.audio?.speaker,
$settings?.audio?.speaker,
sentence
sentence,
$settings?.audio?.model
).catch((error) => {
).catch((error) => {
toast.error(error);
toast.error(error);
...
@@ -324,6 +329,8 @@
...
@@ -324,6 +329,8 @@
});
});
</script>
</script>
<CitationsModal bind:show={showCitationModal} citation={selectedCitation} />
{#key message.id}
{#key message.id}
<div class=" flex w-full message-{message.id}" id="message-{message.id}">
<div class=" flex w-full message-{message.id}" id="message-{message.id}">
<ProfileImage
<ProfileImage
...
@@ -346,9 +353,6 @@
...
@@ -346,9 +353,6 @@
{/if}
{/if}
</Name>
</Name>
{#if message.content === ''}
<Skeleton />
{:else}
{#if message.files}
{#if message.files}
<div class="my-2.5 w-full flex overflow-x-auto gap-2 flex-wrap">
<div class="my-2.5 w-full flex overflow-x-auto gap-2 flex-wrap">
{#each message.files as file}
{#each message.files as file}
...
@@ -423,6 +427,8 @@
...
@@ -423,6 +427,8 @@
{message.content}
{message.content}
</div>
</div>
</div>
</div>
{:else if message.content === ''}
<Skeleton />
{:else}
{:else}
{#each tokens as token}
{#each tokens as token}
{#if token.type === 'code'}
{#if token.type === 'code'}
...
@@ -439,10 +445,47 @@
...
@@ -439,10 +445,47 @@
})}
})}
{/if}
{/if}
{/each}
{/each}
<!-- {@html marked(message.content.replaceAll('\\', '\\\\'))} -->
{/if}
{/if}
{#if message.done}
{#if message.citations}
<div class="mt-1 mb-2 w-full flex gap-1 items-center">
{#each message.citations.reduce((acc, citation) => {
citation.document.forEach((document, index) => {
const metadata = citation.metadata?.[index];
const id = metadata?.source ?? 'N/A';
const existingSource = acc.find((item) => item.id === id);
if (existingSource) {
existingSource.document.push(document);
existingSource.metadata.push(metadata);
} else {
acc.push( { id: id, source: citation?.source, document: [document], metadata: metadata ? [metadata] : [] } );
}
});
return acc;
}, []) as citation, idx}
<div class="flex gap-1 text-xs font-semibold">
<button
class="flex dark:text-gray-300 py-1 px-1 bg-gray-50 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition rounded-xl"
on:click={() => {
showCitationModal = true;
selectedCitation = citation;
}}
>
<div class="bg-white dark:bg-gray-700 rounded-full size-4">
{idx + 1}
</div>
<div class=" mx-2">
{citation.source.name}
</div>
</button>
</div>
{/each}
</div>
{/if}
{#if message.done || siblings.length > 1}
<div
<div
class=" flex justify-start space-x-1 overflow-x-auto buttons text-gray-700 dark:text-gray-500"
class=" flex justify-start space-x-1 overflow-x-auto buttons text-gray-700 dark:text-gray-500"
>
>
...
@@ -494,6 +537,7 @@
...
@@ -494,6 +537,7 @@
</div>
</div>
{/if}
{/if}
{#if message.done}
{#if !readOnly}
{#if !readOnly}
<Tooltip content={$i18n.t('Edit')} placement="bottom">
<Tooltip content={$i18n.t('Edit')} placement="bottom">
<button
<button
...
@@ -854,6 +898,7 @@
...
@@ -854,6 +898,7 @@
</button>
</button>
</Tooltip>
</Tooltip>
{/if}
{/if}
{/if}
</div>
</div>
{/if}
{/if}
...
@@ -871,7 +916,6 @@
...
@@ -871,7 +916,6 @@
{/if}
{/if}
</div>
</div>
</div>
</div>
{/if}
</div>
</div>
</div>
</div>
{/key}
{/key}
...
...
src/lib/components/chat/Messages/Skeleton.svelte
View file @
b8d7fdf1
<div class="w-full mt-3">
<div class="w-full mt-3
mb-4
">
<div class="animate-pulse flex w-full">
<div class="animate-pulse flex w-full">
<div class="space-y-2 w-full">
<div class="space-y-2 w-full">
<div class="h-2 bg-gray-200 dark:bg-gray-600 rounded mr-14" />
<div class="h-2 bg-gray-200 dark:bg-gray-600 rounded mr-14" />
...
...
src/lib/components/chat/ModelSelector.svelte
View file @
b8d7fdf1
...
@@ -82,7 +82,7 @@
...
@@ -82,7 +82,7 @@
</div>
</div>
{:else}
{:else}
<div class=" self-center disabled:text-gray-600 disabled:hover:text-gray-600 mr-2">
<div class=" self-center disabled:text-gray-600 disabled:hover:text-gray-600 mr-2">
<Tooltip content=
"
Remove Model
"
>
<Tooltip content=
{$i18n.t('
Remove Model
')}
>
<button
<button
{disabled}
{disabled}
on:click={() => {
on:click={() => {
...
...
src/lib/components/chat/ModelSelector/Selector.svelte
View file @
b8d7fdf1
...
@@ -151,7 +151,7 @@
...
@@ -151,7 +151,7 @@
models.set(await getModels(localStorage.token));
models.set(await getModels(localStorage.token));
} else {
} else {
toast.error('Download canceled');
toast.error(
$i18n.t(
'Download canceled')
)
;
}
}
delete $MODEL_DOWNLOAD_POOL[sanitizedModelTag];
delete $MODEL_DOWNLOAD_POOL[sanitizedModelTag];
...
@@ -305,7 +305,7 @@
...
@@ -305,7 +305,7 @@
{:else}
{:else}
<div>
<div>
<div class="block px-3 py-2 text-sm text-gray-700 dark:text-gray-100">
<div class="block px-3 py-2 text-sm text-gray-700 dark:text-gray-100">
No results found
{$i18n.t('
No results found
')}
</div>
</div>
</div>
</div>
{/each}
{/each}
...
@@ -317,7 +317,7 @@
...
@@ -317,7 +317,7 @@
pullModelHandler();
pullModelHandler();
}}
}}
>
>
Pull "{searchValue}" from Ollama.com
{$i18n.t(`
Pull "{
{
searchValue}
}
" from Ollama.com
`, { searchValue: searchValue })}
</button>
</button>
{/if}
{/if}
...
@@ -368,7 +368,7 @@
...
@@ -368,7 +368,7 @@
</div>
</div>
<div class="mr-2 translate-y-0.5">
<div class="mr-2 translate-y-0.5">
<Tooltip content=
"
Cancel
"
>
<Tooltip content=
{$i18n.t('
Cancel
')}
>
<button
<button
class="text-gray-800 dark:text-gray-100"
class="text-gray-800 dark:text-gray-100"
on:click={() => {
on:click={() => {
...
...
src/lib/components/chat/Settings/Account.svelte
View file @
b8d7fdf1
...
@@ -447,7 +447,7 @@
...
@@ -447,7 +447,7 @@
{/if}
{/if}
</button>
</button>
<Tooltip content=
"
Create new key
"
>
<Tooltip content=
{$i18n.t('
Create new key
')}
>
<button
<button
class=" px-1.5 py-1 dark:hover:bg-gray-850transition rounded-lg"
class=" px-1.5 py-1 dark:hover:bg-gray-850transition rounded-lg"
on:click={() => {
on:click={() => {
...
@@ -479,7 +479,7 @@
...
@@ -479,7 +479,7 @@
>
>
<Plus strokeWidth="2" className=" size-3.5" />
<Plus strokeWidth="2" className=" size-3.5" />
Create new secret key</button
{$i18n.t('
Create new secret key
')}
</button
>
>
{/if}
{/if}
</div>
</div>
...
...
src/lib/components/chat/Settings/Audio.svelte
View file @
b8d7fdf1
...
@@ -26,6 +26,8 @@
...
@@ -26,6 +26,8 @@
let
voices
=
[];
let
voices
=
[];
let
speaker
=
''
;
let
speaker
=
''
;
let
models
=
[];
let
model
=
''
;
const
getOpenAIVoices
=
()
=>
{
const
getOpenAIVoices
=
()
=>
{
voices
=
[
voices
=
[
...
@@ -38,6 +40,10 @@
...
@@ -38,6 +40,10 @@
];
];
};
};
const
getOpenAIVoicesModel
=
()
=>
{
models
=
[{
name
:
'tts-1'
},
{
name
:
'tts-1-hd'
}];
};
const
getWebAPIVoices
=
()
=>
{
const
getWebAPIVoices
=
()
=>
{
const
getVoicesLoop
=
setInterval
(
async
()
=>
{
const
getVoicesLoop
=
setInterval
(
async
()
=>
{
voices
=
await
speechSynthesis
.
getVoices
();
voices
=
await
speechSynthesis
.
getVoices
();
...
@@ -78,12 +84,16 @@
...
@@ -78,12 +84,16 @@
if
(
TTSEngine
===
'openai'
)
{
if
(
TTSEngine
===
'openai'
)
{
const
res
=
await
updateAudioConfig
(
localStorage
.
token
,
{
const
res
=
await
updateAudioConfig
(
localStorage
.
token
,
{
url
:
OpenAIUrl
,
url
:
OpenAIUrl
,
key: OpenAIKey
key
:
OpenAIKey
,
model
:
model
,
speaker
:
speaker
});
});
if
(
res
)
{
if
(
res
)
{
OpenAIUrl
=
res
.
OPENAI_API_BASE_URL
;
OpenAIUrl
=
res
.
OPENAI_API_BASE_URL
;
OpenAIKey
=
res
.
OPENAI_API_KEY
;
OpenAIKey
=
res
.
OPENAI_API_KEY
;
model
=
res
.
OPENAI_API_MODEL
;
speaker
=
res
.
OPENAI_API_VOICE
;
}
}
}
}
};
};
...
@@ -98,9 +108,11 @@
...
@@ -98,9 +108,11 @@
STTEngine
=
settings
?.
audio
?.
STTEngine
??
''
;
STTEngine
=
settings
?.
audio
?.
STTEngine
??
''
;
TTSEngine
=
settings
?.
audio
?.
TTSEngine
??
''
;
TTSEngine
=
settings
?.
audio
?.
TTSEngine
??
''
;
speaker
=
settings
?.
audio
?.
speaker
??
''
;
speaker
=
settings
?.
audio
?.
speaker
??
''
;
model
=
settings
?.
audio
?.
model
??
''
;
if
(
TTSEngine
===
'openai'
)
{
if
(
TTSEngine
===
'openai'
)
{
getOpenAIVoices
();
getOpenAIVoices
();
getOpenAIVoicesModel
();
}
else
{
}
else
{
getWebAPIVoices
();
getWebAPIVoices
();
}
}
...
@@ -111,6 +123,8 @@
...
@@ -111,6 +123,8 @@
if
(
res
)
{
if
(
res
)
{
OpenAIUrl
=
res
.
OPENAI_API_BASE_URL
;
OpenAIUrl
=
res
.
OPENAI_API_BASE_URL
;
OpenAIKey
=
res
.
OPENAI_API_KEY
;
OpenAIKey
=
res
.
OPENAI_API_KEY
;
model
=
res
.
OPENAI_API_MODEL
;
speaker
=
res
.
OPENAI_API_VOICE
;
}
}
}
}
});
});
...
@@ -126,7 +140,8 @@
...
@@ -126,7 +140,8 @@
audio
:
{
audio
:
{
STTEngine
:
STTEngine
!== '' ? STTEngine : undefined,
STTEngine
:
STTEngine
!== '' ? STTEngine : undefined,
TTSEngine
:
TTSEngine
!== '' ? TTSEngine : undefined,
TTSEngine
:
TTSEngine
!== '' ? TTSEngine : undefined,
speaker: speaker !== '' ? speaker : undefined
speaker
:
speaker
!== '' ? speaker : undefined,
model
:
model
!== '' ? model : undefined
}
}
});
});
dispatch
(
'save'
);
dispatch
(
'save'
);
...
@@ -215,6 +230,7 @@
...
@@ -215,6 +230,7 @@
if
(
e
.
target
.
value
===
'openai'
)
{
if
(
e
.
target
.
value
===
'openai'
)
{
getOpenAIVoices
();
getOpenAIVoices
();
speaker
=
'alloy'
;
speaker
=
'alloy'
;
model
=
'tts-1'
;
}
else
{
}
else
{
getWebAPIVoices
();
getWebAPIVoices
();
speaker
=
''
;
speaker
=
''
;
...
@@ -307,6 +323,25 @@
...
@@ -307,6 +323,25 @@
</
div
>
</
div
>
</
div
>
</
div
>
</
div
>
</
div
>
<
div
>
<
div
class
=
" mb-2.5 text-sm font-medium"
>{$
i18n
.
t
(
'Set Model'
)}</
div
>
<
div
class
=
"flex w-full"
>
<
div
class
=
"flex-1"
>
<
input
list
=
"model-list"
class
=
"w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
bind
:
value
={
model
}
placeholder
=
"Select a model"
/>
<
datalist
id
=
"model-list"
>
{#
each
models
as
model
}
<
option
value
={
model
.
name
}
/>
{/
each
}
</
datalist
>
</
div
>
</
div
>
</
div
>
{/
if
}
{/
if
}
</
div
>
</
div
>
...
...
src/lib/components/chat/Settings/Connections.svelte
View file @
b8d7fdf1
...
@@ -164,7 +164,7 @@
...
@@ -164,7 +164,7 @@
<div class="flex gap-1.5">
<div class="flex gap-1.5">
<input
<input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
placeholder=
"
Enter URL (e.g. http://localhost:11434)
"
placeholder=
{$i18n.t('
Enter URL (e.g. http://localhost:11434)
')}
bind:value={url}
bind:value={url}
/>
/>
...
...
src/lib/components/chat/Settings/Models.svelte
View file @
b8d7fdf1
...
@@ -245,7 +245,7 @@
...
@@ -245,7 +245,7 @@
models.set(await getModels(localStorage.token));
models.set(await getModels(localStorage.token));
} else {
} else {
toast.error('Download canceled');
toast.error(
$i18n.t(
'Download canceled')
)
;
}
}
delete $MODEL_DOWNLOAD_POOL[sanitizedModelTag];
delete $MODEL_DOWNLOAD_POOL[sanitizedModelTag];
...
@@ -652,7 +652,7 @@
...
@@ -652,7 +652,7 @@
</div>
</div>
</div>
</div>
<Tooltip content=
"
Cancel
"
>
<Tooltip content=
{$i18n.t('
Cancel
')}
>
<button
<button
class="text-gray-800 dark:text-gray-100"
class="text-gray-800 dark:text-gray-100"
on:click={() => {
on:click={() => {
...
...
src/lib/components/chat/ShareChatModal.svelte
View file @
b8d7fdf1
...
@@ -97,9 +97,10 @@
...
@@ -97,9 +97,10 @@
<div class=" text-sm dark:text-gray-300 mb-1">
<div class=" text-sm dark:text-gray-300 mb-1">
{#if chat.share_id}
{#if chat.share_id}
<a href="/s/{chat.share_id}" target="_blank"
<a href="/s/{chat.share_id}" target="_blank"
>You have shared this chat <span class=" underline">before</span>.</a
>{$i18n.t('You have shared this chat')}
<span class=" underline">{$i18n.t('before')}</span>.</a
>
>
Click here to
{$i18n.t('
Click here to
')}
<button
<button
class="underline"
class="underline"
on:click={async () => {
on:click={async () => {
...
@@ -108,11 +109,14 @@
...
@@ -108,11 +109,14 @@
if (res) {
if (res) {
chat = await getChatById(localStorage.token, chatId);
chat = await getChatById(localStorage.token, chatId);
}
}
}}>delete this link</button
}}
> and create a new shared link.
>{$i18n.t('delete this link')}
</button>
{$i18n.t('and create a new shared link.')}
{:else}
{:else}
Messages you send after creating your link won't be shared. Users with the URL will be
{$i18n.t(
able to view the shared chat.
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat."
)}
{/if}
{/if}
</div>
</div>
...
...
src/lib/components/chat/ShortcutsModal.svelte
View file @
b8d7fdf1
...
@@ -209,6 +209,58 @@
...
@@ -209,6 +209,58 @@
</div>
</div>
</div>
</div>
</div>
</div>
<div class=" flex justify-between dark:text-gray-300 px-5">
<div class=" text-lg font-medium self-center">{$i18n.t('Input commands')}</div>
</div>
<div class="flex flex-col md:flex-row w-full p-5 md:space-x-4 dark:text-gray-200">
<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6">
<div class="flex flex-col space-y-3 w-full self-start">
<div class="w-full flex justify-between items-center">
<div class=" text-sm">
{$i18n.t('Attach file')}
</div>
<div class="flex space-x-1 text-xs">
<div
class=" h-fit py-1 px-2 flex items-center justify-center rounded border border-black/10 capitalize text-gray-600 dark:border-white/10 dark:text-gray-300"
>
#
</div>
</div>
</div>
<div class="w-full flex justify-between items-center">
<div class=" text-sm">
{$i18n.t('Add custom prompt')}
</div>
<div class="flex space-x-1 text-xs">
<div
class=" h-fit py-1 px-2 flex items-center justify-center rounded border border-black/10 capitalize text-gray-600 dark:border-white/10 dark:text-gray-300"
>
/
</div>
</div>
</div>
<div class="w-full flex justify-between items-center">
<div class=" text-sm">
{$i18n.t('Select model')}
</div>
<div class="flex space-x-1 text-xs">
<div
class=" h-fit py-1 px-2 flex items-center justify-center rounded border border-black/10 capitalize text-gray-600 dark:border-white/10 dark:text-gray-300"
>
@
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</Modal>
</Modal>
...
...
src/lib/components/chat/Tags.svelte
View file @
b8d7fdf1
...
@@ -3,11 +3,15 @@
...
@@ -3,11 +3,15 @@
addTagById,
addTagById,
deleteTagById,
deleteTagById,
getAllChatTags,
getAllChatTags,
getChatList,
getChatListByTagName,
getTagsById,
getTagsById,
updateChatById
updateChatById
} from '$lib/apis/chats';
} from '$lib/apis/chats';
import { tags as _tags } from '$lib/stores';
import { tags as _tags, chats } from '$lib/stores';
import { onMount } from 'svelte';
import { createEventDispatcher, onMount } from 'svelte';
const dispatch = createEventDispatcher();
import Tags from '../common/Tags.svelte';
import Tags from '../common/Tags.svelte';
...
@@ -39,7 +43,21 @@
...
@@ -39,7 +43,21 @@
tags: tags
tags: tags
});
});
_tags.set(await getAllChatTags(localStorage.token));
console.log($_tags);
await _tags.set(await getAllChatTags(localStorage.token));
console.log($_tags);
if ($_tags.map((t) => t.name).includes(tagName)) {
await chats.set(await getChatListByTagName(localStorage.token, tagName));
if ($chats.find((chat) => chat.id === chatId)) {
dispatch('close');
}
} else {
await chats.set(await getChatList(localStorage.token));
}
};
};
onMount(async () => {
onMount(async () => {
...
...
src/lib/components/common/ImagePreview.svelte
View file @
b8d7fdf1
<script lang="ts">
<script lang="ts">
import { onMount } from 'svelte';
export let show = false;
export let show = false;
export let src = '';
export let src = '';
export let alt = '';
export let alt = '';
let mounted = false;
const downloadImage = (url, filename) => {
const downloadImage = (url, filename) => {
fetch(url)
fetch(url)
.then((response) => response.blob())
.then((response) => response.blob())
...
@@ -18,6 +22,27 @@
...
@@ -18,6 +22,27 @@
})
})
.catch((error) => console.error('Error downloading image:', error));
.catch((error) => console.error('Error downloading image:', error));
};
};
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
console.log('Escape');
show = false;
}
};
onMount(() => {
mounted = true;
});
$: if (mounted) {
if (show) {
window.addEventListener('keydown', handleKeyDown);
document.body.style.overflow = 'hidden';
} else {
window.removeEventListener('keydown', handleKeyDown);
document.body.style.overflow = 'unset';
}
}
</script>
</script>
{#if show}
{#if show}
...
@@ -51,7 +76,7 @@
...
@@ -51,7 +76,7 @@
<button
<button
class=" p-5"
class=" p-5"
on:click={() => {
on:click={() => {
downloadImage(src,
'Image.png'
);
downloadImage(src,
src.substring(src.lastIndexOf('/') + 1)
);
}}
}}
>
>
<svg
<svg
...
...
src/lib/components/common/Tags/TagInput.svelte
View file @
b8d7fdf1
...
@@ -17,7 +17,7 @@
...
@@ -17,7 +17,7 @@
tagName = '';
tagName = '';
showTagInput = false;
showTagInput = false;
} else {
} else {
toast.error(
'
Invalid Tag
'
);
toast.error(
$i18n.t(`
Invalid Tag
`)
);
}
}
};
};
</script>
</script>
...
...
Prev
1
2
3
4
5
6
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment