aiGpt.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. <script setup lang='ts'>
  2. import { computed, ref,watch } from 'vue'
  3. import { useRoute } from 'vue-router'
  4. import { useChat } from '../chat/hooks/useChat'
  5. import { homeStore, useChatStore } from '@/store'
  6. import { getInitChat, mlog, subModel,getSystemMessage , localSaveAny, canVisionModel
  7. ,isTTS, subTTS, file2blob, whisperUpload, getHistoryMessage, checkDisableGpt4, chatSetting, isCanBase64Model, } from '@/api'
  8. //import { isNumber } from '@/utils/is'
  9. import { useMessage } from "naive-ui";
  10. import { t } from "@/locales";
  11. const emit = defineEmits(['finished']);
  12. const { addChat , updateChatSome } = useChat()
  13. const chatStore = useChatStore()
  14. const st=ref({uuid:'1002', index:-1, chatType:0, appId:'' });
  15. const controller = ref<AbortController>( );;// new AbortController();
  16. const dataSources = computed(() => chatStore.getChatByUuid(+st.value.uuid))
  17. const ms= useMessage();
  18. const textRz= ref<string[]>([]);
  19. const goFinish= ( )=>{
  20. //let dindex = st.value.index>=0? st.value.index : dataSources.value.length - 1;
  21. //return ;
  22. updateChatSome( +st.value.uuid, st.value.index , { dateTime: new Date().toLocaleString(),loading: false })
  23. //scrollToBottom();
  24. emit('finished');
  25. homeStore.setMyData({act:'scrollToBottomIfAtBottom'});
  26. mlog('🐞 goFinish2',st.value.uuid);
  27. // setTimeout(() => {
  28. // if(textRz.value.length>0 ) textRz.value = [];
  29. // }, 200 );
  30. }
  31. const getMessage= async (start=1000,loadingCnt=3)=>{
  32. return getHistoryMessage(dataSources.value,loadingCnt,start);
  33. }
  34. watch( ()=>textRz.value, (n)=>{
  35. //mlog('🐞 textRz',n);
  36. if(n.length==0) return ;
  37. updateChatSome( +st.value.uuid, st.value.index , { dateTime: new Date().toLocaleString(),text: n.join('') })
  38. //scrollToBottom();
  39. homeStore.setMyData({act:'scrollToBottomIfAtBottom'})
  40. //homeStore.setMyData({act:'scrollToBottom'})
  41. },{deep:true})
  42. const { uuid } = useRoute().params as { uuid: string }
  43. watch(()=>homeStore.myData.act, async (n)=>{
  44. if(n=='gpt.submit' || n=='gpt.whisper' ){
  45. const dd:any = homeStore.myData.actData;
  46. let uuid2 = dd.uuid?? uuid;
  47. st.value.uuid = uuid2 ;
  48. st.value.chatType = dd.chatType;
  49. st.value.appId = dd.appId??'';
  50. const chatSet = new chatSetting( +st.value.uuid );
  51. const nGptStore = chatSet.getGptConfig();
  52. mlog('gpt.submit', dd , dd.uuid, nGptStore ) ;
  53. let model = nGptStore.model ;//gptConfigStore.myData.model
  54. if(checkDisableGpt4( model )){
  55. ms.error( t('mj.disableGpt4') );
  56. return false;
  57. }
  58. let promptMsg = getInitChat(dd.prompt );
  59. if( dd.fileBase64 && dd.fileBase64.length>0 ){
  60. if( !canVisionModel(model) ) model='gpt-4o-mini';
  61. try{
  62. let images= await localSaveAny( JSON.stringify( dd.fileBase64) ) ;
  63. mlog('key', images );
  64. promptMsg.opt= {images:[images]}
  65. }catch(e){
  66. mlog('localSaveAny error',e);
  67. }
  68. }
  69. if( n=='gpt.whisper'){
  70. //model='whisper-1';
  71. try{
  72. let bb= await file2blob( dd.file );
  73. // bb.blob
  74. let lkey = await localSaveAny( bb ) ;
  75. mlog('key', lkey );
  76. promptMsg.opt= { lkey }
  77. promptMsg.text='Loading...'
  78. promptMsg.model='whisper-1';
  79. if(dd.duration && dd.duration>0 ){
  80. promptMsg.text=`${t('mj.lang')} ${dd.duration.toFixed(2)}s`;
  81. }
  82. addChat( +uuid2, promptMsg );
  83. homeStore.setMyData({act:'scrollToBottom'});
  84. }catch(e){
  85. mlog('localSaveAny error',e);
  86. ms.error( t('mj.noSupperChrom') );
  87. return ;
  88. }
  89. try{
  90. const formData = new FormData( );
  91. formData.append('file',dd.file );
  92. formData.append('model', 'whisper-1');
  93. const whisper= await whisperUpload( formData);
  94. mlog('whisper 内容>> ', whisper );
  95. let opt={duration:0,...promptMsg.opt };
  96. opt.duration= dd.duration??0;
  97. updateChatSome( +uuid2, dataSources.value.length-1, {text:whisper.text,opt } );
  98. dd.prompt= whisper.text;
  99. //return ;
  100. }catch(e){
  101. updateChatSome( +uuid2, dataSources.value.length-1, {text:`${t('mj.fail')}:${e}` } );
  102. return ;
  103. }
  104. }else{
  105. addChat( +uuid2, promptMsg );
  106. homeStore.setMyData({act:'scrollToBottom'});
  107. }
  108. let outMsg: Chat.Chat={
  109. dateTime: new Date().toLocaleString(),
  110. text: t('mj.thinking') ,//'思考中...',
  111. loading: true,
  112. inversion: false,
  113. error: false,
  114. conversationOptions: null,
  115. requestOptions: { prompt: dd.prompt, options: { } },
  116. uuid:+uuid2,
  117. model ,
  118. myid: `${Date.now()}`
  119. }
  120. // if(gptConfigStore.myData.gpts){
  121. // outMsg.logo= gptConfigStore.myData.gpts.logo ;
  122. // }
  123. // const chatSet = new chatSetting( +st.value.uuid );
  124. // const nGptStore = chatSet.getGptConfig() ;
  125. //chatSet
  126. if( nGptStore.gpts ){
  127. outMsg.logo= nGptStore.gpts.logo ;
  128. }
  129. addChat( +uuid2, outMsg )
  130. st.value.index= dataSources.value.length - 1;
  131. if(textRz.value.length>=0) textRz.value = [ ];
  132. homeStore.setMyData({act:'scrollToBottom'})
  133. let historyMesg= await getMessage();
  134. mlog('historyMesg', historyMesg );
  135. //return ;
  136. // let message= [ { "role": "system", "content": getSystemMessage( +uuid2) },
  137. // ...historyMesg ];
  138. let message= [...historyMesg ];
  139. if( dd.fileBase64 && dd.fileBase64.length>0 ){
  140. if(isCanBase64Model(model)){
  141. let obj={
  142. "role": "user",
  143. "content": [] as any
  144. }
  145. obj.content.push({ "type": "text", "text": dd.prompt });
  146. dd.fileBase64.forEach((f:any)=>{
  147. obj.content.push({ "type": "image_url", "image_url": {url:f } });
  148. });
  149. message.push(obj);
  150. }else{
  151. let cc= dd.prompt;
  152. //附件需要时远程的图片链接 或者文件 链接
  153. let arr = dd.fileBase64.filter( (ff:string)=>ff.indexOf('http')>-1);
  154. if(arr.length>0) cc = arr.join(' ')+' '+ cc ;
  155. message.push({ "role": "user", "content": cc })
  156. }
  157. }else{
  158. message.push({ "role": "user", "content": dd.prompt })
  159. }
  160. let opt={};
  161. if( n=='gpt.whisper'){
  162. opt= {
  163. file: dd.file
  164. }
  165. }
  166. submit(model,message,opt);
  167. }else if(n=='abort'){
  168. controller.value && controller.value.abort();
  169. }else if(n=='gpt.resubmit'){
  170. // if(checkDisableGpt4(gptConfigStore.myData.model)){
  171. // ms.error( t('mj.disableGpt4') );
  172. // return false;
  173. // }
  174. const dd:any = homeStore.myData.actData;
  175. let uuid2 = dd.uuid?? uuid;
  176. st.value.uuid = uuid2 ;
  177. st.value.index = +dd.index;
  178. mlog('gpt.resubmit', dd ) ;
  179. let historyMesg= await getMessage( (+dd.index)-1,1 ); //
  180. mlog('gpt.resubmit historyMesg', historyMesg );
  181. let nobj = dataSources.value[ dd.index ];
  182. //mlog('gpt.resubmit model', nobj.model );
  183. let model = nobj.model as string
  184. if(checkDisableGpt4( model )){
  185. ms.error( t('mj.disableGpt4') );
  186. return false;
  187. }
  188. //return ;
  189. if(['whisper-1','midjourney'].indexOf(model)>-1){
  190. ms.error( t('mj.noSuppertModel') );
  191. return;
  192. }
  193. controller.value = new AbortController();
  194. let message= [ { "role": "system", "content": getSystemMessage(+st.value.uuid ) },
  195. ...historyMesg ];
  196. textRz.value=[];
  197. submit(model, message);
  198. }else if(n=='gpt.ttsv2'){
  199. const actData:any = homeStore.myData.actData;
  200. mlog('gpt.ttsv2',actData );
  201. st.value.index= actData.index;
  202. st.value.uuid= actData.uuid;
  203. ms.info( t('mj.ttsLoading'));
  204. const chatSet = new chatSetting( +st.value.uuid );
  205. const nGptStore = chatSet.getGptConfig() ;
  206. subTTS({model:'tts-1',input: actData.text , voice:nGptStore.tts_voice }).then(d=>{
  207. ms.success( t('mj.ttsSuccess'));
  208. mlog('subTTS',d );
  209. //d.player.play();
  210. //textRz.value.push('ok');
  211. updateChatSome( +st.value.uuid, st.value.index
  212. , {
  213. dateTime: new Date().toLocaleString(),loading: false
  214. ,opt:{duration:d.duration,lkey:d.saveID }
  215. });
  216. // goFinish();
  217. setTimeout(() => {
  218. homeStore.setMyData({act:'playtts',actData:{ saveID:d.saveID} });
  219. }, 100);
  220. }).catch(e=>{
  221. let emsg = (JSON.stringify( e.reason? JSON.parse( e.reason ):e,null,2));
  222. if(e.message!='canceled' && emsg.indexOf('aborted')==-1 ) textRz.value.push("\n"+t('mjchat.failReason')+" \n```\n"+emsg+"\n```\n");
  223. //goFinish();
  224. });
  225. }
  226. })
  227. const submit= (model:string, message:any[],opt?:any)=>{
  228. mlog('提交Model', model );
  229. const chatSet = new chatSetting( +st.value.uuid );
  230. const nGptStore = chatSet.getGptConfig() ;
  231. controller.value = new AbortController();
  232. if(model=='whisper-1'){
  233. //mlog('whisper-12323',opt );
  234. const formData = new FormData( );
  235. formData.append('file', opt.file );
  236. formData.append('model', 'whisper-1');
  237. //GptUploader('/v1/audio/transcriptions',formData).then(r=>{
  238. whisperUpload( formData).then(r=>{
  239. //mlog('语音识别成功', r );
  240. textRz.value.push(r.text);
  241. goFinish();
  242. }).catch(e=>{
  243. let emsg =( ( e.message?? JSON.stringify(e)) );
  244. textRz.value.push("\n"+t('mj.failOcr')+":\n```\n"+emsg+"\n```\n");
  245. goFinish();
  246. });
  247. return ;
  248. }
  249. else if( isTTS(model)){
  250. let text = message[message.length-1].content;
  251. mlog('whisper-tts', message[message.length-1] , text );
  252. subTTS({model,input: text, voice:nGptStore.tts_voice }).then(d=>{
  253. mlog('subTTS',d );
  254. //d.player.play();
  255. //textRz.value.push('ok');
  256. updateChatSome( +st.value.uuid, st.value.index
  257. , {
  258. dateTime: new Date().toLocaleString(),loading: false
  259. ,text:'ok'
  260. ,opt:{duration:d.duration,lkey:d.saveID }
  261. });
  262. goFinish();
  263. setTimeout(() => {
  264. homeStore.setMyData({act:'playtts',actData:{ saveID:d.saveID} });
  265. }, 100);
  266. }).catch(e=>{
  267. let emsg = (JSON.stringify( e.reason? JSON.parse( e.reason ):e,null,2));
  268. if(e.message!='canceled' && emsg.indexOf('aborted')==-1 ) textRz.value.push("\n"+t('mjchat.failReason')+" \n```\n"+emsg+"\n```\n");
  269. goFinish();
  270. });
  271. }else{
  272. subModel( {message, model,
  273. uuid: st.value.uuid //当前会话
  274. ,onMessage: (d) => {
  275. mlog('🐞消息', d)
  276. textRz.value.push(d.text)
  277. },
  278. onError: (e: any) => {
  279. mlog('onError', e)
  280. let emsg = (JSON.stringify(e.reason ? JSON.parse(e.reason) : e, null, 2))
  281. //if(emsg=='{}' ) emsg= JSON.stringify(e );
  282. if (e.message != 'canceled' && emsg.indexOf('aborted') == -1) textRz.value.push("\n" + t('mjchat.failReason') + "\n```\n" + emsg + "\n```\n")
  283. goFinish()
  284. },
  285. signal: controller.value.signal,
  286. kid: '',
  287. chatType: st.value.chatType,
  288. appId: st.value.appId
  289. }).then(()=>goFinish() ).catch(e=>{
  290. if(e.message!='canceled') textRz.value.push("\n"+t('mj.fail')+":\n```\n"+(e.reason??JSON.stringify(e,null,2)) +"\n```\n")
  291. goFinish();
  292. });
  293. }
  294. }
  295. homeStore.setMyData({isLoader:false});
  296. </script>
  297. <template>
  298. </template>