Browse Source

change aimodel

master
godo 7 months ago
parent
commit
59e37e1863
  1. 152
      frontend/src/components/ai/aimodel.vue
  2. 11
      frontend/src/components/ai/aisetting.vue
  3. 33
      frontend/src/components/window/IframeFile.vue
  4. 42
      frontend/src/hook/useAi.ts
  5. 4
      frontend/src/i18n/lang/en.json
  6. 4
      frontend/src/i18n/lang/zh.json
  7. 2
      frontend/src/stores/db.ts
  8. 93
      frontend/src/stores/model.ts
  9. 2
      frontend/src/stores/prompt/prompts-en.json
  10. 2
      frontend/src/stores/prompt/prompts-zh.json
  11. 4
      frontend/src/system/applist.ts
  12. 6
      frontend/src/system/config.ts
  13. 1
      godo/cmd/main.go
  14. 2
      godo/model/data.go
  15. 81
      godo/model/op.go

152
frontend/src/components/ai/aimodel.vue

@ -20,7 +20,7 @@ const currentCate = ref("all");
const showDetail = ref(false); const showDetail = ref(false);
const detailModel = ref("") const detailModel = ref("")
let downloadAbort:any = {}; let downloadAbort: any = {};
onMounted(async () => { onMounted(async () => {
await modelStore.getList(); await modelStore.getList();
}); });
@ -31,10 +31,10 @@ async function showCate(name: any) {
async function showSearch() { async function showSearch() {
await modelStore.getLabelSearch(searchKey.value); await modelStore.getLabelSearch(searchKey.value);
} }
function downAddUpdate(val:any) { function downAddUpdate(val: any) {
downAdd.value = val; downAdd.value = val;
} }
async function downLabel(modelData:any, labelData:any) { async function downLabel(modelData: any, labelData: any) {
labelData = toRaw(labelData); labelData = toRaw(labelData);
modelData = toRaw(modelData); modelData = toRaw(modelData);
//console.log(modelData, labelData) //console.log(modelData, labelData)
@ -61,7 +61,7 @@ async function saveBox(modelData: any) {
} }
downLabel(modelData, labelData); downLabel(modelData, labelData);
} }
async function download(saveData:any) { async function download(saveData: any) {
saveData = toRaw(saveData); saveData = toRaw(saveData);
saveData.info = toRaw(saveData.info); saveData.info = toRaw(saveData.info);
//saveData.url = toRaw(saveData.url); //saveData.url = toRaw(saveData.url);
@ -74,7 +74,7 @@ async function download(saveData:any) {
return; return;
} }
//console.log(saveData); //console.log(saveData);
const downUrl = config.apiUrl + "/ai/download"; const downUrl = config.aiUrl + "/ai/download";
try { try {
const completion = await fetch(downUrl, { const completion = await fetch(downUrl, {
@ -92,7 +92,7 @@ async function download(saveData:any) {
saveData.progress = 0; saveData.progress = 0;
modelStore.addDownload(saveData); modelStore.addDownload(saveData);
await handleDown(saveData, completion); await handleDown(saveData, completion);
} catch (error:any) { } catch (error: any) {
notifyError(error.message); notifyError(error.message);
} }
} }
@ -104,7 +104,7 @@ function cancelDownload(model: string) {
} }
} }
async function handleDown(modelData:any, completion:any) { async function handleDown(modelData: any, completion: any) {
const reader: any = completion.body?.getReader(); const reader: any = completion.body?.getReader();
if (!reader) { if (!reader) {
notifyError(t("common.cantStream")); notifyError(t("common.cantStream"));
@ -125,7 +125,7 @@ async function handleDown(modelData:any, completion:any) {
//console.log(rawjson); //console.log(rawjson);
const msg = modelStore.parseMsg(rawjson); const msg = modelStore.parseMsg(rawjson);
//console.log(msg) //console.log(msg)
if(msg.message && msg.code) { if (msg.message && msg.code) {
notifyError(msg.message); notifyError(msg.message);
break; break;
} }
@ -135,9 +135,9 @@ async function handleDown(modelData:any, completion:any) {
modelData.status = msg.status; modelData.status = msg.status;
if (msg.total && msg.completed && msg.total > 0) { if (msg.total && msg.completed && msg.total > 0) {
if(msg.total == msg.completed){ if (msg.total == msg.completed) {
msg.status = "success" msg.status = "success"
}else{ } else {
modelData.isLoading = 1; modelData.isLoading = 1;
modelData.progress = Math.ceil((msg.completed / msg.total) * 100); modelData.progress = Math.ceil((msg.completed / msg.total) * 100);
} }
@ -171,7 +171,7 @@ async function deleteModel(modelData: any) {
method: "POST", method: "POST",
body: JSON.stringify(modelData.info), body: JSON.stringify(modelData.info),
}; };
const delUrl = config.apiUrl + "/ai/delete"; const delUrl = config.aiUrl + "/ai/delete";
const completion = await fetch(delUrl, postData); const completion = await fetch(delUrl, postData);
if (completion.status === 404) { if (completion.status === 404) {
notifyError(completion.statusText); notifyError(completion.statusText);
@ -180,12 +180,12 @@ async function deleteModel(modelData: any) {
if (completion.status === 200) { if (completion.status === 200) {
notifySuccess("success!"); notifySuccess("success!");
} }
} catch (error:any) { } catch (error: any) {
console.log(error); console.log(error);
notifyError(error.message); notifyError(error.message);
} }
} }
function labelShow(val:any) { function labelShow(val: any) {
labelId.value = val; labelId.value = val;
labelEditor.value = true; labelEditor.value = true;
} }
@ -202,10 +202,10 @@ async function delLabel(id: number) {
} }
function getModelStatus(model: string) { function getModelStatus(model: string) {
let name = t('model.noDown'); let name = t('model.noDown');
if (modelStore.modelList.find((item:any) => item.model === model)) { if (modelStore.modelList.find((item: any) => item.model === model)) {
name = t('model.hasDown'); name = t('model.hasDown');
} }
if (modelStore.downList.find((item:any) => item.model === model)) { if (modelStore.downList.find((item: any) => item.model === model)) {
name = t('model.downloading'); name = t('model.downloading');
} }
return name; return name;
@ -214,56 +214,42 @@ function showModel(model: string) {
detailModel.value = model; detailModel.value = model;
showDetail.value = true; showDetail.value = true;
} }
async function refreshOllama() {
try {
await modelStore.refreshOllama();
notifySuccess(t('model.refreshSuccess'));
} catch (error) {
notifyError(t('model.refreshFail'));
}
}
</script> </script>
<template> <template>
<el-dialog v-model="showDetail" width="600" append-to-body> <el-dialog v-model="showDetail" width="600" append-to-body>
<DownModelInfo :model="detailModel" /> <DownModelInfo :model="detailModel" />
</el-dialog> </el-dialog>
<div class="app-container"> <div class="app-container">
<el-drawer <el-drawer v-model="downLeft" direction="ltr" :show-close="false" :with-header="false" :size="300">
v-model="downLeft"
direction="ltr"
:show-close="false"
:with-header="false"
:size="300"
>
<div> <div>
<el-tag size="large" style="margin-bottom: 10px">{{ t('model.downloading') }}</el-tag> <el-tag size="large" style="margin-bottom: 10px">{{ t('model.downloading') }}</el-tag>
<div class="pa-2"> <div class="pa-2">
<Vue3Lottie <Vue3Lottie animationLink="/bot/search.json" :height="200" :width="200"
animationLink="/bot/search.json" v-if="modelStore.downList.length < 1" />
:height="200"
:width="200"
v-if="modelStore.downList.length < 1"
/>
<el-space direction="vertical" v-else> <el-space direction="vertical" v-else>
<el-card <el-card v-for="(val, key) in modelStore.downList" :key="key" class="box-card" style="width: 250px">
v-for="(val, key) in modelStore.downList"
:key="key"
class="box-card"
style="width: 250px"
>
<div class="card-header"> <div class="card-header">
<span>{{ val.model }}</span> <span>{{ val.model }}</span>
</div> </div>
<div class="text item" v-if="val.progress && val.isLoading > 0"> <div class="text item" v-if="val.progress && val.isLoading > 0">
<el-progress <el-progress :text-inside="true" :stroke-width="15" :percentage="val.progress" />
:text-inside="true"
:stroke-width="15"
:percentage="val.progress"
/>
</div> </div>
<div class="drawer-model-actions" style="margin-top: 10px"> <div class="drawer-model-actions" style="margin-top: 10px">
<el-tag size="small" v-if="val.isLoading > 0">{{ val.status }}</el-tag> <el-tag size="small" v-if="val.isLoading > 0">{{ val.status }}</el-tag>
<el-icon :size="18" color="red" @click="cancelDownload(val.model)"> <el-icon :size="18" color="red" @click="cancelDownload(val.model)">
<Delete /> <Delete />
</el-icon> </el-icon>
<el-icon <el-icon :size="18" color="blue" v-if="val.isLoading < 1 && val.status != 'success'"
:size="18" @click="download(toRaw(val))">
color="blue"
v-if="val.isLoading < 1 && val.status != 'success'"
@click="download(toRaw(val))"
>
<VideoPlay /> <VideoPlay />
</el-icon> </el-icon>
</div> </div>
@ -272,31 +258,17 @@ function showModel(model: string) {
</div> </div>
<el-tag size="large" style="margin: 10px auto">{{ t('model.hasDown') }}</el-tag> <el-tag size="large" style="margin: 10px auto">{{ t('model.hasDown') }}</el-tag>
<div class="pa-2"> <div class="pa-2">
<div <div class="list-item" v-for="(item, index) in modelStore.modelList" :key="index">
class="list-item"
v-for="(item, index) in modelStore.modelList"
:key="index"
>
<div class="list-title" @click="showModel(item.model)"> <div class="list-title" @click="showModel(item.model)">
{{ item.model }} {{ item.model }}
</div> </div>
<el-button <el-button class="delete-btn" icon="Delete" size="small" @click.stop="deleteModel(item)" circle></el-button>
class="delete-btn"
icon="Delete"
size="small"
@click.stop="deleteModel(item)"
circle
></el-button>
</div> </div>
</div> </div>
</div> </div>
</el-drawer> </el-drawer>
<el-dialog v-model="labelEditor" width="600" :title="t('model.modelLabel')"> <el-dialog v-model="labelEditor" width="600" :title="t('model.modelLabel')">
<down-labeleditor <down-labeleditor @closeFn="closeLabel" @refreshFn="refreshList" :labelId="labelId" />
@closeFn="closeLabel"
@refreshFn="refreshList"
:labelId="labelId"
/>
</el-dialog> </el-dialog>
<el-dialog v-model="downAdd" width="600" :title="t('model.modelDown')"> <el-dialog v-model="downAdd" width="600" :title="t('model.modelDown')">
<down-addbox @closeFn="downAddUpdate" @saveFn="saveBox" /> <down-addbox @closeFn="downAddUpdate" @saveFn="saveBox" />
@ -306,33 +278,16 @@ function showModel(model: string) {
<div></div> <div></div>
</template> </template>
<template #content> <template #content>
<el-button <el-button @click.stop="downLeft = !downLeft" icon="Menu" circle />
@click.stop="downLeft = !downLeft"
icon="Menu"
circle
/>
<el-button @click.stop="downAdd = true" icon="Plus" circle /> <el-button @click.stop="downAdd = true" icon="Plus" circle />
<el-button <el-button @click.stop="labelShow(0)" icon="CollectionTag" circle />
@click.stop="labelShow(0)" <el-button @click.stop="refreshOllama" icon="RefreshRight" circle />
icon="CollectionTag"
circle
/>
<el-button
@click.stop="modelStore.refreshOllama"
icon="RefreshRight"
circle
/>
</template> </template>
<template #extra> <template #extra>
<el-space class="mr-10"> <el-space class="mr-10">
<el-input <el-input :placeholder="t('model.search')" v-model="searchKey" v-on:keydown.enter="showSearch"
:placeholder="t('model.search')" style="width: 200px" :suffix-icon="Search" />
v-model="searchKey"
v-on:keydown.enter="showSearch"
style="width: 200px"
:suffix-icon="Search"
/>
</el-space> </el-space>
</template> </template>
</el-page-header> </el-page-header>
@ -340,22 +295,13 @@ function showModel(model: string) {
<div class="flex-fill ml-10 mr-10"> <div class="flex-fill ml-10 mr-10">
<el-tabs v-model="currentCate" @tab-click="showCate"> <el-tabs v-model="currentCate" @tab-click="showCate">
<el-tab-pane :label="t('model.all')" name="all" /> <el-tab-pane :label="t('model.all')" name="all" />
<el-tab-pane <el-tab-pane :label="t('model.' + item)" :name="item" v-for="(item, key) in modelStore.cateList" :key="key" />
:label="t('model.' + item)"
:name="item"
v-for="(item, key) in modelStore.cateList"
:key="key"
/>
</el-tabs> </el-tabs>
</div> </div>
<el-scrollbar class="scrollbarHeightList"> <el-scrollbar class="scrollbarHeightList">
<div class="model-list"> <div class="model-list">
<div <div v-for="item in modelStore.labelList" :key="item.name" class="model-item flex align-center pa-5">
v-for="item in modelStore.labelList"
:key="item.name"
class="model-item flex align-center pa-5"
>
<div class="flex-fill mx-5"> <div class="flex-fill mx-5">
<div class="font-weight-bold"> <div class="font-weight-bold">
{{ item.name }} {{ item.name }}
@ -371,13 +317,8 @@ function showModel(model: string) {
<el-button icon="Download" circle /> <el-button icon="Download" circle />
</template> </template>
<template #default> <template #default>
<div <div v-for="(el, index) in item.models" :key="index" :value="el.model" @click="downLabel(el, item)"
v-for="(el, index) in item.models" class="list-column">
:key="index"
:value="el.model"
@click="downLabel(el, item)"
class="list-column"
>
<div class="list-column-title"> <div class="list-column-title">
{{ el.model }} {{ el.model }}
<el-tag size="small" type="info">{{ <el-tag size="small" type="info">{{
@ -393,12 +334,7 @@ function showModel(model: string) {
</template> </template>
</el-popover> </el-popover>
<el-button icon="Edit" circle @click="labelShow(item.id)" /> <el-button icon="Edit" circle @click="labelShow(item.id)" />
<el-button <el-button @click.stop="delLabel(item.id)" icon="Delete" v-if="item.models.length === 0" circle />
@click.stop="delLabel(item.id)"
icon="Delete"
v-if="item.models.length === 0"
circle
/>
</div> </div>
</div> </div>
</div> </div>

11
frontend/src/components/ai/aisetting.vue

@ -40,7 +40,6 @@ const hoverTxt = {
const config: any = ref({}); const config: any = ref({});
//const chatConfig: any = ref({}); //const chatConfig: any = ref({});
const currentsModel: any = ref({}); const currentsModel: any = ref({});
const modelList = ref([]);
const pageLoading = ref(true); const pageLoading = ref(true);
import type { TabsPaneContext } from "element-plus"; import type { TabsPaneContext } from "element-plus";
@ -92,7 +91,7 @@ const saveConfig = async () => {
} }
await changeConfig(); await changeConfig();
modelList.value = await modelStore.getModelList(); //await modelStore.getModelList();
//modelStore.updateCurrentModels(modelList.value); //modelStore.updateCurrentModels(modelList.value);
notifySuccess(t('common.saveSuccess')); notifySuccess(t('common.saveSuccess'));
}; };
@ -110,7 +109,9 @@ const initConfig = async () => {
}; };
onMounted(async () => { onMounted(async () => {
await initConfig(); await initConfig();
modelList.value = await modelStore.getModelList(); await modelStore.getModelList();
//modelList.value = modelStore.modelList;
//console.log(modelList.value)
pageLoading.value = false; pageLoading.value = false;
}); });
async function changeDir() { async function changeDir() {
@ -143,7 +144,7 @@ async function changeDir() {
</el-form-item> </el-form-item>
<el-form-item :label="t('aisetting.serverUrl')"> <el-form-item :label="t('aisetting.serverUrl')">
<div class="slider-container"> <div class="slider-container">
<el-input v-model="config.apiUrl" :placeholder="t('aisetting.serverUrl')" prefix-icon="Notification" <el-input v-model="config.aiUrl" :placeholder="t('aisetting.serverUrl')" prefix-icon="Notification"
clearable></el-input> clearable></el-input>
<el-popover placement="left" :width="400" trigger="click"> <el-popover placement="left" :width="400" trigger="click">
<template #reference> <template #reference>
@ -177,7 +178,7 @@ async function changeDir() {
<el-form label-width="150px" style="padding: 0 30px 50px 0"> <el-form label-width="150px" style="padding: 0 30px 50px 0">
<el-form-item :label="t('model.' + item)" v-for="(item, index) in modelStore.cateList" :key="index"> <el-form-item :label="t('model.' + item)" v-for="(item, index) in modelStore.cateList" :key="index">
<el-select v-model="currentsModel[item]" @change="(val: any) => modelStore.setCurrentModel(item, val)"> <el-select v-model="currentsModel[item]" @change="(val: any) => modelStore.setCurrentModel(item, val)">
<el-option v-for="(el, key) in modelStore.getCurrentModelList(modelList, item)" :key="key" <el-option v-for="(el, key) in modelStore.getCurrentModelList(item)" :key="key"
:label="el.model" :value="el.model" /> :label="el.model" :value="el.model" />
</el-select> </el-select>
</el-form-item> </el-form-item>

33
frontend/src/components/window/IframeFile.vue

@ -8,6 +8,7 @@ import { getSplit, getSystemConfig, setSystemKey } from "@/system/config";
import { base64ToBuffer, isBase64 } from "@/util/file"; import { base64ToBuffer, isBase64 } from "@/util/file";
import { isShareFile } from "@/util/sharePath.ts"; import { isShareFile } from "@/util/sharePath.ts";
import { inject, onMounted, onUnmounted, ref, toRaw } from "vue"; import { inject, onMounted, onUnmounted, ref, toRaw } from "vue";
import { askAi } from "@/hook/useAi";
const SP = getSplit(); const SP = getSplit();
const sys: any = inject<System>("system"); const sys: any = inject<System>("system");
@ -187,24 +188,36 @@ const eventHandler = async (e: MessageEvent) => {
} }
else if (eventData.type == 'aiCreater') { else if (eventData.type == 'aiCreater') {
console.log(eventData)
let postData:any = {}
if(eventData.data){
postData.content = eventData.data
}
if(eventData.title){
postData.title = eventData.title
}
if(eventData.category){
postData.category = eventData.category
}
// AI // AI
const res = await askAi(postData, eventData.action);
storeRef.value?.contentWindow?.postMessage( storeRef.value?.contentWindow?.postMessage(
{ {
type: 'aiReciver', type: 'aiReciver',
data: '-------------经过AI处理后的数据-----------', data: res,
},
"*"
);
}
else if (eventData.type == 'aiReciver') {
storeRef.value?.contentWindow?.postMessage(
{
type: eventData.type,
data: '----经过AI处理后的数据-----',
}, },
"*" "*"
); );
} }
// else if (eventData.type == 'aiReciver') {
// storeRef.value?.contentWindow?.postMessage(
// {
// type: eventData.type,
// data: '----AI-----',
// },
// "*"
// );
// }
}; };
// //
const delFileInputPwd = async () => { const delFileInputPwd = async () => {

42
frontend/src/hook/useAi.ts

@ -1,8 +1,44 @@
import { getSystemConfig,fetchGet, fetchPost } from "@/system/config"; import { getSystemConfig, fetchPost } from "@/system/config";
import { useAssistantStore } from '@/stores/assistant'; import { useAssistantStore } from '@/stores/assistant';
export function askAi(question: string,action:string) { import { useModelStore } from "@/stores/model";
export async function askAi(question: any, action: string) {
const assistantStore = useAssistantStore(); const assistantStore = useAssistantStore();
const modelStore = useModelStore();
const config = getSystemConfig(); const config = getSystemConfig();
const model = await modelStore.getModel('chat')
if (!model) {
return '请先设置模型'
}
let prompt = await assistantStore.getPrompt(action)
if (!prompt) {
return '请先设置prompt'
}
if (question.content) {
prompt = prompt.replace('{content}', question.content)
}
if (question.title) {
prompt = prompt.replace('{title}', question.title)
}
if (question.category) {
prompt = prompt.replace('{category}', question.category)
}
const apiUrl = config.aiUrl + '/ai/chat'
const postMsg: any = {
messages: [
{
role: "assistant",
content: prompt
},
],
model: model.model,
stream: false,
options: modelStore.chatConfig.creation,
};
const complain = await fetchPost(apiUrl, JSON.stringify(postMsg))
if (!complain.ok) {
return '请求失败'
}
const data = await complain.json()
return data.choices[0].message.content
} }

4
frontend/src/i18n/lang/en.json

@ -319,7 +319,9 @@
"requiredCPU": "Required CPU:", "requiredCPU": "Required CPU:",
"requiredGPU": "Required GPU:", "requiredGPU": "Required GPU:",
"modelTemplate": "Model Template:", "modelTemplate": "Model Template:",
"modelParameters": "Model Parameters:" "modelParameters": "Model Parameters:",
"refreshSuccess": "Refresh Success",
"refreshFailed": "Refresh Success"
}, },
"aisetting": { "aisetting": {
"modelSetting": "Model Setting", "modelSetting": "Model Setting",

4
frontend/src/i18n/lang/zh.json

@ -322,7 +322,9 @@
"requiredCPU": "所需CPU:", "requiredCPU": "所需CPU:",
"requiredGPU": "所需GPU:", "requiredGPU": "所需GPU:",
"modelTemplate": "模型模版:", "modelTemplate": "模型模版:",
"modelParameters": "模型参数:" "modelParameters": "模型参数:",
"refreshSuccess": "更新成功!",
"refreshFailed": "更新失败!"
}, },
"aisetting": { "aisetting": {
"modelSetting": "模型设置", "modelSetting": "模型设置",

2
frontend/src/stores/db.ts

@ -9,7 +9,7 @@ dbInit.version(1).stores({
// 模型标签 // 模型标签
modelslabel: '++id,name,zhdesc,endesc,family,chanel,models,action,engine', modelslabel: '++id,name,zhdesc,endesc,family,chanel,models,action,engine',
// 模型列表 // 模型列表
modelslist: '++id,model,label,status,progress,url,file_name,isdef,action,chanel,engine,info,options', modelslist: '++id,model,label,action,status,params,type,isdef,info,created_at',
// 用户列表 // 用户列表
workbenchChatUser: '++id,ip,userName,chatId,avatar,mobile,phone,nickName,isOnline,updatedAt,createdAt', workbenchChatUser: '++id,ip,userName,chatId,avatar,mobile,phone,nickName,isOnline,updatedAt,createdAt',
// 会话列表 // 会话列表

93
frontend/src/stores/model.ts

@ -2,6 +2,7 @@ import { defineStore } from "pinia";
import { ref } from "vue"; import { ref } from "vue";
import { db } from "./db.ts" import { db } from "./db.ts"
import { aiLabels } from "./labels/index.ts" import { aiLabels } from "./labels/index.ts"
import { fetchGet, getSystemKey } from "@/system/config"
const modelEngines = [ const modelEngines = [
{ {
name: "ollama", name: "ollama",
@ -90,6 +91,7 @@ export const useModelStore = defineStore('modelStore', () => {
temperature: 0.2, temperature: 0.2,
} }
}) })
const aiUrl = getSystemKey("aiUrl")
async function getLabelCate(cateName: string) { async function getLabelCate(cateName: string) {
const list = await getLabelList() const list = await getLabelList()
@ -132,12 +134,40 @@ export const useModelStore = defineStore('modelStore', () => {
} }
async function getModelList() { async function getModelList() {
return await db.getAll("modelslist") const res = await fetchGet(`${aiUrl}/ai/tags`)
//console.log(res)
if (res.ok) {
resetData(res)
}
return modelList.value
}
async function resetData(res: any) {
const data = await res.json()
//console.log(data)
if (data && data.length > 0) {
await db.clear("modelslist")
await db.addAll("modelslist", data)
modelList.value = data
}
}
async function refreshOllama() {
const res = await fetchGet(`${aiUrl}/ai/refreshOllama`)
//console.log(res)
if (res.ok) {
resetData(res)
}
} }
function getModelInfo(model: string) { function getModelInfo(model: string) {
return modelList.value.find((d: any) => d.model == model) return modelList.value.find((d: any) => d.model == model)
} }
async function getModel(action : string) {
const model = await db.get("modelslist", { action,isdef:1 })
if(!model){
return await db.addOne("modelslist", { action })
}else{
return model
}
}
async function getList() { async function getList() {
labelList.value = await getLabelList() labelList.value = await getLabelList()
await getModelList() await getModelList()
@ -145,46 +175,32 @@ export const useModelStore = defineStore('modelStore', () => {
downList.value[index].isLoading = 0 downList.value[index].isLoading = 0
}) })
} }
async function setCurrentModel(action: string, model: string) { async function setCurrentModel(action: string, model?: string) {
await db.modify("modelslist", "action", action, { isdef: 0 }) await db.modify("modelslist", "action", action, { isdef: 0 })
if (model !== "") {
return await db.modify("modelslist", "model", model, { isdef: 1 }) return await db.modify("modelslist", "model", model, { isdef: 1 })
}
function getCurrentModelList(modelList: any, action: string) {
return modelList.filter((d: any) => d.action == action)
}
async function addDownList(data: any) {
console.log(data);
modelList.value.unshift(data)
const has = modelList.value.find((d: any) => d.model == data.model)
//console.log(has)
if (!has) {
//data = toRaw(data)
const save = await getBaseModelInfo(data.model)
//console.log(save)
if (save) {
//modelList.value.unshift(save)
return await db.addOne("modelslist", save)
} else { } else {
console.log("not get model" + data.model) const data = await db.get("modelslist", { action })
if(data){
return await db.update("modelslist", data.id, { isdef: 1 })
} }
} }
} }
async function getBaseModelInfo(model: string) { async function setDefModel(action: string) {
const baseModel = await db.get("modelslist", { model: model }) const has = await db.get("modelslist", { action, isdef: 1 })
if (baseModel) { if(!has){
return baseModel const data = await db.get("modelslist", { action })
if(data){
return await db.update("modelslist", data.id, { isdef: 1 })
} }
const modelInfo = await db.get("modelslist", { model: model.split(":")[0] })
if (modelInfo) {
return modelInfo
} }
return null
} }
async function refreshOllama() { function getCurrentModelList(action: string) {
//if (!modelList || modelList.length == 0) return
return modelList.value.filter((d: any) => d.action == action)
} }
async function deleteModelList(data: any) { async function deleteModelList(data: any) {
//console.log(data) //console.log(data)
if (!data || !data.model) return if (!data || !data.model) return
@ -194,8 +210,12 @@ export const useModelStore = defineStore('modelStore', () => {
} }
}); });
await db.deleteByField("modelslist", "model", data.model) await db.deleteByField("modelslist", "model", data.model)
if(data.isdef*1 == 1){
await setCurrentModel(data.action, "")
}
//await db.delete("modelslist", data.id) //await db.delete("modelslist", data.id)
await getModelList() //await getModelList()
} }
function checkDownload(name: string) { function checkDownload(name: string) {
@ -230,7 +250,9 @@ export const useModelStore = defineStore('modelStore', () => {
isLoading: modelData.isLoading ?? 0, isLoading: modelData.isLoading ?? 0,
}); });
if (modelData.status === "success") { if (modelData.status === "success") {
await addDownList(modelData); //await addDownList(modelData);
await getModelList();
await setDefModel(modelData.action);
await checkLabelData(modelData); await checkLabelData(modelData);
} }
} }
@ -292,6 +314,7 @@ export const useModelStore = defineStore('modelStore', () => {
getList, getList,
getModelList, getModelList,
getModelInfo, getModelInfo,
getModel,
checkDownload, checkDownload,
addDownload, addDownload,
deleteDownload, deleteDownload,
@ -301,7 +324,7 @@ export const useModelStore = defineStore('modelStore', () => {
getLabelSearch, getLabelSearch,
getLabelList, getLabelList,
delLabel, delLabel,
addDownList, //addDownList,
deleteModelList, deleteModelList,
initModel, initModel,
setCurrentModel, setCurrentModel,

2
frontend/src/stores/prompt/prompts-en.json

@ -669,7 +669,7 @@
}, },
{ {
"name": "Act as a system creator", "name": "Act as a system creator",
"prompt": "Write a highly concise and comprehensive {cate} outline based on the following topic: {title}", "prompt": "Write a highly concise and comprehensive {category} outline based on the following topic: {title}",
"isdef": 1, "isdef": 1,
"action": "creation_leader" "action": "creation_leader"
}, },

2
frontend/src/stores/prompt/prompts-zh.json

@ -513,7 +513,7 @@
}, },
{ {
"name": "充当系统创作总纲", "name": "充当系统创作总纲",
"prompt": "根据以下主题,写一篇高度凝练且全面的{cate}提纲:{title}", "prompt": "根据以下主题,写一篇高度凝练且全面的{category}提纲:{title}",
"isdef": 1, "isdef": 1,
"action": "creation_leader" "action": "creation_leader"
}, },

4
frontend/src/system/applist.ts

@ -80,8 +80,8 @@ export const appList = [
{ {
name: "document", name: "document",
appIcon: "word", appIcon: "word",
url: "/docx/index.html", //url: "/docx/index.html",
//url:"http://localhost:3000/", url:"http://localhost:3000/",
width: 800, width: 800,
frame: true, frame: true,
height: 600, height: 600,

6
frontend/src/system/config.ts

@ -151,6 +151,12 @@ export const getSystemConfig = (ifset = false) => {
if(!config.ollamaUrl) { if(!config.ollamaUrl) {
config.ollamaUrl = 'http://localhost:11434' config.ollamaUrl = 'http://localhost:11434'
} }
if(!config.dataDir) {
config.dataDir = ''
}
if(!config.aiUrl){
config.aiUrl = config.apiUrl
}
// 初始化桌面快捷方式列表,若本地存储中已存在则不进行覆盖 // 初始化桌面快捷方式列表,若本地存储中已存在则不进行覆盖
if (!config.desktopList) { if (!config.desktopList) {
config.desktopList = []; config.desktopList = [];

1
godo/cmd/main.go

@ -134,6 +134,7 @@ func OsStart() {
aiRouter.HandleFunc("/delete", model.DeleteFileHandle).Methods(http.MethodPost) aiRouter.HandleFunc("/delete", model.DeleteFileHandle).Methods(http.MethodPost)
aiRouter.HandleFunc("/tags", model.Tagshandler).Methods(http.MethodGet) aiRouter.HandleFunc("/tags", model.Tagshandler).Methods(http.MethodGet)
aiRouter.HandleFunc("/show", model.ShowHandler).Methods(http.MethodGet) aiRouter.HandleFunc("/show", model.ShowHandler).Methods(http.MethodGet)
aiRouter.HandleFunc("/refreshOllama", model.RefreshOllamaHandler).Methods(http.MethodGet)
aiRouter.HandleFunc("/chat", model.ChatHandler).Methods(http.MethodPost) aiRouter.HandleFunc("/chat", model.ChatHandler).Methods(http.MethodPost)
aiRouter.HandleFunc("/embeddings", model.EmbeddingHandler).Methods(http.MethodPost) aiRouter.HandleFunc("/embeddings", model.EmbeddingHandler).Methods(http.MethodPost)
// router.Handle("/model/uploadimage", http.MethodPost, sd.UploadHandler) // router.Handle("/model/uploadimage", http.MethodPost, sd.UploadHandler)

2
godo/model/data.go

@ -19,7 +19,7 @@ func GetConfigFile() (string, error) {
if !libs.PathExists(modelDir) { if !libs.PathExists(modelDir) {
os.MkdirAll(modelDir, 0755) os.MkdirAll(modelDir, 0755)
} }
configFile := filepath.Join(modelDir, "aimodel.json") configFile := filepath.Join(modelDir, "ai_model.json")
if !libs.PathExists(configFile) { if !libs.PathExists(configFile) {
// 如果文件不存在,则创建一个空的配置文件 // 如果文件不存在,则创建一个空的配置文件
err := os.WriteFile(configFile, []byte("[]"), 0644) err := os.WriteFile(configFile, []byte("[]"), 0644)

81
godo/model/op.go

@ -160,8 +160,6 @@ func ShowHandler(w http.ResponseWriter, r *http.Request) {
} }
} }
func extractParameterSize(sizeStr string, model string) (float64, bool) { func extractParameterSize(sizeStr string, model string) (float64, bool) {
// log.Printf("extractParameterSize: %s", sizeStr)
// log.Printf("extractParameterModel: %s", model)
// 尝试直接从原始sizeStr中提取数字,包括小数 // 尝试直接从原始sizeStr中提取数字,包括小数
if size, err := strconv.ParseFloat(strings.TrimSuffix(sizeStr, "B"), 64); err == nil { if size, err := strconv.ParseFloat(strings.TrimSuffix(sizeStr, "B"), 64); err == nil {
return size, true return size, true
@ -224,6 +222,65 @@ func getOllamaModels() ([]OllamaModelsInfo, error) {
return rest.Models, nil return rest.Models, nil
} }
func RefreshOllamaHandler(w http.ResponseWriter, r *http.Request) {
err := refreshOllamaModels(r)
if err != nil {
libs.ErrorMsg(w, "Refresh Ollama Models error")
return
}
//libs.SuccessMsg(w, nil, "Refresh Ollama Models success")
Tagshandler(w, r)
}
func refreshOllamaModels(r *http.Request) error {
modelList, err := getOllamaModels()
if err != nil {
return fmt.Errorf("load ollama error: %v", err)
}
// 将modelList中的数据写入reqBodyMap
for _, modelInfo := range modelList {
model := modelInfo.Model
if _, exists := reqBodyMap.Load(model); !exists {
// 创建一个新的ReqBody对象并填充相关信息
oinfo := parseOllamaInfo(modelInfo)
details, err := getOllamaInfo(r, model)
if err != nil {
log.Printf("Error getting ollama info: %v", err)
continue
}
architecture := details.ModelInfo["general.architecture"].(string)
contextLength := convertInt(details.ModelInfo, architecture+".context_length")
embeddingLength := convertInt(details.ModelInfo, architecture+".embedding_length")
paths, err := getManifests(model)
if err != nil {
log.Printf("Error parsing Manifests: %v", err)
continue
}
reqBody := ReqBody{
Model: model,
Status: "success",
CreatedAt: time.Now(),
}
reqBody.Info = ModelInfo{
Engine: "ollama",
From: "ollama",
Path: paths,
Size: oinfo.Size,
Quant: oinfo.Quant,
Desk: oinfo.Desk,
CPU: oinfo.CPU,
GPU: oinfo.GPU,
Template: details.Template,
Parameters: details.Parameters,
ContextLength: contextLength,
EmbeddingLength: embeddingLength,
}
// 将新的ReqBody对象写入reqBodyMap
reqBodyMap.Store(model, reqBody)
}
}
return nil
}
func setOllamaInfo(w http.ResponseWriter, r *http.Request, reqBody ReqBody) { func setOllamaInfo(w http.ResponseWriter, r *http.Request, reqBody ReqBody) {
model := reqBody.Model model := reqBody.Model
postQuery := map[string]interface{}{ postQuery := map[string]interface{}{
@ -251,8 +308,8 @@ func setOllamaInfo(w http.ResponseWriter, r *http.Request, reqBody ReqBody) {
if model.Model == reqBody.Model { if model.Model == reqBody.Model {
oinfo := parseOllamaInfo(model) oinfo := parseOllamaInfo(model)
architecture := details.ModelInfo["general.architecture"].(string) architecture := details.ModelInfo["general.architecture"].(string)
contextLength := details.ModelInfo[architecture+".context_length"].(int) contextLength := convertInt(details.ModelInfo, architecture+".context_length")
embeddingLength := details.ModelInfo[architecture+".embedding_length"].(int) embeddingLength := convertInt(details.ModelInfo, architecture+".embedding_length")
paths, err := getManifests(model.Model) paths, err := getManifests(model.Model)
if err != nil { if err != nil {
log.Printf("Error parsing Manifests: %v", err) log.Printf("Error parsing Manifests: %v", err)
@ -260,6 +317,8 @@ func setOllamaInfo(w http.ResponseWriter, r *http.Request, reqBody ReqBody) {
} }
reqBody.Info = ModelInfo{ reqBody.Info = ModelInfo{
Engine: reqBody.Info.Engine,
From: reqBody.Info.From,
Path: paths, Path: paths,
Size: oinfo.Size, Size: oinfo.Size,
Quant: oinfo.Quant, Quant: oinfo.Quant,
@ -282,6 +341,20 @@ func setOllamaInfo(w http.ResponseWriter, r *http.Request, reqBody ReqBody) {
} }
} }
} }
func convertInt(data map[string]interface{}, str string) int {
res := 0
if val, ok := data[str]; ok {
switch v := val.(type) {
case int:
res = v
case float64:
res = int(v)
default:
log.Printf("Unexpected type for embedding_length: %T", v)
}
}
return res
}
func getOllamaInfo(r *http.Request, model string) (OllamaModelDetail, error) { func getOllamaInfo(r *http.Request, model string) (OllamaModelDetail, error) {
infoQuery := map[string]interface{}{ infoQuery := map[string]interface{}{
"name": model, "name": model,

Loading…
Cancel
Save