Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d2ebb30bb | ||
|
|
53d639a9f6 | ||
|
|
47951851c5 | ||
|
|
f1b5f8cf3c | ||
|
|
e6a8868f6c | ||
|
|
e023a13bbc | ||
|
|
69dacca6c5 | ||
|
|
76b865646c |
9
app.vue
9
app.vue
@@ -1,12 +1,3 @@
|
|||||||
<script setup>
|
|
||||||
onNuxtReady(() => {
|
|
||||||
fetchSystemSettings()
|
|
||||||
// api key
|
|
||||||
const apiKey = useApiKey()
|
|
||||||
apiKey.value = getStoredApiKey()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
<NuxtLoadingIndicator />
|
<NuxtLoadingIndicator />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {EventStreamContentType, fetchEventSource} from '@microsoft/fetch-event-source'
|
import {EventStreamContentType, fetchEventSource} from '@microsoft/fetch-event-source'
|
||||||
|
|
||||||
const { $i18n } = useNuxtApp()
|
const { $i18n, $settings } = useNuxtApp()
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const currentModel = useCurrentModel()
|
const currentModel = useCurrentModel()
|
||||||
const openaiApiKey = useApiKey()
|
const openaiApiKey = useApiKey()
|
||||||
@@ -63,7 +63,7 @@ const fetchReply = async (message) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const data = Object.assign({}, currentModel.value, {
|
const data = Object.assign({}, currentModel.value, {
|
||||||
openaiApiKey: enableCustomApiKey.value ? openaiApiKey.value : null,
|
openaiApiKey: $settings.open_api_key_setting === 'True' ? openaiApiKey.value : null,
|
||||||
message: message,
|
message: message,
|
||||||
conversationId: props.conversation.id,
|
conversationId: props.conversation.id,
|
||||||
frugalMode: frugalMode.value
|
frugalMode: frugalMode.value
|
||||||
@@ -169,17 +169,8 @@ const deleteMessage = (index) => {
|
|||||||
props.conversation.messages.splice(index, 1)
|
props.conversation.messages.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const settings = useSettings()
|
|
||||||
const enableWebSearch = ref(false)
|
const enableWebSearch = ref(false)
|
||||||
|
|
||||||
const showWebSearchToggle = computed(() => {
|
|
||||||
return settings.value && settings.value.open_web_search && settings.value.open_web_search === 'True'
|
|
||||||
})
|
|
||||||
|
|
||||||
const enableCustomApiKey = computed(() => {
|
|
||||||
return settings.value && settings.value.open_api_key_setting && settings.value.open_api_key_setting === 'True'
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
onNuxtReady(() => {
|
onNuxtReady(() => {
|
||||||
currentModel.value = getCurrentModel()
|
currentModel.value = getCurrentModel()
|
||||||
@@ -260,7 +251,7 @@ onNuxtReady(() => {
|
|||||||
>
|
>
|
||||||
<Prompt v-show="!fetchingResponse" :use-prompt="usePrompt" />
|
<Prompt v-show="!fetchingResponse" :use-prompt="usePrompt" />
|
||||||
<v-switch
|
<v-switch
|
||||||
v-if="showWebSearchToggle"
|
v-if="$settings.open_web_search === 'True'"
|
||||||
v-model="enableWebSearch"
|
v-model="enableWebSearch"
|
||||||
inline
|
inline
|
||||||
hide-details
|
hide-details
|
||||||
@@ -268,36 +259,43 @@ onNuxtReady(() => {
|
|||||||
:label="$t('webSearch')"
|
:label="$t('webSearch')"
|
||||||
></v-switch>
|
></v-switch>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-switch
|
<div
|
||||||
v-model="frugalMode"
|
v-if="$settings.open_frugal_mode_control === 'True'"
|
||||||
inline
|
class="d-flex align-center"
|
||||||
hide-details
|
|
||||||
color="primary"
|
|
||||||
:label="$t('frugalMode')"
|
|
||||||
></v-switch>
|
|
||||||
<v-dialog
|
|
||||||
transition="dialog-bottom-transition"
|
|
||||||
width="auto"
|
|
||||||
>
|
>
|
||||||
<template v-slot:activator="{ props }">
|
<v-switch
|
||||||
<v-icon
|
v-model="frugalMode"
|
||||||
color="grey"
|
inline
|
||||||
v-bind="props"
|
hide-details
|
||||||
icon="help_outline"
|
color="primary"
|
||||||
></v-icon>
|
:label="$t('frugalMode')"
|
||||||
</template>
|
></v-switch>
|
||||||
<template v-slot:default="{ isActive }">
|
<v-dialog
|
||||||
<v-card>
|
transition="dialog-bottom-transition"
|
||||||
<v-toolbar
|
width="auto"
|
||||||
color="primary"
|
>
|
||||||
:title="$t('frugalMode')"
|
<template v-slot:activator="{ props }">
|
||||||
></v-toolbar>
|
<v-icon
|
||||||
<v-card-text>
|
color="grey"
|
||||||
{{ $t('frugalModeTip') }}
|
v-bind="props"
|
||||||
</v-card-text>
|
icon="help_outline"
|
||||||
</v-card>
|
class="ml-3"
|
||||||
</template>
|
></v-icon>
|
||||||
</v-dialog>
|
</template>
|
||||||
|
<template v-slot:default="{ isActive }">
|
||||||
|
<v-card>
|
||||||
|
<v-toolbar
|
||||||
|
color="primary"
|
||||||
|
:title="$t('frugalMode')"
|
||||||
|
></v-toolbar>
|
||||||
|
<v-card-text>
|
||||||
|
{{ $t('frugalModeTip') }}
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</template>
|
||||||
|
</v-dialog>
|
||||||
|
</div>
|
||||||
|
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
</div>
|
</div>
|
||||||
</v-footer>
|
</v-footer>
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
import hljs from "highlight.js"
|
import hljs from "highlight.js"
|
||||||
import MarkdownIt from 'markdown-it'
|
import MarkdownIt from 'markdown-it'
|
||||||
import copy from 'copy-to-clipboard'
|
import copy from 'copy-to-clipboard'
|
||||||
|
import mathjax3 from 'markdown-it-mathjax3'
|
||||||
|
import mk from 'markdown-it-katex'
|
||||||
|
|
||||||
|
|
||||||
const md = new MarkdownIt({
|
const md = new MarkdownIt({
|
||||||
@@ -11,6 +13,8 @@ const md = new MarkdownIt({
|
|||||||
return `<pre class="hljs-code-container my-3"><div class="hljs-code-header d-flex align-center justify-space-between bg-grey-darken-3 pa-1"><span class="pl-2 text-caption">${language}</span><button class="hljs-copy-button" data-copied="false">Copy</button></div><code class="hljs language-${language}">${hljs.highlight(code, { language: language, ignoreIllegals: true }).value}</code></pre>`
|
return `<pre class="hljs-code-container my-3"><div class="hljs-code-header d-flex align-center justify-space-between bg-grey-darken-3 pa-1"><span class="pl-2 text-caption">${language}</span><button class="hljs-copy-button" data-copied="false">Copy</button></div><code class="hljs language-${language}">${hljs.highlight(code, { language: language, ignoreIllegals: true }).value}</code></pre>`
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
md.use(mathjax3)
|
||||||
|
// md.use(mk)
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
message: {
|
message: {
|
||||||
@@ -71,6 +75,23 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.chat-msg-content {
|
||||||
|
font-size: 0.875rem !important;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.25rem;
|
||||||
|
}
|
||||||
|
.chat-msg-content p,
|
||||||
|
.chat-msg-content table,
|
||||||
|
.chat-msg-content ul,
|
||||||
|
.chat-msg-content ol,
|
||||||
|
.chat-msg-content h1,
|
||||||
|
.chat-msg-content h2,
|
||||||
|
.chat-msg-content h3,
|
||||||
|
.chat-msg-content h4,
|
||||||
|
.chat-msg-content h5,
|
||||||
|
.chat-msg-content h6 {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
.chat-msg-content ol, .chat-msg-content ul {
|
.chat-msg-content ol, .chat-msg-content ul {
|
||||||
padding-left: 2em;
|
padding-left: 2em;
|
||||||
}
|
}
|
||||||
@@ -89,4 +110,10 @@ onMounted(() => {
|
|||||||
.hljs-copy-button:active{border-color:#ffffff66}
|
.hljs-copy-button:active{border-color:#ffffff66}
|
||||||
.hljs-copy-button[data-copied="true"]{text-indent:0;width:auto;background-image:none}
|
.hljs-copy-button[data-copied="true"]{text-indent:0;width:auto;background-image:none}
|
||||||
@media(prefers-reduced-motion){.hljs-copy-button{transition:none}}
|
@media(prefers-reduced-motion){.hljs-copy-button{transition:none}}
|
||||||
|
|
||||||
|
/*MathJax*/
|
||||||
|
.MathJax svg {
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -48,8 +48,11 @@ const send = () => {
|
|||||||
message.value = ""
|
message.value = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const textArea = ref()
|
||||||
|
|
||||||
const usePrompt = (prompt) => {
|
const usePrompt = (prompt) => {
|
||||||
message.value = prompt
|
message.value = prompt
|
||||||
|
textArea.value.focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
const clickSendBtn = () => {
|
const clickSendBtn = () => {
|
||||||
@@ -73,6 +76,7 @@ defineExpose({
|
|||||||
class="flex-grow-1 d-flex align-center justify-space-between"
|
class="flex-grow-1 d-flex align-center justify-space-between"
|
||||||
>
|
>
|
||||||
<v-textarea
|
<v-textarea
|
||||||
|
ref="textArea"
|
||||||
v-model="message"
|
v-model="message"
|
||||||
:label="$t('writeAMessage')"
|
:label="$t('writeAMessage')"
|
||||||
:placeholder="hint"
|
:placeholder="hint"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useDisplay } from 'vuetify'
|
|||||||
import {useDrawer} from "../composables/states";
|
import {useDrawer} from "../composables/states";
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const { $i18n } = useNuxtApp()
|
const { $i18n, $settings } = useNuxtApp()
|
||||||
const colorMode = useColorMode()
|
const colorMode = useColorMode()
|
||||||
const {mdAndUp} = useDisplay()
|
const {mdAndUp} = useDisplay()
|
||||||
const drawerPermanent = computed(() => {
|
const drawerPermanent = computed(() => {
|
||||||
@@ -88,11 +88,6 @@ const loadConversations = async () => {
|
|||||||
loadingConversations.value = false
|
loadingConversations.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const settings = useSettings()
|
|
||||||
const showApiKeySetting = computed(() => {
|
|
||||||
return settings.value && settings.value.open_api_key_setting && settings.value.open_api_key_setting === 'True'
|
|
||||||
})
|
|
||||||
|
|
||||||
const signOut = async () => {
|
const signOut = async () => {
|
||||||
const { data, error } = await useFetch('/api/account/logout/', {
|
const { data, error } = await useFetch('/api/account/logout/', {
|
||||||
method: 'POST'
|
method: 'POST'
|
||||||
@@ -277,7 +272,7 @@ const drawer = useDrawer()
|
|||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<ApiKeyDialog
|
<ApiKeyDialog
|
||||||
v-if="showApiKeySetting"
|
v-if="$settings.open_api_key_setting === 'True'"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ModelParameters/>
|
<ModelParameters/>
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ export const useApiKey = () => useState('apiKey', () => getStoredApiKey())
|
|||||||
|
|
||||||
export const useConversations = () => useState('conversations', () => [])
|
export const useConversations = () => useState('conversations', () => [])
|
||||||
|
|
||||||
export const useSettings = () => useState('settings', () => {})
|
|
||||||
|
|
||||||
export const useUser = () => useState('user', () => null)
|
export const useUser = () => useState('user', () => null)
|
||||||
|
|
||||||
export const useDrawer = () => useState('drawer', () => false)
|
export const useDrawer = () => useState('drawer', () => false)
|
||||||
@@ -20,6 +20,7 @@ services:
|
|||||||
platform: linux/x86_64
|
platform: linux/x86_64
|
||||||
image: wongsaang/chatgpt-ui-wsgi-server:latest
|
image: wongsaang/chatgpt-ui-wsgi-server:latest
|
||||||
environment:
|
environment:
|
||||||
|
- DEBUG=${DEBUG:-False} # Whether to enable debug mode, default False
|
||||||
- APP_DOMAIN=${APP_DOMAIN:-localhost:9000}
|
- APP_DOMAIN=${APP_DOMAIN:-localhost:9000}
|
||||||
- SERVER_WORKERS=3 # The number of worker processes for handling requests.
|
- SERVER_WORKERS=3 # The number of worker processes for handling requests.
|
||||||
- WORKER_TIMEOUT=180 # Workers silent for more than this many seconds are killed and restarted. default 180s
|
- WORKER_TIMEOUT=180 # Workers silent for more than this many seconds are killed and restarted. default 180s
|
||||||
|
|||||||
@@ -78,3 +78,7 @@ After deployment, there is an `open_registration` setting under `Chat->Settings`
|
|||||||
## Web Search Function Control
|
## Web Search Function Control
|
||||||
|
|
||||||
This feature is disabled by default. You can enable it in the admin panel under `Chat->Settings`. There is a setting called `open_web_search`, set its value to `True`.
|
This feature is disabled by default. You can enable it in the admin panel under `Chat->Settings`. There is a setting called `open_web_search`, set its value to `True`.
|
||||||
|
|
||||||
|
## Frugal Mode Control
|
||||||
|
|
||||||
|
This feature is enabled by default. You can disable it in the `Chat->Settings` section of the management backend. There is a setting called `open_frugal_mode_control` in Settings. Set its value to `False`.
|
||||||
@@ -79,3 +79,7 @@ backend-wsgi-server:
|
|||||||
## 网页搜索功能控制
|
## 网页搜索功能控制
|
||||||
|
|
||||||
该功能默认处于关闭状态,你可以在管理后台的 `Chat->Settings` 中开启它,在 Settings 中有一个 `open_web_search` 的设置项,把它的值设置为 `True`。
|
该功能默认处于关闭状态,你可以在管理后台的 `Chat->Settings` 中开启它,在 Settings 中有一个 `open_web_search` 的设置项,把它的值设置为 `True`。
|
||||||
|
|
||||||
|
## 节俭模式控制
|
||||||
|
|
||||||
|
该功能默认处于开启状态,你可以在管理后台的 `Chat->Settings` 中关闭它,在 Settings 中有一个 `open_frugal_mode_control` 的设置项,把它的值设置为 `False`。
|
||||||
96
lang/fr-FR.json
Normal file
96
lang/fr-FR.json
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
{
|
||||||
|
"signIn":"Se connecter",
|
||||||
|
"signUp":"S'inscrire",
|
||||||
|
"username":"Nom d'utilisateur",
|
||||||
|
"password":"Mot de passe",
|
||||||
|
"Username is required":"Nom d'utilisateur requis",
|
||||||
|
"Password is required":"Mot de passe requis",
|
||||||
|
"Create your account":"Créer votre compte",
|
||||||
|
"createAccount":"Créer un compte",
|
||||||
|
"email":"E-mail",
|
||||||
|
"Sign in instead":"S'identifier à la place",
|
||||||
|
"Please enter your username":"Veuillez saisir votre nom d'utilisateur",
|
||||||
|
"Username must be at least 4 characters":"Le nom d'utilisateur doit comporter au moins 4 caractères",
|
||||||
|
"Please enter your e-mail address":"Veuillez saisir votre adresse e-mail",
|
||||||
|
"E-mail address must be valid":"L'adresse e-mail doit être valide",
|
||||||
|
"Please enter your password":"Veuillez saisir votre mot de passe",
|
||||||
|
"Password must be at least 8 characters":"Le mot de passe doit comporter au moins 8 caractères",
|
||||||
|
"Please confirm your password":"Veuillez confirmer votre mot de passe",
|
||||||
|
"welcomeTo": "Bienvenue à",
|
||||||
|
"language": "Langue",
|
||||||
|
"setApiKey": "Définir la clé API",
|
||||||
|
"setOpenAIApiKey": "Définir la clé API OpenAI",
|
||||||
|
"openAIApiKey": "Clé API OpenAI",
|
||||||
|
"getAKey": "Obtenir une clé",
|
||||||
|
"openAIModels": "Modèles OpenAI",
|
||||||
|
"aboutTheModels": "À propos des modèles",
|
||||||
|
"saveAndClose": "Enregistrer et fermer",
|
||||||
|
"pleaseSelectAtLeastOneModelDot": "Veuillez sélectionner au moins un modèle.",
|
||||||
|
"writeAMessage": "Écrire un message",
|
||||||
|
"frequentlyPrompts": "Prompts fréquents",
|
||||||
|
"addPrompt": "Ajouter un prompt",
|
||||||
|
"titlePrompt": "Titre",
|
||||||
|
"addNewPrompt": "Ajouter un nouveau prompt",
|
||||||
|
"pressEnterToSendYourMessageOrShiftEnterToAddANewLine": "Appuyez sur Entrée pour envoyer votre message ou sur Maj+Entrée pour ajouter une nouvelle ligne",
|
||||||
|
"lightMode": "Mode clair",
|
||||||
|
"darkMode": "Mode sombre",
|
||||||
|
"followSystem": "Suivre le système",
|
||||||
|
"themeMode": "Mode thème",
|
||||||
|
"feedback": "Commentaires",
|
||||||
|
"newConversation": "Nouvelle conversation",
|
||||||
|
"defaultConversationTitle": "Sans titre",
|
||||||
|
"clearConversations": "Effacer les conversations",
|
||||||
|
"modelParameters": "Paramètres du modèle",
|
||||||
|
"model": "Modèle",
|
||||||
|
"temperature": "Température",
|
||||||
|
"topP": "Top P",
|
||||||
|
"frequencyPenalty": "Pénalité de fréquence",
|
||||||
|
"presencePenalty": "Pénalité de présence",
|
||||||
|
"maxTokens": "Nombre maximal de jetons",
|
||||||
|
"roles": {
|
||||||
|
"me": "Moi",
|
||||||
|
"ai": "IA"
|
||||||
|
},
|
||||||
|
"edit": "Modifier",
|
||||||
|
"copy": "Copier",
|
||||||
|
"copied": "Copié",
|
||||||
|
"delete": "Supprimer",
|
||||||
|
"signOut": "Déconnexion",
|
||||||
|
"resetPassword": "Réinitialiser le mot de passe",
|
||||||
|
"submit": "Soumettre",
|
||||||
|
"agree": "Accepter",
|
||||||
|
"newPassword": "Nouveau mot de passe",
|
||||||
|
"currentPassword": "Mot de passe actuel",
|
||||||
|
"confirmPassword": "Confirmer le mot de passe",
|
||||||
|
"yourPasswordHasBeenReset": "Votre mot de passe a été réinitialisé",
|
||||||
|
"nowYouNeedToSignInAgain": "Vous devez maintenant vous reconnecter",
|
||||||
|
"webSearch": "Recherche Web",
|
||||||
|
"webSearchDefaultPrompt": "Résultats de la recherche Web : \n\n[résultats_web]\nDate actuelle : [date_actuelle]\n\nInstructions : Utilisez les résultats de la recherche Web fournis pour rédiger une réponse complète à la question donnée. Assurez-vous de citer les résultats en utilisant la notation [nombre] après la référence. Si les résultats de recherche fournis font référence à plusieurs sujets avec le même nom, rédigez des réponses distinctes pour chaque sujet. \nQuestion : [question]",
|
||||||
|
"genTitlePrompt": "Générer un titre court pour le contenu suivant, pas plus de 10 mots. \n\nContenu : ",
|
||||||
|
"maxTokenTips1": "La longueur maximale du contexte pour le modèle actuel est de",
|
||||||
|
"maxTokenTips2": "jeton, ce qui inclut la longueur du prompt et la longueur du texte généré. Le paramètre Max Tokens ici fait référence à la longueur du texte généré. Vous devriez donc laisser de l'espace pour votre prompt et ne pas le régler trop grand ou à la limite maximale.",
|
||||||
|
"frugalMode": "Mode éco",
|
||||||
|
"frugalModeTip": "Activez le mode frugal, le client n'enverra pas les messages historiques à ChatGPT, ce qui peut économiser la consommation de jetons. Si vous souhaitez que ChatGPT comprenne le contexte de la conversation, veuillez désactiver le mode frugal.",
|
||||||
|
"welcomeScreen": {
|
||||||
|
"introduction1": "est un client non officiel pour ChatGPT, mais utilise l'API officielle d'OpenAI.",
|
||||||
|
"introduction2": "Vous aurez besoin d'une clé API OpenAI avant de pouvoir utiliser ce client.",
|
||||||
|
"examples": {
|
||||||
|
"title": "Exemples",
|
||||||
|
"item1": "\"Expliquez l'informatique quantique en termes simples\"",
|
||||||
|
"item2": "\"Avez-vous des idées créatives pour l'anniversaire d'un enfant de 10 ans?\"",
|
||||||
|
"item3": "\"Comment faire une requête HTTP en JavaScript?\""
|
||||||
|
},
|
||||||
|
"capabilities": {
|
||||||
|
"title": "Fonctionnalités",
|
||||||
|
"item1": "Se souvient de ce que l'utilisateur a dit précédemment dans la conversation",
|
||||||
|
"item2": "Permet à l'utilisateur de fournir des corrections de suivi",
|
||||||
|
"item3": "Entraîné à refuser les demandes inappropriées"
|
||||||
|
},
|
||||||
|
"limitations": {
|
||||||
|
"title": "Limitations",
|
||||||
|
"item1": "Peut occasionnellement générer des informations incorrectes",
|
||||||
|
"item2": "Peut occasionnellement produire des instructions dangereuses ou du contenu biaisé",
|
||||||
|
"item3": "Connaissance limitée du monde et des événements après 2021"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"to your account.":"你的账号了。",
|
"to your account.":"你的账号了。",
|
||||||
"welcomeTo": "欢迎来到",
|
"welcomeTo": "欢迎来到",
|
||||||
"language": "语言",
|
"language": "语言",
|
||||||
"setApiKey": "设置API密钥",
|
"setApiKey": "API 密钥",
|
||||||
"setOpenAIApiKey": "设置OpenAI的API密钥",
|
"setOpenAIApiKey": "设置OpenAI的API密钥",
|
||||||
"openAIApiKey": "OpenAI的API密钥",
|
"openAIApiKey": "OpenAI的API密钥",
|
||||||
"getAKey": "获取钥匙",
|
"getAKey": "获取钥匙",
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ export default defineNuxtConfig({
|
|||||||
iso: 'ru-RU',
|
iso: 'ru-RU',
|
||||||
name: 'Русский',
|
name: 'Русский',
|
||||||
file: 'ru-RU.json',
|
file: 'ru-RU.json',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'fr',
|
||||||
|
iso: 'fr-FR',
|
||||||
|
name: 'Français',
|
||||||
|
file: 'fr-FR.json',
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
lazy: true,
|
lazy: true,
|
||||||
|
|||||||
@@ -11,10 +11,11 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@kevinmarrec/nuxt-pwa": "^0.17.0",
|
"@kevinmarrec/nuxt-pwa": "^0.17.0",
|
||||||
|
"@nuxt/devtools": "^0.4.0",
|
||||||
"@nuxtjs/color-mode": "^3.2.0",
|
"@nuxtjs/color-mode": "^3.2.0",
|
||||||
"@nuxtjs/i18n": "^8.0.0-beta.9",
|
"@nuxtjs/i18n": "^8.0.0-beta.9",
|
||||||
"material-design-icons-iconfont": "^6.7.0",
|
"material-design-icons-iconfont": "^6.7.0",
|
||||||
"nuxt": "^3.3.3",
|
"nuxt": "^3.4.0",
|
||||||
"vuepress": "^2.0.0-beta.61"
|
"vuepress": "^2.0.0-beta.61"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
"http-proxy-middleware": "3.0.0-beta.1",
|
"http-proxy-middleware": "3.0.0-beta.1",
|
||||||
"is-mobile": "^3.1.1",
|
"is-mobile": "^3.1.1",
|
||||||
"markdown-it": "^13.0.1",
|
"markdown-it": "^13.0.1",
|
||||||
|
"markdown-it-mathjax3": "^4.3.2",
|
||||||
"nanoid": "^4.0.1",
|
"nanoid": "^4.0.1",
|
||||||
"vuetify": "^3.0.6"
|
"vuetify": "^3.0.6"
|
||||||
},
|
},
|
||||||
|
|||||||
6
plugins/initApiKey.js
Normal file
6
plugins/initApiKey.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default defineNuxtPlugin((nuxtApp) => {
|
||||||
|
nuxtApp.hook('app:created', async () => {
|
||||||
|
const apiKey = useApiKey()
|
||||||
|
apiKey.value = getStoredApiKey()
|
||||||
|
})
|
||||||
|
})
|
||||||
24
plugins/settings.js
Normal file
24
plugins/settings.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
const transformData = (list) => {
|
||||||
|
const result = {};
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
const item = list[i];
|
||||||
|
result[item.name] = item.value;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineNuxtPlugin((nuxtApp) => {
|
||||||
|
nuxtApp.hook('app:created', async () => {
|
||||||
|
let settings = {}
|
||||||
|
|
||||||
|
const { data, error } = await useAuthFetch('/api/chat/settings/', {
|
||||||
|
method: 'GET',
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!error.value) {
|
||||||
|
settings = transformData(data.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
nuxtApp.provide('settings', settings)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -24,12 +24,14 @@ export const addConversation = (conversation) => {
|
|||||||
|
|
||||||
|
|
||||||
export const genTitle = async (conversationId) => {
|
export const genTitle = async (conversationId) => {
|
||||||
const { $i18n } = useNuxtApp()
|
const { $i18n, $settings } = useNuxtApp()
|
||||||
|
const openaiApiKey = useApiKey()
|
||||||
const { data, error } = await useAuthFetch('/api/gen_title/', {
|
const { data, error } = await useAuthFetch('/api/gen_title/', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: {
|
body: {
|
||||||
conversationId: conversationId,
|
conversationId: conversationId,
|
||||||
prompt: $i18n.t('genTitlePrompt')
|
prompt: $i18n.t('genTitlePrompt'),
|
||||||
|
openaiApiKey: $settings.open_api_key_setting === 'True' ? openaiApiKey.value : null,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (!error.value) {
|
if (!error.value) {
|
||||||
@@ -44,25 +46,6 @@ export const genTitle = async (conversationId) => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const transformData = (list) => {
|
|
||||||
const result = {};
|
|
||||||
for (let i = 0; i < list.length; i++) {
|
|
||||||
const item = list[i];
|
|
||||||
result[item.name] = item.value;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const fetchSystemSettings = async () => {
|
|
||||||
const { data, error } = await useAuthFetch('/api/chat/settings/', {
|
|
||||||
method: 'GET',
|
|
||||||
})
|
|
||||||
if (!error.value) {
|
|
||||||
const settings = useSettings()
|
|
||||||
settings.value = transformData(data.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const fetchUser = async () => {
|
export const fetchUser = async () => {
|
||||||
return useMyFetch('/api/account/user/')
|
return useMyFetch('/api/account/user/')
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user