Selaa lähdekoodia

优化模型列表

ageer 1 vuosi sitten
vanhempi
sitoutus
5efacb4e13
44 muutettua tiedostoa jossa 611 lisäystä ja 1795 poistoa
  1. 0 1
      src/api/index.ts
  2. 396 473
      src/api/mjapi.ts
  3. 20 16
      src/api/openapi.ts
  4. 2 2
      src/api/pay.ts
  5. 2 0
      src/api/sse/fetchsse.ts
  6. BIN
      src/assets/avatar.jpg
  7. 6 7
      src/components/common/PromptStore/index.vue
  8. 5 6
      src/components/common/Setting/About.vue
  9. 3 3
      src/components/common/Setting/General.vue
  10. 3 2
      src/components/common/Setting/index.vue
  11. 5 4
      src/components/common/UserAvatar/index.vue
  12. 0 9
      src/hooks/useLanguage.ts
  13. 0 190
      src/locales/en-US.ts
  14. 0 6
      src/locales/index.ts
  15. 0 185
      src/locales/ko-KR.ts
  16. 0 188
      src/locales/ru-RU.ts
  17. 0 187
      src/locales/vi-VN.ts
  18. 14 20
      src/locales/zh-CN.ts
  19. 0 181
      src/locales/zh-TW.ts
  20. 1 1
      src/router/index.ts
  21. 1 1
      src/router/permission.ts
  22. 2 3
      src/store/modules/app/helper.ts
  23. 11 0
      src/store/modules/auth/anth.ts
  24. 1 1
      src/store/modules/auth/helper.ts
  25. 1 6
      src/store/modules/auth/index.ts
  26. 0 8
      src/store/modules/chat/index.ts
  27. 1 1
      src/store/modules/user/index.ts
  28. 5 5
      src/utils/request/axios.ts
  29. 7 9
      src/utils/request/index.ts
  30. 2 0
      src/utils/storage/index.ts
  31. 7 12
      src/views/chat/components/Header/index.vue
  32. 11 18
      src/views/chat/components/Message/Text.vue
  33. 12 22
      src/views/chat/components/Message/index.vue
  34. 17 73
      src/views/chat/index.vue
  35. 11 31
      src/views/chat/layout/Layout.vue
  36. 2 1
      src/views/chat/layout/sider/Footer.vue
  37. 9 25
      src/views/chat/layout/sider/List.vue
  38. 1 1
      src/views/chat/layout/sider/index.vue
  39. 21 14
      src/views/mj/aiDall.vue
  40. 5 58
      src/views/mj/aiGptInput.vue
  41. 1 0
      src/views/mj/aiGptsCom.vue
  42. 1 1
      src/views/mj/aiMobileMenu.vue
  43. 7 7
      src/views/mj/aiModel.vue
  44. 18 17
      src/views/mj/aiSider.vue

+ 0 - 1
src/api/index.ts

@@ -73,5 +73,4 @@ export * from "./units"
 export * from "./mic"
 export * from "./chat"
 export * from "./sse/fetchsse"
-export * from "./Recognition"
 

+ 396 - 473
src/api/mjapi.ts

@@ -1,491 +1,414 @@
 
