Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
10f6a2b1
authored
Jul 16, 2024
by
xiaohong
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev' of
https://gitee.com/yudaocode/yudao-ui-admin-vue3
into dev
parents
806888cc
35b2708c
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
158 additions
and
112 deletions
+158
-112
src/api/ai/write/index.ts
+36
-16
src/views/ai/image/index/components/other/index.vue
+20
-16
src/views/ai/image/index/index.vue
+2
-1
src/views/ai/utils/constants.ts
+28
-52
src/views/ai/write/index/components/Left.vue
+18
-8
src/views/ai/write/index/components/Right.vue
+20
-5
src/views/ai/write/index/components/Tag.vue
+0
-0
src/views/ai/write/index/index.vue
+3
-4
src/views/ai/write/manager/index.vue
+25
-7
src/views/mall/promotion/kefu/index.vue
+1
-3
types/global.d.ts
+5
-0
No files found.
src/api/ai/write
r
/index.ts
→
src/api/ai/write/index.ts
View file @
10f6a2b1
import
{
fetchEventSource
}
from
'@microsoft/fetch-event-source'
import
request
from
'@/config/axios'
import
{
getAccessToken
}
from
'@/utils/auth'
import
{
config
}
from
'@/config/axios/config'
import
{
AiWriteTypeEnum
}
from
'@/views/ai/utils/constants'
import
request
from
'@/config/axios'
export
interface
WriteVO
{
type
:
AiWriteTypeEnum
.
WRITING
|
AiWriteTypeEnum
.
REPLY
// 1:撰写 2:回复
...
...
@@ -21,20 +21,44 @@ export interface WriteVO {
createTime
?:
Date
// 创建时间
}
// TODO @hhero:搞成 WriteApi,类似 ConversationApi 一样。这样更有类的概念,后续引入某个 Api,然后调用它的方法就可以了。
export
const
writeStream
=
({
export
interface
AiWritePageReqVO
extends
PageParam
{
userId
?:
number
// 用户编号
type
?:
AiWriteTypeEnum
// 写作类型
platform
?:
string
// 平台
createTime
?:
[
string
,
string
]
// 创建时间
}
export
interface
AiWriteRespVo
{
id
:
number
userId
:
number
type
:
number
platform
:
string
model
:
string
prompt
:
string
generatedContent
:
string
originalContent
:
string
length
:
number
format
:
number
tone
:
number
language
:
number
errorMessage
:
string
createTime
:
string
}
export
const
WriteApi
=
{
writeStream
:
({
data
,
onClose
,
onMessage
,
onError
,
ctrl
}:
{
}:
{
data
:
WriteVO
onMessage
?:
(
res
:
any
)
=>
void
onError
?:
(...
args
:
any
[])
=>
void
onClose
?:
(...
args
:
any
[])
=>
void
ctrl
:
AbortController
})
=>
{
})
=>
{
const
token
=
getAccessToken
()
return
fetchEventSource
(
`
${
config
.
base_url
}
/ai/write/generate-stream`
,
{
method
:
'post'
,
...
...
@@ -49,17 +73,13 @@ export const writeStream = ({
onclose
:
onClose
,
signal
:
ctrl
.
signal
})
}
// AI 写作 API
export
const
WriteApi
=
{
// 查询AI 写作分页
getWritePage
:
async
(
params
:
any
)
=>
{
return
await
request
.
get
({
url
:
`/ai/write/page`
,
params
})
},
// 删除AI 写作
deleteWrite
:
async
(
id
:
number
)
=>
{
return
await
request
.
delete
({
url
:
`/ai/write/delete?id=`
+
id
})
// 获取写作列表
getWritePage
:
(
params
:
AiWritePageReqVO
)
=>
{
return
request
.
get
<
PageResult
<
AiWriteRespVo
[]
>>
({
url
:
`/ai/write/page`
,
params
})
},
// 删除写作
deleteWrite
(
id
:
number
)
{
return
request
.
delete
({
url
:
`/ai/write/delete`
,
params
:
{
id
}
})
}
}
src/views/ai/image/index/components/other/index.vue
View file @
10f6a2b1
...
...
@@ -36,7 +36,13 @@
<el-text
tag=
"b"
>
平台
</el-text>
</div>
<el-space
wrap
class=
"group-item-body"
>
<el-select
v-model=
"otherPlatform"
placeholder=
"Select"
size=
"large"
class=
"!w-350px"
@
change=
"handlerPlatformChange"
>
<el-select
v-model=
"otherPlatform"
placeholder=
"Select"
size=
"large"
class=
"!w-350px"
@
change=
"handlerPlatformChange"
>
<el-option
v-for=
"item in OtherPlatformEnum"
:key=
"item.key"
...
...
@@ -52,12 +58,7 @@
</div>
<el-space
wrap
class=
"group-item-body"
>
<el-select
v-model=
"model"
placeholder=
"Select"
size=
"large"
class=
"!w-350px"
>
<el-option
v-for=
"item in models"
:key=
"item.key"
:label=
"item.name"
:value=
"item.key"
/>
<el-option
v-for=
"item in models"
:key=
"item.key"
:label=
"item.name"
:value=
"item.key"
/>
</el-select>
</el-space>
</div>
...
...
@@ -77,12 +78,14 @@
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
ImageApi
,
ImageDrawReqVO
,
ImageVO
}
from
'@/api/ai/image'
import
{
ImageApi
,
ImageDrawReqVO
,
ImageVO
}
from
'@/api/ai/image'
import
{
AiPlatformEnum
,
ChatGlmModels
,
ImageHotWords
,
ImageModelVO
,
OtherPlatformEnum
,
QianFanModels
,
TongYiWanXiangModels
}
from
'@/views/ai/utils/constants'
...
...
@@ -96,10 +99,9 @@ const prompt = ref<string>('') // 提示词
const
width
=
ref
<
number
>
(
512
)
// 图片宽度
const
height
=
ref
<
number
>
(
512
)
// 图片高度
const
otherPlatform
=
ref
<
string
>
(
AiPlatformEnum
.
TONG_YI
)
// 平台
const
models
=
ref
<
ImageModelVO
[]
>
(
TongYiWanXiangModels
)
// 模型
const
models
=
ref
<
ImageModelVO
[]
>
(
TongYiWanXiangModels
)
// 模型
TongYiWanXiangModels、QianFanModels
const
model
=
ref
<
string
>
(
models
.
value
[
0
].
key
)
// 模型
const
emits
=
defineEmits
([
'onDrawStart'
,
'onDrawComplete'
])
// 定义 emits
/** 选择热词 */
...
...
@@ -131,9 +133,8 @@ const handleGenerateImage = async () => {
prompt
:
prompt
.
value
,
// 提示词
width
:
width
.
value
,
// 图片宽度
height
:
height
.
value
,
// 图片高度
options
:
{
}
}
as
ImageDrawReqVO
options
:
{}
}
as
unknown
as
ImageDrawReqVO
await
ImageApi
.
drawImage
(
form
)
}
finally
{
// 回调
...
...
@@ -148,14 +149,17 @@ const settingValues = async (detail: ImageVO) => {
prompt
.
value
=
detail
.
prompt
width
.
value
=
detail
.
width
height
.
value
=
detail
.
height
}
/** 平台切换 */
const
handlerPlatformChange
=
async
(
platform
)
=>
{
const
handlerPlatformChange
=
async
(
platform
:
string
)
=>
{
// 切换平台,切换模型、风格
if
(
AiPlatformEnum
.
YI_YAN
===
platform
)
{
if
(
AiPlatformEnum
.
TONG_YI
===
platform
)
{
models
.
value
=
TongYiWanXiangModels
}
else
if
(
AiPlatformEnum
.
YI_YAN
===
platform
)
{
models
.
value
=
QianFanModels
}
else
if
(
AiPlatformEnum
.
ZHI_PU
===
platform
)
{
models
.
value
=
ChatGlmModels
}
else
{
models
.
value
=
[]
}
...
...
src/views/ai/image/index/index.vue
View file @
10f6a2b1
...
...
@@ -62,7 +62,7 @@ const platformOptions = [
value
:
AiPlatformEnum
.
STABLE_DIFFUSION
},
{
label
:
'其
他
'
,
label
:
'其
它
'
,
value
:
'other'
}
]
...
...
@@ -88,6 +88,7 @@ const handleRegeneration = async (image: ImageVO) => {
}
else
if
(
image
.
platform
===
AiPlatformEnum
.
STABLE_DIFFUSION
)
{
stableDiffusionRef
.
value
.
settingValues
(
image
)
}
// TODO @fan:貌似 other 重新设置不行?
}
</
script
>
...
...
src/views/ai/utils/constants.ts
View file @
10f6a2b1
...
...
@@ -20,17 +20,21 @@ export const AiPlatformEnum = {
Ollama
:
'Ollama'
,
STABLE_DIFFUSION
:
'StableDiffusion'
,
// Stability AI
MIDJOURNEY
:
'Midjourney'
,
// Midjourney
SUNO
:
'Suno'
,
// Suno AI
SUNO
:
'Suno'
// Suno AI
}
export
const
OtherPlatformEnum
:
ImageModelVO
[]
=
[
export
const
OtherPlatformEnum
:
ImageModelVO
[]
=
[
{
key
:
AiPlatformEnum
.
TONG_YI
,
name
:
'通义万相'
},
{
key
:
AiPlatformEnum
.
YI_YAN
,
name
:
'百度图片'
name
:
'百度千帆'
},
{
key
:
AiPlatformEnum
.
ZHI_PU
,
name
:
'智谱 AI'
}
]
...
...
@@ -60,6 +64,12 @@ export enum AiWriteTypeEnum {
REPLY
// 回复
}
// 表格展示对照map
export
const
AiWriteTypeTableRender
=
{
[
AiWriteTypeEnum
.
WRITING
]:
'撰写'
,
[
AiWriteTypeEnum
.
REPLY
]:
'回复'
,
}
// ========== 【图片 UI】相关的枚举 ==========
export
const
ImageHotWords
=
[
'中国旗袍'
,
...
...
@@ -200,54 +210,6 @@ export const StableDiffusionStylePresets: ImageModelVO[] = [
}
]
// todo @芋艿 这些是通义的风格,看要不要删除
export
const
TongYiWanXiangStylePresets
:
ImageModelVO
[]
=
[
{
key
:
'-1'
,
name
:
'上传图像风格'
},
{
key
:
'0'
,
name
:
'复古漫画'
},
{
key
:
'1'
,
name
:
'3D童话'
},
{
key
:
'2'
,
name
:
'二次元'
},
{
key
:
'3'
,
name
:
'小清新'
},
{
key
:
'4'
,
name
:
'未来科技'
},
{
key
:
'5'
,
name
:
'国画古风'
},
{
key
:
'6'
,
name
:
'将军百战'
},
{
key
:
'7'
,
name
:
'炫彩卡通'
},
{
key
:
'8'
,
name
:
'清雅国风'
},
{
key
:
'9'
,
name
:
'喜迎新年'
}
]
export
const
TongYiWanXiangModels
:
ImageModelVO
[]
=
[
{
key
:
'wanx-v1'
,
...
...
@@ -259,6 +221,20 @@ export const TongYiWanXiangModels: ImageModelVO[] = [
}
]
export
const
QianFanModels
:
ImageModelVO
[]
=
[
{
key
:
'sd_xl'
,
name
:
'sd_xl'
}
]
export
const
ChatGlmModels
:
ImageModelVO
[]
=
[
{
key
:
'cogview-3'
,
name
:
'cogview-3'
}
]
export
const
StableDiffusionClipGuidancePresets
:
ImageModelVO
[]
=
[
{
key
:
'NONE'
,
...
...
@@ -318,7 +294,7 @@ export const Dall3StyleList: ImageModelVO[] = [
export
interface
ImageSizeVO
{
key
:
string
name
:
string
name
?
:
string
style
:
string
width
:
string
height
:
string
...
...
src/views/ai/write
r
/index/components/Left.vue
→
src/views/ai/write/index/components/Left.vue
View file @
10f6a2b1
...
...
@@ -24,14 +24,15 @@
</h3>
</DefineLabel>
<div
class=
"
relative
"
v-bind=
"$attrs"
>
<div
class=
"
flex flex-col
"
v-bind=
"$attrs"
>
<!-- tab -->
<div
class=
"absolute left-1/2 top-2 -translate-x-1/2 w-[303px] rounded-full bg-[#DDDFE3] p-1 z-10"
>
<div
class=
"w-full pt-2 bg-[#f5f7f9] flex justify-center"
>
<div
class=
"w-[303px] rounded-full bg-[#DDDFE3] p-1 z-10"
>
<div
class=
"flex items-center relative after:content-[''] after:block after:bg-white after:h-[30px] after:w-1/2 after:absolute after:top-0 after:left-0 after:transition-transform after:rounded-full"
:class=
"selectedTab === AiWriteTypeEnum.REPLY && 'after:transform after:translate-x-[100%]'"
:class=
"
selectedTab === AiWriteTypeEnum.REPLY && 'after:transform after:translate-x-[100%]'
"
>
<ReuseTab
v-for=
"tab in tabs"
...
...
@@ -42,8 +43,9 @@
/>
</div>
</div>
</div>
<div
class=
"px-7 pb-2
pt-[46px] overflow-y-auto lg:block w-[380px] box-border bg-[#ECEDEF
] h-full"
class=
"px-7 pb-2
flex-grow overflow-y-auto lg:block w-[380px] box-border bg-[#f5f7f9
] h-full"
>
<div>
<template
v-if=
"selectedTab === 1"
>
...
...
@@ -102,7 +104,7 @@
import
{
createReusableTemplate
}
from
'@vueuse/core'
import
{
ref
}
from
'vue'
import
Tag
from
'./Tag.vue'
import
{
WriteVO
}
from
'
@/api/ai/writer
'
import
{
WriteVO
}
from
'
src/api/ai/write
'
import
{
omit
}
from
'lodash-es'
import
{
DICT_TYPE
,
getIntDictOptions
}
from
'@/utils/dict'
import
{
AiWriteTypeEnum
,
WriteExample
}
from
'@/views/ai/utils/constants'
...
...
@@ -177,10 +179,18 @@ const initData: WriteVO = {
}
const
formData
=
ref
<
WriteVO
>
({
...
initData
})
/** 用来记录切换之前所填写的数据,切换的时候给赋值回来 **/
const
recordFormData
=
{}
as
Record
<
AiWriteTypeEnum
,
WriteVO
>
/** 切换tab **/
const
switchTab
=
(
value
:
TabType
)
=>
{
if
(
value
!==
selectedTab
.
value
)
{
// 保存之前的久数据
recordFormData
[
selectedTab
.
value
]
=
formData
.
value
selectedTab
.
value
=
value
formData
.
value
=
{
...
initData
}
// 将之前的旧数据赋值回来
formData
.
value
=
{
...
initData
,
...
recordFormData
[
value
]
}
}
}
/** 提交写作 */
...
...
src/views/ai/write
r
/index/components/Right.vue
→
src/views/ai/write/index/components/Right.vue
View file @
10f6a2b1
<
template
>
<div
class=
"h-full box-border flex flex-col px-7"
>
<h3
class=
"m-0 h-14 -mx-7 px-7 shrink-0 flex items-center justify-between bg-[#ecedef]"
>
<el-card
class=
"my-card h-full"
>
<template
#
header
><h3
class=
"m-0 px-7 shrink-0 flex items-center justify-between"
>
<span>
预览
</span>
<!-- 展示在右上角 -->
<el-button
color=
"#846af7"
v-show=
"showCopy"
@
click=
"copyContent"
size=
"small"
>
...
...
@@ -9,9 +10,10 @@
</
template
>
复制
</el-button>
</h3>
</h3></template
>
<div
ref=
"contentRef"
class=
"hide-scroll-bar
flex-grow
box-border overflow-y-auto"
>
<div
ref=
"contentRef"
class=
"hide-scroll-bar
h-full
box-border overflow-y-auto"
>
<div
class=
"w-full min-h-full relative flex-grow bg-white box-border p-3 sm:p-7"
>
<!-- 终止生成内容的按钮 -->
<el-button
...
...
@@ -36,7 +38,7 @@
/>
</div>
</div>
</
div
>
</
el-card
>
</template>
<
script
setup
lang=
"ts"
>
...
...
@@ -102,4 +104,17 @@ watch(copied, (val) => {
height
:
0
;
}
}
.my-card
{
display
:
flex
;
flex-direction
:
column
;
:deep(.el-card__body)
{
box-sizing
:
border-box
;
flex-grow
:
1
;
overflow-y
:
auto
;
padding
:
0
;
@extend
.hide-scroll-bar;
}
}
</
style
>
src/views/ai/write
r
/index/components/Tag.vue
→
src/views/ai/write/index/components/Tag.vue
View file @
10f6a2b1
File moved
src/views/ai/write
r
/index/index.vue
→
src/views/ai/write/index/index.vue
View file @
10f6a2b1
<
template
>
<!-- TODO @hhhero:整体没啥问题了。感觉整体框框的样子可以优化下,可以参考下绘图界面。例如说:1)写作的“预览”和绘图的“绘图任务”的 header;2)左右的边界,有个竖线之类的。 -->
<div
class=
"h-[calc(100vh-var(--top-tool-height)-var(--app-footer-height)-40px)] -m-5 flex"
>
<div
class=
"absolute top-0 left-0 right-0 bottom-0 flex"
>
<Left
:is-writing=
"isWriting"
class=
"h-full"
...
...
@@ -21,7 +20,7 @@
<
script
setup
lang=
"ts"
>
import
Left
from
'./components/Left.vue'
import
Right
from
'./components/Right.vue'
import
*
as
WriteApi
from
'@/api/ai/writer
'
import
{
WriteApi
}
from
'@/api/ai/write
'
import
{
WriteExample
}
from
'@/views/ai/utils/constants'
const
message
=
useMessage
()
...
...
@@ -66,7 +65,7 @@ const submit = (data) => {
}
/** 点击示例触发 */
const
handleExampleClick
=
(
type
:
keyof
typeof
WriteExample
DataJson
)
=>
{
const
handleExampleClick
=
(
type
:
keyof
typeof
WriteExample
)
=>
{
writeResult
.
value
=
WriteExample
[
type
].
data
}
...
...
src/views/ai/write/manager/index.vue
View file @
10f6a2b1
...
...
@@ -39,7 +39,7 @@
</el-select>
</el-form-item>
<el-form-item
label=
"平台"
prop=
"platform"
>
<el-select
v-model=
"queryParams.
status
"
placeholder=
"请选择平台"
clearable
class=
"!w-240px"
>
<el-select
v-model=
"queryParams.
platform
"
placeholder=
"请选择平台"
clearable
class=
"!w-240px"
>
<el-option
v-for=
"dict in getStrDictOptions(DICT_TYPE.AI_PLATFORM)"
:key=
"dict.value"
...
...
@@ -70,6 +70,7 @@
>
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
新增
</el-button>
<!-- TODO @YunaiV 目前没有导出接口,需要导出吗 -->
<el-button
type=
"success"
plain
...
...
@@ -103,7 +104,13 @@
</
template
>
</el-table-column>
<el-table-column
label=
"模型"
align=
"center"
prop=
"model"
width=
"180"
/>
<el-table-column
label=
"生成内容提示"
align=
"center"
prop=
"prompt"
width=
"180"
/>
<el-table-column
label=
"生成内容提示"
align=
"center"
prop=
"prompt"
width=
"180"
show-overflow-tooltip
/>
<el-table-column
label=
"生成的内容"
align=
"center"
prop=
"generatedContent"
width=
"180"
/>
<el-table-column
label=
"原文"
align=
"center"
prop=
"originalContent"
width=
"180"
/>
<el-table-column
label=
"长度"
align=
"center"
prop=
"length"
>
...
...
@@ -136,6 +143,7 @@
<el-table-column
label=
"错误信息"
align=
"center"
prop=
"errorMessage"
/>
<el-table-column
label=
"操作"
align=
"center"
>
<
template
#
default=
"scope"
>
<!-- TODO @YunaiV 目前没有修改接口,写作要可以更改吗-->
<el-button
link
type=
"primary"
...
...
@@ -168,8 +176,8 @@
<
script
setup
lang=
"ts"
>
import
{
DICT_TYPE
,
getIntDictOptions
,
getStrDictOptions
}
from
'@/utils/dict'
import
{
dateFormatter
}
from
'@/utils/formatTime'
// TODO 芋艿:这里应该是 write
import
{
WriteApi
,
WriteVO
}
from
'@/api/ai/writer
'
import
{
useRouter
}
from
'vue-router'
import
{
WriteApi
,
AiWritePageReqVO
,
AiWriteRespVo
}
from
'@/api/ai/write
'
import
*
as
UserApi
from
'@/api/system/user'
/** AI 写作列表 */
...
...
@@ -177,17 +185,18 @@ defineOptions({ name: 'AiWriteManager' })
const
message
=
useMessage
()
// 消息弹窗
const
{
t
}
=
useI18n
()
// 国际化
const
router
=
useRouter
()
// 路由
const
loading
=
ref
(
true
)
// 列表的加载中
const
list
=
ref
<
WriteVO
[]
>
([])
// 列表的数据
const
list
=
ref
<
AiWriteRespVo
[]
>
([])
// 列表的数据
const
total
=
ref
(
0
)
// 列表的总页数
const
queryParams
=
reactive
({
const
queryParams
=
reactive
<
AiWritePageReqVO
>
({
pageNo
:
1
,
pageSize
:
10
,
userId
:
undefined
,
type
:
undefined
,
platform
:
undefined
,
createTime
:
[]
createTime
:
undefined
})
const
queryFormRef
=
ref
()
// 搜索的表单
const
userList
=
ref
<
UserApi
.
UserVO
[]
>
([])
// 用户列表
...
...
@@ -216,6 +225,15 @@ const resetQuery = () => {
handleQuery
()
}
/** 新增方法,跳转到写作页面 **/
const
openForm
=
(
type
:
string
,
id
?:
number
)
=>
{
switch
(
type
)
{
case
'create'
:
router
.
push
(
'/ai/write'
)
break
}
}
/** 删除按钮操作 */
const
handleDelete
=
async
(
id
:
number
)
=>
{
try
{
...
...
src/views/mall/promotion/kefu/index.vue
View file @
10f6a2b1
...
...
@@ -28,9 +28,7 @@ const message = useMessage() // 消息弹窗
// ======================= WebSocket start =======================
const
server
=
ref
(
(
import
.
meta
.
env
.
VITE_BASE_URL
+
'/infra/ws/'
).
replace
(
'http'
,
'ws'
)
+
'?token='
+
getAccessToken
()
(
import
.
meta
.
env
.
VITE_BASE_URL
+
'/infra/ws'
).
replace
(
'http'
,
'ws'
)
+
'?token='
+
getAccessToken
()
)
// WebSocket 服务地址
/** 发起 WebSocket 连接 */
...
...
types/global.d.ts
View file @
10f6a2b1
...
...
@@ -50,4 +50,9 @@ declare global {
name
:
string
children
?:
Tree
[]
|
any
[]
}
// 分页数据公共返回
interface
PageResult
<
T
>
{
list
:
T
// 数据
total
:
number
// 总量
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment