2025-02-24 21:26:02 +08:00

264 lines
7.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<q-card style="width: 800px" class="q-pa-sm">
<div class="text-h5 q-my-md q-px-sm">API配置</div>
<div>
<div class="flex q-mb-md q-px-sm" style="height: 26px">
<ButtonGroup
v-model="apiToAdd"
class="col"
:options="[
{ label: 'OPENAI', value: 'openai' },
{ label: 'OLLAMA', value: 'ollama' },
]"
height="26px"
/>
<q-icon
name="add_box"
@click="addModel"
color="primary"
size="26px"
class="cursor-pointer q-ml-sm"
/>
</div>
<q-scroll-area
:style="`height: ${getConfigListHeight()}px;`"
class="q-px-sm"
:vertical-thumb-style="{
width: '2px',
}"
>
<draggable
v-model="aiConfigs"
item-key="id"
handle=".drag-handle"
:animation="200"
class="config-list"
>
<template #item="{ element: aiConfig, index }">
<div class="config-item">
<div class="config-item-side-bar">
<q-icon
name="drag_indicator"
class="drag-handle cursor-move"
size="20px"
/>
</div>
<div class="config-item-content">
<div class="row q-col-gutter-sm">
<q-input
filled
dense
v-model="aiConfig.name"
class="col"
placeholder="请输入名称"
>
<template v-slot:prepend>
<q-badge
color="primary"
text-color="white"
label="名称"
class="q-pa-xs"
/>
</template>
<template v-slot:append>
<q-icon
color="grey"
name="remove_circle"
@click="deleteModel(index)"
size="16px"
class="cursor-pointer"
/>
</template>
</q-input>
<q-input
filled
dense
v-model="aiConfig.apiUrl"
class="col-7"
:placeholder="
aiConfig.apiType === 'openai'
? '例https://api.openai.com'
: '例http://localhost:11434'
"
>
<template v-slot:prepend>
<q-badge
color="primary"
text-color="white"
label="接口"
class="q-pa-xs"
/>
</template>
</q-input>
</div>
<div class="row q-col-gutter-sm">
<q-input filled dense v-model="aiConfig.model" class="col">
<template v-slot:prepend>
<q-badge
color="primary"
text-color="white"
label="模型"
class="q-pa-xs"
/>
</template>
<template v-slot:append>
<q-btn-dropdown
flat
@click="getModels(aiConfig)"
dense
dropdown-icon="refresh"
>
<q-list dense>
<q-item
v-for="model in models"
:key="model"
clickable
v-close-popup
@click="aiConfig.model = model"
>
<q-item-section>
{{ model }}
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
<q-tooltip>获取模型</q-tooltip>
</template>
</q-input>
<q-input
filled
dense
v-model="aiConfig.apiToken"
v-if="aiConfig.apiType === 'openai'"
type="password"
class="col-7"
>
<template v-slot:prepend>
<q-badge
color="primary"
text-color="white"
label="令牌"
class="q-pa-xs"
/>
</template>
</q-input>
</div>
</div>
</div>
</template>
</draggable>
</q-scroll-area>
</div>
<div class="flex justify-end q-gutter-sm q-px-sm">
<q-btn flat color="grey" label="取消" v-close-popup />
<q-btn
flat
color="primary"
label="保存"
v-close-popup
@click="saveConfig"
/>
</div>
</q-card>
</template>
<script>
import { defineComponent } from "vue";
import { dbManager } from "js/utools.js";
import ButtonGroup from "components/composer/common/ButtonGroup.vue";
import draggable from "vuedraggable";
import { getUniqueId } from "js/common/uuid.js";
export default defineComponent({
name: "AIConfig",
components: {
ButtonGroup,
draggable,
},
data() {
return {
apiToAdd: "openai",
aiConfigs: [],
models: [],
};
},
emits: ["save"],
methods: {
async getModels(aiConfig) {
const { success, result, error } = await window.getModelsFromAiApi(
aiConfig
);
if (!success) {
quickcommand.showMessageBox(error, "error");
this.models = [];
return;
}
this.models = result;
},
saveConfig() {
dbManager.setStorage(
"cfg_aiConfigs",
window.lodashM.cloneDeep(this.aiConfigs)
);
this.$emit("save");
},
deleteModel(index) {
this.aiConfigs.splice(index, 1);
},
addModel() {
this.aiConfigs.push({
id: getUniqueId(),
apiType: this.apiToAdd,
apiUrl: "",
apiToken: "",
model: "",
name: "",
});
},
getConfigListHeight() {
const counts = Math.min(this.aiConfigs.length, 3);
return counts * 100 + (counts - 1) * 8;
},
},
mounted() {
this.aiConfigs = (dbManager.getStorage("cfg_aiConfigs") || []).map(
(config) => ({
...config,
id: config.id || getUniqueId(),
})
);
},
});
</script>
<style scoped>
.config-list,
.config-item-content {
display: flex;
flex-direction: column;
gap: 8px;
}
.config-item {
border: 1px solid var(--q-primary);
border-radius: 4px;
padding: 8px;
display: flex;
}
.config-item-side-bar {
width: 20px;
padding-top: 8px;
}
.config-item-content {
flex: 1;
}
.drag-handle {
cursor: move;
color: var(--q-primary);
margin-right: 4px;
}
</style>