138 lines
3.4 KiB
Vue
138 lines
3.4 KiB
Vue
<template>
|
|
<section class="settings">
|
|
<el-form label-position="top" class="w100">
|
|
<el-form-item label="语言模型">
|
|
<el-row class="flexWrap">
|
|
<ai-model v-for="m in models" :model="m" small :class="{active:settings.model.id==m.id}"
|
|
@click="initModel(m)"/>
|
|
</el-row>
|
|
</el-form-item>
|
|
<el-form-item label="流式输出">
|
|
<el-switch v-model="settings.stream" :active-value="true" :inactive-value="false"/>
|
|
</el-form-item>
|
|
<el-form-item label="API KEY" v-if="isGPT">
|
|
<el-row class="w100">
|
|
<el-input v-model="settings.model.apiKey" clearable class="fill mar-r8"/>
|
|
<el-button type="text" @click="getModelAccount">应用</el-button>
|
|
</el-row>
|
|
</el-form-item>
|
|
<el-row v-loading="loadingAccount" element-loading-background="#272A37">
|
|
<el-form-item label="账号用户" class="fill">{{ account.username }}</el-form-item>
|
|
<el-form-item label="账户余额" class="fill">{{ [account.usage, account.total].join(" / ") }}</el-form-item>
|
|
<el-button type="text" @click="getModelAccount">刷新</el-button>
|
|
</el-row>
|
|
</el-form>
|
|
</section>
|
|
</template>
|
|
|
|
<script>
|
|
import AiModel from "../ui/AiModel";
|
|
import AiSelect from "../ui/AiSelect";
|
|
import * as models from "../utils/models";
|
|
|
|
|
|
export default {
|
|
name: "settings",
|
|
components: {AiModel, AiSelect},
|
|
props: {
|
|
modelValue: {default: () => ({})}
|
|
},
|
|
emits: ["update:modelValue"],
|
|
data() {
|
|
return {
|
|
settings: {},
|
|
loadingAccount: false
|
|
}
|
|
},
|
|
watch: {
|
|
modelValue: {
|
|
immediate: true,
|
|
handler(v) {
|
|
this.settings = v
|
|
this.getModelAccount()
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
models: () => Object.values(models),
|
|
account: v => v.settings.account || {usage: 0, total: 0},
|
|
apiKey: v => v.settings.model.apiKey || "key无效或网络波动,请重新尝试",
|
|
isGPT: v => v.settings.model.name == "ChatGPT"
|
|
},
|
|
methods: {
|
|
initModel(model) {
|
|
const ins = new model()
|
|
const timer = setInterval(() => {
|
|
if (ins.apiKey) {
|
|
clearInterval(timer)
|
|
this.settings.model = ins
|
|
this.getModelAccount()
|
|
}
|
|
}, 500)
|
|
},
|
|
getModelAccount(c = 0) {
|
|
const ai = this.settings.model
|
|
if (ai.apiKey) {
|
|
this.loadingAccount = true
|
|
ai.getAccount().then(v => this.settings.account = v).finally(() => this.loadingAccount = false)
|
|
} else if (c < 5) setTimeout(() => this.getModelAccount(++c), 1000)
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.settings {
|
|
min-width: 375px;
|
|
margin-left: 16px;
|
|
|
|
:deep(.el-form) {
|
|
.el-form-item__label {
|
|
color: #bbb;
|
|
}
|
|
|
|
.el-form-item__content {
|
|
color: white;
|
|
}
|
|
|
|
.el-input__wrapper {
|
|
background-color: transparent;
|
|
|
|
& > input {
|
|
color: white;
|
|
}
|
|
}
|
|
|
|
.AiModel {
|
|
padding: 8px;
|
|
border: 1px solid transparent;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
|
|
&.active {
|
|
border-color: #409EFF;
|
|
border-radius: 4px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//移动端布局
|
|
@media screen and (max-width: 1150px) {
|
|
.settings {
|
|
margin-left: 0;
|
|
z-index: 202305181433;
|
|
position: fixed;
|
|
box-sizing: border-box;
|
|
padding: 0 16px 16px;
|
|
width: 100vw;
|
|
top: 80px;
|
|
left: 0;
|
|
height: calc(100vh - 80px);
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
background-color: #272A37;
|
|
}
|
|
}
|
|
</style>
|