mirror of https://gitee.com/godoos/godoos.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
8.4 KiB
267 lines
8.4 KiB
<script setup lang="ts">
|
|
import { useModelStore } from "@/stores/model";
|
|
import { notifyError } from "@/util/msg";
|
|
import { ref, toRaw, computed } from "vue";
|
|
import { t } from "@/i18n/index";
|
|
const modelStore = useModelStore();
|
|
|
|
const formInit = {
|
|
model: "",
|
|
labelId: "",
|
|
ip: "",
|
|
info: {
|
|
url: "",
|
|
from: "ollama",
|
|
file_name: "",
|
|
context_length: "",
|
|
engine: "ollama",
|
|
template: "",
|
|
parameters: "",
|
|
quant: "q4_K_M",
|
|
pb: "",
|
|
},
|
|
type: "",
|
|
};
|
|
const formData = ref(formInit);
|
|
const fromSource = computed(() => {
|
|
if (formData.value.info.engine == "ollama") {
|
|
return [
|
|
{
|
|
label: "ollama.com",
|
|
value: "ollama",
|
|
},
|
|
{
|
|
label: t("model.network"),
|
|
value: "network",
|
|
},
|
|
{
|
|
label: t("model.local"),
|
|
value: "local",
|
|
},
|
|
]
|
|
} else {
|
|
return [
|
|
{
|
|
label: t("model.network"),
|
|
value: "network",
|
|
},
|
|
{
|
|
label: t("model.local"),
|
|
value: "local",
|
|
},
|
|
]
|
|
}
|
|
});
|
|
function setFrom(val: string) {
|
|
if (val == "ollama") {
|
|
formData.value.info.from = "ollama"
|
|
} else {
|
|
formData.value.info.from = "network"
|
|
}
|
|
}
|
|
const emit = defineEmits(["closeFn", "saveFn"]);
|
|
const localModels: any = ref([]);
|
|
async function getLocalModel() {
|
|
const ipv4Pattern = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
console.log(formData.value.ip);
|
|
if (!ipv4Pattern.test(formData.value.ip)) {
|
|
notifyError(t('model.invalidIp'));
|
|
return;
|
|
}
|
|
const url = `http://${formData.value.ip}:56780/ai/tags`;
|
|
try {
|
|
const res = await fetch(url);
|
|
if (!res.ok) {
|
|
notifyError(t('model.fetchFailed'));
|
|
return;
|
|
}
|
|
const data = await res.json();
|
|
if (data && data.length > 0) {
|
|
localModels.value = data;
|
|
}
|
|
} catch (e) {
|
|
console.log(e);
|
|
return;
|
|
}
|
|
}
|
|
function setLocalInfo() {
|
|
let modelData: any = localModels.value.find((item: any) => {
|
|
return item.model === formData.value.model;
|
|
});
|
|
if (!modelData) {
|
|
notifyError(t('model.invalidModel'));
|
|
return;
|
|
}
|
|
modelData = toRaw(modelData);
|
|
const urls: any = [];
|
|
const url = `http://${formData.value.ip}:56780/ai/server?path=`;
|
|
modelData.info.path.forEach((item: any) => {
|
|
urls.push(url + item);
|
|
});
|
|
//formData.value.info.url = urls;
|
|
modelData.info.url = urls;
|
|
formData.value.info = modelData.info;
|
|
//formData.value.file_name = modelData.file_name;
|
|
//formData.value.engine = modelData.engine;
|
|
// if (modelData.engine == "ollama") {
|
|
// formData.value.type = "local";
|
|
// }
|
|
}
|
|
async function download() {
|
|
const saveData: any = toRaw(formData.value);
|
|
// console.log(saveData)
|
|
// return
|
|
if (saveData.labelId == "") {
|
|
notifyError(t('model.selectLabel'));
|
|
return;
|
|
}
|
|
|
|
if (saveData.from == "ollama") {
|
|
if (saveData.model == "") {
|
|
notifyError(t('model.labelNameEmpty'));
|
|
return;
|
|
}
|
|
if (saveData.model.indexOf(":") === -1) {
|
|
saveData.model = saveData.model + ":latest";
|
|
}
|
|
}
|
|
|
|
if (saveData.from == "local") {
|
|
if (!saveData.url || saveData.url.length == 0) {
|
|
notifyError(t('model.invalidModel'));
|
|
return;
|
|
}
|
|
}
|
|
if (saveData.from == "network") {
|
|
if (isNaN(saveData.context_length) || saveData.context_length < 1) {
|
|
notifyError(t('model.invalidContextLength'));
|
|
return;
|
|
}
|
|
saveData.context_length = saveData.context_length * 1;
|
|
|
|
if (saveData.url == "") {
|
|
notifyError(t('model.invalidModelUrl'));
|
|
return;
|
|
}
|
|
|
|
if (saveData.url != "" && typeof saveData.url === "string") {
|
|
saveData.url = saveData.url.split("\n");
|
|
} else {
|
|
saveData.url = [];
|
|
}
|
|
if (saveData.engine == "ollama") {
|
|
saveData.type = 'llm'
|
|
saveData.params = {
|
|
top_p: 0.95,
|
|
stream: true,
|
|
num_keep: 5,
|
|
num_predict: 1,
|
|
top_k: 40,
|
|
temperature: 0.7,
|
|
|
|
};
|
|
if (saveData.parameters != "" && typeof saveData.parameters === "string") {
|
|
saveData.parameters = saveData.parameters.split("\n");
|
|
} else {
|
|
saveData.parameters = [];
|
|
}
|
|
saveData.info = {
|
|
quant: saveData.quant,
|
|
context_length: saveData.context_length,
|
|
template: saveData.template,
|
|
parameters: saveData.parameters,
|
|
pb: saveData.pb.toUpperCase(),
|
|
};
|
|
const lowerName = saveData.info.pb.replace("B", "") * 1;
|
|
if (lowerName < 3) {
|
|
saveData.info.cpu = "8GB";
|
|
saveData.info.gpu = "6GB";
|
|
}
|
|
else if (lowerName < 9) {
|
|
saveData.info.cpu = "16GB";
|
|
saveData.info.gpu = "8GB";
|
|
} else {
|
|
saveData.info.cpu = "32GB";
|
|
saveData.info.gpu = "12GB";
|
|
}
|
|
if (saveData.model.indexOf(":") === -1) {
|
|
saveData.model = saveData.model + ":latest";
|
|
}
|
|
}
|
|
}
|
|
//console.log(saveData)
|
|
emit("saveFn", saveData);
|
|
}
|
|
</script>
|
|
<template>
|
|
<el-form ref="form" :model="formData" label-width="150px" style="margin-top: 15px">
|
|
<el-form-item :label="t('model.selectLabel')">
|
|
<el-select v-model="formData.labelId">
|
|
<el-option v-for="(item, key) in modelStore.labelList" :key="key" :label="item.name" :value="item.id" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item :label="t('model.selectEngine')">
|
|
<el-select v-model="formData.info.engine" :placeholder="t('model.selectEngine')" @change="setFrom">
|
|
<el-option v-for="item, key in modelStore.modelEngines" :key="key" :label="item.name" :value="item.name" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item :label="t('model.selectSource')">
|
|
<el-select v-model="formData.info.from">
|
|
<el-option v-for="(item, key) in fromSource" :key="key" :label="item.label" :value="item.value" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item :label="t('model.modelName')" v-if="formData.info.from !== 'local'">
|
|
<el-input v-model="formData.model" prefix-icon="House" clearable
|
|
:placeholder="t('model.enterModelName')"></el-input>
|
|
</el-form-item>
|
|
|
|
<template v-if="formData.info.from === 'local'">
|
|
<el-form-item :label="t('model.oppositeIpAddress')">
|
|
<el-input v-model="formData.ip" prefix-icon="Key" clearable placeholder="192.168.1.66"
|
|
@blur="getLocalModel"></el-input>
|
|
</el-form-item>
|
|
<el-form-item :label="t('model.selectModel')" v-if="localModels.length > 0">
|
|
<el-select v-model="formData.model" @change="setLocalInfo">
|
|
<el-option v-for="(item, key) in localModels" :key="key" :label="item.model" :value="item.model" />
|
|
</el-select>
|
|
</el-form-item>
|
|
</template>
|
|
<template v-if="formData.info.from === 'network'">
|
|
<el-form-item :label="t('model.modelUrl')">
|
|
<el-input type="textarea" :row="3" v-model="formData.info.url"
|
|
:placeholder="t('model.enterModelUrl')"></el-input>
|
|
</el-form-item>
|
|
<!-- <el-form-item :label="t('model.selectEngine')">
|
|
<el-select v-model="formData.info.engine">
|
|
<el-option v-for="(item, key) in modelStore.modelEngines" :key="key" :label="item.name" :value="item.name" />
|
|
</el-select>
|
|
</el-form-item> -->
|
|
<template v-if="formData.info.engine === 'ollama' && formData.info.from === 'network'">
|
|
<el-form-item :label="t('model.template')">
|
|
<el-input type="textarea" :row="3" v-model="formData.info.template"></el-input>
|
|
</el-form-item>
|
|
|
|
<el-form-item :label="t('model.contextLength')">
|
|
<el-input type="number" v-model="formData.info.context_length" prefix-icon="Key" clearable
|
|
:placeholder="t('model.enterContextLength')"></el-input>
|
|
</el-form-item>
|
|
<el-form-item :label="t('model.parameterSettings')">
|
|
<el-input type="textarea" :row="3" :placeholder="t('model.onePerLine')"
|
|
v-model="formData.info.parameters"></el-input>
|
|
</el-form-item>
|
|
<el-form-item :label="t('model.parameterSize')">
|
|
<el-input type="number" v-model="formData.info.pb" prefix-icon="Key" clearable
|
|
:placeholder="t('model.enterParameterSize')"></el-input>
|
|
</el-form-item>
|
|
<el-form-item :label="t('model.selectQuantization')">
|
|
<el-select v-model="formData.info.quant">
|
|
<el-option v-for="(item, key) in modelStore.llamaQuant" :key="key" :label="item" :value="item" />
|
|
</el-select>
|
|
</el-form-item>
|
|
</template>
|
|
</template>
|
|
<el-form-item>
|
|
<el-button type="primary" icon="Download" @click="download">{{ t('common.confim') }}</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
</template>
|
|
|