Revert "对接接口"
This reverts commit fbc38504507efb67e05a291f9772d3b23abf7bef.
| | |
| | | ICPLicense: '沪ICPå¤14049296å·-2', |
| | | |
| | | WebApiUrl: { |
| | | MainUrl: 'http:///wi.cpolar.top', |
| | | MainUrl: 'http://101.133.133.173:97', |
| | | AuthUrl: 'http://47.100.245.85:8190/', |
| | | }, |
| | | SoftWareInfo: { |
| | |
| | | <div |
| | | :class="{ 'bg-[#d8d8ff]': item.role === RoleEnum.assistant, 'bg-white': item.role === RoleEnum.user }" |
| | | class="prose text-sm rounded-[6px] p-4 leading-relaxed max-w-[100ch]" |
| | | > |
| | | <component :is="answerTypeMapCom[item.content.type]" :data="item.content.values" /> |
| | | </div> |
| | | |
| | | <!-- <div v-if="item.role === RoleEnum.assistant" class="absolute flex items-center right-0 space-x-2 mr-2 mt-2"> |
| | | v-html="md.render(item.content)" |
| | | ></div> |
| | | <div v-if="item.role === RoleEnum.assistant" class="absolute flex items-center right-0 space-x-2 mr-2 mt-2"> |
| | | <SvgIcon class="cursor-pointer" name="ele-CopyDocument" @click="copyClick(item.content)" /> |
| | | <SvgIcon class="cursor-pointer" name="ywicon icon-dianzan" /> |
| | | <SvgIcon class="cursor-pointer" :size="12" name="ywicon icon-buzan" /> |
| | | </div> --> |
| | | </div> |
| | | </div> |
| | | |
| | | <Loding v-else /> |
| | |
| | | |
| | | <script setup lang="ts"> |
| | | import cryptoJS from 'crypto-js'; |
| | | import { ElMessage } from 'element-plus'; |
| | | import { nextTick, onMounted, ref, watch } from 'vue'; |
| | | import useClipboard from 'vue-clipboard3'; |
| | | import Loding from './components/Loding.vue'; |
| | | import { RecordSet } from './model/Record'; |
| | | import type { ChatContent } from './model/types'; |
| | | import { AnswerType, RoleEnum, answerTypeMapCom, roleImageMap, type ChatMessage } from './model/types'; |
| | | import { QuestionAi } from '/@/api/ai/chat'; |
| | | import { md } from './libs/markdown'; |
| | | import { RoleEnum, roleImageMap, type ChatMessage } from './types'; |
| | | import PlayBar from '/@/components/chat/components/playBar/PlayBar.vue'; |
| | | import router from '/@/router'; |
| | | import { activeChatRoom } from '/@/stores/chatRoom'; |
| | | import { ElMessage } from 'element-plus'; |
| | | import router from '/@/router'; |
| | | |
| | | let apiKey = ''; |
| | | let isConfig = ref(false); |
| | | let isTalking = ref(false); |
| | | let messageContent = ref<ChatContent>({ |
| | | type: AnswerType.Text, |
| | | values: '', |
| | | }); |
| | | let messageContent = ref(''); |
| | | const chatListDom = ref<HTMLDivElement>(); |
| | | const decoder = new TextDecoder('utf-8'); |
| | | const roleAlias = { user: 'ME', assistant: 'ChatGPT', system: 'System' }; |
| | |
| | | }); |
| | | return; |
| | | } |
| | | messageContent.value.values = activeChatRoom.value.title; |
| | | messageContent.value = activeChatRoom.value.title; |
| | | sendOrSave(); |
| | | }); |
| | | |
| | | const questionAi = async (text) => { |
| | | const res = await QuestionAi({ |
| | | question: text, |
| | | }); |
| | | let content: ChatContent = { |
| | | type: AnswerType.Text, |
| | | values: 'åçé误ï¼', |
| | | }; |
| | | switch (res.answer_type) { |
| | | case AnswerType.RecordSet: |
| | | content = { |
| | | type: AnswerType.RecordSet, |
| | | values: res.values, |
| | | }; |
| | | break; |
| | | case AnswerType.Text: |
| | | content = { |
| | | type: AnswerType.Text, |
| | | values: res.values, |
| | | }; |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | return content; |
| | | }; |
| | | |
| | | const sendChatMessage = async (content: ChatContent = messageContent.value) => { |
| | | const sendChatMessage = async (content: string = messageContent.value) => { |
| | | try { |
| | | isTalking.value = true; |
| | | // if (messageList.value.length === 0) { |
| | |
| | | // } |
| | | messageList.value.push({ role: RoleEnum.user, content }); |
| | | clearMessageContent(); |
| | | messageList.value.push({ role: RoleEnum.assistant, content }); |
| | | messageList.value.push({ role: RoleEnum.assistant, content: '' }); |
| | | |
| | | // const { body, status } = await chat(messageList.value, getAPIKey()); |
| | | // if (body) { |
| | | // const reader = body.getReader(); |
| | | // await readStream(reader, status); |
| | | // } |
| | | // const a = new Promise<string>((resolve) => { |
| | | // setTimeout(() => { |
| | | // resolve('ä½ å¥½ï¼ææ¯AIè¯è¨æ¨¡å '); |
| | | // }, 500); |
| | | // }); |
| | | const a = new Promise<string>((resolve) => { |
| | | setTimeout(() => { |
| | | resolve('ä½ å¥½ï¼ææ¯AIè¯è¨æ¨¡å '); |
| | | }, 500); |
| | | }); |
| | | |
| | | let msg:ChatContent = { |
| | | type:AnswerType.Text, |
| | | values:'' |
| | | }; |
| | | msg = await questionAi(content); |
| | | const msg = await a; |
| | | appendLastMessageContent(msg); |
| | | } catch (error: any) { |
| | | appendLastMessageContent('åçé误ï¼'); |
| | | appendLastMessageContent(error); |
| | | } finally { |
| | | isTalking.value = false; |
| | | } |
| | |
| | | } |
| | | }; |
| | | |
| | | const appendLastMessageContent = (content: ChatContent) => { |
| | | messageList.value.push( |
| | | |
| | | ) |
| | | }; |
| | | const appendLastMessageContent = (content: string) => (messageList.value[messageList.value.length - 1].content += content); |
| | | |
| | | const sendOrSave = () => { |
| | | if (!messageContent.value) return; |
| | | if (!messageContent.value.length) return; |
| | | if (activeChatRoom.value.isInitial) { |
| | | activeChatRoom.value.title = messageContent.value.values; |
| | | activeChatRoom.value.title = messageContent.value; |
| | | activeChatRoom.value.isInitial = false; |
| | | } |
| | | sendChatMessage(); |
| | | if (isConfig.value) { |
| | | if (saveAPIKey(messageContent.value.trim())) { |
| | | switchConfigStatus(); |
| | | } |
| | | clearMessageContent(); |
| | | } else { |
| | | sendChatMessage(); |
| | | } |
| | | }; |
| | | |
| | | const clickConfig = () => { |
| | | if (!isConfig.value) { |
| | | messageContent.value = getAPIKey(); |
| | | } else { |
| | | clearMessageContent(); |
| | | } |
| | | switchConfigStatus(); |
| | | }; |
| | | |
| | | const getSecretKey = () => 'lianginx'; |
| | | |
| | | const saveAPIKey = (apiKey: string) => { |
| | | if (apiKey.slice(0, 3) !== 'sk-' || apiKey.length !== 51) { |
| | | alert('API Key é误ï¼è¯·æ£æ¥åéæ°è¾å
¥ï¼'); |
| | | return false; |
| | | } |
| | | const aesAPIKey = cryptoJS.AES.encrypt(apiKey, getSecretKey()).toString(); |
| | | localStorage.setItem('apiKey', aesAPIKey); |
| | | return true; |
| | | }; |
| | | |
| | | const getAPIKey = () => { |
| | | if (apiKey) return apiKey; |
| | |
| | | |
| | | const switchConfigStatus = () => (isConfig.value = !isConfig.value); |
| | | |
| | | const clearMessageContent = () => (messageContent.value = null); |
| | | const clearMessageContent = () => (messageContent.value = ''); |
| | | |
| | | const scrollToBottom = () => { |
| | | if (!chatListDom.value) return; |
| | |
| | | </el-button> |
| | | </div> |
| | | <div class="set-input"> |
| | | <el-input |
| | | v-elInputFocus |
| | | @keydown="enterInput" |
| | | v-model="inputValue" |
| | | placeholder="å¨è¿éè¾å
¥æ¨çé®é¢å¼å§åAI对è¯" |
| | | class="set-inputAnswer" |
| | | /> |
| | | <el-input v-elInputFocus @keydown.enter="isTalking || emits('sendClick')" v-model="inputValue" placeholder="å¨è¿éè¾å
¥æ¨çé®é¢å¼å§åAI对è¯" class="set-inputAnswer" /> |
| | | </div> |
| | | <div class="h100 flex items-center"> |
| | | <div class="upload_img space-y"> |
| | |
| | | |
| | | const emits = defineEmits(['sendClick']); |
| | | |
| | | const props = defineProps(['isTalking']); |
| | | defineProps(['isTalking']) |
| | | |
| | | const inputValue = defineModel({ |
| | | type: String, |
| | | }); |
| | | |
| | | const enterInput = (e) => { |
| | | if (props.isTalking) return; |
| | | if (!e.shiftKey && e.keyCode == 13) { |
| | | e.cancelBubble = true; //ie黿¢å泡è¡ä¸º |
| | | e.stopPropagation(); //Firefox黿¢å泡è¡ä¸º |
| | | e.preventDefault(); //åæ¶äºä»¶çé»è®¤å¨ä½*æ¢è¡ |
| | | //以ä¸å¤çåéæ¶æ¯ä»£ç |
| | | emits('sendClick'); |
| | | } |
| | | }; |
| | | type:String |
| | | }) |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | .set-waterTitle { |
| | |
| | | typographer: true, |
| | | breaks: true, |
| | | langPrefix: 'language-', |
| | | html:true, |
| | | // 代ç é«äº® |
| | | highlight(str, lang) { |
| | | if (lang && highlight.getLanguage(lang)) { |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import userPic from './images/user.svg'; |
| | | import assistantPic from './images/assistant.jpg'; |
| | | |
| | | export const enum RoleEnum { |
| | | user = 'user', |
| | | assistant = 'assistant', |
| | | system = 'system', |
| | | } |
| | | |
| | | export interface ChatMessage { |
| | | role: RoleEnum; |
| | | content: string; |
| | | } |
| | | |
| | | export const roleImageMap = { |
| | | [RoleEnum.user]: userPic, |
| | | [RoleEnum.assistant]: assistantPic, |
| | | [RoleEnum.system]: userPic, |
| | | }; |
| | |
| | | }); |
| | | } |
| | | |
| | | export const eleFocusDirective = (app: App) => { |
| | | app.directive('elInputFocus', { |
| | | mounted: (el) => { |
| | | el.querySelector('input.el-input__inner')?.focus(); |
| | | }, |
| | | }); |
| | | }; |
| | | export const eleFocusDirective =(app:App)=>{ |
| | | app.directive('elInputFocus',{ |
| | | mounted:(el)=>{ |
| | | el.querySelector('input.el-input__inner')?.focus() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | /** |
| | | * èªå®ä¹æå¨æä»¤ |
| | |
| | | import type { AxiosInstance, AxiosRequestConfig } from 'axios'; |
| | | import axios from 'axios'; |
| | | import { ElMessage } from 'element-plus'; |
| | | import { AUTH_URL, MAIN_URL, SECONDARY_URL } from '/@/constants'; |
| | | import { Local, Session } from '/@/utils/storage'; |
| | | import { AUTH_URL, MAIN_URL, SECONDARY_URL } from '/@/constants'; |
| | | // import JSONbig from 'json-bigint'; |
| | | |
| | | //#region ====================== å端 res.Code ====================== |
| | |
| | | // // è¶
æ¶ï¼æä¸ä½¿ç¨ï¼ |
| | | // TimeOut = -5 |
| | | //#endregion |
| | | const initRequestInterceptor = (request: AxiosInstance,isAuth=false) => { |
| | | const initRequestInterceptor = (request: AxiosInstance) => { |
| | | // æ·»å è¯·æ±æ¦æªå¨ |
| | | request.interceptors.request.use( |
| | | (config) => { |
| | |
| | | // è·åæ¬å°ç token |
| | | const accessToken = Local.get(accessTokenKey); |
| | | if (accessToken) { |
| | | // å° token æ·»å å°è¯·æ±æ¥æå¤´ä¸â |
| | | if(isAuth){ |
| | | config.headers!['Authorization'] = `Bearer ${accessToken}`; |
| | | |
| | | }else{ |
| | | config.headers['Referrer-Policy'] = undefined; |
| | | } |
| | | // å° token æ·»å å°è¯·æ±æ¥æå¤´ä¸ |
| | | config.headers!['Authorization'] = `Bearer ${accessToken}`; |
| | | |
| | | // 夿 accessToken æ¯å¦è¿æ |
| | | const jwt: any = decryptJWT(accessToken); |
| | |
| | | Local.set(accessTokenKey, accessToken); |
| | | Local.set(refreshAccessTokenKey, refreshAccessToken); |
| | | } |
| | | |
| | | if (!serve.json_ok && !isAuth) { |
| | | // ElMessage.warning(serve.json_msg) |
| | | throw new Error('ååºé误'); |
| | | } |
| | | |
| | | // ååºæ¦æªåèªå®ä¹å¤ç |
| | | if (serve.data === 401) { |
| | | clearAccessTokens(); |
| | |
| | | baseURL: MAIN_URL, |
| | | timeout: 50000, |
| | | headers: { 'Content-Type': 'application/json;charset=utf-8 ' }, |
| | | |
| | | // transformResponse: [ |
| | | // function (data) { |
| | | // const JSONbigToString = JSONbig({ storeAsString: true }); |
| | | // // å°Longç±»åæ°æ®è½¬æ¢ä¸ºå符串 |
| | | // return JSONbigToString.parse(data); |
| | | // }, |
| | | // ], |
| | | }); |
| | | |
| | | const authService = axios.create({ |
| | | // baseURL: MAIN_URL, |
| | | timeout: 50000, |
| | | headers: { 'Content-Type': 'application/json;charset=utf-8 ' }, |
| | | |
| | | }); |
| | | initRequestInterceptor(service); |
| | | initRequestInterceptor(authService,true) |
| | | |
| | | export function secondaryRequest(config: AxiosRequestConfig<any>) { |
| | | return service({ |
| | |
| | | * ç¨äºè®¿é®ç»å½æ¥å£ |
| | | */ |
| | | export function authRequest(config: AxiosRequestConfig<any>) { |
| | | return authService({ |
| | | return service({ |
| | | ...config, |
| | | baseURL: AUTH_URL, |
| | | }); |
| | |
| | | import axios from 'axios'; |
| | | import { MAIN_URL } from '../constants'; |
| | | |
| | | |
| | | /** |
| | | * æ®é对象转为 formData |
| | | * @param obj |
| | | */ |
| | | export const toFormData = (obj: any) => { |
| | | const formData = new FormData(); |
| | | |
| | | const addFormData = (subObj, prePrefix = '', isArray = false) => { |
| | | for (const key in subObj) { |
| | | if (Object.prototype.hasOwnProperty.call(subObj, key)) { |
| | | const value = subObj[key]; |
| | | let currentKey = ''; |
| | | if (prePrefix === '') { |
| | | currentKey = key; |
| | | } else if (isArray) { |
| | | currentKey = `${prePrefix}[${key}]`; |
| | | } else { |
| | | currentKey = `${prePrefix}.${key}`; |
| | | } |
| | | |
| | | if (value != null && Array.isArray(value) && value.length > 0) { |
| | | addFormData(value, currentKey, true); |
| | | } else if (value != null && typeof value === 'object' && Object.values(value).length > 0) { |
| | | addFormData(value, currentKey, false); |
| | | } else { |
| | | formData.append(currentKey, value); |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | addFormData(obj); |
| | | return formData; |
| | | }; |
| | | |
| | | |
| | | /** |
| | | * @description å½ç¢°å° JSON ä¸åå¨è¿é¿çæ°åæ¶ï¼ä½¿ç¨ JSONbigString è§£æï¼æ°åä¼è½¬ä¸ºå符串å¤ç |
| | | * ç¨æ³ï¼JSONbigString.parse(jsonStr)ï¼ |
| | |
| | | }); |
| | | //忢å°åºç¨åºæ¯è¯¦æ
çäºä»¶ |
| | | const changeApp = (item: any) => { |
| | | console.log('ð ~ item:', item); |
| | | if (item.ID === 2) { |
| | | router.push({ |
| | | name: 'ScenarioDetails', |
| | |
| | | <p class="set-waterTitle"><strong>WI æ°´å¡æºè½ä¸å®¶</strong>æºæ
§æ°´å¡å©æ</p> |
| | | </div> |
| | | <div class="flex items-center pc-roleList"> |
| | | <div v-for="(item, index) in llmList" :key="item.logicId" class="flex items-center pl-6" @click="handleClick(item)"> |
| | | <div class="modelItem cursor-pointer flex items-center" :class="{ modelItemActive: item.logicId === activeLLMId }"> |
| | | <img :src="item.icon" alt="icon" class="set-icon box-border" /> |
| | | <span>{{ item.logicTitle }}</span> |
| | | </div> |
| | | <!-- <el-tooltip :content="item.Content" placement="top" effect="light" popper-class="my-pop"> |
| | | <div class="modelItem cursor-pointer flex items-center " :class="{ modelItemActive: item.ID === state.activeRole }"> |
| | | <div v-for="(item, index) in state.roleList" :key="index" class="flex items-center pl-6" @click="handleClick(item)"> |
| | | <el-tooltip :content="item.Content" placement="top" effect="light" popper-class="my-pop"> |
| | | <div class="modelItem cursor-pointer flex items-center" :class="{ modelItemActive: item.ID === state.activeRole }"> |
| | | <img :src="item.Icon" alt="icon" class="set-icon box-border" /> |
| | | <span>{{ item.Title }}</span> |
| | | </div> |
| | | </el-tooltip> --> |
| | | </el-tooltip> |
| | | </div> |
| | | <div class="flex items-center cursor-pointer pl-5"> |
| | | <div class="modelItem cursor-pointer flex items-center"> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { onMounted, reactive, ref } from 'vue'; |
| | | import { GetLLMList, SetLLM } from '/@/api/ai/chat'; |
| | | import { reactive, ref } from 'vue'; |
| | | import PlayBar from '/@/components/chat/components/playBar/PlayBar.vue'; |
| | | import router from '/@/router'; |
| | | import { activeChatRoom } from '/@/stores/chatRoom'; |
| | |
| | | const inputValue = ref(''); |
| | | |
| | | const sendClick = () => { |
| | | if (!inputValue.value) return; |
| | | if(!inputValue.value) return; |
| | | activeChatRoom.value.title = inputValue.value; |
| | | router.push({ |
| | | name: 'AskAnswer', |
| | | |
| | | }); |
| | | }; |
| | | let state = reactive({ |
| | |
| | | }, |
| | | ], |
| | | activeRole: 0, |
| | | inputAnswer: '', |
| | | }); |
| | | |
| | | const activeLLMId = ref(); |
| | | const llmList = ref([]); |
| | | const iconList = ['/static/images/wave/Glm.jpg', '/static/images/wave/Glm.jpg', '/static/images/wave/Glm.jpg']; |
| | | const getLLMList = async () => { |
| | | const res = await GetLLMList(); |
| | | |
| | | const resData = (res?.llm_list || []) as any[]; |
| | | llmList.value = resData.map((item, index) => ({ |
| | | get logicId() { |
| | | return this.logicModel.id; |
| | | }, |
| | | get logicTitle() { |
| | | return this.logicModel.title; |
| | | }, |
| | | icon: iconList[index], |
| | | logicModel: { |
| | | ...item, |
| | | }, |
| | | })); |
| | | const first = llmList.value?.[0]; |
| | | first && setLLm(first.logicId); |
| | | }; |
| | | |
| | | const setLLm = async (llmId: string) => { |
| | | |
| | | const res = await SetLLM({ |
| | | llm: llmId, |
| | | }); |
| | | activeLLMId.value = llmId; |
| | | |
| | | return true; |
| | | }; |
| | | const handleClick = (item) => { |
| | | setLLm(item.logicId); |
| | | state.activeRole = item.id; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getLLMList(); |
| | | }); |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | .set-waterTitle { |
| | |
| | | host: '0.0.0.0', |
| | | port: env.VITE_PORT as unknown as number, |
| | | open: JSON.parse(env.VITE_OPEN), |
| | | hmr: false, |
| | | hmr: true, |
| | | proxy: { |
| | | // '/wiai':{ |
| | | // target:'http://wi.cpolar.top', |
| | | // ws: true, |
| | | // changeOrigin: true, |
| | | // rewrite: (path) => path.replace(/^\/wiai/, ''), |
| | | // } |
| | | '/gitee': { |
| | | target: 'https://gitee.com', |
| | | ws: true, |
| | | changeOrigin: true, |
| | | rewrite: (path) => path.replace(/^\/gitee/, ''), |
| | | }, |
| | | }, |
| | | }, |
| | | build: { |