-import {  gptServerStore, homeStore, useAuthStore } from "@/store";
-import { copyToClip } from "@/utils/copy";
-import { getToken } from "@/store/modules/auth/helper";
-import { localGet, localSaveAny } from "./mjsave";
-import { t } from "@/locales";
-//import { useMessage } from "naive-ui";
-export interface gptsType{
-    gid:string
-    name:string
-    logo:string
-    info:string
-    use_cnt?:string
-    bad?:string|number
-}
- //const { addChat, updateChat, updateChatSome, getChatByUuidAndIndex } = useChat()
-export function upImg(file:any   ):Promise<any>
-{
-    const maxSize= homeStore.myData.session.uploadImgSize? (+homeStore.myData.session.uploadImgSize):1
-    return new Promise((h,r)=>{
-        const filename = file.name;
-        if(file.size>(1024*1024 * maxSize)){
-            r(t('mjchat.no1m',{m:maxSize}))
-            return ;
-        }
-        if (! (filename.endsWith('.jpg') ||
-            filename.endsWith('.gif') ||
-            filename.endsWith('.png') ||
-            filename.endsWith('.jpeg') )) {
-            r(t('mjchat.imgExt') );
-            return ;
-        }
-        const reader = new FileReader();
-        // 当读取操作完成时触发该事件
-        //reader.onload = (e:any)=> st.value.fileBase64 = e.target.result;
-        reader.onload = (e:any)=>  h( e.target.result);
-        reader.readAsDataURL(file);
-    })
-
-}
-
-export const file2blob= (selectedFile: any  )=>{
-    return new Promise<{blob:Blob,filename:string}>((resolve, reject) => {
-        const reader = new FileReader();
-        mlog('selectedFile', selectedFile )
-        reader.onload = function (event:any ) {
-            // 将文件内容转换为 Blob
-            const blob = new Blob([event.target.result], { type: selectedFile.type });
-
-            // 在这里可以使用生成的 Blob 对象
-            //console.log(blob);
-            resolve({blob,filename:selectedFile.name });
-        };
-        reader.onerror = (e)=> reject(e);
-
-        // 开始读取文件
-        reader.readAsArrayBuffer(selectedFile);
-
-    })
-
-}
-
-export const blob2file= ( blob:Blob,fileName:string )=>{
-    const file = new File([blob], fileName, { type: blob.type, lastModified: Date.now() });
-    return file;
-}
-
-export const  isFileMp3= (filename:string )=>{
-    let arr='.mp3, .mp4, .mpeg, .mpga, .m4a, .wav, .webm'.split(/[, ]+/ig);
-    mlog('fileIsMp3', arr );
-    filename= filename.toLocaleLowerCase();
-    for(let ext of arr ){
-        if(filename.endsWith(ext)) return true;
-    }
-    return false;
-}
-
-function containsChinese(str:string ) {
-  return false; //11.18 都不需要翻译
-//   var reg = /[\u4e00-\u9fa5]/g; // 匹配中文的正则表达式
-//   return reg.test(str);
-}
-
-export  async function train( text:string){
-
-    return new Promise<string>((resolve, reject) => {
-
-
-        if( text.trim()  =='') {
-           reject( t('mjchat.placeInput'));
-            return ;
-        }
-
-
-        if( !containsChinese(text.trim()) ){
-            resolve( text.trim() );
-            return ;
-        }
-
-        // myTranslate( text.trim())
-        //     .then((d:any)=>  resolve( d.content.replace(/[?.!]+$/, "")))
-        //     .catch(( )=>   reject('翻译发生错误'))
-        resolve( text.trim() )
-    })
-}
-
-export const mlog = (msg: string, ...args: unknown[]) => {
-    //localStorage.setItem('debug',1 )
-    const logStyles = [
-    // 'padding: 4px 8px',
-    // 'color: #fff',
-    // 'border-radius: 3px',
-    'color:',
-  ].join(';')
-    const debug= localStorage.getItem('debug')
-    if( !debug  ) return ;
-    const style = `${logStyles}${msg.includes('error') ? 'red' : '#dd9089'}`
-    console.log(`%c[mjgpt]`,  style, msg , ...args)
-}
-
-export const myTrim = (str: string, delimiter: string)=>{
-    // 构建正则表达式,使用动态的定界符
-    const regex = new RegExp(`^${delimiter}+|${delimiter}+$`, 'g');
-
-    // 使用正则表达式去除字符串两端的定界符
-    return str.replace(regex, '');
-}
-
-function getHeaderApiSecret(){
-    if(!gptServerStore.myData.MJ_API_SECRET){
-        const authStore = useAuthStore()
-        if( authStore.token ) return { 'x-ptoken':  authStore.token };
-        return {}
-    }
-    return {
-        'mj-api-secret':  import.meta.env.VITE_MJ_API_SECRET
-    }
-}
-
-const getUrl=(url:string)=>{
-    if(url.indexOf('http')==0) return url;
-    // if(gptServerStore.myData.MJ_SERVER){
-    //     return `${ gptServerStore.myData.MJ_SERVER}${url}`;
-    // }
-    return `/mjapi${url}`;
-}
-
-export const mjFetch=(url:string,data?:any)=>{
-    mlog('mjFetch2024', url  );
-    let header = {'Content-Type':'application/json'};
-    header= {...header,...getHeaderApiSecret() }
-
-    return new Promise<any>((resolve, reject) => {
-        let opt:RequestInit ={method:'GET'};
-        opt.headers=header;
-        if(data) {
-            opt.body= JSON.stringify(data) ;
-             opt.method='POST';
-        }
-        fetch(getUrl(url),  opt )
-        .then(d2=>d2.json().then(d=> {
-                if(d2.ok) resolve(d);
-                else{
-                    reject({error: d.error??  (d??'Network response was not ok!'),code:'response_fail',url:getUrl(url), status:d2.status })
-                }
-            }).catch(e=>reject({error:e? e.toString() :'json_error',code:'json_error',url:getUrl(url) , status:d2.status  }))
-        ).catch(e=>reject({error:e? e.toString() :'fetch fail',data ,code:'fetch_fail',url:getUrl(url)  }))
-    })
-
-}
-
-export const myFetch=(url:string,data?:any)=>{
-    //mlog('myFetch', url  );
-    let header = {'Content-Type':'application/json'};
-    //header= {...header  }
-
-    return new Promise<any>((resolve, reject) => {
-        let opt:RequestInit ={method:'GET'};
-        opt.headers=header;
-        if(data) {
-            opt.body= JSON.stringify(data) ;
-             opt.method='POST';
-        }
-        fetch(getUrl(url),  opt )
-        .then(d=>d.json().then(d=> resolve(d))
-        .catch(e=>reject(e)))
-        .catch(e=>reject(e))
-    })
-
-}
-export const my2Fetch=(url:string,data?:any)=>{
-    mlog('mjFetch', url  );
-    let header = {'Content-Type':'application/json'};
-    //header= {...header  }
-
-    return new Promise<any>((resolve, reject) => {
-        let opt:RequestInit ={method:'GET'};
-        opt.headers=header;
-        if(data) {
-            opt.body= JSON.stringify(data) ;
-             opt.method='POST';
-        }
-        fetch((url),  opt )
-        .then(d=>d.json().then(d=> resolve(d))
-        .catch(e=>reject(e)))
-        .catch(e=>reject(e))
-    })
-
-}
-
-
-export const flechTask= ( chat:Chat.Chat)=>{
-    let cnt=0;
-    const check= async ()=>{
-        cnt++;
-        if(!chat.mjID){
-            chat.text +="\n获取失败" ;
-            chat.loading=false;
-            homeStore.setMyData({act:'updateTask', actData:chat });
-            return ;
-        }
-        const ts=  await mjFetch(`/mj/task/${chat.mjID}/fetch`);
-        chat.opt= ts;
-        chat.loading=   (cnt>=99)?false:true;
-        //chat.progress=ts.progress;
-
-        if(ts.progress && ts.progress== "100%") chat.loading=false;
-
-        homeStore.setMyData({act:'updateChat', actData:chat });
-        //"NOT_START" //["SUBMITTED","IN_PROGRESS"].indexOf(ts.status)>-1
-        if( ["FAILURE","SUCCESS"].indexOf(ts.status)==-1 && cnt<100 ){
-
-            setTimeout(() =>   check( ) , 5000 )
-        }
-        mlog('task', ts.progress,ts, chat.uuid,chat.index  );
-    }
-    check();
-}
-export const subTask= async (data:any, chat:Chat.Chat )=>{
-   let d:any;
-   try{
+ import { gptServerStore, homeStore, useAuthStore } from "@/store";
+ import { copyToClip } from "@/utils/copy";
+ import { localGet, localSaveAny } from "./mjsave";
+ import { t } from "@/locales";
+
+ export interface gptsType{
+     gid:string
+     name:string
+     logo:string
+     info:string
+     use_cnt?:string
+     bad?:string|number
+ }
+  //const { addChat, updateChat, updateChatSome, getChatByUuidAndIndex } = useChat()
+ export function upImg(file:any   ):Promise<any>
+ {
+     const maxSize= homeStore.myData.session.uploadImgSize? (+homeStore.myData.session.uploadImgSize):1
+     return new Promise((h,r)=>{
+         const filename = file.name;
+         if(file.size>(1024*1024 * maxSize)){
+             r(t('mjchat.no1m',{m:maxSize}))
+             return ;
+         }
+         if (! (filename.endsWith('.jpg') ||
+             filename.endsWith('.gif') ||
+             filename.endsWith('.png') ||
+             filename.endsWith('.jpeg') )) {
+             r(t('mjchat.imgExt') );
+             return ;
+         }
+         const reader = new FileReader();
+         // 当读取操作完成时触发该事件
+         //reader.onload = (e:any)=> st.value.fileBase64 = e.target.result;
+         reader.onload = (e:any)=>  h( e.target.result);
+         reader.readAsDataURL(file);
+     })
+     
+ }
+ 
+ export const file2blob= (selectedFile: any  )=>{
+     return new Promise<{blob:Blob,filename:string}>((resolve, reject) => {
+         const reader = new FileReader();
+         mlog('selectedFile', selectedFile )
+         reader.onload = function (event:any ) {
+             // 将文件内容转换为 Blob
+             const blob = new Blob([event.target.result], { type: selectedFile.type });
+ 
+             // 在这里可以使用生成的 Blob 对象
+             //console.log(blob);
+             resolve({blob,filename:selectedFile.name });
+         };
+         reader.onerror = (e)=> reject(e);
+ 
+         // 开始读取文件
+         reader.readAsArrayBuffer(selectedFile);
+         
+     })
+      
+ }
+ 
+ export const blob2file= ( blob:Blob,fileName:string )=>{
+     const file = new File([blob], fileName, { type: blob.type, lastModified: Date.now() });
+     return file;
+ }
+ 
+ export const  isFileMp3= (filename:string )=>{
+     let arr='.mp3, .mp4, .mpeg, .mpga, .m4a, .wav, .webm'.split(/[, ]+/ig);
+     mlog('fileIsMp3', arr );
+     filename= filename.toLocaleLowerCase();
+     for(let ext of arr ){
+         if(filename.endsWith(ext)) return true;
+     }
+     return false;
+ }
+ 
+ function containsChinese(str:string ) {
+   return false; //11.18 都不需要翻译
+ //   var reg = /[\u4e00-\u9fa5]/g; // 匹配中文的正则表达式
+ //   return reg.test(str);
+ }
+ 
+ export  async function train( text:string){
+ 
+     return new Promise<string>((resolve, reject) => {
+ 
+ 
+         if( text.trim()  =='') {
+            reject( t('mjchat.placeInput'));
+             return ;
+         }
+ 
+         
+         if( !containsChinese(text.trim()) ){
+             resolve( text.trim() );
+             return ;
+         }
+         
+         // myTranslate( text.trim())
+         //     .then((d:any)=>  resolve( d.content.replace(/[?.!]+$/, "")))
+         //     .catch(( )=>   reject('翻译发生错误'))
+         resolve( text.trim() )
+     }) 
+ }
+ 
+ export const mlog = (msg: string, ...args: unknown[]) => {
+     //localStorage.setItem('debug',1 )
+     const logStyles = [
+     // 'padding: 4px 8px',
+     // 'color: #fff',
+     // 'border-radius: 3px',
+     'color:',
+   ].join(';')
+     const debug= localStorage.getItem('debug')
+     if( !debug  ) return ;
+     const style = `${logStyles}${msg.includes('error') ? 'red' : '#dd9089'}`
+     console.log(`%c[mjgpt]`,  style, msg , ...args)
+ }
+ 
+ export const myTrim = (str: string, delimiter: string)=>{
+     // 构建正则表达式,使用动态的定界符
+     const regex = new RegExp(`^${delimiter}+|${delimiter}+$`, 'g');
+     
+     // 使用正则表达式去除字符串两端的定界符
+     return str.replace(regex, '');
+ }
+ 
+ function getHeaderApiSecret(){
+     if(!gptServerStore.myData.MJ_API_SECRET){
+         const authStore = useAuthStore()
+         if( authStore.token ) return { 'x-ptoken':  authStore.token };
+         return {}
+     }
+     return {
+         'mj-api-secret':  gptServerStore.myData.MJ_API_SECRET
+     }
+ }
+ 
+ const getUrl=(url:string)=>{
+     if(url.indexOf('http')==0) return url;
+     if(gptServerStore.myData.MJ_SERVER){
+         return `${ gptServerStore.myData.MJ_SERVER}${url}`;
+     }
+     return `/mjapi${url}`;
+ }
+ 
+ export const mjFetch=(url:string,data?:any)=>{
+     mlog('mjFetch', url  );
+     let header = {'Content-Type':'application/json'};
+     header= {...header,...getHeaderApiSecret() }
+ 
+     return new Promise<any>((resolve, reject) => {
+         let opt:RequestInit ={method:'GET'}; 
+         opt.headers=header;
+         if(data) {
+             opt.body= JSON.stringify(data) ;
+              opt.method='POST';
+         }
+         fetch(getUrl(url),  opt )
+         .then(d=>d.json().then(d=> resolve(d))
+         .catch(e=>reject(e)))
+         .catch(e=>reject(e))
+     })
+      
+ }
+ 
+ export const myFetch=(url:string,data?:any)=>{
+     mlog('mjFetch', url  );
+     let header = {'Content-Type':'application/json'};
+     //header= {...header  }
+ 
+     return new Promise<any>((resolve, reject) => {
+         let opt:RequestInit ={method:'GET'}; 
+         opt.headers=header;
+         if(data) {
+             opt.body= JSON.stringify(data) ;
+              opt.method='POST';
+         }
+         fetch(getUrl(url),  opt )
+         .then(d=>d.json().then(d=> resolve(d))
+         .catch(e=>reject(e)))
+         .catch(e=>reject(e))
+     })
+      
+ }
+ export const my2Fetch=(url:string,data?:any)=>{
+     mlog('mjFetch', url  );
+     let header = {'Content-Type':'application/json'};
+     //header= {...header  }
+ 
+     return new Promise<any>((resolve, reject) => {
+         let opt:RequestInit ={method:'GET'}; 
+         opt.headers=header;
+         if(data) {
+             opt.body= JSON.stringify(data) ;
+              opt.method='POST';
+         }
+         fetch((url),  opt )
+         .then(d=>d.json().then(d=> resolve(d))
+         .catch(e=>reject(e)))
+         .catch(e=>reject(e))
+     })
+      
+ }
+ 
+ 
+ export const flechTask= ( chat:Chat.Chat)=>{
+     let cnt=0;
+     const check= async ()=>{
+         cnt++;
+         if(!chat.mjID){
+             chat.text +="\n获取失败" ;
+             chat.loading=false;
+             homeStore.setMyData({act:'updateTask', actData:chat });
+             return ;
+         }
+         const ts=  await mjFetch(`/mj/task/${chat.mjID}/fetch`);
+         chat.opt= ts;
+         chat.loading=   (cnt>=99)?false:true; 
+         //chat.progress=ts.progress;
+     
+         if(ts.progress && ts.progress== "100%") chat.loading=false;
+ 
+         homeStore.setMyData({act:'updateChat', actData:chat });
+         //"NOT_START" //["SUBMITTED","IN_PROGRESS"].indexOf(ts.status)>-1
+         if( ["FAILURE","SUCCESS"].indexOf(ts.status)==-1 && cnt<100 ){
+            
+             setTimeout(() =>   check( ) , 5000 )
+         } 
+         mlog('task', ts.progress,ts, chat.uuid,chat.index  );
+     }
+     check();
+ }
+ export const subTask= async (data:any, chat:Chat.Chat )=>{
+    let d:any;
+    
     //return ;
     if(  data.action &&data.action=='change' ){ //执行变化
-        d=  await mjFetch('/mj/submit/change' , data.data  );
+      d=  await mjFetch('/mj/submit/change' , data.data  );
     }else if( data.action &&data.action=="CustomZoom") { //自定义变焦
-            d =  await mjFetch('/mj/submit/action' , data.data  );
-            if(d.result){
-                let bdata= data.maskData;
-                bdata.taskId= d.result;
-                d=  await mjFetch('/mj/submit/modal' , bdata );
-            }
+          d =  await mjFetch('/mj/submit/action' , data.data  );
+         if(d.result){
+             let bdata= data.maskData;
+             bdata.taskId= d.result;
+             d=  await mjFetch('/mj/submit/modal' , bdata );
+         }
     }else if( data.action &&data.action=='mask') { //局部重绘
-        d =  await mjFetch('/mj/submit/action' , data.data  );
-        if(d.result){
-            let bdata= data.maskData;
-            bdata.taskId= d.result;
-            d=  await mjFetch('/mj/submit/modal' , bdata );
-        }
+      d =  await mjFetch('/mj/submit/action' , data.data  );
+      if(d.result){
+         let bdata= data.maskData;
+         bdata.taskId= d.result;
+         d=  await mjFetch('/mj/submit/modal' , bdata );
+      }
     }else if( data.action &&data.action=='blend') { //blend
-        d=  await mjFetch('/mj/submit/blend' ,  data.data );
-    }else if( data.action &&data.action=='shorten') { //shorten
-        d=  await mjFetch('/mj/submit/shorten' ,  data.data );
-        //  mlog('mjFetch shorten' , data );
-    }else if( data.action &&data.action=='face') { //换脸
-        d=  await mjFetch('/mj/insight-face/swap' , data.data  );
-        //mlog('换年服务', data.data );
-        //return;
-    }else if( data.action &&data.action=='img2txt') { //图生文
-            d=  await mjFetch('/mj/submit/describe' , data.data  );
+       d=  await mjFetch('/mj/submit/blend' ,  data.data );
+    }else if( data.action &&data.action=='shorten') { //shorten 
+       d=  await mjFetch('/mj/submit/shorten' ,  data.data );
+      //  mlog('mjFetch shorten' , data );
+    }else if( data.action &&data.action=='face') { //换脸 
+       d=  await mjFetch('/mj/insight-face/swap' , data.data  ); 
+       //mlog('换年服务', data.data );
+       //return; 
+    }else if( data.action &&data.action=='img2txt') { //图生文 
+         d=  await mjFetch('/mj/submit/describe' , data.data  ); 
     }else if( data.action &&data.action=='changeV2') { //执行动作!
-        d=  await mjFetch('/mj/submit/action' , data.data  );
+      d=  await mjFetch('/mj/submit/action' , data.data  );
     }else {
-        let toData =  {
-            "base64Array":data.fileBase64??[],
-            "notifyHook": "",
-            "prompt": data.drawText,
-            "state": "",
-            botType:'MID_JOURNEY'
-            };
-            if(data.bot && data.bot=='NIJI_JOURNEY'){
-                toData.botType= data.bot;
-            }
-            d=  await mjFetch('/mj/submit/imagine' ,toData );
-            mlog('submit',d );
-            //return ;
+     let toData =  {
+         "base64Array":data.fileBase64??[],
+         "notifyHook": "",
+         "prompt": data.drawText,
+         "state": "",
+         botType:'MID_JOURNEY'
+         };
+         if(data.bot && data.bot=='NIJI_JOURNEY'){
+             toData.botType= data.bot;
+         }
+         d=  await mjFetch('/mj/submit/imagine' ,toData );
+         mlog('submit',d );
+         //return ;
     }
     if(d.code==21){
         d=  await mjFetch('/mj/submit/modal' , { taskId:d.result} );
     }
-
-     backOpt(d, chat);
-   }catch(e:any ){
-     mlog('mjFetchError', e )
-     chat.text='失败!'+"\n```json\n"+JSON.stringify(e, null, 2)+"\n```\n";
-     chat.loading=false;
-     homeStore.setMyData({act:'updateChat', actData:chat });
-   }
-
-   //return ;
-   if(  data.action &&data.action=='change' ){ //执行变化
-     d=  await mjFetch('/mj/submit/change' , data.data  );
-   }else if( data.action &&data.action=="CustomZoom") { //自定义变焦
-         d =  await mjFetch('/mj/submit/action' , data.data  );
-        if(d.result){
-            let bdata= data.maskData;
-            bdata.taskId= d.result;
-            d=  await mjFetch('/mj/submit/modal' , bdata );
-        }
-   }else if( data.action &&data.action=='mask') { //局部重绘
-     d =  await mjFetch('/mj/submit/action' , data.data  );
-     if(d.result){
-        let bdata= data.maskData;
-        bdata.taskId= d.result;
-        d=  await mjFetch('/mj/submit/modal' , bdata );
+      
+    backOpt(d, chat);
+    
+     
+     //if( chat.uuid &&  chat.index) updateChat(chat.uuid,chat.index, chat)
+ }
+ const backOpt= (d:any, chat:Chat.Chat )=>{
+      if(d.code==1){
+         chat.text='提交成功!';
+         chat.mjID= d.result;
+         flechTask( chat )
+         chat.loading=true;
+         homeStore.setMyData({act:'updateChat', actData:chat });
+         //chat.m= d.result;
+     }else{
+         chat.text='失败!'+"\n```json\n"+JSON.stringify(d, null, 2)+"\n```\n";
+         chat.loading=false;
+         homeStore.setMyData({act:'updateChat', actData:chat });
      }
-   }else if( data.action &&data.action=='blend') { //blend
-      d=  await mjFetch('/mj/submit/blend' ,  data.data );
-   }else if( data.action &&data.action=='shorten') { //shorten
-      d=  await mjFetch('/mj/submit/shorten' ,  data.data );
-     //  mlog('mjFetch shorten' , data );
-   }else if( data.action &&data.action=='face') { //换脸
-      d=  await mjFetch('/mj/insight-face/swap' , data.data  );
-      //return;
-   }else if( data.action &&data.action=='img2txt') { //图生文
-        d=  await mjFetch('/mj/submit/describe' , data.data  );
-   }else if( data.action &&data.action=='changeV2') { //执行动作!
-     d=  await mjFetch('/mj/submit/action' , data.data  );
-   }else {
-    // 验证是否是付费用户
-    let headerAi = { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + getToken() };
-    let opt: RequestInit = { method: 'POST' };
-    let body = { prompt: data.prompt};
-    opt.body= JSON.stringify(body) ;
-    opt.headers = headerAi;
-    const response = fetch('/api/mjTask', opt);
-
-    const movies = JSON.parse(await (await response).text());
-    if(movies.code == 500){
-        chat.text='失败!'+"\n```json\n"+movies.msg+"\n```\n";
-        chat.loading=false;
-        homeStore.setMyData({act:'updateChat', actData:chat });
-        console.log("movies======",movies);
-        return
+ }
+ 
+ export const mjSeed= async ( mjid:string )=>{
+      const ts=  await mjFetch(`/mj/task/${mjid}/image-seed`);
+      return ts;
+ }
+ 
+ 
+ 
+ export const getSeed = async (cchat:Chat.Chat,message:any )=>{
+    // const message = useMessage();
+   // let cchat = props.chat;
+   if(!cchat.mjID ) return ;
+   let seed=0 ;
+   if(cchat.opt?.seed) seed =cchat.opt?.seed;
+   else{
+    try{
+         message.info('获取中...');
+       const res:any  = await mjSeed( cchat.mjID);
+       seed= res.result;
+       if(seed>0 ) {
+        
+         if ( cchat.opt ){
+           cchat.opt.seed = seed;
+ 
+            homeStore.setMyData({act:'updateChat', actData:cchat });
+         }
+         message.success('获取成功');
+       }
+       
+    } catch(e){
+       message.error('获取失败')
     }
-
-    let toData =  {
-        "base64Array":data.fileBase64??[],
-        "notifyHook": "",
-        "prompt": data.drawText,
-        "state": "",
-        botType:'MID_JOURNEY'
-        };
-        if(data.bot && data.bot=='NIJI_JOURNEY'){
-            toData.botType= data.bot;
-        }
-        d=  await mjFetch('/mj/submit/imagine' ,toData );
-        mlog('submit',d );
-        //return ;
    }
-   if(d.code==21){
-       d=  await mjFetch('/mj/submit/modal' , { taskId:d.result} );
+   mlog('getSeed',seed);
+   if(seed>0 ) {
+     await copyToClip(`${seed}`);
+     message.success('复制seed成功');
    }
-
-   backOpt(d, chat);
-
-
-    //if( chat.uuid &&  chat.index) updateChat(chat.uuid,chat.index, chat)
-}
-const backOpt= (d:any, chat:Chat.Chat )=>{
-     if(d.code==1){
-        chat.text='提交成功!';
-        chat.mjID= d.result;
-        flechTask( chat )
-        chat.loading=true;
-        homeStore.setMyData({act:'updateChat', actData:chat });
-        //chat.m= d.result;
-    }else{
-        chat.text='失败!'+"\n```json\n"+JSON.stringify(d, null, 2)+"\n```\n";
-        chat.loading=false;
-        homeStore.setMyData({act:'updateChat', actData:chat });
-    }
-}
-
-export const mjSeed= async ( mjid:string )=>{
-     const ts=  await mjFetch(`/mj/task/${mjid}/image-seed`);
-     return ts;
-}
-
-
-
-export const getSeed = async (cchat:Chat.Chat,message:any )=>{
-   // const message = useMessage();
-  // let cchat = props.chat;
-  if(!cchat.mjID ) return ;
-  let seed=0 ;
-  if(cchat.opt?.seed) seed =cchat.opt?.seed;
-  else{
-   try{
-        message.info('获取中...');
-      const res:any  = await mjSeed( cchat.mjID);
-      seed= res.result;
-      if(seed>0 ) {
-
-        if ( cchat.opt ){
-          cchat.opt.seed = seed;
-
-           homeStore.setMyData({act:'updateChat', actData:cchat });
-        }
-        message.success('获取成功');
+   
+ }
+ 
+ export const getLastVersion=  async ()=>{
+     const url='https://api.github.com/repos/Dooy/chatgpt-web-midjourney-proxy/tags?per_page=1';
+     const a= await myFetch(url);
+     mlog('lastVersion', a ); 
+     return a;
+     
+ }
+ 
+ export const canVisionModel= (model:string)=>{
+     //['gpt-4-all','gpt-4-v'].indexOf(model)==-1 && model.indexOf('gpt-4-gizmo')==-1
+     if( ['gpt-4-all','gpt-4-v','gpt-4v','gpt-3.5-net'].indexOf(model)>-1 ) return true;
+     if(model.indexOf('gpt-4-gizmo')>-1 )return true; 
+     return false;
+ }
+ 
+ export const isTTS= ( model:string )=>{
+     if(model.indexOf('tts-1')===0 )return true; 
+     return false ;
+ }
+ 
+ function isStringOnlyDigits(input: string): boolean {
+     // 使用正则表达式检查字符串是否只包含数字
+     const regex = /^[0-9]+$/;
+     return regex.test(input);
+ }
+ export const loadGallery  = async ()=>{
+      let localKey= 'mj-list-condition';
+      const d2:any = await localGet(localKey);
+      //mlog('d2',d2 , (Date.now()- d2.ctime));
+      if(d2 && (Date.now()- d2.ctime)<300*1000 ){
+ 
+         return d2.d as any[];
       }
-
-   } catch(e){
-      message.error('获取失败')
-   }
-  }
-  mlog('getSeed',seed);
-  if(seed>0 ) {
-    await copyToClip(`${seed}`);
-    message.success('复制seed成功');
-  }
-
-}
-
-export const getLastVersion=  async ()=>{
-    const url='https://api.github.com/repos/Dooy/chatgpt-web-midjourney-proxy/tags?per_page=1';
-    const a= await myFetch(url);
-    mlog('lastVersion', a );
-    return a;
-
-}
-
-export const canVisionModel= (model:string)=>{
-    //['gpt-4-all','gpt-4-v'].indexOf(model)==-1 && model.indexOf('gpt-4-gizmo')==-1
-    if( ['gpt-4-all','gpt-4-v','gpt-4v','gpt-3.5-net'].indexOf(model)>-1 ) return true;
-    if(model.indexOf('gpt-4-gizmo')>-1 )return true;
-    return false;
-}
-
-export const isTTS= ( model:string )=>{
-    if(model.indexOf('tts-1')===0 )return true;
-    return false ;
-}
-
-function isStringOnlyDigits(input: string): boolean {
-    // 使用正则表达式检查字符串是否只包含数字
-    const regex = /^[0-9]+$/;
-    return regex.test(input);
-}
-export const loadGallery  = async ()=>{
-     let localKey= 'mj-list-condition';
-     const d2:any = await localGet(localKey);
-     //mlog('d2',d2 , (Date.now()- d2.ctime));
-     if(d2 && (Date.now()- d2.ctime)<300*1000 ){
-
-        return d2.d as any[];
+      let  d =  await mjFetch(`/mj/gallery`);
+      //mlog('tsList', d.data.list   );
+      if( !d.data.list  ||  d.data.list.length ==0 ) return [];
+      const list =d.data.list as any[];
+      const ids = list.filter(v=> isStringOnlyDigits(v.reqid)).map(v=> +v.reqid ) ;
+      mlog('ids',  ids   );
+      if(ids.length==0) return [];
+      ///mj/task/list-by-condition
+      d=  await mjFetch('/mj/task/list-by-condition',{ids } );
+ 
+      if( d.length>0 ) localSaveAny({ctime: Date.now(), d}, localKey);
+      return d as any[] ;
+ }
+ 
+ //从剪贴板中读取文件
+ export   function getFileFromClipboard(event:any ){
+     let rz=[];
+     if ( event.clipboardData || event.originalEvent ) {
+         let clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
+         if (clipboardData.items) {
+             let items = clipboardData.items;
+             // mlog('getFileFromClipboard',  items  );
+             for (let i = 0; i < items.length; i++) {
+                 if (items[i].type.indexOf("image") !== -1 || items[i].kind === 'file') {
+                     //rz.push( await fileToBase64(  items[i].getAsFile()) );
+                     //mlog('fff', items[i] );
+                     rz.push( items[i].getAsFile()) 
+                 }
+             }
+ 
+         }
      }
-     let  d =  await mjFetch(`/mj/gallery`);
-     //mlog('tsList', d.data.list   );
-     if( !d.data.list  ||  d.data.list.length ==0 ) return [];
-     const list =d.data.list as any[];
-     const ids = list.filter(v=> isStringOnlyDigits(v.reqid)).map(v=> +v.reqid ) ;
-     mlog('ids',  ids   );
-     if(ids.length==0) return [];
-     ///mj/task/list-by-condition
-     d=  await mjFetch('/mj/task/list-by-condition',{ids } );
-
-     if( d.length>0 ) localSaveAny({ctime: Date.now(), d}, localKey);
-     return d as any[] ;
-}
-
-//从剪贴板中读取文件
-export   function getFileFromClipboard(event:any ){
-    let rz=[];
-    if ( event.clipboardData || event.originalEvent ) {
-        let clipboardData = (event.clipboardData || event.originalEvent.clipboardData);
-        if (clipboardData.items) {
-            let items = clipboardData.items;
-            // mlog('getFileFromClipboard',  items  );
-            for (let i = 0; i < items.length; i++) {
-                if (items[i].type.indexOf("image") !== -1 || items[i].kind === 'file') {
-                    //rz.push( await fileToBase64(  items[i].getAsFile()) );
-                    //mlog('fff', items[i] );
-                    rz.push( items[i].getAsFile())
-                }
-            }
-
-        }
-    }
-    //console.log('passs>>' ,rz );
-    return rz;
-}
+     //console.log('passs>>' ,rz );
+     return rz;
+ }
+ 

+ 20 - 16
src/api/openapi.ts

@@ -33,7 +33,7 @@ const getUrl=(url:string)=>{
 export const gptGetUrl = getUrl
 export const gptFetch=(url:string,data?:any,opt2?:any )=>{
     mlog('gptFetch', url  );
-    let headers= {'Content-Type':'application/json','Authorization':'Bearer ' + getToken()}
+    let headers= {'Content-Type':'application/json'}
     if(opt2 && opt2.headers ) headers= opt2.headers;
 
     headers={...headers,...getHeaderAuthorization()}
@@ -60,7 +60,7 @@ function uploadR2(file: File) {
 	return new Promise<any>((resolve, reject) => {
 			//预签名
 			axios.post(gptGetUrl("/pre_signed"), { file_name: file.name, content_type: file.type }, {
-					headers: { 'Content-Type': 'application/json' }
+					headers: {'Content-Type':'application/json','Authorization':'Bearer ' + getToken()}
 			}).then(response => {
 							if (response.data.status == "Success") {
 									const signedUrl = response.data.data.up;
@@ -125,7 +125,7 @@ export const GptUploader =   ( url:string, FormData:FormData )=>{
 }
 
 export const whisperUpload = ( FormData:FormData )=>{
-    const url = gptGetUrl('/audio');
+    const url = gptGetUrl('/v1/audio/transcriptions');
     let headers=   {'Content-Type': 'multipart/form-data' }
     headers={...headers,...getHeaderAuthorization()}
     return new Promise<any>((resolve, reject) => {
@@ -143,7 +143,7 @@ export const subGPT= async (data:any, chat:Chat.Chat )=>{
    if(  action=='gpt.dall-e-3' ){ //执行变化
        // chat.model= 'dall-e-3';
 
-       let d= await gptFetch('/dall3', data.data);
+       let d= await gptFetch('/v1/images/generations', data.data);
        try{
             const rz : any= d.data[0];
             chat.text= rz.revised_prompt??`图片已完成`;
@@ -224,11 +224,15 @@ export const subModel= async (opt: subModelType)=>{
             "messages": opt.message
            ,stream:true
         }
+        //
 
-        let headers=   {'Content-Type': 'application/json;charset=UTF-8',
-                        'Authorization':'Bearer ' + getToken(),
-                        'Accept': 'text/event-stream '}
+        let  headers ={
+                'Content-Type': 'application/json'
+                //,'Authorization': 'Bearer ' +gptServerStore.myData.OPENAI_API_KEY
+                ,'Accept': 'text/event-stream '
+        }
         headers={...headers,...getHeaderAuthorization()}
+
         try {
          await fetchSSE( gptGetUrl('/chat'),{
             method: 'POST',
@@ -275,7 +279,7 @@ export interface ttsType{
 }
 export const subTTS = async (tts:ttsType )=>{
     if(!tts.voice) tts.voice='alloy';
-    let url= getUrl('/speech');
+    let url= getUrl('/v1/audio/speech');
     let headers=  {
         'Content-Type': 'application/json'
       }
@@ -359,9 +363,9 @@ export const openaiSetting= ( q:any )=>{
             gptServerStore.setMyData(  {OPENAI_API_BASE_URL:url, MJ_SERVER:url, OPENAI_API_KEY:key,MJ_API_SECRET:key } )
             blurClean();
             gptServerStore.setMyData( gptServerStore.myData );
-
+            
         } catch (error) {
-
+            
         }
     }
     else if(isObject(q)){
@@ -401,7 +405,7 @@ export const countTokens= async ( dataSources:Chat.Chat[], input:string ,uuid:nu
     const msg= await getHistoryMessage(  dataSources,1 ) ;
     rz.history= msg.length==0?0: encodeChat(msg, model.indexOf('gpt-4')>-1? 'gpt-4':'gpt-3.5-turbo').length
     //
-    rz.remain = unit *max- rz.history- rz.planOuter- rz.input- rz.system;
+    rz.remain = unit *max- rz.history- rz.planOuter- rz.input- rz.system; 
 
     return rz ;
 }
@@ -416,12 +420,12 @@ const getModelMax=( model:string )=>{
         return 32;
     }else if( model.indexOf('64k')>-1  ){
         return 64;
-    }else if( model.indexOf('128k')>-1
-    || model=='gpt-4-1106-preview'
-    || model=='gpt-4-0125-preview'
+    }else if( model.indexOf('128k')>-1 
+    || model=='gpt-4-1106-preview' 
+    || model=='gpt-4-0125-preview' 
     || model=='gpt-4-vision-preview' ){
-        return 128;
-    }else if( model.indexOf('gpt-4')>-1  ){
+        return 128; 
+    }else if( model.indexOf('gpt-4')>-1  ){  
         max=8;
     }
 

+ 2 - 2
src/api/pay.ts

@@ -1,3 +1,4 @@
+import { post} from '@/utils/request/'
 import request from '@/utils/request/req';
 export interface OrderReq {
 	money:string; // 商品价格
@@ -5,9 +6,8 @@ export interface OrderReq {
 }
 
 export function payUrl(params:OrderReq) {
-	return request({
+	return post({
 		url: '/pay/payUrl',
-		method: 'post',
 		data: params,
 	})
 }

+ 2 - 0
src/api/sse/fetchsse.ts

@@ -19,7 +19,9 @@ export async function fetchSSE(
   let res ;
   try{
      res = await fetch(url, fetchOptions)
+     console.log("res==========",res)
   }catch(e :any ){ 
+    console.log("res==========",res)
     throw {reason: JSON.stringify({message:'fetch error, pleace check url',url ,code:'fetch_error'}) } 
   }
   if (!res.ok) {

BIN
src/assets/avatar.jpg


+ 6 - 7
src/components/common/PromptStore/index.vue

@@ -39,7 +39,6 @@ let intervalId: string | number | NodeJS.Timer | undefined;
 async function getPayUrl(money: string, name: string) {
 	showMeVisible.value = true;
 	const response = await payUrl({ money: money, name: name });
-	console.log("response===", response)
 	imageUrl.value = response.data.url;
 	orderMoney.value = money
 	orderName.value = name
@@ -279,7 +278,7 @@ watch(showMeVisible, (newValue, oldValue) => {
 								</template>
 							</n-tag> -->
 						</n-space>
-
+					
 						<template #footer>
 							<div @click="getPayUrl('60', '高级套餐')" class="outer-container">
 									<NButton>
@@ -295,7 +294,7 @@ watch(showMeVisible, (newValue, oldValue) => {
 					justifyContent: center;
 					alignItems: center;">
 						<n-table :bordered="false" :single-line="false">
-
+							
 							<thead>
 							<tr>
 								<th>模型名称(通常1000个Token约等于750个英文单词或者400~500个汉字)</th>
@@ -323,18 +322,18 @@ watch(showMeVisible, (newValue, oldValue) => {
 								<td>gpt-4-1106-preview</td>
 								<td>0.3元/1K tokens</td>
 								<td>最新版GPT-4,相对GPT-3.5更先进、拥有更多的参数和更强大的语言处理能力</td>
-
+								
 							</tr>
 							<tr>
 								<td>gpt-4-1106-vision-preview</td>
 								<td>0.3元/1K tokens</td>
 								<td> GPT-4 的一个包含视觉处理能力的预览版本,结合了视觉信息处理的能力</td>
-							</tr>
+							</tr>	
 							<tr>
 								<td>gpt4all</td>
 								<td>0.3元/次</td>
 								<td>同时拥有联网查询,高级数据分析,画图 DALL.E功能,GPT 会自动识别并调取相关能力工具</td>
-
+								
 							</tr>
 							<tr>
 								<td>gpt-4-gizmo</td>
@@ -389,4 +388,4 @@ watch(showMeVisible, (newValue, oldValue) => {
     display: flex; /* 设置外部容器为 Flexbox */
     justify-content: center; /* 水平居中对齐子项目 */
 }
-</style>
+</style>

+ 5 - 6
src/components/common/Setting/About.vue

@@ -1,6 +1,5 @@
 <script setup lang='ts'>
   import { NCard,NImage } from 'naive-ui'
-  import defaultAvatar from '@/assets/01.png'
 </script>
 
 <template>
@@ -8,11 +7,11 @@
     <div style="text-align:center">
       <span>联系客服</span>
       <br>
-      <n-image style="margin: 20px;" width="150" :src="defaultAvatar"/>
+      <n-image style="margin: 20px;" width="150" src="http://43.139.70.230:6553/down/v7929z21iHCh.png"/>
       <br>
-
+ 
     </div>
-
+       
       <template #action>
         <div class="p-2 space-y-2 rounded-md">
         <p>
@@ -24,10 +23,10 @@
           >
           Github
           </a>
-          ,如果你觉得此项目对你有帮助,请在Github点个Star谢谢!
+          ,如果你觉得此项目对你有帮助,请在Github帮我点个Star,谢谢!
         </p>
       </div>
       </template>
-
+ 
   </n-card>
 </template>

+ 3 - 3
src/components/common/Setting/General.vue

@@ -80,7 +80,7 @@ async function getLoginUserInfo() {
   if (err) {
         message.error(err.toString())
   }
-  if(newUserInfo){
+  if(newUserInfo){ 
     userBalance.value = newUserInfo.data.user.userBalance
     fileList.value[0].url = newUserInfo.data.user.avatar
     userGrade.value = newUserInfo.data.user.userGrade
@@ -117,8 +117,8 @@ function handleFinish({
     <div class="space-y-6">
       <div class="flex items-center space-x-4">
         <span class="flex-shrink-0 w-[100px]">头像</span>
-        <n-upload action="/api/system/user/edit/avatar"
-          :max=1
+        <n-upload action="/api/system/user/edit/avatar" 
+          :max=1 
           list-type="image-card"
           :default-file-list="fileList"
           :headers="headers" @finish="handleFinish">

+ 3 - 2
src/components/common/Setting/index.vue

@@ -48,11 +48,12 @@ const show = computed({
             <General />
           </div>
         </NTabPane>
+        
         <NTabPane v-if="isChatGPTAPI" name="Advanced" tab="Advanced">
           <template #tab>
             <SvgIcon class="text-lg" icon="ri:equalizer-line" />
             <!-- <span class="ml-2">{{ $t('setting.advanced') }}</span> -->
-            <span class="ml-2">{{ $t('mjset.model') }}</span>
+            <span class="ml-2">模型</span>
           </template>
           <div class="min-h-[100px]">
             <!-- <Advanced /> -->
@@ -63,7 +64,7 @@ const show = computed({
         <NTabPane name="Config" tab="Config">
           <template #tab>
             <SvgIcon class="text-lg" icon="ri:list-settings-line" />
-            <span class="ml-2">{{ $t('mjset.about') }}</span>
+            <span class="ml-2">关于</span>
           </template>
           <About />
         </NTabPane>

+ 5 - 4
src/components/common/UserAvatar/index.vue

@@ -6,6 +6,7 @@ import { isString } from '@/utils/is'
 import { removeToken } from '@/store/modules/auth/helper'
 import { useRouter } from 'vue-router'
 import { loginOut,getUserInfo} from '@/api/user'
+import { UserData } from "@/typings/user"
 import { defaultSetting,UserInfo } from '@/store/modules/user/helper'
 import to from "await-to-js";
 
@@ -20,16 +21,16 @@ onMounted(() => { getLoginUserInfo() });
  */
 
 async function getLoginUserInfo() {
-  const [err, newUserInfo] = await to(getUserInfo());
+  const [err, newUserInfo] = await to(getUserInfo<UserData>());
       if (err) {
         message.error(err.toString())
       }
-  if(newUserInfo){
+  if(newUserInfo){ 
     userInfo.value.avatar = newUserInfo.data.user.avatar;
     userInfo.value.name = newUserInfo.data.user.nickName;
     userInfo.value.userBalance = newUserInfo.data.user.userBalance;
-  }
-}
+  } 
+}  
 
 /**
  * 退出登录

+ 0 - 9
src/hooks/useLanguage.ts

@@ -23,15 +23,6 @@ export function useLanguage() {
       case 'zh-TW':
         setLocale('zh-TW')
         return zhTW
-      case 'vi-VN':
-        setLocale('vi-VN')
-        return zhTW
-      case 'fr-FR':
-        setLocale('fr-FR')
-        return enUS
-      case 'tr-TR':
-        setLocale('tr-TR')
-        return enUS  
       default:
         setLocale('zh-CN')
         return zhCN

+ 0 - 190
src/locales/en-US.ts

@@ -93,194 +93,4 @@ export default {
     onlineImportWarning: 'Note: Please check the JSON file source!',
     downloadError: 'Please check the network status and JSON file validity',
   },
-
-
-  "mj": {
-    "setOpen": "OpenAI Related",
-    "setOpenPlaceholder": "Must include http(s)://",
-    "setOpenUrl": "OpenAI API Address",
-    "setOpenKeyPlaceholder": "Use custom OpenAI Key to bypass password access restrictions",
-    "setMj": "Midjourney Related",
-    "setMjUrl": "Midjourney API Address:",
-    "setMjKeyPlaceholder": "Use custom Api Secret to bypass password access restrictions",
-    "setUploader": "Upload Related",
-    "setUploaderUrl": "Upload Address:",
-    "setBtSave": "Save",
-    "setBtBack": "Restore Default",
-
-    "redraw": "Redraw",
-  "fail1": "Please be patient, it's loading.",
-  "success1": "Image refreshed successfully!",
-  "high_variation": "Strong Variation",
-  "low_variation": "Weak Variation",
-  "p15": "Zoom 1.5x",
-  "p20": "Zoom 2x",
-  "p100": "Normal",
-  "retry": "Retry",
-  "pan_left": "Left",
-  "pan_right": "Right",
-  "pan_up": "Up",
-  "pan_down": "Down",
-  "up2": "HD 2x",
-  "up4": "HD 4x" , 
-
-  "thinking": "Thinking...",
-  "noReUpload": "Cannot re-upload",
-  "uploading": "Uploading...",
-  "uploadSuccess": "Upload successful",
-  "uploadFail": "Upload failed:",
-  "upPdf": "<span>Upload image or attachment<br/>You can upload images, PDFs, EXCEL, and other documents</span><p>Supports drag and drop</p>",
-  "upImg": "<span><b>Upload image</b><br/>Will automatically invoke the gpt-4-vision-preview model<br>Note: Additional image fees may apply<br/>Formats: jpeg, jpg, png, gif</span><p>Supports drag and drop</p> <p class=\"pt-2\"><b>Upload MP3 MP4</b> <br>Will automatically invoke the whisper-1 model<br>Formats: mp3, mp4, mpeg, mpga, m4a, wav, webm</p>",
-  "clearAll": "Clear parameters",
-  "czoom": "Custom",
-  "customTitle": "Custom zoom",
-  "zoominfo": "Modify zoom value, range from 1.0 to 2.0, default is set to 1.8",
-
-  "modleSuccess": "Model loaded successfully",
-  "setingSuccess": "Settings successful",
-
-  "tokenInfo1": "Remaining Tokens = Model Length - Role Setting - Context (Conversation History) - Replies Count - Current Input",
-    "tokenInfo2": "Leave the role setting blank, and the system will provide a default one.",
-    "noSuppertModel": "Refresh, this model is not currently supported!",
-    "failOcr": "Recognition failed",
-    "remain": "Remain:",
-  
-  "totalUsage": "Total subscription amount",
-  "disableGpt4": "GPT4 disabled",
-  "setTextInfo": "OpenAI API Key error, click here to retry",
-
-  "attr1": "Attr",
-  "ulink": "Image Link",
-  "copyFail": "Copy Failed",
-  "tts": "Text to Speech",
-  "fail": "Error",
-  "noSupperChrom": "Browser not supported!",
-  "lang": "Voice",
-  "ttsLoading": "Converting to Speech...",
-  "ttsSuccess": "Conversion successful",
-  "micIng": "Recording, say something...",
-  "mStart": "Start",
-  "mPause": "Pause",
-  "mGoon": "Continue",
-  "mRecord": "Re-record",
-  "mPlay": "Play",
-  "mCanel": "Cancel",
-  "mSent": "Send",
-
-  "findVersion": "Discover updated version",
-  "yesLastVersion": "Already on the latest version",
-  "infoStar": 'This project is open source on <a class="text-blue-600 dark:text-blue-500" href="https://github.com/Dooy/chatgpt-web-midjourney-proxy\" target="_blank">GitHub</a>, free, and based on the MIT license with no form of payment! </p><p>If you find this project helpful, please give it a Star on GitHub, thank you!',
-  "setBtSaveChat": "Save chat only",
-  "setBtSaveSys": "Save to system",
-  "wsrvClose": "Close wsrv",
-  "wsrvOpen": "Open wsrv",
-
-  "temperature": "Temperature",
-  "temperatureInfo": "As the (temperature) value increases, the responses become more random",
-  "top_p": "Top",
-  "top_pInfo": "(top_p) is similar to randomness but should not be changed together with temperature",
-  "presence_penalty": "Presence",
-  "presence_penaltyInfo": "As the (presence_penalty) value increases, there is a higher chance of expanding to new topics",
-  "frequency_penalty": "Frequency",
-  "frequency_penaltyInfo": "As the (frequency_penalty) value increases, there is a higher likelihood of reducing repeated words",
-  "tts_voice": "Voice Role",
-  "typing": "Typing",
-  "authErro": "Authorization failed",
-  "authBt": "Please enter the authorization access password again" ,
-  "micWhisper": "Whisper speech recognition",
-  "micAsr": "Instant recognition",
-  "micRec": "Start recording, please speak! It will automatically stop if there is no sound for 2 seconds.",
-  "micRecEnd": "Recording has ended"
-  },
-  "mjset": {
-    "server": "Server",
-    "about": "About",
-    "model": "Model",
-    "sysname": "AI Drawing"
-  },
-  "mjtab": {
-    "chat": "Chat",
-    "draw": "Drawing",
-    "drawinfo": "AI Drawing with Midjourney Engine",
-    "gallery": "Gallery",
-    "galleryInfo": "My Gallery"
-  },
-  "mjchat": {
-    "loading": "Loading Image",
-    "openurl": "Open Link Directly",
-    "failReason": "Failure Reason:",
-    "reload": "Reload",
-    "progress": "Progress:",
-    "wait": "Task has been submitted, please wait...",
-    "reroll": "Redraw",
-    "wait2": "Task {id} has been submitted, please wait",
-    "redrawEditing": "Partial Redraw Editing",
-    "face": "Change Face",
-    "blend": "Blend Images",
-    "draw": "Drawing",
-    "submiting": "Submitting",
-    "submit": "Submit",
-    "wait3": "Please do not close! Image is being generated...",
-    "success": "Save Successful",
-    "successTitle": "Success",
-    "modlePlaceholder": "Custom models, separated by spaces (optional)",
-    "myModle": "Custom Models",
-    "historyCnt": "Context Count",
-    "historyToken": "More context improves accuracy but consumes more credits",
-    "historyTCnt": "Reply Count",
-    "historyTCntInfo": "Higher reply count may consume more credits",
-    "role": "Role Setting",
-    "rolePlaceholder": "Set an exclusive role for your conversation (optional)",
-    "loading2": "Loading...",
-    "loadmore": "Load More",
-    "nofind": "Unable to find",
-    "nofind2": "related content. You can try the following:",
-    "success2": "Switch Successful!",
-    "modelChange": "Model Change",
-    "search": "Search",
-    "searchPlaceholder": "GPT names, descriptions",
-    "attr": "Attachments",
-    "noproduct": "Gallery has no entries yet",
-    "myGallery": "My Gallery",
-    "yourHead": "Your Avatar",
-    "your2Head": "Celebrity Image",
-    "tipInfo": "Note:<li>1. Images must include faces for proper rendering</li><li>2. 'Celebrity Image' can be created using MJ drawing</li><li>3. 'Celebrity Image' can also include anime characters</li><li>4. 'Your Avatar' is recommended to be a passport-sized personal photo</li>",
-    "placeInput": "Please fill in the prompt!",
-    "more5sb": "Upload up to 5 images at most",
-    "exSuccess": "Export successful... Please check the download folder",
-    "downloadSave": "ai_drawing.txt",
-    "noproducet": "No mature works for now",
-    "imgBili": "Image Ratio",
-    "imagEx": "Export Artwork Image Links",
-    "prompt": "Prompts",
-    "imgCYes": "Contains Base Image",
-    "imgCUpload": "Upload Base Image",
-    "imgCInfo": "Base Image Info:<br/>1. Use your own images as a base for MJ drawing<br/>2. You can use multiple base images, up to 5, each not exceeding 1M in size",
-    "imgCadd": "+Add",
-    "del": "Delete",
-    "img2text": "Image-to-Text",
-    "img2textinfo": "Not sure what prompts to use? Try Image-to-Text! Submit an image to get prompts",
-    "traning": "Translating...",
-    "imgcreate": "Generate Image",
-    "imginfo": "Other parameters:<li>1 --no: Ignore --no car to exclude cars from the image</li><li>2 --seed: Obtain a seed first with --seed 123456</li><li>3 --chaos 10: Mix (range: 0-100)</li><li>4 --tile: Fragmentation</li>",
-    "tStyle": "Style",
-    "tView": "View",
-    "tShot": "Character Shot",
-    "tLight": "Lighting",
-    "tQuality": "Image Quality",
-    "tStyles": "Artistic Level",
-    "tVersion": "Model Version",
-    "dalleInfo": "Note:<li>1. DALL-E is an image generation model provided by OpenAI</li><li>2. OpenAI images have an expiration date, so make backups</li><li>3. Note: The price of 1790px images is double</li>",
-    "version": "Version",
-    "size": "Size",
-    "blendInfo": "Note:<li>1. Blend at least 2 images</li><li>2. Up to 6 images can be used for blending</li>",
-    "blendStart": "Start Blending",
-    "no2add": "Do not add duplicate images",
-    "add2more": "Please add two or more images",
-    "no1m": "Image size cannot exceed 1M",
-    "imgExt": "Images support only jpg, gif, png, jpeg formats"
-  }
-
-
-
 }

+ 0 - 6
src/locales/index.ts

@@ -5,9 +5,6 @@ import koKR from './ko-KR'
 import zhCN from './zh-CN'
 import zhTW from './zh-TW'
 import ruRU from './ru-RU'
-import viVn from './vi-VN'
-import frFr from './fr-FR'
-import trTr from './tr-TR'
 import { useAppStoreWithOut } from '@/store/modules/app'
 import type { Language } from '@/store/modules/app/helper'
 
@@ -25,9 +22,6 @@ const i18n = createI18n({
     'zh-CN': zhCN,
     'zh-TW': zhTW,
     'ru-RU': ruRU,
-    'vi-VN': viVn,
-    'fr-FR': frFr,
-    'tr-TR': trTr,
   },
 })
 

+ 0 - 185
src/locales/ko-KR.ts

@@ -92,189 +92,4 @@ export default {
     importRepeatContent: '내용이 반복되어 건너뜀: {msg}',
     onlineImportWarning: '참고: JSON 파일 소스를 확인하십시오!',
   },
-
-  "mj": {
-    "setOpen": "OpenAI 관련",
-    "setOpenPlaceholder": "http(s)://를 포함해야 함"
-    ,"setOpenUrl": "OpenAI 인터페이스 주소"
-    ,"setOpenKeyPlaceholder": "비밀번호 액세스 제한을 우회하기 위해 사용자 지정 OpenAI 키 사용"
-    ,"setMj": "Midjourney 관련"
-    ,"setMjUrl": "Midjourney 인터페이스 주소:"
-    ,"setMjKeyPlaceholder": "비밀번호 액세스 제한을 우회하기 위해 사용자 지정 Api Secret 사용"
-    ,"setUploader": "업로드 관련"
-    ,"setUploaderUrl": "업로드 주소:"
-    ,"setBtSave": "저장"
-    ,"setBtBack": "기본으로 복원",
-    "redraw": "부분 재그림",
-    "fail1": "고객님은 너무 급해하지 마세요. 로딩 중입니다.",
-    "success1": "이미지가 성공적으로 새로고쳐졌습니다!",
-    "high_variation": "강한 변화",
-    "low_variation": "약한 변화",
-    "p15": "확대 1.5배",
-    "p20": "확대 2배",
-    "p100": "표준",
-    "retry": "분석 다시 시도",
-    "pan_left": "왼쪽으로 다시 분석",
-    "pan_right": "오른쪽으로 다시 분석",
-    "pan_up": "위로 다시 분석",
-    "pan_down": "아래로 다시 분석",
-    "up2": "고화질 2배",
-    "up4": "고화질 4배" ,
-
-    "thinking": "생각 중...",
-    "noReUpload": "다시 업로드할 수 없습니다",
-    "uploading": "업로딩 중...",
-    "uploadSuccess": "업로드 성공",
-    "uploadFail": "업로드 실패:",
-    "upPdf": "<span>이미지 또는 첨부 파일 업로드<br/>이미지, PDF, EXCEL 및 기타 문서를 업로드할 수 있습니다</span><p>드래그 앤 드롭 지원</p>",
-    "upImg": "<span><b>이미지 업로드</b><br/>자동으로 gpt-4-vision-preview 모델을 호출합니다<br>참고: 추가 이미지 비용이 발생할 수 있습니다<br/>포맷: jpeg, jpg, png, gif</span><p>드래그 앤 드롭 지원</p> <p class=\"pt-2\"><b>MP3 MP4 업로드</b> <br>자동으로 whisper-1 모델을 호출합니다<br>포맷: mp3, mp4, mpeg, mpga, m4a, wav, webm</p>",
-    "clearAll": "매개변수 지우기",
-    "czoom": "사용자 정의",
-    "customTitle": "사용자 정의 줌",
-    "zoominfo": "줌 값 수정, 범위는 1.0에서 2.0까지이며 기본 설정은 1.8로 설정됩니다",
-
-    "modleSuccess": "모델이 성공적으로 로드되었습니다",
-    "setingSuccess": "설정이 성공적으로 완료되었습니다",
-    "tokenInfo1": "남은 토큰 = 모델 길이 - 역할 설정 - 컨텍스트 (대화 기록) - 답변 수 - 현재 입력",
-    "tokenInfo2": "역할 설정을 비워두면 시스템에서 기본 값을 제공합니다.",
-    "noSuppertModel": "새로 고침, 현재 이 모델은 지원되지 않습니다!",
-    "failOcr": "인식 실패",
-    "remain": "남:",
-
-    "totalUsage": "총 구독 금액",
-    "disableGpt4": "GPT4 비활성화됨",
-    "setTextInfo": "OpenAI API 키 오류, 여기를 클릭하여 다시 시도",
-    
-    "attr1": "첨부",
-    "ulink": "원본 이미지 링크",
-    "copyFail": "복사 실패",
-    "tts": "텍스트 음성 변환 (TTS)",
-    "fail": "오류가 발생했습니다",
-    "noSupperChrom": "브라우저가 지원되지 않습니다!",
-    "lang": "음성",
-    "ttsLoading": "음성으로 변환 중...",
-    "ttsSuccess": "변환 성공",
-    "micIng": "녹음 중, 무엇인가 말해보세요...",
-    "mStart": "시작",
-    "mPause": "일시 정지",
-    "mGoon": "계속",
-    "mRecord": "다시 녹음",
-    "mPlay": "재생",
-    "mCanel": "취소",
-    "mSent": "전송",
-    "findVersion": "최신 버전 찾기",
-    "yesLastVersion": "최신 버전입니다",
-    "infoStar": "이 프로젝트는 <a class=\"text-blue-600 dark:text-blue-500\" href=\"https://github.com/Dooy/chatgpt-web-midjourney-proxy\" target=\"_blank\">GitHub</a>에서 오픈 소스로 제공되며 MIT 라이선스를 기반으로 하며 어떠한 유료 행위도 없습니다! </p><p>이 프로젝트가 도움이 되었다면 GitHub에서 별을 주시기 바랍니다. 감사합니다!",
-    "setBtSaveChat": "대화만 저장",
-    "setBtSaveSys": "시스템에 저장",
-
-    "wsrvClose": "닫기 wsrv",
-    "wsrvOpen": "열기 wsrv",
-    
-    "temperature": "랜덤성",
-    "temperatureInfo": "(temperature) 값이 증가함에 따라 응답이 더 랜덤해집니다",
-    "top_p": "상위 확률 샘플링",
-    "top_pInfo": "(top_p)은 랜덤성과 유사하지만 온도와 함께 변경되어서는 안 됩니다",
-    "presence_penalty": "주제 신선도",
-    "presence_penaltyInfo": "(presence_penalty) 값이 증가함에 따라 새로운 주제로 확장될 가능성이 높아집니다",
-    "frequency_penalty": "빈도 패널티",
-    "frequency_penaltyInfo": "(frequency_penalty) 값이 증가함에 따라 반복된 단어를 줄이는 가능성이 높아집니다",
-    "tts_voice": "TTS 음성 캐릭터",
-    "typing": "입력 중",
-    "authErro": "인가 실패",
-    "authBt": "인가 액세스 암호를 다시 입력하십시오",
-    "micWhisper": "속삭임 음성 인식",
-    "micAsr": "즉시 인식",
-    "micRec": "녹음 시작, 말씀하세요! 2초 동안 소리가 없으면 자동으로 중지됩니다.",
-    "micRecEnd": "녹음이 종료되었습니다"
-
-  },
-  "mjset": {
-    "server": "서버"
-    ,"about": "소개"
-    ,"model": "모델"
-    ,"sysname": "AI 그림"
-  },
-  "mjtab": {
-    "chat": "대화"
-    ,"draw": "그림"
-    ,"drawinfo": "AI 그림 Midjourney 엔진"
-    ,"gallery": "갤러리"
-    ,"galleryInfo": "내 갤러리"
-  },
-  "mjchat": {
-    "loading": "이미지 로드 중"
-    ,"openurl": "직접 링크 열기"
-    ,"failReason": "실패 이유:"
-    ,"reload": "재로드"
-    ,"progress": "진행:"
-    ,"wait": "작업이 제출되었습니다. 기다려주세요..."
-    ,"reroll": "재그림"
-    ,"wait2": "작업 {id}이(가) 제출되었습니다. 기다려주세요"
-    ,"redrawEditing": "일부 재그림 편집"
-    ,"face": "얼굴 바꾸기"
-    ,"blend": "혼합"
-    ,"draw": "그림 그리기"
-    ,"submiting": "제출 중"
-    ,"submit": "제출"
-    ,"wait3": "닫지 마세요! 이미지 생성 중..."
-    ,"success": "저장 성공"
-    ,"successTitle": "성공"
-    ,"modlePlaceholder": "여러 개의 사용자 정의 모델은 띄어쓰기로 구분됩니다. 필수 사항은 아닙니다."
-    ,"myModle": "내 모델"
-    ,"historyCnt": "컨텍스트 수"
-    ,"historyToken": "더 많은 컨텍스트는 기억을 더 정확하게 만들지만 더 많은 크레딧을 소비할 수 있습니다."
-    ,"historyTCnt": "답장 수"
-    ,"historyTCntInfo": "답장 수가 많을수록 더 많은 크레딧이 소비될 수 있습니다."
-    ,"role": "역할 설정"
-    ,"rolePlaceholder": "대화에 고유한 역할을 설정하십시오. 필수는 아닙니다."
-    ,"loading2": "로딩 중..."
-    ,"loadmore": "더 보기"
-    ,"nofind": "찾을 수 없음"
-    ,"nofind2": "관련 내용을 찾을 수 없습니다. 다음을 시도해 보십시오."
-    ,"success2": "전환 성공!"
-    ,"modelChange": "모델 변경"
-    ,"search": "검색"
-    ,"searchPlaceholder": "GPTs 이름, 소개"
-    ,"attr": "첨부 파일"
-    ,"noproduct": "갤러리에 작품이 없습니다."
-    ,"myGallery": "내 갤러리"
-    ,"yourHead": "당신의 프로필 사진"
-    ,"your2Head": "스타 이미지"
-    ,"tipInfo": "설명:<li>1. 이미지에는 얼굴이 반드시 포함되어야 합니다. 그렇지 않으면 이미지가 생성되지 않습니다.</li> <li>2. '스타 이미지'는 먼저 MJ 그림으로 만들 수 있습니다.</li> <li>3. '스타 이미지'는 애니메이션 이미지로도 괜찮습니다.</li> <li>4. '당신의 프로필 사진'은 1인치 개인 사진을 사용하는 것이 좋습니다.</li>"
-    ,"placeInput": "힌트를 입력하세요!"
-    ,"more5sb": "최대 5장의 이미지를 업로드할 수 있습니다."
-    ,"exSuccess": "내보내기 성공... 다운로드 창을 확인하세요."
-    ,"downloadSave": "ai그림.txt"
-    ,"noproducet": "아직 미완성 작품이 없습니다."
-    ,"imgBili": "이미지 비율"
-    ,"imagEx": "작품 이미지 링크 내보내기"
-    ,"prompt": "힌트"
-    ,"imgCYes": "쿠션 이미지 포함"
-    ,"imgCUpload": "자체 쿠션 이미지 업로드"
-    ,"imgCInfo": "쿠션 이미지 안내:<br/> 1. 쿠션 이미지는 자체 이미지를 기본으로 사용하여 MJ로 그림을 그릴 수 있습니다.<br/> 2. 최대 5 장의 쿠션 이미지를 사용할 수 있으며 각 이미지의 크기는 1M를 초과하지 않아야 합니다.<br/>"
-    ,"imgCadd": "+추가"
-    ,"del": "삭제"
-    ,"img2text": "이미지에서 텍스트 생성"
-    ,"img2textinfo": "힌트가 어떻게 쓰여야 할지 모르겠나요? 이미지에서 텍스트를 생성해 보세요! <br/>이미지를 제출하면 힌트가 생성됩니다."
-    ,"traning": "번역 중..."
-    ,"imgcreate": "이미지 생성"
-    ,"imginfo": "기타 매개변수:<li>1 --no를 무시하면 --no car가 이미지에 표시되지 않습니다.</li><li>2 --seed는 먼저 시드를 얻을 수 있습니다. --seed 123456</li> <li>3 --chaos 10은 혼합(범위: 0-100)</li> <li>4 --tile 조각화</li>"
-    ,"tStyle": "스타일"
-    ,"tView": "시점"
-    ,"tShot": "캐릭터 샷"
-    ,"tLight": "조명"
-    ,"tQuality": "화질"
-    ,"tStyles": "아트 정도"
-    ,"tVersion": "모델 버전"
-    ,"dalleInfo": "설명:<li>1. DALL-E는 OpenAI에서 제공하는 그림 모델입니다.</li>  <li>2. OpenAI의 이미지는 일시적입니다. 백업을 잘 해 두세요.</li>   <li>3. 주의: 1790px 이미지의 가격은 두 배입니다.</li> "
-    ,"version": "버전"
-    ,"size": "크기"
-    ,"blendInfo": "설명:<li>1. 최소 2 장의 이미지를 합성하십시오.</li> <li>2. 최대 6 장의 이미지를 업로드할 수 있습니다.</li> "
-    ,"blendStart": "합성 시작"
-    ,"no2add": "이미지를 중복해서 추가하지 마십시오."
-    ,"add2more": "두 장 이상의 이미지를 추가하십시오."
-    ,"no1m": "이미지 크기는 1M를 초과할 수 없습니다."
-    ,"imgExt": "이미지는 jpg, gif, png, jpeg 형식만 지원됩니다."
-  }
 }

+ 0 - 188
src/locales/ru-RU.ts

@@ -93,192 +93,4 @@ export default {
     onlineImportWarning: 'Внимание! Проверьте источник JSON-файла!',
     downloadError: 'Проверьте состояние сети и правильность JSON-файла',
   },
-  "mj": {
-    "setOpen": "OpenAI связанный",
-    "setOpenPlaceholder": "Должен содержать http(s)://",
-    "setOpenUrl": "Адрес интерфейса OpenAI",
-    "setOpenKeyPlaceholder": "Используйте свой собственный ключ OpenAI для обхода ограничений доступа по паролю",
-    "setMj": "Midjourney связанный",
-    "setMjUrl": "Адрес интерфейса Midjourney:",
-    "setMjKeyPlaceholder": "Используйте свой собственный Api Secret для обхода ограничений доступа по паролю",
-    "setUploader": "Связанный с загрузкой",
-    "setUploaderUrl": "Адрес загрузки:",
-    "setBtSave": "Сохранить",
-    "setBtBack": "Восстановить по умолчанию",
-
-   
-  "redraw": "Частичная Перерисовка",
-  "fail1": "Пожалуйста, будьте терпеливы, идет загрузка.",
-  "success1": "Изображение успешно обновлено!",
-  "high_variation": "Сильные Изменения",
-  "low_variation": "Слабые Изменения",
-  "p15": "Увеличение 1.5x",
-  "p20": "Увеличение 2x",
-  "p100": "Обычное",
-  "retry": "Повторный Анализ",
-  "pan_left": "Переанализировать влево",
-  "pan_right": "Переанализировать вправо",
-  "pan_up": "Переанализировать вверх",
-  "pan_down": "Переанализировать вниз",
-  "up2": "Высокое Разрешение 2x",
-  "up4": "Высокое Разрешение 4x",
-
-  "thinking": "В раздумьях...",
-  "noReUpload": "Нельзя повторно загружать",
-  "uploading": "Загрузка...",
-  "uploadSuccess": "Загрузка успешна",
-  "uploadFail": "Ошибка загрузки:",
-  "upPdf": "<span>Загрузите изображение или вложение<br/>Вы можете загрузить изображения, PDF, EXCEL и другие документы</span><p>Поддерживается перетаскивание</p>",
-  "upImg": "<span><b>Загрузить изображение</b><br/>Автоматически вызовет модель gpt-4-vision-preview<br>Примечание: Могут действовать дополнительные тарифы за изображения<br/>Форматы: jpeg, jpg, png, gif</span><p>Поддерживается перетаскивание</p> <p class=\"pt-2\"><b>Загрузить MP3 MP4</b> <br>Автоматически вызовет модель whisper-1<br>Форматы: mp3, mp4, mpeg, mpga, m4a, wav, webm</p>",
-  "clearAll": "Очистить параметры",
-  "czoom": "Настроить",
-  "customTitle": "Настроить зум",
-  "zoominfo": "Измените значение зума, диапазон от 1.0 до 2.0, по умолчанию установлено 1.8",
-
-  "modleSuccess": "Модель успешно загружена",
-  "setingSuccess": "Настройки успешно выполнены",
-
- "tokenInfo1": "Оставшиеся токены = Длина модели - Установка роли - Контекст (История разговора) - Количество ответов - Текущий ввод",
-"tokenInfo2": "Оставьте установку роли пустой, и система предоставит значение по умолчанию.",
-"noSuppertModel": "Обновите, эта модель в настоящее время не поддерживается!",
-"failOcr": "Ошибка распознавания",
-"remain": "Осталось:",
-
-  "totalUsage": "Общая сумма подписки",
-  "disableGpt4": "GPT4 отключен",
-  "setTextInfo": "Ошибка ключа OpenAI API, нажмите здесь, чтобы повторить попытку",
-
-  "attr1": "Вложение",
-  "ulink": "Ссылка на оригинальное изображение",
-  "copyFail": "Не удалось скопировать",
-  "tts": "Текст в речь",
-  "fail": "Произошла ошибка",
-  "noSupperChrom": "Браузер не поддерживается!",
-  "lang": "Голос",
-  "ttsLoading": "Преобразование в речь...",
-  "ttsSuccess": "Преобразование успешно",
-  "micIng": "Идет запись, скажите что-нибудь...",
-  "mStart": "Начать",
-  "mPause": "Пауза",
-  "mGoon": "Продолжить",
-  "mRecord": "Перезаписать",
-  "mPlay": "Воспроизвести",
-  "mCanel": "Отмена",
-  "mSent": "Отправить",
-  "findVersion": "Обнаружить обновленную версию",
-  "yesLastVersion": "Уже последняя версия",
-  "infoStar": "Этот проект с открытым исходным кодом находится на <a class=\"text-blue-600 dark:text-blue-500\" href=\"https://github.com/Dooy/chatgpt-web-midjourney-proxy\" target=\"_blank\">GitHub</a>, бесплатный и основан на лицензии MIT без каких-либо форм оплаты! </p><p>Если вы находите этот проект полезным, пожалуйста, добавьте звезду на GitHub, спасибо!",
-  "setBtSaveChat": "Сохранить только чат",
-  "setBtSaveSys": "Сохранить в систему",
-
-  "wsrvClose": "Закрыть wsrv",
-  "wsrvOpen": "Открыть wsrv",
-
-  "temperature": "Случайность",
-  "temperatureInfo": "При увеличении значения (temperature) ответы становятся более случайными",
-  "top_p": "Верхняя вероятность выборки",
-  "top_pInfo": "(top_p) аналогично случайности, но не следует изменять вместе с температурой",
-  "presence_penalty": "Свежесть темы",
-  "presence_penaltyInfo": "При увеличении значения (presence_penalty) увеличивается вероятность расширения на новые темы",
-  "frequency_penalty": "Частотное наказание",
-  "frequency_penaltyInfo": "При увеличении значения (frequency_penalty) увеличивается вероятность уменьшения повторяющихся слов"
-  ,"tts_voice": "Голос TTS",
-  "typing": "Печать",
-  "authErro": "Ошибка авторизации",
-  "authBt": "Пожалуйста, введите пароль доступа к авторизации снова",
-  
-  "micWhisper": "Распознавание шепота",
-  "micAsr": "Мгновенное распознавание",
-  "micRec": "Начать запись, пожалуйста, говорите! Запись автоматически остановится, если 2 секунды не будет звука.",
-  "micRecEnd": "Запись завершена"
-  },
-  "mjset": {
-    "server": "Сервер",
-    "about": "О нас",
-    "model": "Модель",
-    "sysname": "Искусственный интеллект для рисования"
-  },
-  "mjtab": {
-    "chat": "Чат",
-    "draw": "Рисование",
-    "drawinfo": "Рисование с использованием искусственного интеллекта Midjourney",
-    "gallery": "Галерея",
-    "galleryInfo": "Моя галерея"
-  },
-  "mjchat": {
-    "loading": "Идет загрузка изображения",
-    "openurl": "Открыть ссылку напрямую",
-    "failReason": "Причина сбоя:",
-    "reload": "Перезагрузить",
-    "progress": "Прогресс:",
-    "wait": "Задача отправлена, подождите...",
-    "reroll": "Перерисовать",
-    "wait2": "Задача {id} отправлена, подождите",
-    "redrawEditing": "Редактирование части изображения",
-    "face": "Сменить лицо",
-    "blend": "Смешивание изображений",
-    "draw": "Рисовать",
-    "submiting": "Отправка...",
-    "submit": "Отправить",
-    "wait3": "Пожалуйста, не закрывайте! Создание изображения...",
-    "success": "Сохранено успешно",
-    "successTitle": "Успешно",
-    "modlePlaceholder": "Пользовательские модели (разделять пробелами, необязательно)",
-    "myModle": "Мои модели",
-    "historyCnt": "Количество контекста",
-    "historyToken": "Больше контекста делает память точнее, но расходует больше квоты",
-    "historyTCnt": "Количество ответов",
-    "historyTCntInfo": "Больше ответов, возможно, потребуется больше квоты",
-    "role": "Настройка роли",
-    "rolePlaceholder": "Дайте своему разговору уникальную роль, необязательно",
-    "loading2": "Загрузка...",
-    "loadmore": "Загрузить еще",
-    "nofind": "Не удалось найти",
-    "nofind2": "Связанные материалы отсутствуют. Попробуйте следующее",
-    "success2": "Переключение успешно!",
-    "modelChange": "Смена модели",
-    "search": "Поиск",
-    "searchPlaceholder": "Имя и описание GPTs",
-    "attr": "Прикрепленные файлы",
-    "noproduct": "В галерее пока нет ваших работ",
-    "myGallery": "Моя галерея",
-    "yourHead": "Ваш аватар",
-    "your2Head": "Изображение знаменитости",
-    "tipInfo": "Примечание:<li>1 Изображение должно содержать лицо, иначе не будет изображения</li> <li>2 «Изображение знаменитости» можно сначала создать с помощью mj</li> <li>3 «Изображение знаменитости» может быть аниме</li> <li>4 «Ваш аватар» рекомендуется использовать фотографию лица</li>",
-    "placeInput": "Пожалуйста, введите подсказку!",
-    "more5sb": "Максимум 5 изображений для загрузки",
-    "exSuccess": "Экспорт успешен... Проверьте загрузки",
-    "downloadSave": "aiрисование.txt",
-    "noproducet": "Пока нет готовых работ",
-    "imgBili": "Соотношение изображения",
-    "imagEx": "Экспорт ссылок изображений",
-    "prompt": "Подсказка",
-    "imgCYes": "Содержит макет",
-    "imgCUpload": "Загрузить свой макет",
-    "imgCInfo": "Информация о макете:<br/> 1. Макет позволяет использовать свои изображения для создания рисунков MJ<br/> 2. Можно использовать несколько макетов, максимум 5, размер каждого изображения не более 1 Мб<br/>",
-    "imgCadd": "+Добавить",
-    "del": "Удалить",
-    "img2text": "Изображение в текст",
-    "img2textinfo": "Не знаете, как написать подсказку? Попробуйте изображение в тексте! <br/> Передайте изображение, получите подсказку",
-    "traning": "Перевод...",
-    "imgcreate": "Создание изображения",
-    "imginfo": "Дополнительные параметры: <li>1 --no Игнорировать --no car, чтобы не рисовать машины на изображении</li><li>2 --seed Получить сначала сид --seed 123456</li><li>3 --chaos 10 Смешивание (диапазон: 0-100)</li><li>4 --tile Фрагментирование</li>",
-    "tStyle": "Стиль",
-    "tView": "Вид",
-    "tShot": "Угол обзора",
-    "tLight": "Освещение",
-    "tQuality": "Качество изображения",
-    "tStyles": "Уровень искусства",
-    "tVersion": "Версия модели",
-    "dalleInfo": "Инструкции: <li>1 DALL-E - это модель от OpenAI для создания изображений</li><li>2 Изображения от OpenAI имеют ограниченный срок годности, сделайте резервную копию</li><li>3 Внимание: изображения размером 1790 пикселей стоят вдвое дороже</li>",
-    "version": "Версия",
-    "size": "Размер",
-    "blendInfo": "Инструкции: <li>1 Смешивание как минимум двух изображений</li><li>2 Максимальное количество загружаемых изображений - 6</li>",
-    "blendStart": "Начать смешивание",
-    "no2add": "Не добавляйте одно и то же изображение повторно",
-    "add2more": "Добавьте как минимум два изображения",
-    "no1m": "Размер изображения не должен превышать 1 Мб",
-    "imgExt": "Формат изображения должен быть jpg, gif, png, jpeg"
-  
-  }
 }

+ 0 - 187
src/locales/vi-VN.ts

@@ -91,191 +91,4 @@ export default {
     onlineImportWarning: 'Lưu ý: Vui lòng kiểm tra nguồn tệp JSON!',
     downloadError: 'Vui lòng kiểm tra trạng thái mạng và tính hợp lệ của tệp JSON',
   },
-  "mj": {
-    "setOpen": "OpenAI liên quan",
-    "setOpenPlaceholder": "Phải chứa http(s)://",
-    "setOpenUrl": "Địa chỉ giao diện OpenAI",
-    "setOpenKeyPlaceholder": "Sử dụng khóa OpenAI tùy chỉnh để bỏ qua hạn chế mật khẩu",
-    "setMj": "Midjourney liên quan",
-    "setMjUrl": "Địa chỉ giao diện Midjourney:",
-    "setMjKeyPlaceholder": "Sử dụng Khóa Api Secret tùy chỉnh để bỏ qua hạn chế mật khẩu",
-    "setUploader": "Tải lên liên quan",
-    "setUploaderUrl": "Địa chỉ tải lên:",
-    "setBtSave": "Lưu",
-    "setBtBack": "Khôi phục mặc định",
-
-    "redraw": "Vẽ Lại Phần",
-    "fail1": "Anh/chị đừng vội, đang tải đó.",
-    "success1": "Ảnh đã làm mới thành công!",
-    "high_variation": "Biến Động Mạnh",
-    "low_variation": "Biến Động Nhẹ",
-    "p15": "Thu Phóng 1.5 lần",
-    "p20": "Thu Phóng 2 lần",
-    "p100": "Bình thường",
-    "retry": "Thử Lại Phân Tích",
-    "pan_left": "Phân Tích Lại Bên Trái",
-    "pan_right": "Phân Tích Lại Bên Phải",
-    "pan_up": "Phân Tích Lại Lên",
-    "pan_down": "Phân Tích Lại Xuống",
-    "up2": "Độ Phân Giải Cao 2 lần",
-    "up4": "Độ Phân Giải Cao 4 lần",
-
-    "thinking": "Đang suy nghĩ...",
-    "noReUpload": "Không thể tải lên lại",
-    "uploading": "Đang tải lên...",
-    "uploadSuccess": "Tải lên thành công",
-    "uploadFail": "Tải lên thất bại:",
-    "upPdf": "<span>Tải lên hình ảnh hoặc tệp đính kèm<br/>Bạn có thể tải lên hình ảnh, PDF, EXCEL và các tài liệu khác</span><p>Hỗ trợ kéo và thả</p>",
-    "upImg": "<span><b>Tải lên hình ảnh</b><br/>Sẽ tự động gọi mô hình gpt-4-vision-preview<br>Chú ý: Có thể áp dụng phí ảnh bổ sung<br/>Định dạng: jpeg, jpg, png, gif</span><p>Hỗ trợ kéo và thả</p> <p class=\"pt-2\"><b>Tải lên MP3 MP4</b> <br>Sẽ tự động gọi mô hình whisper-1<br>Định dạng: mp3, mp4, mpeg, mpga, m4a, wav, webm</p>",
-    "clearAll": "Xóa tất cả các tham số",
-    "czoom": "Tùy chỉnh",
-    "customTitle": "Tùy chỉnh zoom",
-    "zoominfo": "Sửa giá trị zoom, khoảng từ 1.0 đến 2.0, mặc định được đặt là 1.8",
-
-    "modleSuccess": "Tải mô hình thành công",
-    "setingSuccess": "Thiết lập thành công",
-
-    "tokenInfo1": "Còn lại Tokens = Độ dài mô hình - Thiết lập vai trò - Bối cảnh (Lịch sử cuộc trò chuyện) - Số phản hồi - Đầu vào hiện tại",
-    "tokenInfo2": "Để trống thiết lập vai trò và hệ thống sẽ cung cấp một giá trị mặc định.",
-    "noSuppertModel": "Làm mới, hiện tại mô hình này không được hỗ trợ!",
-    "failOcr": "Nhận dạng thất bại",
-    "remain": "Còn:",
-
-    "totalUsage": "Tổng số tiền đăng ký",
-    "disableGpt4": "GPT4 đã tắt",
-    "setTextInfo": "Lỗi Khóa API OpenAI, nhấp vào đây để thử lại" ,
-
-    "attr1": "Đính",
-    "ulink": "Liên kết Ảnh gốc",
-    "copyFail": "Sao chép thất bại",
-    "tts": "Văn bản thành Tiếng nói (TTS)",
-    "fail": "Đã xảy ra lỗi",
-    "noSupperChrom": "Trình duyệt không được hỗ trợ!",
-    "lang": "Âm thanh",
-    "ttsLoading": "Đang chuyển đổi thành tiếng nói...",
-    "ttsSuccess": "Chuyển đổi thành công",
-    "micIng": "Đang ghi âm, nói điều gì đó...",
-    "mStart": "Bắt đầu",
-    "mPause": "Tạm dừng",
-    "mGoon": "Tiếp tục",
-    "mRecord": "Ghi lại",
-    "mPlay": "Phát",
-    "mCanel": "Hủy",
-    "mSent": "Gửi",
-    "findVersion": "Phát hiện phiên bản cập nhật",
-    "yesLastVersion": "Đã là phiên bản mới nhất",
-    "infoStar": "Dự án này được mở nguồn tại <a class=\"text-blue-600 dark:text-blue-500\" href=\"https://github.com/Dooy/chatgpt-web-midjourney-proxy\" target=\"_blank\">GitHub</a>, miễn phí và dựa trên giấy phép MIT mà không có bất kỳ hình thức thanh toán nào! </p><p>Nếu bạn thấy dự án này hữu ích, hãy cho nó một sao trên GitHub, cảm ơn bạn!",
-    "setBtSaveChat": "Chỉ lưu trò chuyện",
-    "setBtSaveSys": "Lưu vào hệ thống",
-
-    "wsrvClose": "Đóng wsrv",
-    "wsrvOpen": "Mở wsrv",
-    
-    "temperature": "Ngẫu nhiên",
-    "temperatureInfo": "Khi giá trị (temperature) tăng, các phản hồi trở nên ngẫu nhiên hơn",
-    "top_p": "Lấy Mẫu Xác Suất Cao Nhất",
-    "top_pInfo": "(top_p) tương tự như ngẫu nhiên nhưng không nên thay đổi cùng với nhiệt độ",
-    "presence_penalty": "Sự Tươi Mới của Chủ đề",
-    "presence_penaltyInfo": "Khi giá trị (presence_penalty) tăng, có khả năng mở rộng đến các chủ đề mới cao hơn",
-    "frequency_penalty": "Hình Phạt Tần Số",
-    "frequency_penaltyInfo": "Khi giá trị (frequency_penalty) tăng, có khả năng giảm sự lặp lại của các từ nhiều hơn"
-   ,"tts_voice": "Nhân vật giọng TTS",
-    "typing": "Đang nhập",
-    "authErro": "Xác thực không thành công",
-    "authBt": "Vui lòng nhập lại mật khẩu truy cập xác thực",
-
-    "micWhisper": "Nhận diện giọng nói thì thầm",
-    "micAsr": "Nhận diện ngay lập tức",
-    "micRec": "Bắt đầu ghi âm, vui lòng nói chuyện! Sẽ tự động dừng nếu không có âm thanh trong vòng 2 giây.",
-    "micRecEnd": "Ghi âm đã kết thúc"
-
-  },
-  "mjset": {
-    "server": "Máy chủ",
-    "about": "Về",
-    "model": "Mô hình",
-    "sysname": "Trí tuệ nhân tạo vẽ"
-  },
-  "mjtab": {
-    "chat": "nói",
-    "draw": "Vẽ",
-    "drawinfo": "Vẽ trí tuệ nhân tạo Midjourney",
-    "gallery": "sách",
-    "galleryInfo": "Phòng trưng bày của tôi"
-  },
-  "mjchat": {
-    "loading": "Đang tải hình ảnh",
-    "openurl": "Mở liên kết trực tiếp",
-    "failReason": "Lý do thất bại:",
-    "reload": "Tải lại",
-    "progress": "Tiến triển:",
-    "wait": "Nhiệm vụ đã được gửi, vui lòng đợi...",
-    "reroll": "Vẽ lại",
-    "wait2": "Nhiệm vụ {id} đã được gửi, vui lòng đợi",
-    "redrawEditing": "Chỉnh sửa vẽ lại",
-    "face": "Thay đổi khuôn mặt",
-    "blend": "Trộn ảnh",
-    "draw": "Vẽ",
-    "submiting": "Đang gửi",
-    "submit": "Gửi",
-    "wait3": "Vui lòng không tắt! Đang tạo ảnh...",
-    "success": "Lưu thành công",
-    "successTitle": "Thành công",
-    "modlePlaceholder": "Mô hình tùy chỉnh, cách nhau bằng khoảng trắng, không bắt buộc",
-    "myModle": "Mô hình tùy chỉnh của tôi",
-    "historyCnt": "Số ngữ cảnh",
-    "historyToken": "Số ngữ cảnh nhiều hơn sẽ làm cho bộ nhớ chính xác hơn, nhưng sẽ tiêu tốn nhiều chi phí hơn",
-    "historyTCnt": "Số câu trả lời",
-    "historyTCntInfo": "Số câu trả lời càng nhiều, khả năng tiêu tốn chi phí càng cao",
-    "role": "Đặt vai trò",
-    "rolePlaceholder": "Đặt một vai trò riêng cho cuộc trò chuyện của bạn, không bắt buộc",
-    "loading2": "Đang tải...",
-    "loadmore": "Tải thêm",
-    "nofind": "Không thể tìm thấy",
-    "nofind2": "Nội dung liên quan không tìm thấy, bạn có thể thử những nội dung sau đây",
-    "success2": "Chuyển đổi thành công!",
-    "modelChange": "Thay đổi mô hình",
-    "search": "Tìm kiếm",
-    "searchPlaceholder": "Tên GPTs, giới thiệu",
-    "attr": "Phụ kiện",
-    "noproduct": "Phòng trưng bày chưa có sản phẩm của bạn",
-    "myGallery": "Phòng trưng bày của tôi",
-    "yourHead": "Ảnh đại diện của bạn",
-    "your2Head": "Ảnh ngôi sao",
-    "tipInfo": "Chú ý: <li>1 Hình ảnh phải chứa khuôn mặt, nếu không sẽ không xuất hiện ảnh</li> <li>2 'Ảnh ngôi sao' có thể sử dụng MJ để vẽ trước</li> <li>3 'Ảnh ngôi sao' có thể là hình ảnh hoạt hình</li> <li>4 'Ảnh đại diện của bạn' nên sử dụng ảnh cá nhân 1 inch</li>",
-    "placeInput": "Vui lòng điền từ gợi ý!",
-    "more5sb": "Tối đa tải lên 5 ảnh",
-    "exSuccess": "Xuất thành công... Vui lòng kiểm tra thanh tải về",
-    "downloadSave": "ai vẽ.txt",
-    "noproducet": "Hiện chưa có sản phẩm chín thành",
-    "imgBili": "Tỉ lệ ảnh",
-    "imagEx": "Xuất liên kết hình ảnh tác phẩm",
-    "prompt": "Từ gợi ý",
-    "imgCYes": "Có ảnh nền",
-    "imgCUpload": "Tự tải ảnh nền",
-    "imgCInfo": "Thông tin ảnh nền: <br/> 1. Ảnh nền có thể sử dụng ảnh cá nhân của bạn làm cơ sở để MJ vẽ hình <br/> 2. Có thể sử dụng nhiều ảnh nền, tối đa 5 ảnh, mỗi ảnh không quá 1M",
-    "imgCadd": "+ Thêm",
-    "del": "Xóa",
-    "img2text": "Hình thành văn",
-    "img2textinfo": "Không biết cách đặt từ gợi ý? Hãy thử Hình thành văn! <br/> Gửi hình ảnh, nhận từ gợi ý",
-    "traning": "Đang dịch...",
-    "imgcreate": "Tạo ảnh",
-    "imginfo": "Tham số khác: <li>1 --no Bỏ qua --no, không xuất hiện xe trong hình ảnh </li><li>2 --seed Có thể lấy hạt giống trước --seed 123456 </li> <li>3 --chaos 10 Hỗn loạn (phạm vi: 0-100)</li> <li>4 --tile Fragmentation </li>",
-    "tStyle": "Phong cách",
-    "tView": "Góc nhìn",
-    "tShot": "Góc chụp người",
-    "tLight": "Ánh sáng",
-    "tQuality": "Chất lượng hình ảnh",
-    "tStyles": "Mức độ nghệ thuật",
-    "tVersion": "Phiên bản mô hình",
-    "dalleInfo": "Chú ý: <li>1 Dall-e là mô hình vẽ hình do OpenAI cung cấp</li>  <li>2 Hình ảnh của OpenAI có thời gian sử dụng, hãy sao lưu đúng cách</li>   <li>3 Lưu ý: Giá của hình ảnh 1790px là gấp đôi</li>",
-    "version": "Phiên bản",
-    "size": "Kích thước",
-    "blendInfo": "Chú ý: <li>1 Kết hợp ít nhất 2 hình ảnh</li> <li>2 Tối đa có thể tải lên 6 hình ảnh</li>",
-    "blendStart": "Bắt đầu kết hợp",
-    "no2add": "Vui lòng không thêm hình ảnh giống nhau",
-    "add2more": "Vui lòng thêm ít nhất hai hình ảnh",
-    "no1m": "Kích thước hình ảnh không quá 1M",
-    "imgExt": "Chỉ hỗ trợ định dạng jpg, gif, png, jpeg cho hình ảnh"
-    }
 }

+ 14 - 20
src/locales/zh-CN.ts

@@ -94,12 +94,12 @@ export default {
     downloadError: '请检查网络状态与 JSON 文件有效性',
   },
 
-
+  
   mjset:{
     server:'服务端'
     ,about:'关于'
     ,model:'模型'
-    ,sysname:'熊猫助手'
+    ,sysname:'AI绘图'
   }
 
   ,mjtab:{
@@ -124,7 +124,7 @@ export default {
     ,draw:'绘图'
     ,submiting:'提交中'
     ,submit:'提交'
-    ,wait3:'请勿关闭! 图片生成中...'
+    ,wait3:'请勿关闭! 图片生成中...' 
     ,success:'保存成功'
     ,successTitle:'成功'
     ,modlePlaceholder:'自定义模型多个用空格隔开,不是必须'
@@ -192,7 +192,7 @@ export default {
     ,setMj:'Midjourney 相关'
     ,setMjUrl:'Midjourney接口地址:'
     ,setMjKeyPlaceholder:'使用自定义 Api Secret 绕过密码访问限制'
-    ,setUploader:'上传相关'
+    ,setUploader:'上传相关' 
     ,setUploaderUrl:'上传地址:'
     ,setBtSave:'保存'
     ,setBtBack:'恢复默认'
@@ -206,7 +206,7 @@ export default {
     ,p15:'变焦1.5倍'
     ,p20:'变焦2倍'
     ,p100:'方正'
-
+    
     ,retry:'重分析'
     ,pan_left:'向左'
     ,pan_right:'向右'
@@ -214,7 +214,7 @@ export default {
     ,pan_down:'向下'
     ,up2:'高清2倍'
     ,up4:'高清4倍',
-
+    
     thinking:'思考中...'
     ,noReUpload:'不能重复上传'
     ,uploading:'上传中...'
@@ -222,21 +222,21 @@ export default {
     ,uploadFail:'上传失败:'
     ,upPdf:'<span>上传图片、附件<br/>能上传图片、PDF、EXCEL等文档</span><p>支持拖拽</p>'
     ,upImg:'<span><b>上传图片</b><br/>会自动调用 gpt-4-vision-preview 模型<br>注意:会有额外的图片费用<br/>格式: jpeg jpg png gif</span><p>支持拖拽</p> <p class="pt-2"><b>上传MP3 MP4</b> <br>会自动直接调用 whisper-1 模型<br>格式有:mp3 mp4 mpeg mpga m4a wav webm</p>'
-    ,clearAll:'清参数'
+    ,clearAll:'清参数'  
     ,czoom:'自定义'
     ,customTitle:'自定义变焦'
     ,zoominfo:'修改zoom值,范围在 1.0~2.0 默认设置为1.8',
-
+    
     modleSuccess:'模型加载成功'
     ,setingSuccess:'设置成功'
 
     ,tokenInfo1:'剩余Tokens = 模型长度 - 角色设定 - 上下文(会话历史) - 回复数 - 当前输入'
     ,tokenInfo2:'角色设定留空,系统会给一个默认的'
     ,noSuppertModel:'刷新,暂不支持此模型!'
-    ,failOcr:'识别失败'
-    ,remain:'剩:'
-
-    ,totalUsage:'订阅总额'
+    ,failOcr:'识别失败' 
+    ,remain:'剩:' 
+    
+    ,totalUsage:'订阅总额' 
     ,disableGpt4:'已禁用GPT4'
     ,setTextInfo:'OpenAi Api Key 错误,点击这里重新'
 
@@ -261,7 +261,7 @@ export default {
     ,findVersion:'发现更新版本'
     ,yesLastVersion:'已是最新版本'
     ,infoStar:'此项目开源于 <a  class="text-blue-600 dark:text-blue-500" href="https://github.com/Dooy/chatgpt-web-midjourney-proxy" target="_blank"> GitHub </a>,免费且基于 MIT 协议,没有任何形式的付费行为! </p><p>如果你觉得此项目对你有帮助,请在 GitHub 帮我点个 Star,谢谢!'
-    ,setBtSaveChat:'保存会话'
+    ,setBtSaveChat:'保存会话'
     ,setBtSaveSys: '保存至系统'
 
     ,wsrvClose:'关闭 wsrv'
@@ -280,12 +280,6 @@ export default {
     ,typing:'正在输入'
 
     ,authErro:'授权失败'
-    ,authBt:'请重新输入授权访问密码'
-
-    ,micWhisper:'Whisper语音识别'
-    ,micAsr:'即时识别'
-    ,micRec:'开始录音,请说话!2秒内无声音将自动关闭'
-    ,micRecEnd:'录音已结束'
-
+    ,authBt:'请重新授权'
   }
 }

+ 0 - 181
src/locales/zh-TW.ts

@@ -93,185 +93,4 @@ export default {
     onlineImportWarning: '注意:請檢查 JSON 檔案來源!',
     downloadError: '請檢查網路狀態與 JSON 檔案有效性',
   },
-
-  "mj": {
-    "setOpen": "OpenAI 相關",
-    "setOpenPlaceholder": "必須包含 http(s)://",
-    "setOpenUrl": "OpenAI接口地址",
-    "setOpenKeyPlaceholder": "使用自定義 OpenAI Key 繞過密碼訪問限制",
-    "setMj": "Midjourney 相關",
-    "setMjUrl": "Midjourney接口地址:",
-    "setMjKeyPlaceholder": "使用自定義 Api Secret 繞過密碼訪問限制",
-    "setUploader": "上傳相關",
-    "setUploaderUrl": "上傳地址:",
-    "setBtSave": "保存",
-    "setBtBack": "恢復默認",
-    "redraw": "局部重繪",
-    "fail1": "客官不要太急嘛,正在加載呢",
-    "success1": "圖片刷新成功!",
-    "high_variation": "強變化",
-    "low_variation": "弱變化",
-    "p15": "變焦1.5倍",
-    "p20": "變焦2倍",
-    "p100": "方正",
-    "retry": "重分析",
-    "pan_left": "向左",
-    "pan_right": "向右",
-    "pan_up": "向上",
-    "pan_down": "向下",
-    "up2": "高清2倍",
-    "up4": "高清4倍",
-
-    "thinking": "思考中...",
-    "noReUpload": "不能重複上傳",
-    "uploading": "上傳中...",
-    "uploadSuccess": "上傳成功",
-    "uploadFail": "上傳失敗:",
-    "upPdf": "<span>上傳圖片或附件<br/>可以上傳圖片、PDF、EXCEL等文檔</span><p>支持拖放</p>",
-    "upImg": "<span><b>上傳圖片</b><br/>將自動調用 gpt-4-vision-preview 模型<br>注意:可能會有額外的圖片費用<br/>格式:jpeg、jpg、png、gif</span><p>支持拖放</p> <p class=\"pt-2\"><b>上傳MP3 MP4</b> <br>將自動直接調用 whisper-1 模型<br>格式:mp3、mp4、mpeg、mpga、m4a、wav、webm</p>",
-    "clearAll": "清參數",
-    "czoom": "自定義",
-    "customTitle": "自定義變焦",
-    "zoominfo": "修改zoom值,範圍在 1.0 到 2.0,默认设置為1.8",
-
-  "modleSuccess": "模型成功載入",
-    "setingSuccess": "設定成功",
-
-    "tokenInfo1": "剩餘Tokens = 模型長度 - 角色設定 - 上下文(對話歷史) - 回覆數 - 目前輸入",
-    "tokenInfo2": "保持角色設定為空,系統將提供默認值。",
-    "noSuppertModel": "刷新,目前不受此模型支持!",
-    "failOcr": "識別失敗",
-    "remain": "餘:",
-
-    "totalUsage": "訂閱總額",
-    "disableGpt4": "已禁用GPT4",
-    "setTextInfo": "OpenAI API Key 錯誤,點擊這裡重新",
-
-    "attr1": "附",
-    "ulink": "原圖鏈接",
-    "copyFail": "複製失敗",
-    "tts": "文字轉語音",
-    "fail": "發生錯誤",
-    "noSupperChrom": "瀏覽器不支援!",
-    "lang": "語音",
-    "ttsLoading": "轉換中...",
-    "ttsSuccess": "轉換成功",
-    "micIng": "錄音中,請說些什麼...",
-    "mStart": "開始",
-    "mPause": "暫停",
-    "mGoon": "繼續",
-    "mRecord": "重新錄製",
-    "mPlay": "播放",
-    "mCanel": "取消",
-    "mSent": "發送",
-    "findVersion": "發現更新版本",
-    "yesLastVersion": "已是最新版本",
-    "infoStar": "此專案在 <a class=\"text-blue-600 dark:text-blue-500\" href=\"https://github.com/Dooy/chatgpt-web-midjourney-proxy\" target=\"_blank\">GitHub</a> 上以 MIT 協議開源,免費且沒有任何付費行為! </p><p>如果你覺得這個專案對你有幫助,請在 GitHub 上給它一顆星,謝謝!",
-    "setBtSaveChat": "保存對話",
-    "setBtSaveSys": "保存至系統",
-    "wsrvClose": "關閉 wsrv",
-    "wsrvOpen": "開啟 wsrv",
-    "temperature": "隨機性",
-    "temperatureInfo": "隨著 (temperature) 值的增加,回覆變得更隨機",
-    "top_p": "概率抽樣",
-    "top_pInfo": "(top_p) 類似於隨機性,但不應與溫度一同更改",
-    "presence_penalty": "話題新鮮度",
-    "presence_penaltyInfo": "隨著 (presence_penalty) 值的增加,擴展到新話題的機會更高",
-    "frequency_penalty": "頻率懲罰",
-    "frequency_penaltyInfo": "隨著 (frequency_penalty) 值的增加,降低重複字詞的可能性更高",
-    "tts_voice": "TTS 語音角色",
-    "typing": "正在輸入",
-    "authErro": "授權失敗",
-    "authBt": "請重新輸入授權訪問密碼",
-    "micWhisper": "Whisper語音識別",
-    "micAsr": "即時識別",
-    "micRec": "開始錄音,請說話!2秒內無聲音將自動關閉",
-    "micRecEnd": "錄音已結束"
-  },
-  "mjset": {
-    "server": "服務端",
-    "about": "關於",
-    "model": "模型",
-    "sysname": "AI繪圖"
-  },
-  "mjtab": {
-    "chat": "對話",
-    "draw": "繪畫",
-    "drawinfo": "AI繪畫 Midjourney引擎",
-    "gallery": "畫廊",
-    "galleryInfo": "我的畫廊"
-  },
-  "mjchat": {
-    "loading": "正在載入圖片",
-    "openurl": "直接打開鏈接",
-    "failReason": "失敗原因:",
-    "reload": "重新獲取",
-    "progress": "進度:",
-    "wait": "任務已經提交請等待...",
-    "reroll": "重繪",
-    "wait2": "任務 {id} 已經提交請等待",
-    "redrawEditing": "局部重繪編輯",
-    "face": "換臉",
-    "blend": "混圖",
-    "draw": "繪圖",
-    "submiting": "提交中",
-    "submit": "提交",
-    "wait3": "請勿關閉! 圖片生成中...",
-    "success": "保存成功",
-    "successTitle": "成功",
-    "modlePlaceholder": "自定義模型多個用空格隔開,不是必須",
-    "myModle": "自定義模型",
-    "historyCnt": "上下文數量",
-    "historyToken": "更多的上下文會使記憶更精確,但會消耗更多的額度",
-    "historyTCnt": "回復數",
-    "historyTCntInfo": "回復數越大 ,越有可能消耗更多的額度",
-    "role": "角色設定",
-    "rolePlaceholder": "給你的會話設置一個專屬的角色,不是必須",
-    "loading2": "正在加載...",
-    "loadmore": "加載更多",
-    "nofind": "未能找到",
-    "nofind2": "相關內容, 你可嘗試以下內容",
-    "success2": "切換成功!",
-    "modelChange": "模型切換",
-    "search": "搜索",
-    "searchPlaceholder": "GPTs名字、介紹",
-    "attr": "附件",
-    "noproduct": "畫廊還沒有您的作品",
-    "myGallery": "我的畫廊",
-    "yourHead": "你的頭像",
-    "your2Head": "明星圖",
-    "tipInfo": "說明:<li>1 圖片都必須包含臉,否則出不來圖</li> <li>2 “明星圖”可以先用mj繪畫製作出來</li> <li>3 “明星圖”其實動漫圖也行</li> <li>4 “你的頭像”建議用一寸個人照</li>",
-    "placeInput": "請填寫提示詞!",
-    "more5sb": "最多上傳5張圖片",
-    "exSuccess": "導出成功... 請看下載欄",
-    "downloadSave": "ai繪畫.txt",
-    "noproducet": "暫時沒成熟作品",
-    "imgBili": "圖片比例",
-    "imagEx": "作品圖片鏈接導出",
-    "prompt": "提示詞",
-    "imgCYes": "含有墊圖",
-    "imgCUpload": "自傳墊圖",
-    "imgCInfo": "墊圖說明:<br/> 1.墊圖可使用自己的圖片作為基礎,讓MJ來繪圖<br/> 2.可以使用多張墊圖 最多5張, 單張圖片不超過1M<br/>",
-    "imgCadd": "+添加",
-    "del": "刪除",
-    "img2text": "圖生文",
-    "img2textinfo": "不知如何寫提示詞?用圖生文試試!<br/>提交圖片,出提示詞",
-    "traning": "翻譯中...",
-    "imgcreate": "生成圖片",
-    "imginfo": "其他參數:  <li>1 --no 忽略 --no car 圖中不出現車 </li><li>2 --seed 可先獲取種子 --seed 123456 </li> <li>3 --chaos 10 混合(範圍:0-100)</li> <li>4 --tile 碎片化 </li> ",
-    "tStyle": "風格",
-    "tView": "視角",
-    "tShot": "人物鏡頭",
-    "tLight": "燈光",
-    "tQuality": "畫質",
-    "tStyles": "藝術程度",
-    "version": "版本",
-    "size": "尺寸",
-    "blendInfo": "說明: <li>1 合成至少2張圖片</li> <li>2 最多可傳6張圖</li> ",
-    "blendStart": "開始合成",
-    "no2add": "請勿重複添加圖片",
-    "add2more": "請添加兩張以上圖片",
-    "no1m": "圖片大小不能超過1M",
-    "imgExt": "圖片僅支持jpg,gif,png,jpeg格式"
-  }
 }

+ 1 - 1
src/router/index.ts

@@ -81,7 +81,7 @@ const routes: RouteRecordRaw[] = [
     name: 'resetpassword',
     component: () => import('@/views/resetpassword/index.vue'),
   },
-
+  
   {
     path: '/500',
     name: '500',

+ 1 - 1
src/router/permission.ts

@@ -10,7 +10,7 @@ export function setupPageGuard(router: Router) {
           next({ path: '/' });
         }else{
           next();
-        }
+        } 
     } else {
       if (whiteList.indexOf(to.path) !== -1) {
         next();

+ 2 - 3
src/store/modules/app/helper.ts

@@ -1,11 +1,10 @@
-import { homeStore } from '@/store/homeStore'
 import { ss } from '@/utils/storage'
 
 const LOCAL_NAME = 'appSetting'
 
 export type Theme = 'light' | 'dark' | 'auto'
 
-export type Language = 'zh-CN' | 'zh-TW' | 'en-US' | 'ko-KR' | 'ru-RU' | 'vi-VN' | 'fr-FR' | 'tr-TR'
+export type Language = 'zh-CN' | 'zh-TW' | 'en-US' | 'ko-KR' | 'ru-RU'
 
 export interface AppState {
   siderCollapsed: boolean
@@ -14,7 +13,7 @@ export interface AppState {
 }
 
 export function defaultSetting(): AppState {
-  return { siderCollapsed: false, theme: homeStore.myData.session.theme=='light'?'light': 'auto', language: 'zh-CN' }
+  return { siderCollapsed: false, theme: 'dark', language: 'zh-CN' }
 }
 
 export function getLocalSetting(): AppState {

+ 11 - 0
src/store/modules/auth/anth.ts

@@ -0,0 +1,11 @@
+import { useStorage } from "@vueuse/core";
+
+const TokenKey = 'RuoYi-Token';
+
+const tokenStorage = useStorage<null | string>(TokenKey, null);
+
+export const getToken = () => tokenStorage.value;
+
+export const setToken = (token: string) => (tokenStorage.value = token);
+
+export const removeToken = () => (tokenStorage.value = null);

+ 1 - 1
src/store/modules/auth/helper.ts

@@ -1,6 +1,6 @@
 import { ss } from '@/utils/storage'
 
-const LOCAL_NAME = 'SECRET_TOKEN'
+const LOCAL_NAME = 'TOKEN'
 
 export function getToken() {
   return ss.get(LOCAL_NAME)

+ 1 - 6
src/store/modules/auth/index.ts

@@ -3,10 +3,8 @@ import { getToken, removeToken, setToken } from './helper'
 import { store } from '@/store/helper'
 import { fetchSession } from '@/api'
 import { gptConfigStore, homeStore } from '@/store/homeStore'
-import { useAppStore } from '@/store'
-const appStore = useAppStore()
+
 interface SessionResponse {
-  theme?: string
   auth: boolean
   model: 'ChatGPTAPI' | 'ChatGPTUnofficialProxyAPI'
 }
@@ -34,9 +32,6 @@ export const useAuthStore = defineStore('auth-store', {
         const { data } = await fetchSession<SessionResponse>()
         this.session = { ...data }
         homeStore.setMyData({session: data });
-        if(appStore.$state.theme=='auto' ){
-            appStore.setTheme(  data.theme && data.theme=='light' ?'light':'dark')
-        }
 
         let str = localStorage.getItem('gptConfigStore');
         if( ! str ) setTimeout( ()=>  gptConfigStore.setInit() , 500); 

+ 0 - 8
src/store/modules/chat/index.ts

@@ -181,14 +181,6 @@ export const useChatStore = defineStore('chat-store', {
         this.chat[index].data = []
         this.recordState()
       }
-
-      //清空标题
-      const i2= this.history.findIndex( v=>v.uuid===uuid )
-      if (i2 !== -1) {
-        this.history[i2].title= "New Chat"
-         this.recordState()
-      }
-      //end 清空标题
     },
 
     clearHistory() {

+ 1 - 1
src/store/modules/user/index.ts

@@ -34,7 +34,7 @@ export const useUserStore = defineStore('user-store', {
       token.value = '';
       removeToken();
     },
-
+   
     updateUserInfo(userInfo: Partial<UserInfo>) {
       this.userInfo = { ...this.userInfo, ...userInfo }
       this.recordState()

+ 5 - 5
src/utils/request/axios.ts

@@ -1,18 +1,18 @@
 import axios, { type AxiosResponse } from 'axios'
-import { useAuthStore } from '@/store'
+import { getToken } from '@/store/modules/auth/helper'
 
 const service = axios.create({
   baseURL: import.meta.env.VITE_GLOB_API_URL,
 })
 
 service.interceptors.request.use(
-  (config) => {
-    const token = useAuthStore().token
+  (config: { headers: { Authorization: string } }) => {
+    const token = getToken()
     if (token)
       config.headers.Authorization = `Bearer ${token}`
     return config
   },
-  (error) => {
+  (error: { response: any }) => {
     return Promise.reject(error.response)
   },
 )
@@ -24,7 +24,7 @@ service.interceptors.response.use(
 
     throw new Error(response.status.toString())
   },
-  (error) => {
+  (error: any) => {
     return Promise.reject(error)
   },
 )

+ 7 - 9
src/utils/request/index.ts

@@ -15,8 +15,8 @@ export interface HttpOption {
 
 export interface Response<T = any> {
   data: T
-  message: string | null
-  status: string
+  msg: string | undefined
+  code: number
 }
 
 function http<T = any>(
@@ -24,21 +24,19 @@ function http<T = any>(
 ) {
   const successHandler = (res: AxiosResponse<Response<T>>) => {
     const authStore = useAuthStore()
-
-    if (res.data.status === 'Success' || typeof res.data === 'string')
+    if (res.data.code === 200 ){
       return res.data
-
-    if (res.data.status === 'Unauthorized') {
+    }else{
       authStore.removeToken()
       window.location.reload()
-    }
-
+    } 
     return Promise.reject(res.data)
   }
 
   const failHandler = (error: Response<Error>) => {
+    alert("failHandler")
     afterRequest?.()
-    throw new Error(error?.message || 'Error')
+    return { error: true, message: error?.msg || 'Error' };
   }
 
   beforeRequest?.()

+ 2 - 0
src/utils/storage/index.ts

@@ -4,6 +4,7 @@ interface StorageData<T = any> {
 }
 
 export function createLocalStorage(options?: { expire?: number | null }) {
+  // token默认保存7天
   const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7
 
   const { expire } = Object.assign({ expire: DEFAULT_CACHE_TIME }, options)
@@ -20,6 +21,7 @@ export function createLocalStorage(options?: { expire?: number | null }) {
 
   function get(key: string) {
     const json = window.localStorage.getItem(key)
+
     if (json) {
       let storageData: StorageData | null = null
 

+ 7 - 12
src/views/chat/components/Header/index.vue

@@ -1,11 +1,10 @@
 <script lang="ts" setup>
-import { computed, nextTick,ref,watch  } from 'vue'
+import { computed, nextTick,ref  } from 'vue'
 import { HoverButton, SvgIcon } from '@/components/common'
-import {  gptConfigStore, homeStore, useAppStore, useChatStore } from '@/store'
+import { gptConfigStore, homeStore, useAppStore, useChatStore } from '@/store'
 import { useBasicLayout } from '@/hooks/useBasicLayout'
 import {NModal} from "naive-ui"
 import aiModel from "@/views/mj/aiModel.vue"
-import { chatSetting } from '@/api'
 
 const { isMobile } = useBasicLayout()
 
@@ -45,12 +44,8 @@ function handleExport() {
 function handleClear() {
   emit('handleClear')
 }
-const uuid = chatStore.active;
-const chatSet = new chatSetting( uuid==null?1002:uuid);
-const nGptStore = ref( chatSet.getGptConfig())  ;
+
 const st = ref({isShow:false});
-watch(()=>gptConfigStore.myData,()=>nGptStore.value=  chatSet.getGptConfig() , {deep:true})
-watch(()=>homeStore.myData.act,(n)=> n=='saveChat' && (nGptStore.value=  chatSet.getGptConfig() ), {deep:true})
 </script>
 
 <template>
@@ -89,20 +84,20 @@ watch(()=>homeStore.myData.act,(n)=> n=='saveChat' && (nGptStore.value=  chatSet
     
     <div @click="st.isShow=true" class="absolute left-1/2   top-full -translate-x-1/2 cursor-pointer select-none rounded-b-md border  bg-white px-2 dark:border-neutral-800 dark:bg-[#111114]">
         <div class="flex items-center   justify-center space-x-1 cursor-pointer hover:text-[#4b9e5f]" v-if="homeStore.myData.local!='draw'">
-            <template   v-if="nGptStore.gpts">
+            <template   v-if="gptConfigStore.myData.gpts">
              <SvgIcon icon="ri:apps-fill" /> 
-             <span class="line-clamp-1 overflow-hidden">{{ nGptStore.gpts.name }}</span> 
+             <span class="line-clamp-1 overflow-hidden">{{ gptConfigStore.myData.gpts.name }}</span> 
             </template>
             <template v-else >
             <SvgIcon icon="heroicons:sparkles" /> 
-            <span >{{ nGptStore.model }}</span> 
+            <span >{{ gptConfigStore.myData.model }}</span> 
             </template>
             <SvgIcon icon="icon-park-outline:right" />
         </div>
     </div>
   </header>
 
-  <NModal v-model:show="st.isShow"   preset="card"  :title="$t('mjchat.modelChange')" class="!max-w-[620px]" @close="st.isShow=false" >  
+  <NModal v-model:show="st.isShow"   preset="card"  title="模型切换" class="!max-w-[660px]" @close="st.isShow=false" >  
         <aiModel @close="st.isShow=false"/>
   </NModal>
 </template>

+ 11 - 18
src/views/chat/components/Message/Text.vue

@@ -13,9 +13,7 @@ import dallText from '@/views/mj/dallText.vue'
 import ttsText from '@/views/mj/ttsText.vue'
 import whisperText from '@/views/mj/whisperText.vue'
 import MjTextAttr from '@/views/mj/mjTextAttr.vue'
-import aiTextSetting from '@/views/mj/aiTextSetting.vue'
-import aiSetAuth from '@/views/mj/aiSetAuth.vue'
-import { isApikeyError, isAuthSessionError, isTTS } from '@/api'
+import { isTTS } from '@/api'
 
 interface Props {
   inversion?: boolean
@@ -63,10 +61,9 @@ const wrapClass = computed(() => {
 
 const text = computed(() => {
   const value = props.text ?? ''
-  // if (!props.asRawText)
-  //   return mdi.render(value)
-  // return value
-  return mdi.render(value)
+  if (!props.asRawText)
+    return mdi.render(value)
+  return value
 })
 
 function highlightBlock(str: string, lang?: string) {
@@ -118,11 +115,8 @@ onUnmounted(() => {
   <div class="text-black" :class="wrapClass">
     <div ref="textRef" class="leading-relaxed break-words">
       <div v-if="!inversion">
-        <aiTextSetting v-if="!inversion && isApikeyError(text)"/>
-        <aiSetAuth v-if="!inversion && isAuthSessionError(text)" />
-          
         <dallText :chat="chat" v-if="chat.model=='dall-e-3' || chat.model=='dall-e-2'" class="whitespace-pre-wrap" />
-        <mjText v-if="chat.mjID" class="whitespace-pre-wrap" :chat="chat" :mdi="mdi"></mjText>
+        <mjText v-if="chat.mjID" class="whitespace-pre-wrap" :chat="chat"></mjText>
         <ttsText v-else-if="chat.model && isTTS(chat.model) && chat.text=='ok'" :chat="chat"/>
         <template v-else>
           <div v-if="!asRawText" class="markdown-body" :class="{ 'markdown-body-generate': loading }" v-html="text" />
@@ -130,14 +124,13 @@ onUnmounted(() => {
         </template>
       </div>
       <whisperText v-else-if="text=='whisper' && chat.opt?.lkey "  :chat="chat" />
-      <div v-else class="markdown-body "  style="--color-fg-default:#24292f"  v-html="text" />
-      <!-- <div v-else class="whitespace-pre-wrap" v-text="text" /> -->
+      <div v-else class="whitespace-pre-wrap" v-text="text" />
       <MjTextAttr :image="chat.opt?.images[0]" v-if="chat.opt?.images"></MjTextAttr>
-      <whisperText v-if="chat.model && chat.model.indexOf('whisper')>-1 && chat.opt?.lkey " :isW="true"  :chat="chat" class="w-full" />
-      <ttsText v-if="!inversion && chat.opt?.duration && chat.opt?.duration>0 && chat.opt?.lkey " :isW="true"  :chat="chat" class="w-full" />
-
-      
-
+      <!-- <div v-if="chat.opt?.images" class="flex flex-wrap justify-start items-baseline">
+          <div v-for="(img,k ) of chat.opt?.images" :key="k" class="p-1" >
+            <NImage :src="img" preview class="w-[200px] rounded" />
+          </div>
+      </div> -->
     </div>
   </div>
 </template>

+ 12 - 22
src/views/chat/components/Message/index.vue

@@ -9,7 +9,7 @@ import { t } from '@/locales'
 import { useBasicLayout } from '@/hooks/useBasicLayout'
 import { copyToClip } from '@/utils/copy'
 import { homeStore } from '@/store'
-import { getSeed, mlog ,mjImgUrl} from '@/api' 
+import { getSeed, mlog } from '@/api' 
 
 interface Props {
   dateTime?: string
@@ -61,22 +61,14 @@ const options = computed(() => {
       label: asRawText.value ? t('chat.preview') : t('chat.showRawText'),
       key: 'toggleRenderType',
       icon: iconRender({ icon: asRawText.value ? 'ic:outline-code-off' : 'ic:outline-code' }),
-    });
-    common.unshift({
-      label: t('mj.tts'),
-      key: 'tts',
-      icon: iconRender({ icon:'mdi:tts' }),
     })
   }
 
   return common
 })
 
-function handleSelect(key: 'copyText' | 'delete' | 'toggleRenderType' |'tts') {
+function handleSelect(key: 'copyText' | 'delete' | 'toggleRenderType') {
   switch (key) {
-    case 'tts': 
-      homeStore.setMyData({act:'gpt.ttsv2', actData:{ index:props.index , uuid:props.chat.uuid, text:props.text } });
-      return;
     case 'copyText':
       handleCopy()
       return
@@ -88,19 +80,14 @@ function handleSelect(key: 'copyText' | 'delete' | 'toggleRenderType' |'tts') {
   }
 }
 
-function handleRegenerate() {
-  messageRef.value?.scrollIntoView()
-  emit('regenerate')
-}
-
 
 async function handleCopy(txt?:string) {
   try {
     await copyToClip( txt|| props.text || '')
-    message.success( t('chat.copied'))
+    message.success('复制成功')
   }
   catch {
-    message.error( t('mj.copyFail') )
+    message.error('复制失败')
   }
 }
 
@@ -114,7 +101,7 @@ function handleRegenerate2() {
   mlog('重新发送!');
   homeStore.setMyData({act:'gpt.resubmit', actData:{ index:props.index , uuid:props.chat.uuid } });
 }
- 
+
 </script>
 
 <template>
@@ -130,7 +117,7 @@ function handleRegenerate2() {
       <AvatarComponent :image="inversion" :logo="chat.logo"/>
     </div>
     <div class="overflow-hidden text-sm " :class="[inversion ? 'items-end' : 'items-start']">
-      <p class="text-xs group  text-[#b4bbc4] flex  items-center space-x-2 " :class="[inversion ? 'justify-end' : 'justify-start']">
+      <p class="text-xs group  text-[#b4bbc4] flex justify-start items-center space-x-2 " :class="[inversion ? 'text-right' : 'text-left']">
         <span>{{ dateTime }}</span>
         <span v-if="chat.model"  class="text-[#b4bbc4]/50">{{ chat.model }}</span>
         <!-- <span>{{ chat.opt?.progress }}</span> -->
@@ -141,12 +128,15 @@ function handleRegenerate2() {
             <span v-if="chat.opt?.seed">Seed:{{ chat.opt?.seed }}</span>
             <span v-else>Seed</span>
           </div>
-          <a :href=" mjImgUrl(chat.opt?.imageUrl)" class="hidden group-hover:block active  cursor-pointer underline " target="_blank">{{ $t('mj.ulink') }}</a>
+          <a :href="chat.opt?.imageUrl" class="hidden group-hover:block active  cursor-pointer underline " target="_blank">原图链接</a>
         </template>
       </p>
       
-      <div  class="flex items-end gap-1 mt-2"
-        :class="[inversion ? 'flex-row-reverse' : 'flex-row']" > 
+      <div
+        class="flex items-end gap-1 mt-2"
+        :class="[inversion ? 'flex-row-reverse' : 'flex-row']"
+      >
+        
         <TextComponent 
           ref="textRef"
           :inversion="inversion"

+ 17 - 73
src/views/chat/index.vue

@@ -1,11 +1,9 @@
-
-
 <script setup lang='ts'>
 import type { Ref } from 'vue'
-import { computed, onMounted, onUnmounted, ref,watch,h } from 'vue'
-import { useRoute, useRouter } from 'vue-router'
+import { computed, onMounted, onUnmounted, ref,watch } from 'vue'
+import { useRoute } from 'vue-router'
 import { storeToRefs } from 'pinia'
-import { NAutoComplete, NButton, NInput, useDialog, useMessage,NAvatar } from 'naive-ui'
+import { NAutoComplete, NButton, NInput, useDialog, useMessage } from 'naive-ui'
 import html2canvas from 'html2canvas'
 import { Message } from './components'
 import { useScroll } from './hooks/useScroll'
@@ -14,13 +12,14 @@ import { useUsingContext } from './hooks/useUsingContext'
 import HeaderComponent from './components/Header/index.vue'
 import {  SvgIcon } from '@/components/common'
 import { useBasicLayout } from '@/hooks/useBasicLayout'
-import { gptConfigStore, gptsUlistStore, homeStore, useChatStore, usePromptStore } from '@/store'
-import { chatSetting, fetchChatAPIProcess, gptsType, mlog, myFetch } from '@/api'
+import { gptConfigStore, homeStore, useChatStore, usePromptStore } from '@/store'
+import { fetchChatAPIProcess } from '@/api'
 import { t } from '@/locales'
 import drawListVue from '../mj/drawList.vue'
 import aiGPT from '../mj/aiGpt.vue'
 import AiSiderInput from '../mj/aiSiderInput.vue'
 import aiGptInput from '../mj/aiGptInput.vue'
+import { router } from '@/router'
 
 let controller = new AbortController()
 
@@ -29,7 +28,7 @@ const openLongReply = import.meta.env.VITE_GLOB_OPEN_LONG_REPLY === 'true'
 const route = useRoute()
 const dialog = useDialog()
 const ms = useMessage()
-const router = useRouter()
+
 const chatStore = useChatStore()
 
 const { isMobile } = useBasicLayout()
@@ -58,14 +57,17 @@ dataSources.value.forEach((item, index) => {
     updateChatSome(+uuid, index, { loading: false })
 })
 
+
 function handleSubmit() {
+  alert("进来了")
   //onConversation() //把这个放到aiGpt
   let message = prompt.value;
   if (!message || message.trim() === '')
     return
    if (loading.value) return;
+  
    loading.value = true
-  homeStore.setMyData({act:'gpt.submit', actData:{ prompt:prompt.value, uuid } });
+   homeStore.setMyData({act:'gpt.submit', actData:{ prompt:prompt.value, uuid } });
    prompt.value='';
 }
 
@@ -427,61 +429,20 @@ function handleStop() {
 // 理想状态下其实应该是key作为索引项,但官方的renderOption会出现问题,所以就需要value反renderLabel实现
 const searchOptions = computed(() => {
   if (prompt.value.startsWith('/')) {
-    const abc= promptTemplate.value.filter((item: { key: string }) => item.key.toLowerCase().includes(prompt.value.substring(1).toLowerCase())).map((obj: { value: any }) => {
+    return promptTemplate.value.filter((item: { key: string }) => item.key.toLowerCase().includes(prompt.value.substring(1).toLowerCase())).map((obj: { value: any }) => {
       return {
         label: obj.value,
         value: obj.value,
       }
     })
-    mlog('搜索选项', abc);
-    return abc;
-  }else if(prompt.value=='@'){
-    const abc=  gptsUlistStore.myData.slice(0,10).map( (v:gptsType) => {
-      return {
-        label:v.info,
-        gpts:v,
-        value:v.gid
-      }
-    })
-   return abc ;
-  }else {
+  }
+  else {
     return []
   }
 })
 
-const goUseGpts= async ( item: gptsType)=>{
-    const saveObj= {model:  `${ item.gid }`   ,gpts:item}
-    gptConfigStore.setMyData(saveObj); 
-    if(chatStore.active){ //保存到对话框
-        const  chatSet = new chatSetting( chatStore.active );
-        if( chatSet.findIndex()>-1 ) chatSet.save( saveObj )
-    }
-    ms.success(t('mjchat.success2'));
-    const gptUrl= `https://gpts.ddaiai.com/open/gptsapi/use`; 
-    myFetch(gptUrl,item );
-     
-    mlog('go local ', homeStore.myData.local );
-    if(homeStore.myData.local!=='Chat') router.replace({name:'Chat',params:{uuid:chatStore.active}});
-
-    gptsUlistStore.setMyData( item );
-
-}
-
 // value反渲染key
-const renderOption = (option: { label: string,gpts?:gptsType }) => {
-  if( prompt.value=='@'){
-    //return [ h( NAvatar,{src:'https://cos.aitutu.cc/gpts/gpt4all.jpg',size:"small",round:true}),option.label ]
-    return [h("div",{class:'flex justify-start items-center'
-    , onclick:()=>{  
-      if(option.gpts)   goUseGpts(option.gpts) ;
-      prompt.value='';
-      setTimeout(() =>  prompt.value='', 80);
-    }}
-    ,[h(NAvatar,{src:option.gpts?.logo, "fallback-src" : 'https://cos.aitutu.cc/gpts/3.5net.png',size:"small",round:true, class:"w-8 h-8"})
-    , h('span', { class: 'pl-1' }, option.gpts?.name  ) 
-    , h('span', { class: 'line-clamp-1 flex-1 pl-1 opacity-50' }, option.label  ) 
-    ])]
-  }
+const renderOption = (option: { label: string }) => {
   for (const i of promptTemplate.value) {
     if (i.value === option.label)
       return [i.key]
@@ -502,7 +463,7 @@ const buttonDisabled = computed(() => {
 const footerClass = computed(() => {
   let classes = ['p-4']
   if (isMobile.value)
-    classes = ['sticky', 'left-0', 'bottom-0', 'right-0', 'p-2', 'pr-3'] //, 'overflow-hidden'
+    classes = ['sticky', 'left-0', 'bottom-0', 'right-0', 'p-2', 'pr-3', 'overflow-hidden']
   return classes
 })
 
@@ -524,20 +485,10 @@ watch(()=>homeStore.myData.act,(n)=>{
     if(n=='scrollToBottom') scrollToBottom();
     if(n=='scrollToBottomIfAtBottom') scrollToBottomIfAtBottom();
     if(n=='gpt.submit' || n=='gpt.resubmit'){ loading.value = true;}
-    if(n=='stopLoading'){ loading.value = false;}
 });
 const st =ref({inputme:true});
 
 watch( ()=>loading.value ,(n)=> homeStore.setMyData({isLoader:n }))
-
-const ychat = computed( ()=>{
-  let text= prompt.value
-  if (loading.value) text= "";
-  else {
-    scrollToBottomIfAtBottom();
-  }
-  return { text, dateTime: t('chat.preview')} as Chat.Chat;
-}) 
 </script>
 
 <template>
@@ -578,13 +529,6 @@ const ychat = computed( ()=>{
                 :chat="item"
                 :index="index"
               />
-              <Message  v-if="ychat.text && !homeStore.myData.session.isCloseMdPreview"
-              :key="dataSources.length" :inversion="true"
-              :date-time="$t('mj.typing')"
-              :chat="ychat"
-              :text="ychat.text"
-              :index="dataSources.length"
-              />
               <div class="sticky bottom-0 left-0 flex justify-center">
                 <NButton v-if="loading" type="warning" @click="handleStop">
                   <template #icon>
@@ -645,9 +589,9 @@ const ychat = computed( ()=>{
               </span>
             </template>
           </NButton>
-
         </div>
       </div>
+
     </footer>
   </div>
 

+ 11 - 31
src/views/chat/layout/Layout.vue

@@ -6,11 +6,7 @@ import Sider from './sider/index.vue'
 import Permission from './Permission.vue'
 import { useBasicLayout } from '@/hooks/useBasicLayout'
 import { gptConfigStore, homeStore, useAppStore, useAuthStore, useChatStore } from '@/store'
-import { aiSider,aiFooter} from '@/views/mj' 
-import aiMobileMenu from '@/views/mj/aiMobileMenu.vue'; 
-import { t } from '@/locales'
-import { mlog, openaiSetting } from '@/api'
-import { isObject } from '@/utils/is'
+import { aiSider,aiGpts ,aiGallery} from '@/views/mj' 
 
 const router = useRouter()
 const appStore = useAppStore()
@@ -18,23 +14,18 @@ const chatStore = useChatStore()
 const authStore = useAuthStore()
 
 const rt = useRoute();
-const ms = useMessage();
-openaiSetting( rt.query)
-if(rt.name =='GPTs'){ 
+if(rt.name =='GPTs'){
+  const ms = useMessage();
   let model= `gpt-4-gizmo-${rt.params.gid.toString()}`  ;
   gptConfigStore.setMyData({model:model});
-  ms.success(`GPTs ${t('mj.modleSuccess')}`);
-}else if(rt.name=='Setting'){ 
-  openaiSetting( rt.query);
-  if(isObject( rt.query ))  ms.success( t('mj.setingSuccess') ); 
-}else if(rt.name=='Model'){ 
+  ms.success(`GPTs 模型加载成功`);
+}else if(rt.name=='Model'){
+   const ms = useMessage();
   let model= `${rt.params.gid.toString()}`  ;
   gptConfigStore.setMyData({model:model});
-  ms.success( t('mj.modleSuccess') );
+  ms.success(`模型加载成功`);
 }
 
- 
-
 router.replace({ name: 'Chat', params: { uuid: chatStore.active } })
 homeStore.setMyData({local:'Chat'});
 const { isMobile } = useBasicLayout()
@@ -42,11 +33,7 @@ const { isMobile } = useBasicLayout()
 
 const collapsed = computed(() => appStore.siderCollapsed)
 
-const needPermission = computed(() => {
-//mlog( 'Layout token',  authStore.token   )
-   
- return  !!authStore.session?.auth && !authStore.token
-})
+const needPermission = computed(() => !!authStore.session?.auth && !authStore.token)
 
 const getMobileClass = computed(() => {
   if (isMobile.value)
@@ -63,7 +50,7 @@ const getContainerClass = computed(() => {
 </script>
 
 <template>
-  <div class="  dark:bg-[#24272e] transition-all p-0"  :class="[isMobile ? 'h55' : 'h-full' ]">
+  <div class="h-full dark:bg-[#24272e] transition-all" :class="[isMobile ? 'p-0' : 'p-0']">
     <div class="h-full overflow-hidden" :class="getMobileClass">
       <NLayout class="z-40 transition" :class="getContainerClass" has-sider>
         <aiSider v-if="!isMobile"/>
@@ -77,13 +64,6 @@ const getContainerClass = computed(() => {
     </div>
     <Permission :visible="needPermission" />
   </div>
-   <aiMobileMenu v-if="isMobile"   /> 
-
-  <aiFooter/>
+  <aiGpts/>
+  <aiGallery/>
 </template>
-
-<style  >
-.h55{
-  height: calc(100% - 55px);
-}
-</style>

+ 2 - 1
src/views/chat/layout/sider/Footer.vue

@@ -3,8 +3,9 @@ import { defineAsyncComponent, ref } from 'vue'
 import { HoverButton, SvgIcon, UserAvatar } from '@/components/common'
 
 const Setting = defineAsyncComponent(() => import('@/components/common/Setting/index.vue'))
-
 const show = ref(false)
+
+
 </script>
 
 <template>

+ 9 - 25
src/views/chat/layout/sider/List.vue

@@ -1,12 +1,10 @@
 <script setup lang='ts'>
-import { computed ,watch,ref} from 'vue'
+import { computed } from 'vue'
 import { NInput, NPopconfirm, NScrollbar } from 'naive-ui'
 import { SvgIcon } from '@/components/common'
-import { gptConfigStore, gptConfigType, homeStore, useAppStore, useChatStore } from '@/store'
+import { useAppStore, useChatStore } from '@/store'
 import { useBasicLayout } from '@/hooks/useBasicLayout'
 import { debounce } from '@/utils/functions/debounce'
-import { chatSetting, mlog } from '@/api'
-import AiListText from '@/views/mj/aiListText.vue'
 
 const { isMobile } = useBasicLayout()
 
@@ -50,23 +48,6 @@ function handleEnter({ uuid }: Chat.History, isEdit: boolean, event: KeyboardEve
 function isActive(uuid: number) {
   return chatStore.active === uuid
 }
-
-const chatSet= new chatSetting( chatStore.active??1002);
-const myuid= ref<gptConfigType[]>( []) //computed( ()=>chatSet.getObjs() ) ;
-const toMyuid= ( )=> myuid.value= chatSet.getObjs();
-toMyuid();
-const isInObjs= (uuid:number):undefined|gptConfigType =>{
-  if(!myuid.value.length) return ;
-  const index = myuid.value.findIndex((item:gptConfigType)=>{
-    return item.uuid==uuid
-  })
-  if(index==-1) return ;
-  mlog('index',index, myuid.value[index]  );
-  return myuid.value[index] ;
-}
-watch(()=>homeStore.myData.act,(n:string)=>n=='saveChat' && toMyuid() , {deep:true})
-watch(()=>gptConfigStore.myData , toMyuid , {deep:true})
-
 </script>
 
 <template>
@@ -85,14 +66,17 @@ watch(()=>gptConfigStore.myData , toMyuid , {deep:true})
             :class="isActive(item.uuid) && ['border-[#4b9e5f]', 'bg-neutral-100', 'text-[#4b9e5f]', 'dark:bg-[#24272e]', 'dark:border-[#4b9e5f]', 'pr-14']"
             @click="handleSelect(item)"
           >
-             
-             <AiListText   :myObj="isInObjs(item.uuid)" :myItem="item">
-               <NInput
+            <span>
+              <SvgIcon icon="ri:message-3-line" />
+            </span>
+            <div class="relative flex-1 overflow-hidden break-all text-ellipsis whitespace-nowrap">
+              <NInput
                 v-if="item.isEdit"
                 v-model:value="item.title" size="tiny"
                 @keypress="handleEnter(item, false, $event)"
               />
-             </AiListText>
+              <span v-else>{{ item.title }}</span>
+            </div>
             <div v-if="isActive(item.uuid)" class="absolute z-10 flex visible right-1">
               <template v-if="item.isEdit">
                 <button class="p-1" @click="handleEdit(item, false, $event)">

+ 1 - 1
src/views/chat/layout/sider/index.vue

@@ -82,7 +82,7 @@ watch(
     :width="260"
     :show-trigger="isMobile ? false : 'arrow-circle'"
     collapse-mode="transform"
-
+    
     bordered
     :style="getMobileClass"
     @update-collapsed="handleUpdateCollapsed"

+ 21 - 14
src/views/mj/aiDall.vue

@@ -1,15 +1,16 @@
 <script setup lang="ts">
 import { ref ,computed,watch} from 'vue';
-import { NButton,NSelect,NInput} from 'naive-ui';
+import {useMessage, NButton,NSelect,NInput} from 'naive-ui';
 import { homeStore } from '@/store';
 import { SvgIcon } from '@/components/common';
 
+const ms = useMessage();
 const config = ref( {
     model:[{"label": "DALL·E 3", "value": "dall-e-3" }],
     quality:[{"label": "标准", "value": "standard"},{"label": "高清", "value": "hd" }],
     style:[{"label": "现实", "value": "vivid"},{"label": "自然", "value": "natural"}],
 });
-const st =ref({isGo:false });
+const st =ref({isGo:false });     
 const f = ref({size:'1024x1024',quality:'hd',style:'natural', prompt:'',"model": "dall-e-3","n": 1});
 
 
@@ -19,6 +20,12 @@ const isDisabled= computed(()=>{
     return false;
 });
 const create= async ()=>{
+    // const d= await gptFetch('/v1/embeddings',{
+    // "input":  f.value.prompt,
+    // "model": "text-embedding-ada-002"
+    // });
+    // mlog('test',d );
+    //return ;
     let obj= {
         action:'gpt.dall-e-3',
         data:f.value
@@ -31,12 +38,12 @@ watch(()=>homeStore.myData.act,(n)=>{
         st.value.isGo=false;
         f.value.prompt='';
     }
-    if(n=='updateChat')  st.value.isGo=false;
+    if(n=='updateChat')  st.value.isGo=false;  
 })
 
 const dimensionsList= computed(()=>{
     if(f.value.model=='dall-e-2'){
-        return [{
+        return [{ 
                 "label": "1024px*1024px",
                 "value": "1024x1024"
             }, {
@@ -47,8 +54,8 @@ const dimensionsList= computed(()=>{
                 "value": "256x256"
             }
     ];
-    }
-    return [{
+    } 
+    return [{ 
                 "label": "1024px*1024px",
                 "value": "1024x1024"
             }, {
@@ -59,7 +66,7 @@ const dimensionsList= computed(()=>{
                 "value": "1024x1792"
             }
      ]
-
+     
 })
 watch(()=>f.value.model,(n)=>{
     f.value.size='1024x1024';
@@ -83,17 +90,17 @@ watch(()=>f.value.model,(n)=>{
     <n-select v-model:value="f.style" :options="config.style" size="small"  class="!w-[70%]" :clearable="false" />
 </section>
 <div class="mb-1">
-     <n-input    type="textarea"  v-model:value="f.prompt"   placeholder="提示词" round clearable maxlength="500" show-count
+     <n-input    type="textarea"  v-model:value="f.prompt"   placeholder="提示词" round clearable maxlength="500" show-count 
       :autosize="{   minRows:3, maxRows:10 }" />
 </div>
 
 <div class="mb-4 flex justify-end items-center">
     <div class="flex ">
          <n-button type="primary" :block="true" :disabled="isDisabled" @click="create()"  >
-            <SvgIcon icon="mingcute:send-plane-fill" />
-
-             生成图片
+            <SvgIcon icon="mingcute:send-plane-fill" />  
 
+             生成图片 
+            
         </n-button>
     </div>
 </div>
@@ -101,7 +108,7 @@ watch(()=>f.value.model,(n)=>{
 <ul class="pt-4">
     说明:
     <li>1 dall-e 是openAi提供的画图模型</li>
-    <li>2 openAi的图片有时效性,请做好备份</li>
-    <li>3 注意:1790px的图片价格是双倍</li>
+    <li>2 openAi的图片有时效性,请做好备份</li> 
+    <li>3 注意:1790px的图片价格是双倍</li> 
 </ul>
-</template>
+</template>

+ 5 - 58
src/views/mj/aiGptInput.vue

@@ -3,19 +3,16 @@ import { ref ,computed,watch } from 'vue';
 import { useBasicLayout } from '@/hooks/useBasicLayout'
 import { t } from '@/locales'
 import { NInput ,NButton,useMessage,NImage,NTooltip, NAutoComplete,NTag
-,NPopover,NModal, NDropdown  } from 'naive-ui'
+,NPopover,NModal  } from 'naive-ui'
 import { SvgIcon } from '@/components/common';
-import { canVisionModel, GptUploader, mlog, upImg,getFileFromClipboard,isFileMp3
-    ,countTokens, checkDisableGpt4, Recognition } from '@/api';
+import { canVisionModel, GptUploader, mlog, upImg,getFileFromClipboard,isFileMp3,countTokens, checkDisableGpt4} from '@/api';
 import { gptConfigStore, homeStore,useChatStore } from '@/store';
 import { AutoCompleteOptions } from 'naive-ui/es/auto-complete/src/interface';
 import { RenderLabel } from 'naive-ui/es/_internal/select-menu/src/interface';
 import { useRoute } from 'vue-router' 
 import aiModel from "@/views/mj/aiModel.vue"
 import AiMic from './aiMic.vue';
-import { useIconRender } from '@/hooks/useIconRender'
 
-const { iconRender } = useIconRender()
 //import FormData from 'form-data'
 const route = useRoute() 
 const chatStore = useChatStore()
@@ -23,8 +20,7 @@ const chatStore = useChatStore()
 const emit = defineEmits(['update:modelValue'])
 const props = defineProps<{ modelValue:string,disabled?:boolean,searchOptions?:AutoCompleteOptions,renderOption?: RenderLabel }>();
 const fsRef = ref()
-const st = ref<{fileBase64:string[],isLoad:number,isShow:boolean,showMic:boolean,micStart:boolean}>({fileBase64:[],isLoad:0
-    ,isShow:false,showMic:false , micStart:false})
+const st = ref<{fileBase64:string[],isLoad:number,isShow:boolean,showMic:boolean}>({fileBase64:[],isLoad:0,isShow:false,showMic:false })
 const { isMobile } = useBasicLayout()
 const placeholder = computed(() => {
   if (isMobile.value)
@@ -170,43 +166,6 @@ const sendMic= (e:any )=>{
     homeStore.setMyData({act:'gpt.whisper', actData:{ file , prompt:'whisper',duration : e.stat?.duration } });
 }
 
-//语音识别ASR
-const goASR=()=>{
-    const olod = mvalue.value;
-    const rec= new Recognition();
-    let rz= '';
-    rec.setListener( (r:string)=>{
-        //mlog('result ', r  );
-        rz= r ; 
-        mvalue.value= r;
-        st.value.micStart= true 
-    }).setOnEnd( ( )=>{
-        //mlog('rec end');
-        mvalue.value= olod+rz;
-        ms.info( t('mj.micRecEnd'));
-        st.value.micStart= false 
-    }).setOpt({
-        timeOut:2000,
-        onStart:()=>{ ms.info( t('mj.micRec')); st.value.micStart= true },
-    }).start();
-}
-
-const drOption=[
-    {
-        label:  t('mj.micWhisper'),
-        key: "whisper",
-        icon:iconRender({ icon: 'ri:openai-fill' }),
-    },{
-        label:  t('mj.micAsr'),
-        icon:iconRender({ icon: 'ri:chrome-line' }),
-        key: "asr"
-    }
-]
-const handleSelectASR = ( key: string | number )=>{ 
-    if(key=='asr')    goASR(); 
-    if(key=='whisper')   st.value.showMic=true; 
-}
-
 </script>
 <template>
 <div v-if="st.showMic" class="  myinputs flex justify-center items-center" >
@@ -271,21 +230,9 @@ const handleSelectASR = ( key: string | number )=>{
                     </div>
                     </n-tooltip>
                 </div>
-                <!-- <div  class=" relative; w-[22px]">
+                <div  class=" relative; w-[22px]">
                     <SvgIcon icon="bi:mic"  class="absolute bottom-[10px] left-[30px] cursor-pointer" @click="st.showMic=true"></SvgIcon>
-                </div> -->
-                <n-dropdown trigger="hover" :options="drOption" @select="handleSelectASR">
-                    <div  class=" relative; w-[22px]">
-                        <div class="absolute bottom-[14px] left-[31px]" v-if="st.micStart">
-                            <span class="relative flex h-3 w-3" >
-                                <span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-500 opacity-75"></span>
-                                <span class="relative inline-flex rounded-full h-3 w-3 bg-red-400"></span>
-                            </span>
-                        </div>
-                        <!-- <SvgIcon icon="bi:mic"  class="absolute bottom-[10px] left-[55px] cursor-pointer" @click="goASR()"></SvgIcon> -->
-                        <SvgIcon icon="bi:mic"  class="absolute bottom-[10px] left-[30px] cursor-pointer"></SvgIcon>
-                    </div>
-                </n-dropdown>
+                </div>
                 
             </template>
             <template #suffix>

+ 1 - 0
src/views/mj/aiGptsCom.vue

@@ -7,6 +7,7 @@ import { SvgIcon } from '@/components/common';
 import { useRouter } from 'vue-router';
 import { t } from '@/locales'; 
 
+
 const router = useRouter()
 const ms = useMessage();
 const chatStore = useChatStore()

+ 1 - 1
src/views/mj/aiMobileMenu.vue

@@ -53,7 +53,7 @@ watch(()=>homeStore.myData.act, (n:string)=>{
       </div> 
   </div>
 
-  <n-drawer v-model:show="st.show"  class="!h-[90vh] !max-h-[660px]"  placement="bottom" v-if="goHome=='draw'">
+  <n-drawer v-model:show="st.show" :height="650"  placement="bottom" v-if="goHome=='draw'">
     <n-drawer-content   style="--n-body-padding:0" class="h-full">
       <aiDrawInput @draw-sent="drawSent" />
     </n-drawer-content>

+ 7 - 7
src/views/mj/aiModel.vue

@@ -14,13 +14,13 @@ const chatSet = new chatSetting( uuid==null?1002:uuid);
 const nGptStore = ref(  chatSet.getGptConfig() );
 
 const config = ref({
-model:[ 'gpt-4-0125-preview','gpt-3.5-turbo-0125','gpt-4-all','net-gpt-3.5-turbo']
+model:['gpt-3.5-turbo','gpt-3.5-turbo-0125','gpt-4-0125-preview','gpt-4-all']
 ,maxToken:2048
-});
+}); 
 const st= ref({openMore:false });
 const voiceList= computed(()=>{
     let rz=[];
-    for(let o of "alloy,echo,fable,onyx,nova,shimmer".split(/[ ,]+/ig))rz.push({label:o,value:o})
+    for(let o of "alloy,echo,fable,onyx,nova,shimmer".split(/[ ,]+/ig))rz.push({label:o,value:o}) 
     return rz;
 });
 const modellist = computed(() => { //
@@ -60,7 +60,7 @@ const modellist = computed(() => { //
     return uniqueArray ;
 });
 const ms= useMessage();
-const save = ()=>{
+const save = ()=>{ 
     gptConfigStore.setMyData( nGptStore.value );
     ms.success( t('common.saveSuccess')); //'保存成功'
     emit('close');
@@ -73,7 +73,7 @@ const saveChat=()=>{
      ms.success( t('common.saveSuccess'));
      emit('close');
 }
-
+ 
 watch(()=>nGptStore.value.model,(n)=>{
     nGptStore.value.gpts=undefined;
     let max=4096;
@@ -122,7 +122,7 @@ onMounted(() => {
 <div class="mb-4 text-[12px] text-gray-300 dark:text-gray-300/20">{{ $t('mjchat.historyToken') }}</div>
 
  <section class=" flex justify-between items-center"  >
-     <div> {{ $t('mjchat.historyTCnt') }}
+     <div> {{ $t('mjchat.historyTCnt') }} 
      </div>
      <div class=" flex justify-end items-center w-[80%] max-w-[240px]">
         <div class=" w-[200px]"><n-slider v-model:value="nGptStore.max_tokens" :step="1" :max="config.maxToken" :min="1" /></div>
@@ -194,4 +194,4 @@ onMounted(() => {
     <NButton type="primary" @click="saveChat">{{ $t('mj.setBtSaveChat') }}</NButton>
     <!-- <NButton type="primary" @click="save">{{ $t('mj.setBtSaveSys') }}</NButton> -->
  </section>
-</template>
+</template>

+ 18 - 17
src/views/mj/aiSider.vue

@@ -40,7 +40,7 @@ const chatId= computed(()=>chatStore.active??'1002' );
         <div class="flex flex-col space-y-4 flex-1">
             <a :href="`#/chat/${chatId}`"    @click="st.active='chat'" class="router-link-active router-link-exact-active h-12 w-12 cursor-pointer rounded-xl bg-white duration-300 dark:bg-[#34373c] hover:bg-[#bbb] dark:hover:bg-[#555]">
                 <n-tooltip placement="right" trigger="hover">
-                  <template #trigger>
+                  <template #trigger> 
                     <div  class="flex h-full justify-center items-center py-1 flex-col " :class="[ goHome =='Chat' ? 'active' : '']">
                     <SvgIcon icon="ri:wechat-line" class="text-3xl  flex-1"></SvgIcon>
                      <span class="text-[10px]">{{$t('mjtab.chat')}}</span>
@@ -48,27 +48,27 @@ const chatId= computed(()=>chatStore.active??'1002' );
                  </template>
                 AI Chat
                 </n-tooltip>
-            </a>
+            </a> 
             <a   @click="homeStore.setMyData({act:'showgpts'}) " class=" router-link-exact-active h-12 w-12 cursor-pointer rounded-xl bg-white duration-300 dark:bg-[#34373c] hover:bg-[#bbb] dark:hover:bg-[#555]">
                 <n-tooltip placement="right" trigger="hover">
-                  <template #trigger>
+                  <template #trigger> 
                     <div  class="flex h-full justify-center items-center   py-1 flex-col" >
                     <SvgIcon icon="ri:apps-fill" class="text-3xl flex-1"></SvgIcon>
                      <span class="text-[10px]">GPTs</span>
-                    </div>
+                    </div> 
                   </template>
-                    ChatGPT Store
+                    ChatGPT Store 
                 </n-tooltip>
             </a>
 
 
             <a :href="`#/draw/${chatId}`" @click="st.active='draw'" class=" router-link-exact-active h-12 w-12 cursor-pointer rounded-xl bg-white duration-300 dark:bg-[#34373c] hover:bg-[#bbb] dark:hover:bg-[#555]">
                 <n-tooltip placement="right" trigger="hover">
-                  <template #trigger>
+                  <template #trigger> 
                     <div  class="flex h-full justify-center items-center   py-1 flex-col" :class="[goHome=='draw' ? 'active' : '']">
                     <SvgIcon icon="ic:outline-palette" class="text-3xl flex-1"></SvgIcon>
                      <span class="text-[10px]">{{$t('mjtab.draw')}}</span>
-                    </div>
+                    </div> 
                   </template>
                     {{$t('mjtab.drawinfo')}}
                 </n-tooltip>
@@ -78,11 +78,11 @@ const chatId= computed(()=>chatStore.active??'1002' );
 
              <a   @click="homeStore.setMyData({act:'gallery'}) " class=" router-link-exact-active h-12 w-12 cursor-pointer rounded-xl bg-white duration-300 dark:bg-[#34373c] hover:bg-[#bbb] dark:hover:bg-[#555]">
                 <n-tooltip placement="right" trigger="hover">
-                  <template #trigger>
+                  <template #trigger> 
                     <div  class="flex h-full justify-center items-center   py-1 flex-col" >
                     <SvgIcon icon="material-symbols:imagesmode-outline" class="text-3xl flex-1"></SvgIcon>
                      <span class="text-[10px]">{{$t('mjtab.gallery')}}</span>
-                    </div>
+                    </div> 
                   </template>
                     {{ $t('mjtab.galleryInfo') }}
                 </n-tooltip>
@@ -92,25 +92,25 @@ const chatId= computed(()=>chatStore.active??'1002' );
             <!-- <section  class=" router-link-exact-active h-12 w-12 cursor-pointer rounded-xl bg-white duration-300 dark:bg-[#34373c] hover:bg-[#bbb] dark:hover:bg-[#555]"
              >
                 <n-tooltip placement="right" trigger="hover">
-                  <template #trigger>
+                  <template #trigger> 
                     <div  class="flex  h-full justify-center items-center py-1 flex-col ">
                       <SvgIcon icon="mingcute:grid-2-line" class="text-3xl flex-1"></SvgIcon>
                       <span class="text-[10px]">画廊</span>
-                    </div>
+                    </div>  
                   </template>
                     画廊:看看别人是如何画的
-                </n-tooltip>
+                </n-tooltip>                
             </section> -->
 
-
+             
 
         </div>
-        <!-- <div class="flex flex-col  space-y-2 ">
-
+        <!-- <div class="flex flex-col  space-y-2 "> 
 
+            
             <NAvatar  size="large"  round  :src="userInfo.avatar"   v-if="userInfo.avatar"
              class=" cursor-pointer"  />
-
+            
             <HoverButton>
                 <div class="text-xl text-[#4f555e] dark:text-white flex h-full justify-center items-center "  @click="st.show = true">
                     <SvgIcon icon="ri:settings-4-line" />
@@ -123,8 +123,9 @@ const chatId= computed(()=>chatStore.active??'1002' );
 
  <!-- <n-drawer v-model:show="st.showImg" :placement="isMobile?'bottom':'right'"  :class="isMobile?['!h-[90vh]']: ['!w-[80vw]']" style="--n-body-padding:0">
     <n-drawer-content title="GPT store" closable>
-      sdsd
+      sdsd 
     </n-drawer-content>
 </n-drawer> -->
 </template>
 
+