Change the api key to local storage
This commit is contained in:
8
app.vue
8
app.vue
@@ -3,6 +3,7 @@ import { fetchEventSource } from '@microsoft/fetch-event-source'
|
|||||||
|
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
const currentModel = useCurrentModel()
|
const currentModel = useCurrentModel()
|
||||||
|
const openaiApiKey = useApiKey()
|
||||||
const fetchingResponse = ref(false)
|
const fetchingResponse = ref(false)
|
||||||
const fetchReply = async (message, parentMessageId) => {
|
const fetchReply = async (message, parentMessageId) => {
|
||||||
const ctrl = new AbortController()
|
const ctrl = new AbortController()
|
||||||
@@ -15,6 +16,7 @@ const fetchReply = async (message, parentMessageId) => {
|
|||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
model: currentModel.value,
|
model: currentModel.value,
|
||||||
|
openaiApiKey: openaiApiKey.value,
|
||||||
message: message,
|
message: message,
|
||||||
parentMessageId: parentMessageId,
|
parentMessageId: parentMessageId,
|
||||||
conversationId: currentConversation.value.id
|
conversationId: currentConversation.value.id
|
||||||
@@ -126,8 +128,12 @@ onNuxtReady(() => {
|
|||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
<v-divider></v-divider>
|
<v-divider></v-divider>
|
||||||
<v-list>
|
<v-list>
|
||||||
<ApiKeyEditor/>
|
<ClientOnly>
|
||||||
|
<ApiKeyDialog/>
|
||||||
|
</ClientOnly>
|
||||||
|
|
||||||
<v-list-item
|
<v-list-item
|
||||||
|
rounded="xl"
|
||||||
:prepend-icon="theme === 'light' ? 'dark_mode' : 'light_mode'"
|
:prepend-icon="theme === 'light' ? 'dark_mode' : 'light_mode'"
|
||||||
:title="(theme === 'light' ? 'Dark' : 'Light') + ' mode'"
|
:title="(theme === 'light' ? 'Dark' : 'Light') + ' mode'"
|
||||||
@click="toggleTheme"
|
@click="toggleTheme"
|
||||||
|
|||||||
84
components/ApiKeyDialog.vue
Normal file
84
components/ApiKeyDialog.vue
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<template>
|
||||||
|
<v-dialog
|
||||||
|
v-model="dialog"
|
||||||
|
persistent
|
||||||
|
>
|
||||||
|
<template v-slot:activator="{ props }">
|
||||||
|
<v-list-item
|
||||||
|
rounded="xl"
|
||||||
|
v-bind="props"
|
||||||
|
prepend-icon="vpn_key"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
Set OpenAI Api Key
|
||||||
|
</v-list-item>
|
||||||
|
</template>
|
||||||
|
<v-card>
|
||||||
|
<v-card-title>
|
||||||
|
<span class="text-h5">OpenAI Api Key</span>
|
||||||
|
</v-card-title>
|
||||||
|
<v-divider></v-divider>
|
||||||
|
<v-card-text>
|
||||||
|
<div>
|
||||||
|
Get a key:
|
||||||
|
<a target="_blank" href="https://platform.openai.com/account/api-keys">https://platform.openai.com/account/api-keys</a>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mt-5 d-flex align-center"
|
||||||
|
>
|
||||||
|
<v-text-field
|
||||||
|
v-model="apiKey"
|
||||||
|
label="Api Key"
|
||||||
|
hide-details
|
||||||
|
clearable
|
||||||
|
:disabled="!editable"
|
||||||
|
></v-text-field>
|
||||||
|
<v-div
|
||||||
|
v-if="editable"
|
||||||
|
>
|
||||||
|
<v-btn class="ml-3" icon="done" @click="save"></v-btn>
|
||||||
|
</v-div>
|
||||||
|
<v-div
|
||||||
|
v-else
|
||||||
|
>
|
||||||
|
<v-btn class="ml-3" icon="edit" @click="editable = true"></v-btn>
|
||||||
|
</v-div>
|
||||||
|
</div>
|
||||||
|
</v-card-text>
|
||||||
|
<v-divider></v-divider>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-alert
|
||||||
|
v-if="warningText"
|
||||||
|
density="compact"
|
||||||
|
type="warning"
|
||||||
|
:text="warningText"
|
||||||
|
></v-alert>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
@click="dialog = false"
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const dialog = ref(false)
|
||||||
|
const apiKey = useApiKey()
|
||||||
|
const inputApiKey = ref('')
|
||||||
|
const editable = ref(false)
|
||||||
|
const warningText = ref(null)
|
||||||
|
const showWarning = (text) => {
|
||||||
|
warningText.value = text
|
||||||
|
setTimeout(() => {
|
||||||
|
warningText.value = null
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
const save = async () => {
|
||||||
|
setApiKey(apiKey.value)
|
||||||
|
editable.value = false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -18,17 +18,17 @@
|
|||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title>
|
<v-card-title>
|
||||||
<span class="text-h5">OpenAI Models</span>
|
<span class="text-h5">OpenAI Models</span>
|
||||||
|
</v-card-title>
|
||||||
|
<v-divider></v-divider>
|
||||||
|
<v-card-text>
|
||||||
<div>
|
<div>
|
||||||
About the models:
|
About the models:
|
||||||
<a target="_blank" href="https://platform.openai.com/docs/models/overview">https://platform.openai.com/docs/models/overview</a>
|
<a target="_blank" href="https://platform.openai.com/docs/models/overview">https://platform.openai.com/docs/models/overview</a>
|
||||||
</div>
|
</div>
|
||||||
</v-card-title>
|
|
||||||
<v-divider></v-divider>
|
|
||||||
<v-card-text>
|
|
||||||
<div
|
<div
|
||||||
v-for="(model, index) in models"
|
v-for="(model, index) in models"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="d-flex align-center"
|
class="mt-5 d-flex align-center"
|
||||||
>
|
>
|
||||||
<v-switch
|
<v-switch
|
||||||
v-model="currentModel"
|
v-model="currentModel"
|
||||||
@@ -109,7 +109,6 @@ const removeModel = (index) => {
|
|||||||
models.value.splice(index, 1)
|
models.value.splice(index, 1)
|
||||||
}
|
}
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
console.log(currentModel.value)
|
|
||||||
if (!currentModel.value) {
|
if (!currentModel.value) {
|
||||||
showWarning('Please select at least one model.')
|
showWarning('Please select at least one model.')
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
|
||||||
export const useModels = () => useState('models', () => getStoredModels())
|
export const useModels = () => useState('models', () => getStoredModels())
|
||||||
export const useCurrentModel = () => useState('currentModel', () => getCurrentModel())
|
|
||||||
|
export const useCurrentModel = () => useState('currentModel', () => getCurrentModel())
|
||||||
|
|
||||||
|
export const useApiKey = () => useState('apiKey', () => getStoredApiKey())
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import ChatGPTClient from '@waylaidwanderer/chatgpt-api'
|
import ChatGPTClient from '@waylaidwanderer/chatgpt-api'
|
||||||
import { PassThrough } from 'node:stream'
|
import { PassThrough } from 'node:stream'
|
||||||
import {getSetting, setSetting} from "~/utils/keyv";
|
|
||||||
|
|
||||||
const serializeSSEEvent = (chunk) => {
|
const serializeSSEEvent = (chunk) => {
|
||||||
let payload = "";
|
let payload = "";
|
||||||
@@ -24,7 +23,6 @@ const serializeSSEEvent = (chunk) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
const runtimeConfig = useRuntimeConfig()
|
|
||||||
const body = await readBody(event)
|
const body = await readBody(event)
|
||||||
const conversationId = body.conversationId ? body.conversationId.toString() : undefined
|
const conversationId = body.conversationId ? body.conversationId.toString() : undefined
|
||||||
const parentMessageId = body.parentMessageId ? body.parentMessageId.toString() : undefined
|
const parentMessageId = body.parentMessageId ? body.parentMessageId.toString() : undefined
|
||||||
@@ -38,9 +36,7 @@ export default defineEventHandler(async (event) => {
|
|||||||
'Connection': 'keep-alive'
|
'Connection': 'keep-alive'
|
||||||
})
|
})
|
||||||
|
|
||||||
const apiKey = await getSetting('apiKey')
|
if (!body.openaiApiKey) {
|
||||||
|
|
||||||
if (!apiKey) {
|
|
||||||
writeToTunnel({
|
writeToTunnel({
|
||||||
event: 'error',
|
event: 'error',
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
@@ -76,7 +72,7 @@ export default defineEventHandler(async (event) => {
|
|||||||
uri: 'sqlite://database.sqlite'
|
uri: 'sqlite://database.sqlite'
|
||||||
};
|
};
|
||||||
|
|
||||||
const chatGptClient = new ChatGPTClient(apiKey, clientOptions, cacheOptions);
|
const chatGptClient = new ChatGPTClient(body.openaiApiKey, clientOptions, cacheOptions);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await chatGptClient.sendMessage(body.message, {
|
const response = await chatGptClient.sendMessage(body.message, {
|
||||||
|
|||||||
@@ -2,4 +2,5 @@
|
|||||||
export const STORAGE_KEY = {
|
export const STORAGE_KEY = {
|
||||||
OPENAI_MODELS: 'openai_models',
|
OPENAI_MODELS: 'openai_models',
|
||||||
CURRENT_OPENAI_MODEL: 'current_openai_model',
|
CURRENT_OPENAI_MODEL: 'current_openai_model',
|
||||||
|
OPENAI_API_KEY: 'openai_api_key',
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
import {useCurrentModel, useModels} from "~/composables/states";
|
|
||||||
|
|
||||||
const get = (key) => {
|
const get = (key) => {
|
||||||
let val = localStorage.getItem(key)
|
if (typeof window !== 'undefined') {
|
||||||
if (val) {
|
let val = localStorage.getItem(key)
|
||||||
val = JSON.parse(val)
|
if (val) {
|
||||||
|
val = JSON.parse(val)
|
||||||
|
}
|
||||||
|
return val
|
||||||
}
|
}
|
||||||
return val
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const set = (key, val) => {
|
const set = (key, val) => {
|
||||||
@@ -40,4 +42,14 @@ export const getCurrentModel = () => {
|
|||||||
model = DEFAULT_OPENAI_MODEL
|
model = DEFAULT_OPENAI_MODEL
|
||||||
}
|
}
|
||||||
return model
|
return model
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setApiKey = (val) => {
|
||||||
|
const apiKey = useApiKey()
|
||||||
|
set(STORAGE_KEY.OPENAI_API_KEY, val)
|
||||||
|
apiKey.value = val
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getStoredApiKey = () => {
|
||||||
|
return get(STORAGE_KEY.OPENAI_API_KEY)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user