Compare commits

...

3 Commits

Author SHA1 Message Date
Rafi
27c5e2a3ac Get settings from backend, added web search functionality 2023-03-23 11:45:56 +08:00
Rafi
e90dc0c12b web_search toolbar 2023-03-22 23:29:58 +08:00
Rafi
837fd8c9ff update readme 2023-03-22 17:26:22 +08:00
10 changed files with 103 additions and 23 deletions

View File

@@ -156,6 +156,16 @@ Before you can start chatting, you need to add an OpenAI API key. In the Setting
Now you can access the web client at `http(s)://your.domain` or `http://123.123.123.123` to start chatting. Now you can access the web client at `http(s)://your.domain` or `http://123.123.123.123` to start chatting.
## Donation
> If it is helpful to you, it is also helping me.
If you want to support me, Buy me a coffee ❤️ [https://www.buymeacoffee.com/WongSaang](https://www.buymeacoffee.com/WongSaang)
<p align="center">
<img height="150" src="https://github.com/WongSaang/chatgpt-ui/blob/main/demos/bmc_qr.png?raw=true"/>
</p>
## Development ## Development
### Setup ### Setup

View File

@@ -96,10 +96,12 @@ onMounted( () => {
<template v-slot:activator="{ props }"> <template v-slot:activator="{ props }">
<v-btn <v-btn
v-bind="props" v-bind="props"
icon="speaker_notes" icon
title="Common prompts" >
class="mr-3" <v-icon
></v-btn> icon="speaker_notes"
></v-icon>
</v-btn>
</template> </template>
<v-container> <v-container>

View File

@@ -7,4 +7,6 @@ export const useApiKey = () => useState('apiKey', () => getStoredApiKey())
export const useConversion = () => useState('conversion', () => getDefaultConversionData()) export const useConversion = () => useState('conversion', () => getDefaultConversionData())
export const useConversions = () => useState('conversions', () => []) export const useConversions = () => useState('conversions', () => [])
export const useSettings = () => useState('settings', () => {})

BIN
demos/bmc_qr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@@ -154,6 +154,16 @@ networks:
现在可以访问客户端地址 `http(s)://your.domain` / `http://123.123.123.123` 开始聊天。 现在可以访问客户端地址 `http(s)://your.domain` / `http://123.123.123.123` 开始聊天。
## 续杯咖啡
> 如果对您有帮助,也是在帮助我自己.
如果你想支持我,给我续杯咖啡吧 ❤️ [https://www.buymeacoffee.com/WongSaang](https://www.buymeacoffee.com/WongSaang)
<p align="center">
<img height="150" src="https://github.com/WongSaang/chatgpt-ui/blob/main/demos/bmc_qr.png?raw=true"/>
</p>
## Development ## Development
### Setup ### Setup

View File

@@ -34,6 +34,7 @@
"copied": "Copied", "copied": "Copied",
"delete": "Delete", "delete": "Delete",
"signOut": "Sign out", "signOut": "Sign out",
"webSearch": "Web Search",
"welcomeScreen": { "welcomeScreen": {
"introduction1": "is an unofficial client for ChatGPT, but uses the official OpenAI API.", "introduction1": "is an unofficial client for ChatGPT, but uses the official OpenAI API.",
"introduction2": "You will need an OpenAI API Key before you can use this client.", "introduction2": "You will need an OpenAI API Key before you can use this client.",

View File

@@ -34,6 +34,7 @@
"copied": "已复制", "copied": "已复制",
"delete": "删除", "delete": "删除",
"signOut": "退出登录", "signOut": "退出登录",
"webSearch": "网页搜索",
"welcomeScreen": { "welcomeScreen": {
"introduction1": "是一个非官方的ChatGPT客户端但使用OpenAI的官方API", "introduction1": "是一个非官方的ChatGPT客户端但使用OpenAI的官方API",
"introduction2": "在使用本客户端之前您需要一个OpenAI API密钥。", "introduction2": "在使用本客户端之前您需要一个OpenAI API密钥。",

View File

@@ -84,6 +84,7 @@ const loadConversations = async () => {
const {mdAndUp} = useDisplay() const {mdAndUp} = useDisplay()
const drawerPermanent = computed(() => { const drawerPermanent = computed(() => {
return mdAndUp.value return mdAndUp.value
}) })
@@ -97,8 +98,9 @@ const signOut = async () => {
} }
} }
onNuxtReady(async () => { onMounted(async () => {
loadConversations() loadConversations()
loadSettings()
}) })
</script> </script>

View File

@@ -5,8 +5,6 @@ definePageMeta({
middleware: ["auth"] middleware: ["auth"]
}) })
import {EventStreamContentType, fetchEventSource} from '@microsoft/fetch-event-source' import {EventStreamContentType, fetchEventSource} from '@microsoft/fetch-event-source'
import { nextTick } from 'vue'
import MessageActions from "~/components/MessageActions.vue";
const { $i18n, $auth } = useNuxtApp() const { $i18n, $auth } = useNuxtApp()
const runtimeConfig = useRuntimeConfig() const runtimeConfig = useRuntimeConfig()
@@ -53,11 +51,19 @@ const abortFetch = () => {
const fetchReply = async (message) => { const fetchReply = async (message) => {
ctrl = new AbortController() ctrl = new AbortController()
let webSearchParams = {}
console.log(enableWebSearch.value)
if (enableWebSearch.value) {
webSearchParams['web_search'] = {
ua: navigator.userAgent
}
}
const data = Object.assign({}, currentModel.value, { const data = Object.assign({}, currentModel.value, {
openaiApiKey: openaiApiKey.value, openaiApiKey: openaiApiKey.value,
message: message, message: message,
conversationId: currentConversation.value.id conversationId: currentConversation.value.id
}) }, webSearchParams)
try { try {
await fetchEventSource('/api/conversation/', { await fetchEventSource('/api/conversation/', {
@@ -157,6 +163,18 @@ const deleteMessage = (index) => {
currentConversation.value.messages.splice(index, 1) currentConversation.value.messages.splice(index, 1)
} }
const showWebSearchToggle = ref(false)
const enableWebSearch = ref(false)
const settings = useSettings()
watchEffect(() => {
if (settings.value) {
const settingsValue = toRaw(settings.value)
showWebSearchToggle.value = settingsValue.open_web_search && settingsValue.open_web_search === 'True'
}
})
</script> </script>
<template> <template>
@@ -197,21 +215,36 @@ const deleteMessage = (index) => {
<div ref="grab" class="w-100" style="height: 200px;"></div> <div ref="grab" class="w-100" style="height: 200px;"></div>
</div> </div>
<Welcome v-else /> <Welcome v-else />
<v-footer app class="d-flex flex-column"> <v-footer app>
<div class="px-md-16 w-100 d-flex align-center"> <div class="px-md-16 w-100 d-flex flex-column">
<Prompt v-show="!fetchingResponse" :use-prompt="usePrompt" /> <div class="d-flex align-center">
<v-btn <v-btn
v-show="fetchingResponse" v-show="fetchingResponse"
icon="close" icon="close"
title="stop" title="stop"
class="mr-3" class="mr-3"
@click="stop" @click="stop"
></v-btn> ></v-btn>
<MsgEditor ref="editor" :send-message="send" :disabled="fetchingResponse" :loading="fetchingResponse" /> <MsgEditor ref="editor" :send-message="send" :disabled="fetchingResponse" :loading="fetchingResponse" />
</div> </div>
<v-toolbar
density="comfortable"
color="transparent"
>
<Prompt v-show="!fetchingResponse" :use-prompt="usePrompt" />
<v-switch
v-if="showWebSearchToggle"
v-model="enableWebSearch"
hide-details
color="primary"
:label="$t('webSearch')"
></v-switch>
<v-spacer></v-spacer>
</v-toolbar>
<div class="px-4 py-2 text-disabled text-caption font-weight-light text-center w-100"> <!-- <div class="py-2 text-disabled text-caption font-weight-light text-center">-->
© {{ new Date().getFullYear() }} {{ runtimeConfig.public.appName }} <!-- © {{ new Date().getFullYear() }} {{ runtimeConfig.public.appName }}-->
<!-- </div>-->
</div> </div>
</v-footer> </v-footer>
<v-snackbar <v-snackbar

View File

@@ -50,4 +50,23 @@ export const genTitle = async (conversationId) => {
return data.value.title return data.value.title
} }
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 loadSettings = async () => {
const settings = useSettings()
const { data, error } = await useAuthFetch('/api/chat/settings/', {
method: 'GET'
})
if (!error.value) {
settings.value = transformData(data.value)
}
} }