Explorar el Código

修复付费用户验证

ageer hace 1 año
padre
commit
94753a1566

+ 5 - 4
src/api/openapi.ts

@@ -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('/v1/images/generations', data.data);
+       let d= await gptFetch('/dell3', data.data);
        try{
             const rz : any= d.data[0];
             chat.text= rz.revised_prompt??`图片已完成`;
@@ -237,11 +237,12 @@ export const subModel= async (opt: subModelType)=>{
             signal:opt.signal,
             onMessage: async (data:string)=> {
                  //mlog('🐞测试'  ,  data )  ;
-                 if(data=='[DONE]') opt.onMessage({text:'',isFinish:true})
-                 else {
+                 try{
                     const obj= JSON.parse(data );
                     opt.onMessage({text:obj.choices[0].delta?.content??'' ,isFinish:obj.choices[0].finish_reason!=null })
-                 }
+                }catch{
+                    opt.onMessage({text:data,isFinish:true})    
+                }
             },
             onError(e ){
                 //console.log('eee>>', e )

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

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

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

@@ -1,10 +1,11 @@
 <script lang="ts" setup>
-import { computed, nextTick,ref  } from 'vue'
+import { computed, nextTick,ref,watch  } 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()
 
@@ -44,8 +45,12 @@ 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>
@@ -84,20 +89,20 @@ const st = ref({isShow:false});
     
     <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="gptConfigStore.myData.gpts">
+            <template   v-if="nGptStore.gpts">
              <SvgIcon icon="ri:apps-fill" /> 
-             <span class="line-clamp-1 overflow-hidden">{{ gptConfigStore.myData.gpts.name }}</span> 
+             <span class="line-clamp-1 overflow-hidden">{{ nGptStore.gpts.name }}</span> 
             </template>
             <template v-else >
             <SvgIcon icon="heroicons:sparkles" /> 
-            <span >{{ gptConfigStore.myData.model }}</span> 
+            <span >{{ nGptStore.model }}</span> 
             </template>
             <SvgIcon icon="icon-park-outline:right" />
         </div>
     </div>
   </header>
 
-  <NModal v-model:show="st.isShow"   preset="card"  title="模型切换" class="!max-w-[660px]" @close="st.isShow=false" >  
+  <NModal v-model:show="st.isShow"   preset="card"  :title="$t('mjchat.modelChange')" class="!max-w-[620px]" @close="st.isShow=false" >  
         <aiModel @close="st.isShow=false"/>
   </NModal>
 </template>

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

@@ -1,9 +1,11 @@
+
+
 <script setup lang='ts'>
 import type { Ref } from 'vue'
-import { computed, onMounted, onUnmounted, ref,watch } from 'vue'
-import { useRoute } from 'vue-router'
+import { computed, onMounted, onUnmounted, ref,watch,h } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
 import { storeToRefs } from 'pinia'
-import { NAutoComplete, NButton, NInput, useDialog, useMessage } from 'naive-ui'
+import { NAutoComplete, NButton, NInput, useDialog, useMessage,NAvatar } from 'naive-ui'
 import html2canvas from 'html2canvas'
 import { Message } from './components'
 import { useScroll } from './hooks/useScroll'
@@ -12,14 +14,13 @@ import { useUsingContext } from './hooks/useUsingContext'
 import HeaderComponent from './components/Header/index.vue'
 import {  SvgIcon } from '@/components/common'
 import { useBasicLayout } from '@/hooks/useBasicLayout'
-import { gptConfigStore, homeStore, useChatStore, usePromptStore } from '@/store'
-import { fetchChatAPIProcess } from '@/api'
+import { gptConfigStore, gptsUlistStore, homeStore, useChatStore, usePromptStore } from '@/store'
+import { chatSetting, fetchChatAPIProcess, gptsType, mlog, myFetch } 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()
 
@@ -28,7 +29,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()
@@ -57,17 +58,14 @@ 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='';
 }
 
@@ -429,20 +427,61 @@ function handleStop() {
 // 理想状态下其实应该是key作为索引项,但官方的renderOption会出现问题,所以就需要value反renderLabel实现
 const searchOptions = computed(() => {
   if (prompt.value.startsWith('/')) {
-    return promptTemplate.value.filter((item: { key: string }) => item.key.toLowerCase().includes(prompt.value.substring(1).toLowerCase())).map((obj: { value: any }) => {
+    const abc= 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,
       }
     })
-  }
-  else {
+    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 {
     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 }) => {
+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  ) 
+    ])]
+  }
   for (const i of promptTemplate.value) {
     if (i.value === option.label)
       return [i.key]
@@ -463,7 +502,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
 })
 
