feat: 创建项目ID
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
# VITE_APP_URL = http://192.168.31.82:8771
|
# VITE_APP_URL = http://192.168.31.82:8771
|
||||||
VITE_APP_URL = http://18.167.251.121:10015
|
# VITE_APP_URL = http://18.167.251.121:10015
|
||||||
# VITE_APP_URL = http://192.168.31.118:8080
|
# VITE_APP_URL = http://192.168.31.118:8080
|
||||||
|
VITE_APP_URL = http://192.168.31.82:8755
|
||||||
VITE_GOOGLE_CLIENT_ID = 216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com
|
VITE_GOOGLE_CLIENT_ID = 216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com
|
||||||
|
|||||||
@@ -17,3 +17,13 @@ export const fetchAgentReply = (data: AgentParamsType): Promise<AgentResponse> =
|
|||||||
meta: { responseAll: true }
|
meta: { responseAll: true }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CreateProjectParamsType {
|
||||||
|
type: string
|
||||||
|
region: string
|
||||||
|
style: string
|
||||||
|
temperature: number | string
|
||||||
|
}
|
||||||
|
export const createProject = (data: CreateProjectParamsType): Promise<any> => {
|
||||||
|
return request({ url: '/api/project/init', method: 'post', data })
|
||||||
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 295 B |
@@ -8,3 +8,4 @@ export default store
|
|||||||
export * from './global'
|
export * from './global'
|
||||||
export * from './userInfo'
|
export * from './userInfo'
|
||||||
export * from './projectData'
|
export * from './projectData'
|
||||||
|
export * from './agent'
|
||||||
@@ -5,25 +5,25 @@ import { ElMessage } from 'element-plus'
|
|||||||
|
|
||||||
// 扩展 AxiosRequestConfig 接口
|
// 扩展 AxiosRequestConfig 接口
|
||||||
declare module 'axios' {
|
declare module 'axios' {
|
||||||
interface AxiosRequestConfig {
|
interface AxiosRequestConfig {
|
||||||
loading?: boolean
|
loading?: boolean
|
||||||
loadingDom?: any
|
loadingDom?: any
|
||||||
repeatRequest?: boolean
|
repeatRequest?: boolean
|
||||||
meta?: {
|
meta?: {
|
||||||
responseAll?: boolean
|
responseAll?: boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建axios实例
|
// 创建axios实例
|
||||||
// console.log(import.meta.env,123)
|
// console.log(import.meta.env,123)
|
||||||
|
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
// baseURL: import.meta.env.VITE_APP_URL, // api的base_url
|
// baseURL: import.meta.env.VITE_APP_URL, // api的base_url
|
||||||
timeout: 60000 // 请求超时时间
|
timeout: 60000 // 请求超时时间
|
||||||
})
|
})
|
||||||
if (import.meta.env.MODE != 'development') {
|
if (import.meta.env.MODE != 'development') {
|
||||||
service.defaults.baseURL = import.meta.env.VITE_APP_URL
|
service.defaults.baseURL = import.meta.env.VITE_APP_URL
|
||||||
}
|
}
|
||||||
axios.defaults.headers.post['Content-Type'] = 'application/json'
|
axios.defaults.headers.post['Content-Type'] = 'application/json'
|
||||||
axios.defaults.headers.post['lang'] = 'en' //配置语言请求头
|
axios.defaults.headers.post['lang'] = 'en' //配置语言请求头
|
||||||
@@ -31,97 +31,98 @@ axios.defaults.withCredentials = true //跨域携带cookie
|
|||||||
|
|
||||||
// request拦截器
|
// request拦截器
|
||||||
service.interceptors.request.use(
|
service.interceptors.request.use(
|
||||||
(config: any) => {
|
(config: any) => {
|
||||||
removePending(config)
|
removePending(config)
|
||||||
// 如果repeatRequest不配置,那么默认该请求就取消重复接口请求
|
// 如果repeatRequest不配置,那么默认该请求就取消重复接口请求
|
||||||
!config.repeatRequest && addPending(config)
|
!config.repeatRequest && addPending(config)
|
||||||
// 打开loading
|
// 打开loading
|
||||||
if (config.loading) {
|
if (config.loading) {
|
||||||
LoadingInstance._count++
|
LoadingInstance._count++
|
||||||
if (LoadingInstance._count === 1) {
|
if (LoadingInstance._count === 1) {
|
||||||
openLoading(config.loadingDom)
|
openLoading(config.loadingDom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 如果登录了,有token,则请求携带token
|
// 如果登录了,有token,则请求携带token
|
||||||
// Do something before request is sent
|
// Do something before request is sent
|
||||||
const token = useUserInfoStore().state.token
|
const token = useUserInfoStore().state.token
|
||||||
if (token) {
|
if (token) {
|
||||||
config.headers.Authorization = token // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
|
config.headers.Authorization = 'Bearer ' + token // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
|
||||||
// config.headers['X-Token'] = getLocal('token') // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
|
// config.headers['X-Token'] = getLocal('token') // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
|
||||||
}
|
}
|
||||||
return config
|
return config
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
// Do something with request error
|
// Do something with request error
|
||||||
console.log(error) // for debug
|
console.log(error) // for debug
|
||||||
Promise.reject(error)
|
Promise.reject(error)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// respone拦截器
|
// respone拦截器
|
||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
// response => response,
|
// response => response,
|
||||||
/**
|
/**
|
||||||
* 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
|
* 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
|
||||||
* 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
|
* 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
|
||||||
*/
|
*/
|
||||||
(response: any) => {
|
(response: any) => {
|
||||||
// 如果是llm/streamChat这样的流式接口,不走这样的处理
|
// 如果是llm/streamChat这样的流式接口,不走这样的处理
|
||||||
if (response.config.url.includes('llm/streamChat')) {
|
if (response.config.url.includes('llm/streamChat')) {
|
||||||
return response
|
return response
|
||||||
}
|
|
||||||
|
|
||||||
// 已完成请求的删除请求中数组
|
|
||||||
removePending(response.config)
|
|
||||||
// 关闭loading
|
|
||||||
if (response.config.loading) {
|
|
||||||
closeLoading()
|
|
||||||
}
|
|
||||||
const res = response.data
|
|
||||||
// 处理异常的情况
|
|
||||||
// console.log(res)
|
|
||||||
if (res.code != 200) {
|
|
||||||
ElMessage.error(res.message)
|
|
||||||
return Promise.reject(new Error(res.errMsg || res.message || 'error'))
|
|
||||||
} else {
|
|
||||||
// 默认只返回data,不返回状态码和message
|
|
||||||
// 通过 meta 中的 responseAll 配置来取决后台是否返回所有数据(包括状态码,message和data)
|
|
||||||
const isbackAll = response.config.meta && response.config.meta.responseAll
|
|
||||||
if (isbackAll) {
|
|
||||||
return res
|
|
||||||
} else {
|
|
||||||
return res.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
if(error?.response){
|
|
||||||
if (error.config?.loading) closeLoading() // 关闭loading
|
|
||||||
if(error?.response?.status === 401){//如果是记录浏览器页面就不跳转login
|
|
||||||
// showConfirmDialog({
|
|
||||||
// title: '确定登出',
|
|
||||||
// message: '你已被登出,可以取消继续留在该页面,或者重新登录',
|
|
||||||
// confirmButtonText: '重新登录',
|
|
||||||
// cancelButtonText: '取消'
|
|
||||||
// }).then(() => {
|
|
||||||
// store.loginOut().then(() => {
|
|
||||||
// location.reload() // 为了重新实例化vue-router对象 避免bug
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// showToast({
|
|
||||||
// message: 'Please log in and try again.',
|
|
||||||
// duration: 5000
|
|
||||||
// })
|
|
||||||
// router.push('/login')
|
|
||||||
// useGenerateStore().clearGenerateData()
|
|
||||||
return Promise.reject(false)
|
|
||||||
}
|
}
|
||||||
error.config && removePending(error.config)
|
|
||||||
console.log('err' + error) // for debug
|
// 已完成请求的删除请求中数组
|
||||||
ElMessage.error(error.message)
|
removePending(response.config)
|
||||||
|
// 关闭loading
|
||||||
|
if (response.config.loading) {
|
||||||
|
closeLoading()
|
||||||
|
}
|
||||||
|
const res = response.data
|
||||||
|
// 处理异常的情况
|
||||||
|
// console.log(res)
|
||||||
|
if (res.code != 200) {
|
||||||
|
ElMessage.error(res.message)
|
||||||
|
return Promise.reject(new Error(res.errMsg || res.message || 'error'))
|
||||||
|
} else {
|
||||||
|
// 默认只返回data,不返回状态码和message
|
||||||
|
// 通过 meta 中的 responseAll 配置来取决后台是否返回所有数据(包括状态码,message和data)
|
||||||
|
const isbackAll = response.config.meta && response.config.meta.responseAll
|
||||||
|
if (isbackAll) {
|
||||||
|
return res
|
||||||
|
} else {
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
if (error?.response) {
|
||||||
|
if (error.config?.loading) closeLoading() // 关闭loading
|
||||||
|
if (error?.response?.status === 401) {
|
||||||
|
//如果是记录浏览器页面就不跳转login
|
||||||
|
// showConfirmDialog({
|
||||||
|
// title: '确定登出',
|
||||||
|
// message: '你已被登出,可以取消继续留在该页面,或者重新登录',
|
||||||
|
// confirmButtonText: '重新登录',
|
||||||
|
// cancelButtonText: '取消'
|
||||||
|
// }).then(() => {
|
||||||
|
// store.loginOut().then(() => {
|
||||||
|
// location.reload() // 为了重新实例化vue-router对象 避免bug
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// showToast({
|
||||||
|
// message: 'Please log in and try again.',
|
||||||
|
// duration: 5000
|
||||||
|
// })
|
||||||
|
// router.push('/login')
|
||||||
|
// useGenerateStore().clearGenerateData()
|
||||||
|
return Promise.reject(false)
|
||||||
|
}
|
||||||
|
error.config && removePending(error.config)
|
||||||
|
console.log('err' + error) // for debug
|
||||||
|
ElMessage.error(error.message)
|
||||||
|
}
|
||||||
|
return Promise.reject(error)
|
||||||
}
|
}
|
||||||
return Promise.reject(error)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// --------------------------------取消接口重复请求的函数-----------------------------------
|
// --------------------------------取消接口重复请求的函数-----------------------------------
|
||||||
@@ -133,10 +134,10 @@ const pendingMap = new Map()
|
|||||||
* @returns string
|
* @returns string
|
||||||
*/
|
*/
|
||||||
function getPendingKey(config: any) {
|
function getPendingKey(config: any) {
|
||||||
const { url, method, params } = config
|
const { url, method, params } = config
|
||||||
let { data } = config
|
let { data } = config
|
||||||
if (typeof data === 'string') data = JSON.parse(data) // response里面返回的config.data是个字符串对象
|
if (typeof data === 'string') data = JSON.parse(data) // response里面返回的config.data是个字符串对象
|
||||||
return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&')
|
return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -144,39 +145,39 @@ function getPendingKey(config: any) {
|
|||||||
* @param {*} config
|
* @param {*} config
|
||||||
*/
|
*/
|
||||||
function addPending(config: any) {
|
function addPending(config: any) {
|
||||||
const pendingKey = getPendingKey(config)
|
const pendingKey = getPendingKey(config)
|
||||||
config.cancelToken =
|
config.cancelToken =
|
||||||
config.cancelToken ||
|
config.cancelToken ||
|
||||||
new axios.CancelToken((cancel) => {
|
new axios.CancelToken((cancel) => {
|
||||||
if (!pendingMap.has(pendingKey)) {
|
if (!pendingMap.has(pendingKey)) {
|
||||||
pendingMap.set(pendingKey, cancel)
|
pendingMap.set(pendingKey, cancel)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 删除重复的请求
|
* 删除重复的请求
|
||||||
* @param {*} config
|
* @param {*} config
|
||||||
*/
|
*/
|
||||||
function removePending(config: any) {
|
function removePending(config: any) {
|
||||||
const pendingKey = getPendingKey(config)
|
const pendingKey = getPendingKey(config)
|
||||||
if (pendingMap.has(pendingKey)) {
|
if (pendingMap.has(pendingKey)) {
|
||||||
const cancelToken = pendingMap.get(pendingKey)
|
const cancelToken = pendingMap.get(pendingKey)
|
||||||
cancelToken(pendingKey)
|
cancelToken(pendingKey)
|
||||||
pendingMap.delete(pendingKey)
|
pendingMap.delete(pendingKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----------------------------------loading的函数-------------------------------
|
// ----------------------------------loading的函数-------------------------------
|
||||||
const LoadingInstance: { _count: number } = {
|
const LoadingInstance: { _count: number } = {
|
||||||
_count: 0
|
_count: 0
|
||||||
}
|
}
|
||||||
function openLoading(loadingDom: any) {
|
function openLoading(loadingDom: any) {
|
||||||
useGlobalStore().setLoading(true)
|
useGlobalStore().setLoading(true)
|
||||||
}
|
}
|
||||||
function closeLoading() {
|
function closeLoading() {
|
||||||
if (LoadingInstance._count > 0) LoadingInstance._count--
|
if (LoadingInstance._count > 0) LoadingInstance._count--
|
||||||
if (LoadingInstance._count === 0) {
|
if (LoadingInstance._count === 0) {
|
||||||
useGlobalStore().setLoading(false)
|
useGlobalStore().setLoading(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default service
|
export default service
|
||||||
|
|||||||
@@ -8,8 +8,13 @@
|
|||||||
<SvgIcon name="equal" color="#0d0d0d" size="24" />
|
<SvgIcon name="equal" color="#0d0d0d" size="24" />
|
||||||
</div>
|
</div>
|
||||||
<div class="agent-body flex-1 flex flex-col">
|
<div class="agent-body flex-1 flex flex-col">
|
||||||
<List ref="listRef" :message-list="messageList" />
|
<List ref="listRef" :message-list="messageList" @regenerate="handleRegenerate" />
|
||||||
<Input is-agent-mode @send="handleSendMessage" />
|
<Input
|
||||||
|
is-agent-mode
|
||||||
|
:generating="isGenerating"
|
||||||
|
@send="handleSendMessage"
|
||||||
|
@pause="handlePause"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -20,7 +25,7 @@
|
|||||||
import Input from '../../components/Input.vue'
|
import Input from '../../components/Input.vue'
|
||||||
import { fetchAgentReply } from '@/api/agent'
|
import { fetchAgentReply } from '@/api/agent'
|
||||||
import type { AgentParamsType } from '@/api/agent'
|
import type { AgentParamsType } from '@/api/agent'
|
||||||
import { useUserInfoStore,useProjectStore } from '@/stores'
|
import { useUserInfoStore, useProjectStore } from '@/stores'
|
||||||
import { useAgentStore } from '@/stores/agent'
|
import { useAgentStore } from '@/stores/agent'
|
||||||
|
|
||||||
const userStore = useUserInfoStore()
|
const userStore = useUserInfoStore()
|
||||||
@@ -37,8 +42,10 @@
|
|||||||
|
|
||||||
const messageList = ref([])
|
const messageList = ref([])
|
||||||
const listRef = ref()
|
const listRef = ref()
|
||||||
|
const isGenerating = ref(false)
|
||||||
|
const isPaused = ref(false) // 标记是否为主动暂停
|
||||||
const params = reactive<AgentParamsType>({
|
const params = reactive<AgentParamsType>({
|
||||||
projectID: '1',
|
projectID: projectStore.state.id,
|
||||||
message: '',
|
message: '',
|
||||||
token: userStore.state.token,
|
token: userStore.state.token,
|
||||||
versionID: '',
|
versionID: '',
|
||||||
@@ -51,22 +58,32 @@
|
|||||||
imageUrlList: []
|
imageUrlList: []
|
||||||
})
|
})
|
||||||
|
|
||||||
const abort = new AbortController()
|
// 每次请求时创建新的 AbortController
|
||||||
|
let abort: AbortController
|
||||||
|
|
||||||
|
const createAbortController = () => {
|
||||||
|
// 如果已有未完成的中止,先中止它
|
||||||
|
if (abort) {
|
||||||
|
abort.abort()
|
||||||
|
}
|
||||||
|
abort = new AbortController()
|
||||||
|
return abort
|
||||||
|
}
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
abort.abort()
|
abort?.abort()
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 检查 store 中是否有初始项目数据
|
// 检查 store 中是否有初始项目数据
|
||||||
projectStore.setId('1') // 临时设置项目ID为1,实际应用中应根据上下文动态设置
|
// projectStore.setId('1') // 临时设置项目ID为1,实际应用中应根据上下文动态设置
|
||||||
const initialData = agentStore.getInitialProjectData
|
const initialData = agentStore.getInitialProjectData
|
||||||
if (initialData) {
|
if (initialData) {
|
||||||
// 等待页面渲染完成后自动发送初始消息
|
// 等待页面渲染完成后自动发送初始消息
|
||||||
params.configParams = {
|
params.configParams = {
|
||||||
type: initialData.type || 'Chair',
|
type: initialData.type ,
|
||||||
region: initialData.area || 'China',
|
region: initialData.area,
|
||||||
style: initialData.style || 'Transitional',
|
style: initialData.style ,
|
||||||
temperature: 0.7
|
temperature: 0.7
|
||||||
}
|
}
|
||||||
handleSendMessage({
|
handleSendMessage({
|
||||||
@@ -83,15 +100,21 @@
|
|||||||
const handleSendMessage = async (message: {
|
const handleSendMessage = async (message: {
|
||||||
text: string
|
text: string
|
||||||
images: Array<{ url: string; name: string }>
|
images: Array<{ url: string; name: string }>
|
||||||
}) => {
|
}, skipUserMessage = false) => {
|
||||||
console.log('Message sent:', message)
|
console.log('Message sent:', message)
|
||||||
|
isPaused.value = false
|
||||||
|
isGenerating.value = true
|
||||||
params.message = message.text
|
params.message = message.text
|
||||||
params.imageUrlList = message.images || []
|
params.imageUrlList = message.images || []
|
||||||
messageList.value.push({
|
|
||||||
id: messageList.value.length + 1,
|
// 如果不是重新生成模式,则添加用户消息到列表
|
||||||
text: message.text,
|
if (!skipUserMessage) {
|
||||||
isUser: true
|
messageList.value.push({
|
||||||
})
|
id: messageList.value.length + 1,
|
||||||
|
text: message.text,
|
||||||
|
isUser: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Add AI loading message
|
// Add AI loading message
|
||||||
const aiMessage = reactive({
|
const aiMessage = reactive({
|
||||||
@@ -106,6 +129,9 @@
|
|||||||
})
|
})
|
||||||
messageList.value.push(aiMessage)
|
messageList.value.push(aiMessage)
|
||||||
|
|
||||||
|
// 创建新的 AbortController
|
||||||
|
const abortController = createAbortController()
|
||||||
|
|
||||||
// console.log('token---', params.token, '参数---', params)
|
// console.log('token---', params.token, '参数---', params)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -116,7 +142,7 @@
|
|||||||
|
|
||||||
const response = await fetch(`/api/ai-design/chat?${urlParams.toString()}`, {
|
const response = await fetch(`/api/ai-design/chat?${urlParams.toString()}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
signal: abort.signal
|
signal: abortController.signal
|
||||||
})
|
})
|
||||||
|
|
||||||
// 检查响应内容类型,判断是否为流式响应
|
// 检查响应内容类型,判断是否为流式响应
|
||||||
@@ -128,9 +154,12 @@
|
|||||||
// 非流式错误响应,使用 text() 读取错误信息
|
// 非流式错误响应,使用 text() 读取错误信息
|
||||||
const errorText = await response.text()
|
const errorText = await response.text()
|
||||||
console.error('请求错误:', errorText)
|
console.error('请求错误:', errorText)
|
||||||
aiMessage.text = '发送失败,请重试'
|
if (!isPaused.value) {
|
||||||
|
aiMessage.text = '发送失败,请重试'
|
||||||
|
}
|
||||||
aiMessage.streaming = false
|
aiMessage.streaming = false
|
||||||
aiMessage.loading = false
|
aiMessage.loading = false
|
||||||
|
isGenerating.value = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,9 +172,12 @@
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('非流式响应文本:', text)
|
console.error('非流式响应文本:', text)
|
||||||
}
|
}
|
||||||
aiMessage.text = '发送失败,请重试'
|
if (!isPaused.value) {
|
||||||
|
aiMessage.text = '发送失败,请重试'
|
||||||
|
}
|
||||||
aiMessage.streaming = false
|
aiMessage.streaming = false
|
||||||
aiMessage.loading = false
|
aiMessage.loading = false
|
||||||
|
isGenerating.value = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,17 +213,17 @@
|
|||||||
// 过滤掉 id: 等字段,只取 data:
|
// 过滤掉 id: 等字段,只取 data:
|
||||||
|
|
||||||
let isNodeIdEvent = false
|
let isNodeIdEvent = false
|
||||||
if(event.startsWith('event:')){
|
if (event.startsWith('event:')) {
|
||||||
isNodeIdEvent = true
|
isNodeIdEvent = true
|
||||||
// continue
|
// continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const dataLines = event
|
const dataLines = event
|
||||||
.split(/\n/)
|
.split(/\n/)
|
||||||
.filter((line) => line.startsWith('data:'))
|
.filter((line) => line.startsWith('data:'))
|
||||||
.map((line) => line.replace(/^data:\s*/, '').trim())
|
.map((line) => line.replace(/^data:\s*/, '').trim())
|
||||||
console.log('dataLInes',dataLines);
|
console.log('dataLInes', dataLines)
|
||||||
if(isNodeIdEvent){
|
if (isNodeIdEvent) {
|
||||||
params.versionID = dataLines[0]
|
params.versionID = dataLines[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,6 +247,7 @@
|
|||||||
if (jsonData.type === 'end') {
|
if (jsonData.type === 'end') {
|
||||||
aiMessage.streaming = false
|
aiMessage.streaming = false
|
||||||
aiMessage.loading = false
|
aiMessage.loading = false
|
||||||
|
isGenerating.value = false
|
||||||
flag = false
|
flag = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -224,6 +257,7 @@
|
|||||||
console.log('结束-----------------------')
|
console.log('结束-----------------------')
|
||||||
aiMessage.streaming = false
|
aiMessage.streaming = false
|
||||||
aiMessage.loading = false
|
aiMessage.loading = false
|
||||||
|
isGenerating.value = false
|
||||||
flag = false
|
flag = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -239,19 +273,59 @@
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('流式传输错误:', error)
|
console.error('流式传输错误:', error)
|
||||||
aiMessage.text = '发送失败,请重试'
|
if (!isPaused.value) {
|
||||||
|
aiMessage.text = '发送失败,请重试'
|
||||||
|
}
|
||||||
aiMessage.streaming = false
|
aiMessage.streaming = false
|
||||||
aiMessage.loading = false
|
aiMessage.loading = false
|
||||||
|
isGenerating.value = false
|
||||||
} finally {
|
} finally {
|
||||||
reader.releaseLock()
|
reader.releaseLock()
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('fetch请求失败:', error)
|
console.error('fetch请求失败:', error)
|
||||||
aiMessage.text = '发送失败,请重试'
|
if (!isPaused.value) {
|
||||||
|
aiMessage.text = '发送失败,请重试'
|
||||||
|
}
|
||||||
aiMessage.streaming = false
|
aiMessage.streaming = false
|
||||||
aiMessage.loading = false
|
aiMessage.loading = false
|
||||||
|
isGenerating.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handlePause = () => {
|
||||||
|
isPaused.value = true
|
||||||
|
isGenerating.value = false
|
||||||
|
abort?.abort()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRegenerate = async (aiMessage: any) => {
|
||||||
|
// 找到当前 AI 消息在列表中的索引
|
||||||
|
const aiIndex = messageList.value.findIndex((msg) => msg.id === aiMessage.id)
|
||||||
|
if (aiIndex === -1) return
|
||||||
|
|
||||||
|
// 找到对应的用户消息(AI 消息前面的最近一条用户消息)
|
||||||
|
let userMessage = null
|
||||||
|
for (let i = aiIndex - 1; i >= 0; i--) {
|
||||||
|
if (messageList.value[i].isUser) {
|
||||||
|
userMessage = messageList.value[i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!userMessage) return
|
||||||
|
|
||||||
|
// 删除当前的 AI 回复消息
|
||||||
|
messageList.value.splice(aiIndex, 1)
|
||||||
|
|
||||||
|
// 重新调用 API(跳过用户消息添加,因为用户消息已存在)
|
||||||
|
await handleSendMessage(
|
||||||
|
{
|
||||||
|
text: userMessage.text,
|
||||||
|
images: userMessage.images || []
|
||||||
|
},
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@@ -81,6 +81,8 @@
|
|||||||
return str
|
return str
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['regenerate'])
|
||||||
|
|
||||||
const operateList = ref([
|
const operateList = ref([
|
||||||
{
|
{
|
||||||
name: 'thumbUp',
|
name: 'thumbUp',
|
||||||
@@ -97,7 +99,7 @@
|
|||||||
{
|
{
|
||||||
name: 'refreshTransparent',
|
name: 'refreshTransparent',
|
||||||
action: () => {
|
action: () => {
|
||||||
console.log('refresh')
|
emit('regenerate')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="agent-list flex flex-col flex-1" ref="listContainer">
|
<div class="agent-list flex flex-col flex-1" ref="listContainer">
|
||||||
<Item v-for="message in messageList" :key="message.id" :content="message" />
|
<Item v-for="message in messageList" :key="message.id" :content="message" @regenerate="$emit('regenerate', message)" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -12,6 +12,8 @@
|
|||||||
messageList: Array<any>
|
messageList: Array<any>
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits(['regenerate'])
|
||||||
|
|
||||||
const listContainer = ref<HTMLDivElement>()
|
const listContainer = ref<HTMLDivElement>()
|
||||||
|
|
||||||
const scrollToBottom = () => {
|
const scrollToBottom = () => {
|
||||||
|
|||||||
@@ -151,12 +151,16 @@
|
|||||||
<img src="@/assets/images/shining.png" class="shining-icon" alt="" />
|
<img src="@/assets/images/shining.png" class="shining-icon" alt="" />
|
||||||
<span class="create-btn-text">{{ $t('Input.createProject') }}</span>
|
<span class="create-btn-text">{{ $t('Input.createProject') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<img
|
|
||||||
v-else
|
<div v-else class="sender-btn flex flex-center" @click="handleSendAgent">
|
||||||
src="@/assets/images/sender.png"
|
<img
|
||||||
class="sender-icon"
|
v-show="!generating"
|
||||||
@click="handleSendAgent"
|
src="@/assets/images/sender.png"
|
||||||
/>
|
alt=""
|
||||||
|
class="sender-icon"
|
||||||
|
/>
|
||||||
|
<div v-show="generating" class="sender-pause" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!isAgentMode" class="report-btn flex flex-center" @click="toogltReportTag">
|
<div v-if="!isAgentMode" class="report-btn flex flex-center" @click="toogltReportTag">
|
||||||
@@ -171,24 +175,28 @@
|
|||||||
import { areaList } from '@/utils/area'
|
import { areaList } from '@/utils/area'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useAgentStore } from '@/stores/agent'
|
import { useAgentStore, useProjectStore } from '@/stores'
|
||||||
import lightIcon from '@/assets/images/light-icon.png'
|
import lightIcon from '@/assets/images/light-icon.png'
|
||||||
import closeIcon from '@/assets/images/close-icon.png'
|
import closeIcon from '@/assets/images/close-icon.png'
|
||||||
|
import { createProject } from '@/api/agent'
|
||||||
// import Tag from './Tag.vue'
|
// import Tag from './Tag.vue'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const agentStore = useAgentStore()
|
const agentStore = useAgentStore()
|
||||||
|
const projectStore = useProjectStore()
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
isAgentMode?: boolean
|
isAgentMode?: boolean
|
||||||
|
generating?: boolean
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
isAgentMode: false
|
isAgentMode: false,
|
||||||
|
generating: false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const emits = defineEmits(['send'])
|
const emits = defineEmits(['send', 'pause'])
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
@@ -424,7 +432,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSendAgent = () => {
|
const handleSendAgent = async () => {
|
||||||
|
if (props.generating) {
|
||||||
|
emits('pause')
|
||||||
|
return
|
||||||
|
}
|
||||||
if (!inputValue.value.trim()) return
|
if (!inputValue.value.trim()) return
|
||||||
emits('send', { text: inputValue.value.trim(), images: uploadedImages.value })
|
emits('send', { text: inputValue.value.trim(), images: uploadedImages.value })
|
||||||
// 发送后清空输入框
|
// 发送后清空输入框
|
||||||
@@ -499,21 +511,22 @@
|
|||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleCreateProject = () => {
|
const handleCreateProject = async () => {
|
||||||
// 这里可以添加创建项目的逻辑
|
// 这里可以添加创建项目的逻辑
|
||||||
const params = {
|
const params = {
|
||||||
type: typeValue.value,
|
type: typeValue.value,
|
||||||
area: areaValue.value,
|
area: areaValue.value,
|
||||||
style: styleValue.value
|
style: styleValue.value,
|
||||||
|
temperature: 0.7
|
||||||
}
|
}
|
||||||
|
const projectres = await createProject(params)
|
||||||
|
console.log('projectres', projectres)
|
||||||
|
projectStore.setId(projectres)
|
||||||
// 保存初始数据到 store
|
// 保存初始数据到 store
|
||||||
agentStore.setInitialProjectData({
|
agentStore.setInitialProjectData({
|
||||||
text: inputValue.value.trim(),
|
text: inputValue.value.trim(),
|
||||||
images: uploadedImages.value,
|
images: uploadedImages.value,
|
||||||
type: typeValue.value,
|
...params
|
||||||
area: areaValue.value,
|
|
||||||
style: styleValue.value
|
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('Create project with:', params)
|
console.log('Create project with:', params)
|
||||||
@@ -736,10 +749,21 @@
|
|||||||
.right {
|
.right {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
.sender-icon {
|
.sender-btn {
|
||||||
width: 3.2rem;
|
width: 3.2rem;
|
||||||
height: 3.2rem;
|
height: 3.2rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
background-color: #ff7a51;
|
||||||
|
border-radius: 50%;
|
||||||
|
.sender-icon {
|
||||||
|
width: 1.3rem;
|
||||||
|
height: 1.3rem;
|
||||||
|
}
|
||||||
|
.sender-pause {
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user