refactor parameters for JimengCreate page
@@ -9,10 +9,8 @@ type JimengConfig struct {
|
||||
|
||||
// JimengPower 即梦AI算力配置
|
||||
type JimengPower struct {
|
||||
TextToImage int `json:"text_to_image"`
|
||||
ImageToImage int `json:"image_to_image"`
|
||||
ImageEdit int `json:"image_edit"`
|
||||
ImageEffects int `json:"image_effects"`
|
||||
TextToVideo int `json:"text_to_video"`
|
||||
ImageToVideo int `json:"image_to_video"`
|
||||
Image int `json:"image"` // 图片生成算力,单位:积分/张
|
||||
Video int `json:"video"` // 视频生成算力,单位:积分/秒
|
||||
VirtualHuman int `json:"virtual_human"` // 数字人视频生成算力,单位:积分/秒
|
||||
ActionTransfer int `json:"action_transfer"` // 视频动作迁移算力,单位:积分/秒
|
||||
}
|
||||
|
||||
@@ -231,28 +231,20 @@ func (h *AdminJimengHandler) UpdateConfig(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 验证算力配置
|
||||
if req.Power.TextToImage <= 0 {
|
||||
resp.ERROR(c, "文生图算力必须大于0")
|
||||
if req.Power.Image <= 0 {
|
||||
resp.ERROR(c, "图片生成算力必须大于0")
|
||||
return
|
||||
}
|
||||
if req.Power.ImageToImage <= 0 {
|
||||
resp.ERROR(c, "图生图算力必须大于0")
|
||||
if req.Power.Video <= 0 {
|
||||
resp.ERROR(c, "视频生成算力必须大于0")
|
||||
return
|
||||
}
|
||||
if req.Power.ImageEdit <= 0 {
|
||||
resp.ERROR(c, "图片编辑算力必须大于0")
|
||||
if req.Power.VirtualHuman <= 0 {
|
||||
resp.ERROR(c, "数字人生成算力必须大于0")
|
||||
return
|
||||
}
|
||||
if req.Power.ImageEffects <= 0 {
|
||||
resp.ERROR(c, "图片特效算力必须大于0")
|
||||
return
|
||||
}
|
||||
if req.Power.TextToVideo <= 0 {
|
||||
resp.ERROR(c, "文生视频算力必须大于0")
|
||||
return
|
||||
}
|
||||
if req.Power.ImageToVideo <= 0 {
|
||||
resp.ERROR(c, "图生视频算力必须大于0")
|
||||
if req.Power.ActionTransfer <= 0 {
|
||||
resp.ERROR(c, "视频动作迁移算力必须大于0")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -132,8 +132,8 @@ func (h *JimengHandler) CreateTask(c *gin.Context) {
|
||||
|
||||
switch req.TaskType {
|
||||
case "text_to_image":
|
||||
powerCost = h.getPowerFromConfig(model.JMTaskTypeTextToImage)
|
||||
taskType = model.JMTaskTypeTextToImage
|
||||
powerCost = h.getPowerFromConfig(model.JMTaskTypeImage)
|
||||
taskType = model.JMTaskTypeImage
|
||||
reqKey = jimeng.ReqKeyTextToImage
|
||||
modelName = "即梦文生图"
|
||||
if req.Scale == 0 {
|
||||
@@ -147,8 +147,8 @@ func (h *JimengHandler) CreateTask(c *gin.Context) {
|
||||
"use_pre_llm": req.UsePreLLM,
|
||||
}
|
||||
case "image_to_image":
|
||||
powerCost = h.getPowerFromConfig(model.JMTaskTypeImageToImage)
|
||||
taskType = model.JMTaskTypeImageToImage
|
||||
powerCost = h.getPowerFromConfig(model.JMTaskTypeVideo)
|
||||
taskType = model.JMTaskTypeVideo
|
||||
reqKey = jimeng.ReqKeyImageToImagePortrait
|
||||
modelName = "即梦图生图"
|
||||
if req.Gpen == 0 {
|
||||
@@ -175,8 +175,8 @@ func (h *JimengHandler) CreateTask(c *gin.Context) {
|
||||
"seed": req.Seed,
|
||||
}
|
||||
case "image_edit":
|
||||
powerCost = h.getPowerFromConfig(model.JMTaskTypeImageEdit)
|
||||
taskType = model.JMTaskTypeImageEdit
|
||||
powerCost = h.getPowerFromConfig(model.JMTaskTypeVirtualHuman)
|
||||
taskType = model.JMTaskTypeVirtualHuman
|
||||
reqKey = jimeng.ReqKeyImageEdit
|
||||
modelName = "即梦图像编辑"
|
||||
if req.Scale == 0 {
|
||||
@@ -188,8 +188,8 @@ func (h *JimengHandler) CreateTask(c *gin.Context) {
|
||||
}
|
||||
params["image_urls"] = []string{req.ImageInput}
|
||||
case "image_effects":
|
||||
powerCost = h.getPowerFromConfig(model.JMTaskTypeImageEffects)
|
||||
taskType = model.JMTaskTypeImageEffects
|
||||
powerCost = h.getPowerFromConfig(model.JMTaskTypeActionTransfer)
|
||||
taskType = model.JMTaskTypeActionTransfer
|
||||
reqKey = jimeng.ReqKeyImageEffects
|
||||
modelName = "即梦图像特效"
|
||||
if req.Width == 0 {
|
||||
@@ -205,8 +205,8 @@ func (h *JimengHandler) CreateTask(c *gin.Context) {
|
||||
"height": req.Height,
|
||||
}
|
||||
case "text_to_video":
|
||||
powerCost = h.getPowerFromConfig(model.JMTaskTypeTextToVideo)
|
||||
taskType = model.JMTaskTypeTextToVideo
|
||||
powerCost = h.getPowerFromConfig(model.JMTaskTypeVideo)
|
||||
taskType = model.JMTaskTypeVideo
|
||||
reqKey = jimeng.ReqKeyTextToVideo
|
||||
modelName = "即梦文生视频"
|
||||
if req.AspectRatio == "" {
|
||||
@@ -217,8 +217,8 @@ func (h *JimengHandler) CreateTask(c *gin.Context) {
|
||||
"aspect_ratio": req.AspectRatio,
|
||||
}
|
||||
case "image_to_video":
|
||||
powerCost = h.getPowerFromConfig(model.JMTaskTypeImageToVideo)
|
||||
taskType = model.JMTaskTypeImageToVideo
|
||||
powerCost = h.getPowerFromConfig(model.JMTaskTypeVideo)
|
||||
taskType = model.JMTaskTypeVideo
|
||||
reqKey = jimeng.ReqKeyImageToVideo
|
||||
modelName = "即梦图生视频"
|
||||
params = map[string]any{
|
||||
@@ -287,17 +287,9 @@ func (h *JimengHandler) Jobs(c *gin.Context) {
|
||||
|
||||
switch req.Filter {
|
||||
case "image":
|
||||
query = query.Where("type IN (?)", []model.JMTaskType{
|
||||
model.JMTaskTypeTextToImage,
|
||||
model.JMTaskTypeImageToImage,
|
||||
model.JMTaskTypeImageEdit,
|
||||
model.JMTaskTypeImageEffects,
|
||||
})
|
||||
query = query.Where("type = ?", model.JMTaskTypeImage)
|
||||
case "video":
|
||||
query = query.Where("type IN (?)", []model.JMTaskType{
|
||||
model.JMTaskTypeTextToVideo,
|
||||
model.JMTaskTypeImageToVideo,
|
||||
})
|
||||
query = query.Where("type = ?", model.JMTaskTypeVideo)
|
||||
}
|
||||
|
||||
if len(req.Ids) > 0 {
|
||||
@@ -438,18 +430,14 @@ func (h *JimengHandler) getPowerFromConfig(taskType model.JMTaskType) int {
|
||||
config := h.App.SysConfig.Jimeng
|
||||
|
||||
switch taskType {
|
||||
case model.JMTaskTypeTextToImage:
|
||||
return config.Power.TextToImage
|
||||
case model.JMTaskTypeImageToImage:
|
||||
return config.Power.ImageToImage
|
||||
case model.JMTaskTypeImageEdit:
|
||||
return config.Power.ImageEdit
|
||||
case model.JMTaskTypeImageEffects:
|
||||
return config.Power.ImageEffects
|
||||
case model.JMTaskTypeTextToVideo:
|
||||
return config.Power.TextToVideo
|
||||
case model.JMTaskTypeImageToVideo:
|
||||
return config.Power.ImageToVideo
|
||||
case model.JMTaskTypeImage:
|
||||
return config.Power.Image
|
||||
case model.JMTaskTypeVideo:
|
||||
return config.Power.Video
|
||||
case model.JMTaskTypeVirtualHuman:
|
||||
return config.Power.VirtualHuman
|
||||
case model.JMTaskTypeActionTransfer:
|
||||
return config.Power.ActionTransfer
|
||||
default:
|
||||
return 10
|
||||
}
|
||||
@@ -459,11 +447,9 @@ func (h *JimengHandler) getPowerFromConfig(taskType model.JMTaskType) int {
|
||||
func (h *JimengHandler) GetPowerConfig(c *gin.Context) {
|
||||
config := h.App.SysConfig.Jimeng
|
||||
resp.SUCCESS(c, gin.H{
|
||||
"text_to_image": config.Power.TextToImage,
|
||||
"image_to_image": config.Power.ImageToImage,
|
||||
"image_edit": config.Power.ImageEdit,
|
||||
"image_effects": config.Power.ImageEffects,
|
||||
"text_to_video": config.Power.TextToVideo,
|
||||
"image_to_video": config.Power.ImageToVideo,
|
||||
"image": config.Power.Image,
|
||||
"video": config.Power.Video,
|
||||
"image_edit": config.Power.VirtualHuman,
|
||||
"image_effects": config.Power.ActionTransfer,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -199,18 +199,14 @@ func (s *Service) buildTaskRequest(job *model.JimengJob) (*SubmitTaskRequest, er
|
||||
|
||||
// 根据任务类型设置特定参数
|
||||
switch job.Type {
|
||||
case model.JMTaskTypeTextToImage:
|
||||
case model.JMTaskTypeImage:
|
||||
s.setTextToImageParams(req, params)
|
||||
case model.JMTaskTypeImageToImage:
|
||||
case model.JMTaskTypeVideo:
|
||||
s.setImageToImageParams(req, params)
|
||||
case model.JMTaskTypeImageEdit:
|
||||
case model.JMTaskTypeVirtualHuman:
|
||||
s.setImageEditParams(req, params)
|
||||
case model.JMTaskTypeImageEffects:
|
||||
case model.JMTaskTypeActionTransfer:
|
||||
s.setImageEffectsParams(req, params)
|
||||
case model.JMTaskTypeTextToVideo:
|
||||
s.setTextToVideoParams(req, params)
|
||||
case model.JMTaskTypeImageToVideo:
|
||||
s.setImageToVideoParams(req, params)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported task type: %s", job.Type)
|
||||
}
|
||||
|
||||
@@ -41,12 +41,10 @@ const (
|
||||
type JMTaskType string
|
||||
|
||||
const (
|
||||
JMTaskTypeTextToImage = JMTaskType("text_to_image") // 文生图
|
||||
JMTaskTypeImageToImage = JMTaskType("image_to_image") // 图生图
|
||||
JMTaskTypeImageEdit = JMTaskType("image_edit") // 图像编辑
|
||||
JMTaskTypeImageEffects = JMTaskType("image_effects") // 图像特效
|
||||
JMTaskTypeTextToVideo = JMTaskType("text_to_video") // 文生视频
|
||||
JMTaskTypeImageToVideo = JMTaskType("image_to_video") // 图生视频
|
||||
JMTaskTypeImage = JMTaskType("image") // 文生图
|
||||
JMTaskTypeVideo = JMTaskType("video") // 图生图
|
||||
JMTaskTypeVirtualHuman = JMTaskType("virtual_human") // 图像编辑
|
||||
JMTaskTypeActionTransfer = JMTaskType("action_transfer") // 图像特效
|
||||
)
|
||||
|
||||
// TableName 返回数据表名称
|
||||
|
||||
@@ -49,16 +49,17 @@
|
||||
|
||||
.category-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 15px 10px;
|
||||
padding: 10px 15px;
|
||||
border: 2px solid var(--border-color, #f0f0f0);
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
background: var(--card-bg-secondary, #fafafa);
|
||||
/* 暗色主题支持 */
|
||||
[data-theme="dark"] & {
|
||||
[data-theme='dark'] & {
|
||||
background: var(--card-bg-secondary-dark, #23242a);
|
||||
border-color: var(--border-color-dark, #33343a);
|
||||
}
|
||||
@@ -66,7 +67,7 @@
|
||||
&:hover {
|
||||
border-color: var(--primary-color, #5865f2);
|
||||
background: var(--card-bg-hover, #f8f9ff);
|
||||
[data-theme="dark"] & {
|
||||
[data-theme='dark'] & {
|
||||
background: var(--card-bg-hover-dark, #2a2b31);
|
||||
}
|
||||
transform: translateY(-2px);
|
||||
@@ -76,8 +77,11 @@
|
||||
border-color: var(--primary-color, #5865f2);
|
||||
background: var(--primary-gradient, linear-gradient(135deg, #5865f2 0%, #7289da 100%));
|
||||
color: var(--primary-text-on-primary, #fff);
|
||||
[data-theme="dark"] & {
|
||||
background: var(--primary-gradient-dark, linear-gradient(135deg, #23242a 0%, #2a2b31 100%));
|
||||
[data-theme='dark'] & {
|
||||
background: var(
|
||||
--primary-gradient-dark,
|
||||
linear-gradient(135deg, #23242a 0%, #2a2b31 100%)
|
||||
);
|
||||
color: var(--primary-text-on-primary-dark, #fff);
|
||||
}
|
||||
transform: translateY(-2px);
|
||||
@@ -96,108 +100,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 功能开关
|
||||
.function-switch {
|
||||
margin-bottom: 25px;
|
||||
|
||||
.switch-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--text-theme-color);
|
||||
|
||||
.el-icon {
|
||||
margin-right: 8px;
|
||||
color: var(--primary-color, #5865f2);
|
||||
}
|
||||
}
|
||||
|
||||
.switch-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 5px 15px;
|
||||
border: 1px solid var(--border-color, #e0e0e0);
|
||||
border-radius: 10px;
|
||||
background: var(--card-bg-secondary, #f9f9f9);
|
||||
[data-theme="dark"] & {
|
||||
background: var(--card-bg-secondary-dark, #23242a);
|
||||
border-color: var(--border-color-dark, #33343a);
|
||||
}
|
||||
|
||||
.switch-info {
|
||||
flex: 1;
|
||||
|
||||
.switch-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text-theme-color);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.switch-desc {
|
||||
font-size: 12px;
|
||||
color: var(--text-sub-color, #666);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 参数容器
|
||||
.params-container {
|
||||
.function-panel {
|
||||
.param-line {
|
||||
margin-bottom: 15px;
|
||||
|
||||
&.pt {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 600;
|
||||
color: var(--text-theme-color);
|
||||
}
|
||||
}
|
||||
|
||||
.item-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.label {
|
||||
margin-right: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--text-theme-color);
|
||||
min-width: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.text-info {
|
||||
margin: 20px 0;
|
||||
padding: 15px;
|
||||
background: var(--info-bg, #f0f8ff);
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid var(--primary-color, #5865f2);
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
margin-top: 30px;
|
||||
|
||||
.el-button {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 右侧主要内容区域
|
||||
@@ -239,6 +141,23 @@
|
||||
&:hover {
|
||||
box-shadow: 0 4px 24px rgba(88, 101, 242, 0.12);
|
||||
}
|
||||
|
||||
// 增强任务项悬停动画
|
||||
transition: box-shadow 3s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
transform 0.5s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.5s;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
border: 1.5px solid transparent;
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18), 0 1.5px 8px rgba(0, 0, 0, 0.1);
|
||||
border-color: #a259ff;
|
||||
transform: scale(1.025) translateY(-2px);
|
||||
z-index: 10;
|
||||
}
|
||||
.task-left {
|
||||
width: 100%;
|
||||
flex: none;
|
||||
@@ -253,18 +172,69 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.preview-image, .preview-video {
|
||||
.preview-image,
|
||||
.preview-video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
// 视频预览包装器
|
||||
.preview-video-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.video-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&:hover .video-mask {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.play-btn {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
cursor: pointer;
|
||||
z-index: 3;
|
||||
transition: background 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.preview-placeholder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: var(--text-disabled-color, #999);
|
||||
font-size: 16px;
|
||||
.el-icon, .iconfont {
|
||||
.el-icon,
|
||||
.iconfont {
|
||||
font-size: 32px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
@@ -347,3 +317,69 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 错误信息样式
|
||||
.err-msg-clip {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
word-break: break-all;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
// 模板选择器样式
|
||||
.jimeng-template-select {
|
||||
.el-select-dropdown__item {
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
// 提示词指南样式
|
||||
.prompt-guide {
|
||||
margin: 12px 0 16px;
|
||||
|
||||
.guide-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.guide-content {
|
||||
max-height: 220px;
|
||||
overflow: auto;
|
||||
line-height: 1.6;
|
||||
font-size: 12px;
|
||||
color: #555;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.guide-section {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.guide-subtitle {
|
||||
font-weight: 600;
|
||||
margin-bottom: 6px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: disc;
|
||||
padding-left: 18px;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.quote {
|
||||
margin: 8px 0;
|
||||
padding: 8px 10px;
|
||||
border-left: 3px solid #a3a3a3;
|
||||
background: #f8f8f8;
|
||||
border-radius: 4px;
|
||||
color: #444;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 4125778 */
|
||||
src: url('iconfont.woff2?t=1757465848673') format('woff2'),
|
||||
url('iconfont.woff?t=1757465848673') format('woff'),
|
||||
url('iconfont.ttf?t=1757465848673') format('truetype');
|
||||
src: url('iconfont.woff2?t=1757571432313') format('woff2'),
|
||||
url('iconfont.woff?t=1757571432313') format('woff'),
|
||||
url('iconfont.ttf?t=1757571432313') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@@ -13,6 +13,26 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-resize:before {
|
||||
content: "\e718";
|
||||
}
|
||||
|
||||
.icon-template:before {
|
||||
content: "\e8a6";
|
||||
}
|
||||
|
||||
.icon-error-line:before {
|
||||
content: "\e868";
|
||||
}
|
||||
|
||||
.icon-success-line:before {
|
||||
content: "\e88c";
|
||||
}
|
||||
|
||||
.icon-yunjing:before {
|
||||
content: "\e69b";
|
||||
}
|
||||
|
||||
.icon-action:before {
|
||||
content: "\e658";
|
||||
}
|
||||
|
||||
@@ -5,6 +5,41 @@
|
||||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "10564356",
|
||||
"name": "resize",
|
||||
"font_class": "resize",
|
||||
"unicode": "e718",
|
||||
"unicode_decimal": 59160
|
||||
},
|
||||
{
|
||||
"icon_id": "1727381",
|
||||
"name": "34模板、框架",
|
||||
"font_class": "template",
|
||||
"unicode": "e8a6",
|
||||
"unicode_decimal": 59558
|
||||
},
|
||||
{
|
||||
"icon_id": "9626841",
|
||||
"name": "错误",
|
||||
"font_class": "error-line",
|
||||
"unicode": "e868",
|
||||
"unicode_decimal": 59496
|
||||
},
|
||||
{
|
||||
"icon_id": "9626990",
|
||||
"name": "正确",
|
||||
"font_class": "success-line",
|
||||
"unicode": "e88c",
|
||||
"unicode_decimal": 59532
|
||||
},
|
||||
{
|
||||
"icon_id": "40613765",
|
||||
"name": "运镜控制",
|
||||
"font_class": "yunjing",
|
||||
"unicode": "e69b",
|
||||
"unicode_decimal": 59035
|
||||
},
|
||||
{
|
||||
"icon_id": "5215282",
|
||||
"name": "动作",
|
||||
|
||||
BIN
web/src/assets/img/jimeng/texiao/Christmas_green_background.jpeg
Normal file
|
After Width: | Height: | Size: 111 KiB |
BIN
web/src/assets/img/jimeng/texiao/Christmas_tree.jpeg
Normal file
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
BIN
web/src/assets/img/jimeng/texiao/acrylic_ornaments.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
web/src/assets/img/jimeng/texiao/angel_figurine.png
Normal file
|
After Width: | Height: | Size: 933 KiB |
BIN
web/src/assets/img/jimeng/texiao/birthday_photo_gorgeous.jpeg
Normal file
|
After Width: | Height: | Size: 137 KiB |
BIN
web/src/assets/img/jimeng/texiao/birthday_photo_party.jpeg
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
web/src/assets/img/jimeng/texiao/birthday_photo_red.jpeg
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
web/src/assets/img/jimeng/texiao/car_miniature_ornaments.jpeg
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
web/src/assets/img/jimeng/texiao/claw_machine_style.jpeg
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
web/src/assets/img/jimeng/texiao/earphone_case_style.jpeg
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
web/src/assets/img/jimeng/texiao/electronic_pet_egg_style.jpeg
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
web/src/assets/img/jimeng/texiao/felt_3d_polaroid.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
web/src/assets/img/jimeng/texiao/felt_keychain.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
web/src/assets/img/jimeng/texiao/furry_dream_doll.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
web/src/assets/img/jimeng/texiao/glass_ball.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
web/src/assets/img/jimeng/texiao/graduation_photo.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
BIN
web/src/assets/img/jimeng/texiao/lying_in_fluffy_belly.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
web/src/assets/img/jimeng/texiao/micro_landscape_mini_world.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 982 KiB |
BIN
web/src/assets/img/jimeng/texiao/my_world.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
web/src/assets/img/jimeng/texiao/my_world_universal.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
web/src/assets/img/jimeng/texiao/patchwork_collage_style.jpeg
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
web/src/assets/img/jimeng/texiao/plastic_bubble_figure.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1022 KiB After Width: | Height: | Size: 1022 KiB |
|
Before Width: | Height: | Size: 1016 KiB After Width: | Height: | Size: 1016 KiB |
|
Before Width: | Height: | Size: 1002 KiB After Width: | Height: | Size: 1002 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 856 KiB After Width: | Height: | Size: 856 KiB |
|
Before Width: | Height: | Size: 877 KiB After Width: | Height: | Size: 877 KiB |
|
Before Width: | Height: | Size: 698 KiB After Width: | Height: | Size: 698 KiB |
|
Before Width: | Height: | Size: 948 KiB After Width: | Height: | Size: 948 KiB |
|
Before Width: | Height: | Size: 1021 KiB After Width: | Height: | Size: 1021 KiB |
|
Before Width: | Height: | Size: 874 KiB After Width: | Height: | Size: 874 KiB |
|
Before Width: | Height: | Size: 809 KiB After Width: | Height: | Size: 809 KiB |
@@ -2,10 +2,10 @@
|
||||
<div class="foot-container">
|
||||
<div class="footer text-base">
|
||||
<div>
|
||||
<a :href="gitURL" target="_blank">
|
||||
<span>
|
||||
{{ title }} -
|
||||
{{ version }}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex justify-center text-sm">
|
||||
<span class="mr-2">{{ copyRight }}</span>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<span class="label text-sm">{{ item.name }}</span>
|
||||
<div class="whitespace-pre-line">
|
||||
<span
|
||||
class="text-xs text-gray-500 break-words whitespace-pre-line line-clamp-1"
|
||||
class="text-xs text-gray-500 break-words line-clamp-1 max-w-[200px]"
|
||||
:title="item.label"
|
||||
>{{ item.label }}</span
|
||||
>
|
||||
@@ -90,7 +90,11 @@
|
||||
v-model="modelValue[param.name]"
|
||||
:placeholder="param.placeholder"
|
||||
:popper-class="param.popperClass"
|
||||
filterable
|
||||
>
|
||||
<template #prefix v-if="param.prefix">
|
||||
<i class="iconfont !text-lg" :class="param.prefix"></i>
|
||||
</template>
|
||||
<el-option
|
||||
v-for="option in param.options"
|
||||
:key="option.value"
|
||||
@@ -99,11 +103,18 @@
|
||||
>
|
||||
<div class="flex justify-start" v-if="option.image">
|
||||
<span class="flex py-3 mr-2">
|
||||
<img :src="option.image" class="w-[54px] h-[54px] rounded-lg"
|
||||
<img
|
||||
:src="option.image"
|
||||
class="rounded-lg"
|
||||
:style="{ width: param.imgSize, height: param.imgSize }"
|
||||
/></span>
|
||||
<div class="flex !items-start flex-col py-2 space-y-1">
|
||||
<span class="label text-sm">{{ option.label }}</span>
|
||||
<span class="text-xs text-gray-500">{{ option.value }}</span>
|
||||
<span
|
||||
class="text-xs text-gray-500 break-words line-clamp-1 max-w-[200px]"
|
||||
:title="option.value"
|
||||
>{{ option.value }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-start items-center h-full" v-else>
|
||||
@@ -148,6 +159,11 @@ const props = defineProps({
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
requiredKeys: {
|
||||
type: Object,
|
||||
default: {},
|
||||
required: false,
|
||||
},
|
||||
items: {
|
||||
type: Array,
|
||||
required: true,
|
||||
@@ -159,15 +175,20 @@ const props = defineProps({
|
||||
},
|
||||
})
|
||||
|
||||
const selectedModel = ref({ label: '请选择模型' })
|
||||
const selectedModel = ref(props.items[0])
|
||||
const requiredKeys = ref(props.requiredKeys)
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
// 初始化 modelValue 默认值
|
||||
const initModelValue = (model) => {
|
||||
const defaultValues = {}
|
||||
requiredKeys.value = {}
|
||||
if (model && model.params) {
|
||||
model.params.forEach((param) => {
|
||||
if (param.required) {
|
||||
requiredKeys.value[param.name] = { required: true, label: param.label }
|
||||
}
|
||||
// 根据参数类型设置默认值
|
||||
switch (param.type) {
|
||||
case 'text':
|
||||
@@ -201,6 +222,7 @@ const initModelValue = (model) => {
|
||||
}
|
||||
})
|
||||
}
|
||||
defaultValues.model = selectedModel.value.key
|
||||
return defaultValues
|
||||
}
|
||||
|
||||
@@ -216,6 +238,22 @@ watch(
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
requiredKeys,
|
||||
(newValue) => {
|
||||
emit('update:requiredKeys', newValue)
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.items,
|
||||
(newValue) => {
|
||||
selectedModel.value = newValue[0]
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
// 组件挂载时初始化
|
||||
onMounted(() => {
|
||||
// 确保初始值被正确设置
|
||||
|
||||
@@ -1,17 +1,107 @@
|
||||
import central_orbit from '@/assets/img/jimeng/central_orbit.webp'
|
||||
import clockwise_swivel from '@/assets/img/jimeng/clockwise_swivel.webp'
|
||||
import counterclockwise_swivel from '@/assets/img/jimeng/counterclockwise_swivel.webp'
|
||||
import crane_push from '@/assets/img/jimeng/crane_push.webp'
|
||||
import dynamic_orbit from '@/assets/img/jimeng/dynamic_orbit.webp'
|
||||
import handheld from '@/assets/img/jimeng/handheld.webp'
|
||||
import hitchcock_dolly_in from '@/assets/img/jimeng/hitchcock_dolly_in.webp'
|
||||
import hitchcock_dolly_out from '@/assets/img/jimeng/hitchcock_dolly_out.webp'
|
||||
import quick_pull_back from '@/assets/img/jimeng/quick_pull_back.webp'
|
||||
import rapid_push_pull from '@/assets/img/jimeng/rapid_push_pull.webp'
|
||||
import robo_arm from '@/assets/img/jimeng/robo_arm.webp'
|
||||
import central_orbit from '@/assets/img/jimeng/yunjing/central_orbit.webp'
|
||||
import clockwise_swivel from '@/assets/img/jimeng/yunjing/clockwise_swivel.webp'
|
||||
import counterclockwise_swivel from '@/assets/img/jimeng/yunjing/counterclockwise_swivel.webp'
|
||||
import crane_push from '@/assets/img/jimeng/yunjing/crane_push.webp'
|
||||
import dynamic_orbit from '@/assets/img/jimeng/yunjing/dynamic_orbit.webp'
|
||||
import handheld from '@/assets/img/jimeng/yunjing/handheld.webp'
|
||||
import hitchcock_dolly_in from '@/assets/img/jimeng/yunjing/hitchcock_dolly_in.webp'
|
||||
import hitchcock_dolly_out from '@/assets/img/jimeng/yunjing/hitchcock_dolly_out.webp'
|
||||
import quick_pull_back from '@/assets/img/jimeng/yunjing/quick_pull_back.webp'
|
||||
import rapid_push_pull from '@/assets/img/jimeng/yunjing/rapid_push_pull.webp'
|
||||
import robo_arm from '@/assets/img/jimeng/yunjing/robo_arm.webp'
|
||||
|
||||
import acrylic_ornaments from '@/assets/img/jimeng/texiao/acrylic_ornaments.png'
|
||||
import angel_figurine from '@/assets/img/jimeng/texiao/angel_figurine.png'
|
||||
import birthday_photo_gorgeous from '@/assets/img/jimeng/texiao/birthday_photo_gorgeous.jpeg'
|
||||
import birthday_photo_party from '@/assets/img/jimeng/texiao/birthday_photo_party.jpeg'
|
||||
import birthday_photo_red from '@/assets/img/jimeng/texiao/birthday_photo_red.jpeg'
|
||||
import car_miniature_ornaments from '@/assets/img/jimeng/texiao/car_miniature_ornaments.jpeg'
|
||||
import Christmas_green_background from '@/assets/img/jimeng/texiao/Christmas_green_background.jpeg'
|
||||
import Christmas_tree from '@/assets/img/jimeng/texiao/Christmas_tree.jpeg'
|
||||
import claw_machine_style from '@/assets/img/jimeng/texiao/claw_machine_style.jpeg'
|
||||
import earphone_case_style from '@/assets/img/jimeng/texiao/earphone_case_style.jpeg'
|
||||
import electronic_pet_egg_style from '@/assets/img/jimeng/texiao/electronic_pet_egg_style.jpeg'
|
||||
import felt_3d_polaroid from '@/assets/img/jimeng/texiao/felt_3d_polaroid.png'
|
||||
import felt_keychain from '@/assets/img/jimeng/texiao/felt_keychain.png'
|
||||
import furry_dream_doll from '@/assets/img/jimeng/texiao/furry_dream_doll.png'
|
||||
import glass_ball from '@/assets/img/jimeng/texiao/glass_ball.png'
|
||||
import graduation_photo from '@/assets/img/jimeng/texiao/graduation_photo.png'
|
||||
import lofi_pixel_character_mini_card from '@/assets/img/jimeng/texiao/lofi_pixel_character_mini_card.png'
|
||||
import lying_in_fluffy_belly from '@/assets/img/jimeng/texiao/lying_in_fluffy_belly.png'
|
||||
import micro_landscape_mini_world from '@/assets/img/jimeng/texiao/micro_landscape_mini_world.png'
|
||||
import micro_landscape_mini_world_professional from '@/assets/img/jimeng/texiao/micro_landscape_mini_world_professional.png'
|
||||
import Mid_Autumn_Festival_individual from '@/assets/img/jimeng/texiao/Mid-Autumn_Festival_individual.jpeg'
|
||||
import Mid_Autumn_Festival_new_chinese_style from '@/assets/img/jimeng/texiao/Mid-Autumn_Festival_new_chinese_style.jpeg'
|
||||
import my_world from '@/assets/img/jimeng/texiao/my_world.png'
|
||||
import my_world_universal from '@/assets/img/jimeng/texiao/my_world_universal.png'
|
||||
import patchwork_collage_style from '@/assets/img/jimeng/texiao/patchwork_collage_style.jpeg'
|
||||
import plastic_bubble_figure from '@/assets/img/jimeng/texiao/plastic_bubble_figure.png'
|
||||
import plastic_bubble_figure_cartoon_text from '@/assets/img/jimeng/texiao/plastic_bubble_figure_cartoon_text.png'
|
||||
import Spring_Festival_traditional_Chinese_architecture from '@/assets/img/jimeng/texiao/Spring_Festival_traditional_Chinese_architecture.png'
|
||||
|
||||
export const JimengParams = {
|
||||
image: [
|
||||
{
|
||||
name: '图片 4.0 文/图生图',
|
||||
version: '4.0',
|
||||
label: '支持文本、单图和多图输入,实现基于主体一致性的多图融合创作、图像编辑等多样玩法',
|
||||
key: 'doubao-seedream-4-0-250828',
|
||||
params: [
|
||||
{
|
||||
name: 'prompt',
|
||||
label: '提示词',
|
||||
type: 'textarea',
|
||||
required: true,
|
||||
showWordLimit: true,
|
||||
maxlength: 800,
|
||||
autosize: { minRows: 3, maxRows: 5 },
|
||||
placeholder: '请输入用于编辑图像的提示词,如:把xxx改成xxx,删除xxx,添加xxx等',
|
||||
info: '建议不超过300个汉字或600个英文单词。字数过多信息容易分散,模型可能因此忽略细节。',
|
||||
},
|
||||
{
|
||||
name: 'image_urls',
|
||||
label: '参考图片',
|
||||
type: 'image',
|
||||
required: false,
|
||||
placeholder: '请上传图片',
|
||||
maxSize: 5,
|
||||
multiple: true,
|
||||
maxCount: 10,
|
||||
accept: '.png,.jpg,.jpeg',
|
||||
info: '支持编辑单张图片,或者一次融合多张图片',
|
||||
},
|
||||
{
|
||||
name: 'size',
|
||||
type: 'select',
|
||||
required: true,
|
||||
placeholder: '请选择尺寸',
|
||||
label: '图片尺寸',
|
||||
prefix: 'icon-resize',
|
||||
options: [
|
||||
{
|
||||
label: '1:1 (1328 * 1328)',
|
||||
value: '1328x1328',
|
||||
},
|
||||
{
|
||||
label: '4:3 (1472 * 1104)',
|
||||
value: '1472x1104',
|
||||
},
|
||||
{
|
||||
label: '3:2 (1584 * 1056)',
|
||||
value: '1584x1056',
|
||||
},
|
||||
{
|
||||
label: '16:9 (1664 * 936)',
|
||||
value: '1664x936',
|
||||
},
|
||||
{
|
||||
label: '21:9 (2016 * 864)',
|
||||
value: '2016x864',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '图片 2.1 文生图',
|
||||
version: '2.1',
|
||||
@@ -36,6 +126,7 @@ export const JimengParams = {
|
||||
required: true,
|
||||
placeholder: '请选择尺寸',
|
||||
label: '图片尺寸',
|
||||
prefix: 'icon-resize',
|
||||
options: [
|
||||
{
|
||||
label: '21:9 (1195 * 512)',
|
||||
@@ -104,7 +195,7 @@ export const JimengParams = {
|
||||
required: true,
|
||||
placeholder: '请选择尺寸',
|
||||
label: '图片尺寸',
|
||||
|
||||
prefix: 'icon-resize',
|
||||
options: [
|
||||
{
|
||||
label: '1:1 (1328 * 1328)',
|
||||
@@ -181,7 +272,7 @@ export const JimengParams = {
|
||||
required: true,
|
||||
placeholder: '请选择尺寸',
|
||||
label: '图片尺寸',
|
||||
|
||||
prefix: 'icon-resize',
|
||||
options: [
|
||||
{
|
||||
label: '1:1 (1328 * 1328)',
|
||||
@@ -263,54 +354,56 @@ export const JimengParams = {
|
||||
accept: '.png,.jpg,.jpeg',
|
||||
info: '长边与短边比例在3以内,超出此比例或比例相对极端,会导致报错。',
|
||||
},
|
||||
{
|
||||
name: 'scale',
|
||||
label: '文本描述影响的程度',
|
||||
type: 'slider',
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.1,
|
||||
value: 0.5,
|
||||
info: '该值越大代表文本描述影响程度越大,且输入图片影响程度越小',
|
||||
},
|
||||
{
|
||||
name: 'size',
|
||||
type: 'select',
|
||||
required: true,
|
||||
placeholder: '请选择尺寸',
|
||||
label: '图片尺寸',
|
||||
|
||||
prefix: 'icon-resize',
|
||||
options: [
|
||||
{
|
||||
label: '1:1 (1328 * 1328)',
|
||||
value: '1328x1328',
|
||||
label: '1:1 (2048 * 2048)',
|
||||
value: '2048x2048',
|
||||
},
|
||||
{
|
||||
label: '4:3 (1472 * 1104)',
|
||||
value: '1472x1104',
|
||||
label: '4:3 (2304 * 1728)',
|
||||
value: '2304x1728',
|
||||
},
|
||||
{
|
||||
label: '3:2 (1584 * 1056)',
|
||||
value: '1584x1056',
|
||||
label: '3:4 (1728 * 2304)',
|
||||
value: '1728x2304',
|
||||
},
|
||||
{
|
||||
label: '16:9 (1664 * 936)',
|
||||
value: '1664x936',
|
||||
label: '16:9 (2560 * 1440)',
|
||||
value: '2560x1440',
|
||||
},
|
||||
{
|
||||
label: '21:9 (2016 * 864)',
|
||||
value: '2016x864',
|
||||
label: '9:16 (1440 * 2560)',
|
||||
value: '1440x2560',
|
||||
},
|
||||
{
|
||||
label: '3:2 (2496 * 1664)',
|
||||
value: '2496x1664',
|
||||
},
|
||||
{
|
||||
label: '2:3 (1664 * 2496)',
|
||||
value: '1664x2496',
|
||||
},
|
||||
{
|
||||
label: '21:9 (3024 * 1296)',
|
||||
value: '3024x1296',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
name: '图片 4.0 文/图生图',
|
||||
version: '4.0',
|
||||
label:
|
||||
'支持文本、单图和多图输入,实现基于主体一致性的多图融合创作、图像编辑、组图生成等多样玩法',
|
||||
key: 'jimeng_i2i_v30',
|
||||
name: '图片 3.0 图像特效',
|
||||
version: '3.0',
|
||||
label: '将输入的单人写真图片,进行有创意的特效化处理。',
|
||||
key: 'i2i_multi_style_zx2x',
|
||||
params: [
|
||||
{
|
||||
name: 'prompt',
|
||||
@@ -331,17 +424,159 @@ export const JimengParams = {
|
||||
placeholder: '请上传图片',
|
||||
maxSize: 5,
|
||||
accept: '.png,.jpg,.jpeg',
|
||||
info: '长边与短边比例在3以内,超出此比例或比例相对极端,会导致报错。',
|
||||
info: '支持输入人像写真图片。',
|
||||
},
|
||||
{
|
||||
name: 'scale',
|
||||
label: '文本描述影响的程度',
|
||||
type: 'slider',
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.1,
|
||||
value: 0.5,
|
||||
info: '该值越大代表文本描述影响程度越大,且输入图片影响程度越小',
|
||||
name: 'template_id',
|
||||
label: '特效模板ID',
|
||||
type: 'select',
|
||||
required: true,
|
||||
placeholder: '请选择特效模板ID',
|
||||
imgSize: '40px',
|
||||
popperClass: 'model-select',
|
||||
prefix: 'icon-sd',
|
||||
options: [
|
||||
{
|
||||
label: '毛毡3D拍立得风格',
|
||||
value: 'felt_3d_polaroid',
|
||||
image: felt_3d_polaroid,
|
||||
},
|
||||
{
|
||||
label: '像素世界风',
|
||||
value: 'my_world',
|
||||
image: my_world,
|
||||
},
|
||||
{
|
||||
label: '像素世界-万物通用版',
|
||||
value: 'my_world_universal',
|
||||
image: my_world_universal,
|
||||
},
|
||||
{
|
||||
label: '盲盒玩偶风',
|
||||
value: 'plastic_bubble_figure',
|
||||
image: plastic_bubble_figure,
|
||||
},
|
||||
{
|
||||
label: '塑料泡罩人偶-文字卡头版',
|
||||
value: 'plastic_bubble_figure_cartoon_text',
|
||||
image: plastic_bubble_figure_cartoon_text,
|
||||
},
|
||||
{
|
||||
label: '毛绒玩偶风',
|
||||
value: 'furry_dream_doll',
|
||||
image: furry_dream_doll,
|
||||
},
|
||||
{
|
||||
label: '迷你世界玩偶风',
|
||||
value: 'micro_landscape_mini_world',
|
||||
image: micro_landscape_mini_world,
|
||||
},
|
||||
{
|
||||
label: '微型景观小世界-职业版',
|
||||
value: 'micro_landscape_mini_world_professional',
|
||||
image: micro_landscape_mini_world_professional,
|
||||
},
|
||||
{
|
||||
label: '亚克力挂饰',
|
||||
value: 'acrylic_ornaments',
|
||||
image: acrylic_ornaments,
|
||||
},
|
||||
{
|
||||
label: '毛毡钥匙扣',
|
||||
value: 'felt_keychain',
|
||||
image: felt_keychain,
|
||||
},
|
||||
{
|
||||
label: 'Lofi 像素人物小卡',
|
||||
value: 'lofi_pixel_character_mini_card',
|
||||
image: lofi_pixel_character_mini_card,
|
||||
},
|
||||
{
|
||||
label: '天使形象手办',
|
||||
value: 'angel_figurine',
|
||||
image: angel_figurine,
|
||||
},
|
||||
{
|
||||
label: '躺在毛茸茸肚皮里',
|
||||
value: 'lying_in_fluffy_belly',
|
||||
image: lying_in_fluffy_belly,
|
||||
},
|
||||
{
|
||||
label: '玻璃球',
|
||||
value: 'glass_ball',
|
||||
image: glass_ball,
|
||||
},
|
||||
{
|
||||
label: '耳机盒',
|
||||
value: 'earphone_case_style',
|
||||
image: earphone_case_style,
|
||||
},
|
||||
{
|
||||
label: '电子宠物蛋',
|
||||
value: 'electronic_pet_egg_style',
|
||||
image: electronic_pet_egg_style,
|
||||
},
|
||||
{
|
||||
label: '拼贴缝布',
|
||||
value: 'patchwork_collage_style',
|
||||
image: patchwork_collage_style,
|
||||
},
|
||||
{
|
||||
label: '抓娃娃机',
|
||||
value: 'claw_machine_style',
|
||||
image: claw_machine_style,
|
||||
},
|
||||
{
|
||||
label: '车内微缩摆件',
|
||||
value: 'car_miniature_ornaments',
|
||||
image: car_miniature_ornaments,
|
||||
},
|
||||
{
|
||||
label: '中秋节-新中式',
|
||||
value: 'Mid-Autumn_Festival_new_chinese_style',
|
||||
image: Mid_Autumn_Festival_new_chinese_style,
|
||||
},
|
||||
{
|
||||
label: '中秋单人',
|
||||
value: 'Mid-Autumn_Festival_individual',
|
||||
image: Mid_Autumn_Festival_individual,
|
||||
},
|
||||
{
|
||||
label: '圣诞节绿背景',
|
||||
value: 'Christmas_green_background',
|
||||
image: Christmas_green_background,
|
||||
},
|
||||
{
|
||||
label: '圣诞节圣诞树',
|
||||
value: 'Christmas_tree',
|
||||
image: Christmas_tree,
|
||||
},
|
||||
{
|
||||
label: '春节红墙',
|
||||
value: 'Spring_Festival_traditional_Chinese_architecture',
|
||||
image: Spring_Festival_traditional_Chinese_architecture,
|
||||
},
|
||||
{
|
||||
label: '生日照华丽',
|
||||
value: 'birthday_photo_gorgeous',
|
||||
image: birthday_photo_gorgeous,
|
||||
},
|
||||
{
|
||||
label: '生日照红色',
|
||||
value: 'birthday_photo_red',
|
||||
image: birthday_photo_red,
|
||||
},
|
||||
{
|
||||
label: '生日照派对',
|
||||
value: 'birthday_photo_party',
|
||||
image: birthday_photo_party,
|
||||
},
|
||||
{
|
||||
label: '毕业照',
|
||||
value: 'graduation_photo',
|
||||
image: graduation_photo,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'size',
|
||||
@@ -349,26 +584,26 @@ export const JimengParams = {
|
||||
required: true,
|
||||
placeholder: '请选择尺寸',
|
||||
label: '图片尺寸',
|
||||
|
||||
prefix: 'icon-resize',
|
||||
options: [
|
||||
{
|
||||
label: '1:1 (1328 * 1328)',
|
||||
label: '1:1 (1328 * 1328)',
|
||||
value: '1328x1328',
|
||||
},
|
||||
{
|
||||
label: '4:3 (1472 * 1104)',
|
||||
label: '4:3 (1472 * 1104)',
|
||||
value: '1472x1104',
|
||||
},
|
||||
{
|
||||
label: '3:2 (1584 * 1056)',
|
||||
label: '3:2 (1584 * 1056)',
|
||||
value: '1584x1056',
|
||||
},
|
||||
{
|
||||
label: '16:9 (1664 * 936)',
|
||||
label: '16:9 (1664 * 936)',
|
||||
value: '1664x936',
|
||||
},
|
||||
{
|
||||
label: '21:9 (2016 * 864)',
|
||||
label: '21:9 (2016 * 864)',
|
||||
value: '2016x864',
|
||||
},
|
||||
],
|
||||
@@ -377,6 +612,7 @@ export const JimengParams = {
|
||||
},
|
||||
],
|
||||
video: [
|
||||
// 视频 3.0 720P-文生视频
|
||||
{
|
||||
name: '视频 3.0 720P-文生视频',
|
||||
version: '3.0',
|
||||
@@ -398,8 +634,9 @@ export const JimengParams = {
|
||||
name: 'aspect_ratio',
|
||||
label: '视频比例',
|
||||
type: 'select',
|
||||
required: false,
|
||||
required: true,
|
||||
placeholder: '请选择视频比例',
|
||||
prefix: 'icon-resize',
|
||||
options: [
|
||||
{
|
||||
label: '16:9 (横版)',
|
||||
@@ -431,6 +668,7 @@ export const JimengParams = {
|
||||
name: 'duration',
|
||||
type: 'select',
|
||||
label: '视频时长',
|
||||
prefix: 'icon-clock',
|
||||
options: [
|
||||
{
|
||||
label: '5秒',
|
||||
@@ -444,7 +682,7 @@ export const JimengParams = {
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// 视频 3.0 图生视频-首帧
|
||||
{
|
||||
name: '视频 3.0 720P-图生视频-首帧',
|
||||
version: '3.0',
|
||||
@@ -466,7 +704,7 @@ export const JimengParams = {
|
||||
name: 'image_urls',
|
||||
label: '首帧图片',
|
||||
type: 'image',
|
||||
required: false,
|
||||
required: true,
|
||||
multiple: false,
|
||||
maxCount: 1,
|
||||
maxSize: 5,
|
||||
@@ -476,6 +714,7 @@ export const JimengParams = {
|
||||
name: 'duration',
|
||||
type: 'select',
|
||||
label: '视频时长',
|
||||
prefix: 'icon-clock',
|
||||
options: [
|
||||
{
|
||||
label: '5秒',
|
||||
@@ -489,7 +728,7 @@ export const JimengParams = {
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// 视频 3.0 图生视频-首尾帧
|
||||
{
|
||||
name: '视频 3.0 720P-图生视频-首尾帧',
|
||||
version: '3.0',
|
||||
@@ -511,7 +750,7 @@ export const JimengParams = {
|
||||
name: 'image_urls',
|
||||
label: '首尾帧图片',
|
||||
type: 'image',
|
||||
required: false,
|
||||
required: true,
|
||||
multiple: true,
|
||||
maxCount: 2,
|
||||
maxSize: 5,
|
||||
@@ -522,6 +761,7 @@ export const JimengParams = {
|
||||
name: 'duration',
|
||||
type: 'select',
|
||||
label: '视频时长',
|
||||
prefix: 'icon-clock',
|
||||
options: [
|
||||
{
|
||||
label: '5秒',
|
||||
@@ -535,7 +775,7 @@ export const JimengParams = {
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// 视频 3.0 图生视频-运镜
|
||||
{
|
||||
name: '视频 3.0 720P-图生视频-运镜',
|
||||
version: '3.0',
|
||||
@@ -557,7 +797,7 @@ export const JimengParams = {
|
||||
name: 'image_urls',
|
||||
label: '运镜图片',
|
||||
type: 'image',
|
||||
required: false,
|
||||
required: true,
|
||||
placeholder: '请上传图片',
|
||||
maxSize: 5,
|
||||
multiple: true,
|
||||
@@ -571,6 +811,8 @@ export const JimengParams = {
|
||||
required: true,
|
||||
placeholder: '请选择运镜控制',
|
||||
popperClass: 'model-select',
|
||||
prefix: 'icon-yunjing',
|
||||
imgSize: '54px',
|
||||
options: [
|
||||
{
|
||||
label: '希区柯克推进',
|
||||
@@ -656,6 +898,7 @@ export const JimengParams = {
|
||||
name: 'duration',
|
||||
type: 'select',
|
||||
label: '视频时长',
|
||||
prefix: 'icon-clock',
|
||||
options: [
|
||||
{
|
||||
label: '5秒',
|
||||
@@ -670,7 +913,7 @@ export const JimengParams = {
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// 视频 3.0 1080P-文生视频
|
||||
{
|
||||
name: '视频 3.0 1080P-文生视频',
|
||||
version: '3.0',
|
||||
@@ -694,6 +937,7 @@ export const JimengParams = {
|
||||
type: 'select',
|
||||
required: false,
|
||||
placeholder: '请选择视频比例',
|
||||
prefix: 'icon-resize',
|
||||
options: [
|
||||
{
|
||||
label: '16:9 (横版)',
|
||||
@@ -725,6 +969,7 @@ export const JimengParams = {
|
||||
name: 'duration',
|
||||
type: 'select',
|
||||
label: '视频时长',
|
||||
prefix: 'icon-clock',
|
||||
options: [
|
||||
{
|
||||
label: '5秒',
|
||||
@@ -738,7 +983,7 @@ export const JimengParams = {
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// 视频 3.0 1080P-图生视频-首帧
|
||||
{
|
||||
name: '视频 3.0 1080P-图生视频-首帧',
|
||||
version: '3.0',
|
||||
@@ -760,7 +1005,7 @@ export const JimengParams = {
|
||||
name: 'image_urls',
|
||||
label: '首帧图片',
|
||||
type: 'image',
|
||||
required: false,
|
||||
required: true,
|
||||
multiple: false,
|
||||
maxCount: 1,
|
||||
maxSize: 5,
|
||||
@@ -770,6 +1015,7 @@ export const JimengParams = {
|
||||
name: 'duration',
|
||||
type: 'select',
|
||||
label: '视频时长',
|
||||
prefix: 'icon-clock',
|
||||
options: [
|
||||
{
|
||||
label: '5秒',
|
||||
@@ -783,7 +1029,7 @@ export const JimengParams = {
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// 视频 3.0 1080P-图生视频-首尾帧
|
||||
{
|
||||
name: '视频 3.0 1080P-图生视频-首尾帧',
|
||||
version: '3.0',
|
||||
@@ -805,7 +1051,7 @@ export const JimengParams = {
|
||||
name: 'image_urls',
|
||||
label: '首尾帧图片',
|
||||
type: 'image',
|
||||
required: false,
|
||||
required: true,
|
||||
multiple: true,
|
||||
maxCount: 2,
|
||||
maxSize: 5,
|
||||
@@ -816,6 +1062,7 @@ export const JimengParams = {
|
||||
name: 'duration',
|
||||
type: 'select',
|
||||
label: '视频时长',
|
||||
prefix: 'icon-clock',
|
||||
options: [
|
||||
{
|
||||
label: '5秒',
|
||||
@@ -829,7 +1076,7 @@ export const JimengParams = {
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// 视频 3.0Pro 1080P-图生视频
|
||||
{
|
||||
name: '视频 3.0Pro 1080P-图生视频',
|
||||
version: '3.0',
|
||||
@@ -866,6 +1113,7 @@ export const JimengParams = {
|
||||
required: false,
|
||||
placeholder: '请选择视频比例',
|
||||
info: '只在文生视频场景下生效,图生视频场景会根据输入图的长宽比自动适配',
|
||||
prefix: 'icon-resize',
|
||||
options: [
|
||||
{
|
||||
label: '21:9 (2176 * 928)',
|
||||
@@ -897,6 +1145,8 @@ export const JimengParams = {
|
||||
name: 'duration',
|
||||
type: 'select',
|
||||
label: '视频时长',
|
||||
prefix: 'icon-clock',
|
||||
placeholder: '请选择视频时长',
|
||||
options: [
|
||||
{
|
||||
label: '5秒',
|
||||
@@ -919,7 +1169,7 @@ export const JimengParams = {
|
||||
export const JimengFunctions = [
|
||||
{
|
||||
key: 'image',
|
||||
icon: 'iconfont icon-image',
|
||||
icon: 'icon-image',
|
||||
name: '图片生成',
|
||||
},
|
||||
{
|
||||
@@ -6,24 +6,16 @@
|
||||
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
import { checkSession } from '@/store/cache'
|
||||
import { JimengParams } from '@/store/data'
|
||||
import { JimengFunctions, JimengParams } from '@/store/data/jimeng_data'
|
||||
import { useSharedStore } from '@/store/sharedata'
|
||||
import { showMessageError, showMessageOK } from '@/utils/dialog'
|
||||
import { httpDownload, httpGet, httpPost } from '@/utils/http'
|
||||
import { replaceImg, substr } from '@/utils/libs'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { reactive, ref } from 'vue'
|
||||
|
||||
export const useJimengStore = defineStore('jimeng', () => {
|
||||
// 当前激活的功能分类和具体功能
|
||||
const activeCategory = ref('image_generation')
|
||||
const activeFunction = ref('text_to_image')
|
||||
const useImageInput = ref(false)
|
||||
|
||||
// 新增:全局提示词
|
||||
const currentPrompt = ref('')
|
||||
|
||||
// 共同状态
|
||||
const loading = ref(false)
|
||||
const submitting = ref(false)
|
||||
@@ -45,73 +37,8 @@ export const useJimengStore = defineStore('jimeng', () => {
|
||||
// 登录弹窗
|
||||
const shareStore = useSharedStore()
|
||||
|
||||
const paramsMap = JimengParams
|
||||
|
||||
// 功能分类配置
|
||||
const categories = [
|
||||
{ key: 'image_generation', name: '图片生成' },
|
||||
{ key: 'image_editing', name: 'AI修图' },
|
||||
{ key: 'image_effects', name: '图像特效' },
|
||||
{ key: 'video_generation', name: '视频生成' },
|
||||
]
|
||||
|
||||
// 新增:动态获取算力消耗配置
|
||||
const powerConfig = reactive({})
|
||||
|
||||
// 功能配置
|
||||
const functions = reactive([
|
||||
{
|
||||
key: 'text_to_image',
|
||||
name: '文生图',
|
||||
category: 'image_generation',
|
||||
needsPrompt: true,
|
||||
needsImage: false,
|
||||
power: 20,
|
||||
},
|
||||
{
|
||||
key: 'image_to_image',
|
||||
name: '图生图',
|
||||
category: 'image_generation',
|
||||
needsPrompt: true,
|
||||
needsImage: true,
|
||||
power: 30,
|
||||
},
|
||||
{
|
||||
key: 'image_edit',
|
||||
name: '图像编辑',
|
||||
category: 'image_editing',
|
||||
needsPrompt: true,
|
||||
needsImage: true,
|
||||
multiple: true,
|
||||
power: 25,
|
||||
},
|
||||
{
|
||||
key: 'image_effects',
|
||||
name: '图像特效',
|
||||
category: 'image_effects',
|
||||
needsPrompt: false,
|
||||
needsImage: true,
|
||||
power: 15,
|
||||
},
|
||||
{
|
||||
key: 'text_to_video',
|
||||
name: '文生视频',
|
||||
category: 'video_generation',
|
||||
needsPrompt: true,
|
||||
needsImage: false,
|
||||
power: 100,
|
||||
},
|
||||
{
|
||||
key: 'image_to_video',
|
||||
name: '图生视频',
|
||||
category: 'video_generation',
|
||||
needsPrompt: true,
|
||||
needsImage: true,
|
||||
multiple: true,
|
||||
power: 120,
|
||||
},
|
||||
])
|
||||
|
||||
// 动态设置算力消耗
|
||||
const setFunctionPowers = (config) => {
|
||||
functions.forEach((f) => {
|
||||
@@ -121,114 +48,32 @@ export const useJimengStore = defineStore('jimeng', () => {
|
||||
})
|
||||
}
|
||||
|
||||
// 各功能的参数
|
||||
const textToImageParams = reactive({
|
||||
size: '1328x1328',
|
||||
scale: 2.5,
|
||||
seed: -1,
|
||||
use_pre_llm: true,
|
||||
// 功能配置
|
||||
const functions = JimengFunctions
|
||||
// 当前激活的功能
|
||||
const activeFunction = ref('image')
|
||||
// 参数配置
|
||||
const functionParams = JimengParams
|
||||
// 表单数据
|
||||
const formData = ref({})
|
||||
// 必填参数
|
||||
const requiredKeys = ref({})
|
||||
// 进度
|
||||
const progress = ref({
|
||||
image: 100,
|
||||
video: 100,
|
||||
virtualHuman: 38,
|
||||
actionTransfer: 65,
|
||||
})
|
||||
|
||||
const imageToImageParams = reactive({
|
||||
image_input: '',
|
||||
size: '1328x1328',
|
||||
gpen: 0.4,
|
||||
skin: 0.3,
|
||||
skin_unifi: 0,
|
||||
gen_mode: 'creative',
|
||||
seed: -1,
|
||||
})
|
||||
|
||||
const imageEditParams = reactive({
|
||||
image_input: '',
|
||||
scale: 0.5,
|
||||
seed: -1,
|
||||
})
|
||||
|
||||
const imageEffectsParams = reactive({
|
||||
image_input: '',
|
||||
template_id: '',
|
||||
size: '1328x1328',
|
||||
})
|
||||
|
||||
const textToVideoParams = reactive({
|
||||
aspect_ratio: '16:9',
|
||||
seed: -1,
|
||||
})
|
||||
|
||||
const imageToVideoParams = reactive({
|
||||
image_input: [],
|
||||
aspect_ratio: '16:9',
|
||||
seed: -1,
|
||||
})
|
||||
|
||||
// 计算属性
|
||||
const currentFunction = computed(() => {
|
||||
return functions.find((f) => f.key === activeFunction.value) || functions[0]
|
||||
})
|
||||
|
||||
const currentFunctions = computed(() => {
|
||||
return functions.filter((f) => f.category === activeCategory.value)
|
||||
})
|
||||
|
||||
const needsPrompt = computed(() => currentFunction.value.needsPrompt)
|
||||
const needsImage = computed(() => currentFunction.value.needsImage)
|
||||
const needsMultipleImages = computed(() => currentFunction.value.multiple)
|
||||
const currentPowerCost = computed(() => currentFunction.value.power)
|
||||
|
||||
// 初始化方法
|
||||
const init = async () => {
|
||||
try {
|
||||
// 获取算力消耗配置
|
||||
const powerRes = await httpGet('/api/jimeng/power-config')
|
||||
if (powerRes.data) {
|
||||
Object.assign(powerConfig, powerRes.data)
|
||||
setFunctionPowers(powerRes.data)
|
||||
}
|
||||
const user = await checkSession()
|
||||
isLogin.value = true
|
||||
userPower.value = user.power
|
||||
// 获取任务列表
|
||||
await fetchData(1)
|
||||
// 开始轮询
|
||||
startPolling()
|
||||
} catch (error) {
|
||||
console.error('初始化失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 切换功能分类
|
||||
const switchCategory = (category) => {
|
||||
activeCategory.value = category
|
||||
const categoryFunctions = functions.filter((f) => f.category === category)
|
||||
if (categoryFunctions.length > 0) {
|
||||
if (category === 'image_generation') {
|
||||
activeFunction.value = useImageInput.value ? 'image_to_image' : 'text_to_image'
|
||||
} else if (category === 'video_generation') {
|
||||
activeFunction.value = useImageInput.value ? 'image_to_video' : 'text_to_video'
|
||||
} else {
|
||||
activeFunction.value = categoryFunctions[0].key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 切换输入模式
|
||||
const switchInputMode = () => {
|
||||
if (activeCategory.value === 'image_generation') {
|
||||
activeFunction.value = useImageInput.value ? 'image_to_image' : 'text_to_image'
|
||||
} else if (activeCategory.value === 'video_generation') {
|
||||
activeFunction.value = useImageInput.value ? 'image_to_video' : 'text_to_video'
|
||||
}
|
||||
}
|
||||
|
||||
// 切换功能
|
||||
const switchFunction = (functionKey) => {
|
||||
activeFunction.value = functionKey
|
||||
const switchFunction = (f) => {
|
||||
activeFunction.value = f.key
|
||||
formData.value = {}
|
||||
}
|
||||
|
||||
// 获取当前算力消耗
|
||||
const getCurrentPowerCost = () => {
|
||||
return currentFunction.value.power
|
||||
return activeFunction.value.power
|
||||
}
|
||||
|
||||
// 获取功能名称
|
||||
@@ -353,71 +198,21 @@ export const useJimengStore = defineStore('jimeng', () => {
|
||||
shareStore.setShowLoginDialog(true)
|
||||
return
|
||||
}
|
||||
if (userPower.value < currentPowerCost.value) {
|
||||
showMessageError('算力不足')
|
||||
return
|
||||
}
|
||||
// 新增:除图像特效外,其他任务类型必须有提示词
|
||||
if (activeFunction.value !== 'image_effects' && !currentPrompt.value) {
|
||||
showMessageError('提示词不能为空')
|
||||
return
|
||||
// if (userPower.value < currentPowerCost.value) {
|
||||
// showMessageError('算力不足')
|
||||
// return
|
||||
// }
|
||||
for (const key in requiredKeys.value) {
|
||||
if (!formData.value[key].required) {
|
||||
showMessageError('缺少参数:' + requiredKeys.value[key].label)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
submitting.value = true
|
||||
let requestData = { task_type: activeFunction.value, prompt: currentPrompt.value }
|
||||
switch (activeFunction.value) {
|
||||
case 'text_to_image':
|
||||
Object.assign(requestData, {
|
||||
width: parseInt(textToImageParams.size.split('x')[0]),
|
||||
height: parseInt(textToImageParams.size.split('x')[1]),
|
||||
scale: textToImageParams.scale,
|
||||
seed: textToImageParams.seed,
|
||||
use_pre_llm: textToImageParams.use_pre_llm,
|
||||
})
|
||||
break
|
||||
case 'image_to_image':
|
||||
Object.assign(requestData, {
|
||||
image_input: imageToImageParams.image_input[0],
|
||||
width: parseInt(imageToImageParams.size.split('x')[0]),
|
||||
height: parseInt(imageToImageParams.size.split('x')[1]),
|
||||
gpen: imageToImageParams.gpen,
|
||||
skin: imageToImageParams.skin,
|
||||
skin_unifi: imageToImageParams.skin_unifi,
|
||||
gen_mode: imageToImageParams.gen_mode,
|
||||
seed: imageToImageParams.seed,
|
||||
})
|
||||
break
|
||||
case 'image_edit':
|
||||
Object.assign(requestData, {
|
||||
image_input: imageEditParams.image_input[0],
|
||||
scale: imageEditParams.scale,
|
||||
seed: imageEditParams.seed,
|
||||
})
|
||||
break
|
||||
case 'image_effects':
|
||||
Object.assign(requestData, {
|
||||
image_input: imageEffectsParams.image_input[0],
|
||||
template_id: imageEffectsParams.template_id,
|
||||
width: parseInt(imageEffectsParams.size.split('x')[0]),
|
||||
height: parseInt(imageEffectsParams.size.split('x')[1]),
|
||||
prompt: imageEffectsParams.prompt,
|
||||
})
|
||||
break
|
||||
case 'text_to_video':
|
||||
Object.assign(requestData, {
|
||||
aspect_ratio: textToVideoParams.aspect_ratio,
|
||||
seed: textToVideoParams.seed,
|
||||
})
|
||||
break
|
||||
case 'image_to_video':
|
||||
Object.assign(requestData, {
|
||||
image_urls: imageToVideoParams.image_input,
|
||||
aspect_ratio: imageToVideoParams.aspect_ratio,
|
||||
seed: imageToVideoParams.seed,
|
||||
})
|
||||
break
|
||||
}
|
||||
const response = await httpPost('/api/jimeng/task', requestData)
|
||||
|
||||
const response = await httpPost('/api/jimeng/task', formData.value)
|
||||
if (response.data) {
|
||||
showMessageOK('任务提交成功')
|
||||
isOver.value = false
|
||||
@@ -501,6 +296,27 @@ export const useJimengStore = defineStore('jimeng', () => {
|
||||
showDialog.value = true
|
||||
}
|
||||
|
||||
// 初始化方法
|
||||
const init = async () => {
|
||||
try {
|
||||
// 获取算力消耗配置
|
||||
const powerRes = await httpGet('/api/jimeng/power-config')
|
||||
if (powerRes.data) {
|
||||
Object.assign(powerConfig, powerRes.data)
|
||||
setFunctionPowers(powerRes.data)
|
||||
}
|
||||
const user = await checkSession()
|
||||
isLogin.value = true
|
||||
userPower.value = user.power
|
||||
// 获取任务列表
|
||||
await fetchData(1)
|
||||
// 开始轮询
|
||||
startPolling()
|
||||
} catch (error) {
|
||||
console.error('初始化失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 页面卸载时清理轮询
|
||||
const cleanup = () => {
|
||||
stopPolling()
|
||||
@@ -509,9 +325,7 @@ export const useJimengStore = defineStore('jimeng', () => {
|
||||
// 返回所有状态和方法
|
||||
return {
|
||||
// 状态
|
||||
activeCategory,
|
||||
activeFunction,
|
||||
useImageInput,
|
||||
loading,
|
||||
submitting,
|
||||
page,
|
||||
@@ -526,31 +340,16 @@ export const useJimengStore = defineStore('jimeng', () => {
|
||||
currentVideoUrl,
|
||||
|
||||
// 配置
|
||||
categories,
|
||||
functions,
|
||||
currentFunctions,
|
||||
|
||||
// 参数
|
||||
currentPrompt,
|
||||
textToImageParams,
|
||||
imageToImageParams,
|
||||
imageEditParams,
|
||||
imageEffectsParams,
|
||||
textToVideoParams,
|
||||
imageToVideoParams,
|
||||
|
||||
// 计算属性
|
||||
currentFunction,
|
||||
needsPrompt,
|
||||
needsImage,
|
||||
needsMultipleImages,
|
||||
currentPowerCost,
|
||||
activeFunction,
|
||||
functionParams,
|
||||
formData,
|
||||
requiredKeys,
|
||||
progress,
|
||||
|
||||
// 方法
|
||||
init,
|
||||
switchCategory,
|
||||
switchFunction,
|
||||
switchInputMode,
|
||||
getCurrentPowerCost,
|
||||
getFunctionName,
|
||||
getTaskStatusText,
|
||||
@@ -569,85 +368,3 @@ export const useJimengStore = defineStore('jimeng', () => {
|
||||
replaceImg,
|
||||
}
|
||||
})
|
||||
export const imageSizeOptions = [
|
||||
{ label: '1:1 (1328x1328)', value: '1328x1328' },
|
||||
{ label: '3:2 (1584x1056)', value: '1584x1056' },
|
||||
{ label: '2:3 (1056x1584)', value: '1056x1584' },
|
||||
{ label: '4:3 (1472x1104)', value: '1472x1104' },
|
||||
{ label: '3:4 (1104x1472)', value: '1104x1472' },
|
||||
{ label: '16:9 (1664x936)', value: '1664x936' },
|
||||
{ label: '9:16 (936x1664)', value: '936x1664' },
|
||||
{ label: '21:9 (2016x864)', value: '2016x864' },
|
||||
{ label: '9:21 (864x2016)', value: '864x2016' },
|
||||
]
|
||||
|
||||
export const videoAspectRatioOptions = [
|
||||
{ label: '1:1 (正方形)', value: '1:1' },
|
||||
{ label: '16:9 (横版)', value: '16:9' },
|
||||
{ label: '9:16 (竖版)', value: '9:16' },
|
||||
]
|
||||
|
||||
export const imageEffectsTemplateOptions = [
|
||||
{
|
||||
label: '毛毡3D拍立得风格',
|
||||
value: 'felt_3d_polaroid',
|
||||
preview: '/images/jimeng/templates/felt_3d_polaroid.png',
|
||||
},
|
||||
{ label: '像素世界风', value: 'my_world', preview: '/images/jimeng/templates/my_world.png' },
|
||||
{
|
||||
label: '像素世界-万物通用版',
|
||||
value: 'my_world_universal',
|
||||
preview: '/images/jimeng/templates/my_world_universal.png',
|
||||
},
|
||||
{
|
||||
label: '盲盒玩偶风',
|
||||
value: 'plastic_bubble_figure',
|
||||
preview: '/images/jimeng/templates/plastic_bubble_figure.png',
|
||||
},
|
||||
{
|
||||
label: '塑料泡罩人偶-文字卡头版',
|
||||
value: 'plastic_bubble_figure_cartoon_text',
|
||||
preview: '/images/jimeng/templates/plastic_bubble_figure_cartoon_text.png',
|
||||
},
|
||||
{
|
||||
label: '毛绒玩偶风',
|
||||
value: 'furry_dream_doll',
|
||||
preview: '/images/jimeng/templates/furry_dream_doll.png',
|
||||
},
|
||||
{
|
||||
label: '迷你世界玩偶风',
|
||||
value: 'micro_landscape_mini_world',
|
||||
preview: '/images/jimeng/templates/micro_landscape_mini_world.png',
|
||||
},
|
||||
{
|
||||
label: '微型景观小世界-职业版',
|
||||
value: 'micro_landscape_mini_world_professional',
|
||||
preview: '/images/jimeng/templates/micro_landscape_mini_world_professional.png',
|
||||
},
|
||||
{
|
||||
label: '亚克力挂饰',
|
||||
value: 'acrylic_ornaments',
|
||||
preview: '/images/jimeng/templates/acrylic_ornaments.png',
|
||||
},
|
||||
{
|
||||
label: '毛毡钥匙扣',
|
||||
value: 'felt_keychain',
|
||||
preview: '/images/jimeng/templates/felt_keychain.png',
|
||||
},
|
||||
{
|
||||
label: 'Lofi 像素人物小卡',
|
||||
value: 'lofi_pixel_character_mini_card',
|
||||
preview: '/images/jimeng/templates/lofi_pixel_character_mini_card.png',
|
||||
},
|
||||
{
|
||||
label: '天使形象手办',
|
||||
value: 'angel_figurine',
|
||||
preview: '/images/jimeng/templates/angel_figurine.png',
|
||||
},
|
||||
{
|
||||
label: '躺在毛茸茸肚皮里',
|
||||
value: 'lying_in_fluffy_belly',
|
||||
preview: '/images/jimeng/templates/lying_in_fluffy_belly.png',
|
||||
},
|
||||
{ label: '玻璃球', value: 'glass_ball', preview: '/images/jimeng/templates/glass_ball.png' },
|
||||
]
|
||||
|
||||
@@ -5,17 +5,16 @@
|
||||
<!-- 功能分类按钮组 -->
|
||||
<div class="category-buttons">
|
||||
<div class="category-grid">
|
||||
<div
|
||||
v-for="category in store.categories"
|
||||
:key="category.key"
|
||||
:class="['category-btn', { active: store.activeCategory === category.key }]"
|
||||
@click="store.switchCategory(category.key)"
|
||||
<button
|
||||
v-for="f in store.functions"
|
||||
:key="f.key"
|
||||
class="category-btn text-base"
|
||||
:class="{ active: store.activeFunction === f.key }"
|
||||
@click="store.switchFunction(f)"
|
||||
>
|
||||
<div class="category-icon">
|
||||
<i :class="getCategoryIcon(category.key)"></i>
|
||||
</div>
|
||||
<div class="category-name">{{ category.name }}</div>
|
||||
</div>
|
||||
<i class="iconfont mr-2 !text-xl" :class="f.icon"></i>
|
||||
{{ f.name }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -139,290 +138,17 @@
|
||||
</div>
|
||||
|
||||
<!-- 功能开关 -->
|
||||
<div
|
||||
class="function-switch"
|
||||
v-if="
|
||||
store.activeCategory === 'image_generation' || store.activeCategory === 'video_generation'
|
||||
"
|
||||
>
|
||||
<div class="switch-label">
|
||||
<el-icon><Switch /></el-icon>
|
||||
生成模式
|
||||
</div>
|
||||
<div class="switch-container">
|
||||
<div class="switch-info">
|
||||
<div class="switch-title">
|
||||
{{ store.activeCategory === 'image_generation' ? '图生图人像写真' : '图生视频' }}
|
||||
</div>
|
||||
</div>
|
||||
<el-switch v-model="store.useImageInput" @change="store.switchInputMode" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 参数容器 -->
|
||||
<div class="params-container">
|
||||
<!-- 文生图 -->
|
||||
<div v-if="store.activeFunction === 'text_to_image'" class="function-panel">
|
||||
<div class="param-line pt">
|
||||
<span class="label">提示词:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<el-input
|
||||
v-model="store.currentPrompt"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 5 }"
|
||||
placeholder="请输入图片描述,越详细越好"
|
||||
maxlength="2000"
|
||||
show-word-limit
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="param-line pt">
|
||||
<span class="label">图片尺寸:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<el-select v-model="store.textToImageParams.size" placeholder="选择尺寸">
|
||||
<el-option
|
||||
v-for="opt in imageSizeOptions"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<div class="param-line">
|
||||
<span class="label"
|
||||
>创意度
|
||||
<el-tooltip content="创意度越高,影响文本描述的程度越高" placement="top">
|
||||
<i class="iconfont icon-info cursor-pointer ml-1"></i> </el-tooltip
|
||||
></span>
|
||||
</div>
|
||||
<div class="item-group">
|
||||
<el-slider v-model="store.textToImageParams.scale" :min="1" :max="10" :step="0.5" />
|
||||
</div>
|
||||
|
||||
<div class="item-group flex justify-between">
|
||||
<span class="label">智能优化提示词</span>
|
||||
<el-switch v-model="store.textToImageParams.use_pre_llm" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 图生图 -->
|
||||
<div v-if="store.activeFunction === 'image_to_image'" class="function-panel">
|
||||
<div class="param-line pt">
|
||||
<span class="label">上传图片:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<ImageUpload
|
||||
v-model="store.imageToImageParams.image_input"
|
||||
:max-count="1"
|
||||
:multiple="false"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="param-line pt">
|
||||
<span class="label">提示词:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<el-input
|
||||
v-model="store.currentPrompt"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 5 }"
|
||||
placeholder="描述你想要的图片效果"
|
||||
maxlength="2000"
|
||||
show-word-limit
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="param-line pt">
|
||||
<span class="label">图片尺寸:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<el-select v-model="store.imageToImageParams.size" placeholder="选择尺寸">
|
||||
<el-option
|
||||
v-for="opt in imageSizeOptions"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 图像编辑 -->
|
||||
<div v-if="store.activeFunction === 'image_edit'" class="function-panel">
|
||||
<div class="param-line pt">
|
||||
<span class="label">上传图片:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<ImageUpload
|
||||
v-model="store.imageEditParams.image_input"
|
||||
:max-count="1"
|
||||
:multiple="false"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="param-line pt">
|
||||
<span class="label">编辑提示词:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<el-input
|
||||
v-model="store.currentPrompt"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 5 }"
|
||||
placeholder="描述你想要的编辑效果"
|
||||
maxlength="2000"
|
||||
show-word-limit
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="item-group">
|
||||
<span class="label">编辑强度:</span>
|
||||
<el-slider v-model="store.imageEditParams.scale" :min="0" :max="1" :step="0.1" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 图像特效 -->
|
||||
<div v-if="store.activeFunction === 'image_effects'" class="function-panel">
|
||||
<div class="param-line pt">
|
||||
<span class="label">上传图片:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<ImageUpload
|
||||
v-model="store.imageEffectsParams.image_input"
|
||||
:max-count="1"
|
||||
:multiple="false"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="param-line pt">
|
||||
<span class="label">特效模板:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<el-select
|
||||
v-model="store.imageEffectsParams.template_id"
|
||||
placeholder="选择特效模板"
|
||||
popper-class="jimeng-template-select"
|
||||
@change="handleTemplateChange($event)"
|
||||
>
|
||||
<template #prefix>
|
||||
<div class="flex items-center py-1">
|
||||
<el-image
|
||||
v-if="templatePreview"
|
||||
:src="templatePreview"
|
||||
class="w-[50px] h-[50px] object-cover rounded-md"
|
||||
:preview-src-list="[templatePreview]"
|
||||
:preview-teleported="true"
|
||||
@click.stop
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<el-option
|
||||
v-for="opt in imageEffectsTemplateOptions"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
>
|
||||
<div class="flex flex-row justify-between">
|
||||
<span class="template-label">{{ opt.label }}</span>
|
||||
<img
|
||||
v-if="opt.preview"
|
||||
:src="opt.preview"
|
||||
:alt="opt.label"
|
||||
class="w-[50px] h-[50px] object-cover rounded-md"
|
||||
/>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<div class="param-line pt">
|
||||
<span class="label">输出尺寸:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<el-select v-model="store.imageEffectsParams.size" placeholder="选择尺寸">
|
||||
<el-option
|
||||
v-for="opt in imageSizeOptions"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 文生视频 -->
|
||||
<div v-if="store.activeFunction === 'text_to_video'" class="function-panel">
|
||||
<div class="param-line pt">
|
||||
<span class="label">提示词:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<el-input
|
||||
v-model="store.currentPrompt"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 5 }"
|
||||
placeholder="描述你想要的视频内容"
|
||||
maxlength="2000"
|
||||
show-word-limit
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="param-line pt">
|
||||
<span class="label">视频比例:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<el-select v-model="store.textToVideoParams.aspect_ratio" placeholder="选择比例">
|
||||
<el-option
|
||||
v-for="opt in videoAspectRatioOptions"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 图生视频 -->
|
||||
<div v-if="store.activeFunction === 'image_to_video'" class="function-panel">
|
||||
<div class="param-line pt">
|
||||
<span class="label">上传图片:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<ImageUpload
|
||||
v-model="store.imageToVideoParams.image_input"
|
||||
:max-count="2"
|
||||
:multiple="true"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="param-line pt">
|
||||
<span class="label">提示词:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<el-input
|
||||
v-model="store.currentPrompt"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 5 }"
|
||||
placeholder="描述你想要的视频效果"
|
||||
maxlength="2000"
|
||||
show-word-limit
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="param-line pt">
|
||||
<span class="label">视频比例:</span>
|
||||
</div>
|
||||
<div class="param-line">
|
||||
<el-select v-model="store.imageToVideoParams.aspect_ratio" placeholder="选择比例">
|
||||
<el-option
|
||||
v-for="opt in videoAspectRatioOptions"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
/>
|
||||
</el-select>
|
||||
<div class="function-params">
|
||||
<div class="mb-3">
|
||||
<div class="mb-2">
|
||||
<label class="label text-left font-bold">模型选择</label>
|
||||
</div>
|
||||
<param-builder
|
||||
v-model="store.formData"
|
||||
v-model:required-keys="store.requiredKeys"
|
||||
:items="store.functionParams[store.activeFunction]"
|
||||
:progress="store.progress[store.activeFunction]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
@@ -660,20 +386,13 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import '@/assets/css/jimeng.scss'
|
||||
import loadingIcon from '@/assets/img/loading.gif'
|
||||
import ImageUpload from '@/components/ImageUpload.vue'
|
||||
|
||||
import ParamBuilder from '@/components/ParamBuilder.vue'
|
||||
import Generating from '@/components/ui/Generating.vue'
|
||||
import {
|
||||
imageEffectsTemplateOptions,
|
||||
imageSizeOptions,
|
||||
useJimengStore,
|
||||
videoAspectRatioOptions,
|
||||
} from '@/store/jimeng'
|
||||
import { useJimengStore } from '@/store/jimeng'
|
||||
import { useSharedStore } from '@/store/sharedata'
|
||||
import { dateFormat } from '@/utils/libs'
|
||||
import { Switch } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { Waterfall } from 'vue-waterfall-plugin-next'
|
||||
@@ -682,17 +401,6 @@ import 'vue-waterfall-plugin-next/dist/style.css'
|
||||
const sharedStore = useSharedStore()
|
||||
const waterfallOptions = sharedStore.waterfallOptions
|
||||
|
||||
// 获取分类图标
|
||||
const getCategoryIcon = (category) => {
|
||||
const iconMap = {
|
||||
image_generation: 'iconfont icon-image',
|
||||
image_editing: 'iconfont icon-edit',
|
||||
image_effects: 'iconfont icon-chuangzuo',
|
||||
video_generation: 'iconfont icon-video',
|
||||
}
|
||||
return iconMap[category] || 'iconfont icon-image'
|
||||
}
|
||||
|
||||
const store = useJimengStore()
|
||||
|
||||
// 新增:瀑布流渲染完成状态
|
||||
@@ -730,13 +438,6 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
function handleTemplateChange(value) {
|
||||
templatePreview.value = imageEffectsTemplateOptions.find((opt) => opt.value === value)?.preview
|
||||
store.imageEffectsParams.prompt = imageEffectsTemplateOptions.find(
|
||||
(opt) => opt.value === value
|
||||
)?.label
|
||||
}
|
||||
|
||||
function onWaterfallAfterRender() {
|
||||
waterfallRendered.value = true
|
||||
if (!store.loading && !store.isOver) {
|
||||
@@ -768,150 +469,5 @@ function copyErrorMsg(msg) {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.task-list {
|
||||
.task-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
gap: 20px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
// 新增:增强任务项悬停动画
|
||||
.task-item {
|
||||
transition: box-shadow 3s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
transform 0.5s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.5s;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
border: 1.5px solid transparent;
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.task-item:hover {
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18), 0 1.5px 8px rgba(0, 0, 0, 0.1);
|
||||
border-color: #a259ff;
|
||||
transform: scale(1.025) translateY(-2px);
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
.task-list .task-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
||||
}
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.task-list .task-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
.preview-video-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.video-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&:hover .video-mask {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.play-btn {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
cursor: pointer;
|
||||
z-index: 3;
|
||||
transition: background 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.err-msg-clip {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
word-break: break-all;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.jimeng-template-select {
|
||||
.el-select-dropdown__item {
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:提示词指南样式
|
||||
.prompt-guide {
|
||||
margin: 12px 0 16px;
|
||||
|
||||
.guide-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.guide-content {
|
||||
max-height: 220px;
|
||||
overflow: auto;
|
||||
line-height: 1.6;
|
||||
font-size: 12px;
|
||||
color: #555;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.guide-section {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.guide-subtitle {
|
||||
font-weight: 600;
|
||||
margin-bottom: 6px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: disc;
|
||||
padding-left: 18px;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.quote {
|
||||
margin: 8px 0;
|
||||
padding: 8px 10px;
|
||||
border-left: 3px solid #a3a3a3;
|
||||
background: #f8f8f8;
|
||||
border-radius: 4px;
|
||||
color: #444;
|
||||
}
|
||||
}
|
||||
@use '@/assets/css/jimeng.scss' as *;
|
||||
</style>
|
||||
|
||||
@@ -56,134 +56,55 @@
|
||||
<h3 class="heading-3 mb-3">算力配置</h3>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="label-title">
|
||||
文生图算力
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="用户使用文生图功能时消耗的算力"
|
||||
raw-content
|
||||
placement="right"
|
||||
<div class="text-gray-500 text-sm">
|
||||
生成图片消耗的积分,包括:文生图、图生图、图片编辑、图片特效,<span
|
||||
class="text-red-500"
|
||||
>单位:积分/张</span
|
||||
>
|
||||
<el-icon>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="jimengConfig.power.text_to_image"
|
||||
v-model="jimengConfig.power.image"
|
||||
:min="1"
|
||||
placeholder="请输入文生图算力消耗"
|
||||
placeholder="请输入图片生成算力消耗"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="label-title">
|
||||
图生图算力
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="用户使用图生图功能时消耗的算力"
|
||||
raw-content
|
||||
placement="right"
|
||||
<div class="text-gray-500 text-sm">
|
||||
生成视频消耗的积分,包括:文生视频、图生视频,<span class="text-red-500"
|
||||
>单位:积分/秒</span
|
||||
>
|
||||
<el-icon>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="jimengConfig.power.image_to_image"
|
||||
v-model="jimengConfig.power.video"
|
||||
:min="1"
|
||||
placeholder="请输入图生图算力消耗"
|
||||
placeholder="请输入视频生成算力消耗"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="label-title">
|
||||
图片编辑算力
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="用户使用图片编辑功能时消耗的算力"
|
||||
raw-content
|
||||
placement="right"
|
||||
>
|
||||
<el-icon>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<div class="text-gray-500 text-sm">
|
||||
生成数字人视频消耗的积分,<span class="text-red-500">单位:积分/秒</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="jimengConfig.power.image_edit"
|
||||
v-model="jimengConfig.power.virtual_human"
|
||||
:min="1"
|
||||
placeholder="请输入图片编辑算力消耗"
|
||||
placeholder="请输入数字人视频生成算力消耗"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="label-title">
|
||||
图片特效算力
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="用户使用图片特效功能时消耗的算力"
|
||||
raw-content
|
||||
placement="right"
|
||||
>
|
||||
<el-icon>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<div class="text-gray-500 text-sm">
|
||||
生成视频动作迁移消耗的积分,<span class="text-red-500">单位:积分/秒</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="jimengConfig.power.image_effects"
|
||||
v-model="jimengConfig.power.action_transfer"
|
||||
:min="1"
|
||||
placeholder="请输入图片特效算力消耗"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="label-title">
|
||||
文生视频算力
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="用户使用文生视频功能时消耗的算力"
|
||||
raw-content
|
||||
placement="right"
|
||||
>
|
||||
<el-icon>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="jimengConfig.power.text_to_video"
|
||||
:min="1"
|
||||
placeholder="请输入文生视频算力消耗"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="label-title">
|
||||
图生视频算力
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="用户使用图生视频功能时消耗的算力"
|
||||
raw-content
|
||||
placement="right"
|
||||
>
|
||||
<el-icon>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input-number
|
||||
v-model="jimengConfig.power.image_to_video"
|
||||
:min="1"
|
||||
placeholder="请输入图生视频算力消耗"
|
||||
placeholder="请输入视频动作迁移算力消耗"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
@@ -201,7 +122,6 @@
|
||||
<script setup>
|
||||
import Alert from '@/components/ui/Alert.vue'
|
||||
import { httpGet, httpPost } from '@/utils/http'
|
||||
import { InfoFilled } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
<script setup>
|
||||
import ParamBuilder from '@/components/ParamBuilder.vue'
|
||||
import { JimengFunctions, JimengParams } from '@/store/data'
|
||||
import { JimengFunctions, JimengParams } from '@/store/data/jimeng_data'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const functions = JimengFunctions
|
||||
|
||||