@@ -485,10 +524,20 @@ 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>
@@ -529,6 +578,13 @@ watch( ()=>loading.value ,(n)=> homeStore.setMyData({isLoader:n }))
                 :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>
@@ -589,9 +645,9 @@ watch( ()=>loading.value ,(n)=> homeStore.setMyData({isLoader:n }))
               </span>
             </template>
           </NButton>
+
         </div>
       </div>
-
     </footer>
   </div>
 

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

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

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

@@ -3,9 +3,8 @@ 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)
-
 
+const show = ref(false)
 </script>
 
 <template>

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

@@ -1,10 +1,12 @@
 <script setup lang='ts'>
-import { computed } from 'vue'
+import { computed ,watch,ref} from 'vue'
 import { NInput, NPopconfirm, NScrollbar } from 'naive-ui'
 import { SvgIcon } from '@/components/common'
-import { useAppStore, useChatStore } from '@/store'
+import { gptConfigStore, gptConfigType, homeStore, 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()
 
@@ -48,6 +50,23 @@ 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>
@@ -66,17 +85,14 @@ function isActive(uuid: number) {
             :class="isActive(item.uuid) && ['border-[#4b9e5f]', 'bg-neutral-100', 'text-[#4b9e5f]', 'dark:bg-[#24272e]', 'dark:border-[#4b9e5f]', 'pr-14']"
             @click="handleSelect(item)"
           >
-            <span>
-              <SvgIcon icon="ri:message-3-line" />
-            </span>
-            <div class="relative flex-1 overflow-hidden break-all text-ellipsis whitespace-nowrap">
-              <NInput
+             
+             <AiListText   :myObj="isInObjs(item.uuid)" :myItem="item">
+               <NInput
                 v-if="item.isEdit"
                 v-model:value="item.title" size="tiny"
                 @keypress="handleEnter(item, false, $event)"
               />
-              <span v-else>{{ item.title }}</span>
-            </div>
+             </AiListText>
             <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)">

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

@@ -100,7 +100,7 @@ watch(
         <div class="flex items-center p-4 space-x-4">
           <div class="flex-1">
             <NButton block @click="show = true">
-              进入市场选购您的商品
+              {{ $t('store.siderButton') }}
             </NButton>
           </div>
           <NButton @click="handleClearAll">
@@ -108,11 +108,11 @@ watch(
           </NButton>
         </div>
       </main>
-      <Footer></Footer>
+      <Footer />
     </div>
   </NLayoutSider>
   <template v-if="isMobile">
     <div v-show="!collapsed" class="fixed inset-0 z-40 w-full h-full bg-black/40" @click="handleUpdateCollapsed" />
   </template>
-  <PromptStore v-model:visible="show" ></PromptStore>
+  <PromptStore v-model:visible="show" />
 </template>

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

@@ -14,7 +14,7 @@ const chatSet = new chatSetting( uuid==null?1002:uuid);
 const nGptStore = ref(  chatSet.getGptConfig() );
 
 const config = ref({
-model:['gpt-3.5-turbo','gpt-3.5-turbo-0125','gpt-4-0125-preview','gpt-4-all']
+model:['gpt-3.5-turbo','gpt-4-0125-preview','gpt-4-all']
 ,maxToken:2048
 }); 
 const st= ref({openMore:false });