添加青云AI服务提供商支持,修复火山引擎图片生成问题
- 新增青云(qingyun)provider支持,提供文本/图片/视频AI服务 - 修复火山引擎img2img模式下图片尺寸问题(参考图片时强制使用2K) - 修复火山引擎水印参数(watermark设为必需字段) - 前端添加图片删除功能,支持删除不满意的生成图片 - 优化素材选择器布局样式,提升用户体验 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -458,7 +458,8 @@ func (s *VideoGenerationService) getVideoClient(provider string, modelName strin
|
||||
var queryEndpoint string
|
||||
|
||||
switch config.Provider {
|
||||
case "chatfire":
|
||||
case "chatfire", "qingyun":
|
||||
// 青云和 Chatfire 都使用 OpenAI 兼容格式
|
||||
endpoint = "/video/generations"
|
||||
queryEndpoint = "/video/task/{taskId}"
|
||||
return video.NewChatfireClient(baseURL, apiKey, model, endpoint, queryEndpoint), nil
|
||||
|
||||
@@ -24,7 +24,7 @@ type VolcEngineImageRequest struct {
|
||||
Image []string `json:"image,omitempty"`
|
||||
SequentialImageGeneration string `json:"sequential_image_generation,omitempty"`
|
||||
Size string `json:"size,omitempty"`
|
||||
Watermark bool `json:"watermark,omitempty"`
|
||||
Watermark bool `json:"watermark"`
|
||||
}
|
||||
|
||||
type VolcEngineImageResponse struct {
|
||||
@@ -82,7 +82,11 @@ func (c *VolcEngineImageClient) GenerateImage(prompt string, opts ...ImageOption
|
||||
}
|
||||
|
||||
size := options.Size
|
||||
if size == "" {
|
||||
// 火山引擎 img2img 模式要求图片尺寸至少 3686400 像素(约1920x1920)
|
||||
// 当使用参考图片时,强制使用 2K 尺寸
|
||||
if len(options.ReferenceImages) > 0 {
|
||||
size = "2K"
|
||||
} else if size == "" || size == "1024x1024" {
|
||||
if model == "doubao-seedream-4-5-251128" {
|
||||
size = "2K"
|
||||
} else {
|
||||
|
||||
@@ -288,6 +288,18 @@ const providerConfigs: Record<AIServiceType, ProviderConfig[]> = {
|
||||
'doubao-seed-1-8-251228'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'qingyun',
|
||||
name: '青云',
|
||||
models: [
|
||||
'gpt-5.2',
|
||||
'claude-opus-4-5-20251101',
|
||||
'gemini-3-pro-preview',
|
||||
'deepseek-v3.2',
|
||||
'qwen-max',
|
||||
'doubao-seed-1-8-251228'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'gemini',
|
||||
name: 'Google Gemini',
|
||||
@@ -305,6 +317,17 @@ const providerConfigs: Record<AIServiceType, ProviderConfig[]> = {
|
||||
name: 'Chatfire',
|
||||
models: ['doubao-seedream-4-5-251128', 'nano-banana-pro']
|
||||
},
|
||||
{
|
||||
id: 'qingyun',
|
||||
name: '青云',
|
||||
models: [
|
||||
'gpt-image-1.5',
|
||||
'gemini-3-pro-image-preview',
|
||||
'jimeng-4.5',
|
||||
'jimeng-4.1',
|
||||
'mj_imagine'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'gemini',
|
||||
name: 'Google Gemini',
|
||||
@@ -337,6 +360,19 @@ const providerConfigs: Record<AIServiceType, ProviderConfig[]> = {
|
||||
'sora-2-pro'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'qingyun',
|
||||
name: '青云',
|
||||
models: [
|
||||
'grok-video-3',
|
||||
'veo3.1-pro-4k',
|
||||
'sora-2-all',
|
||||
'sora-2-pro-all',
|
||||
'jimeng-video-3.0',
|
||||
'kling-video-1.5',
|
||||
'wan2.6-i2v'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'minimax',
|
||||
name: 'MiniMax 海螺',
|
||||
@@ -444,7 +480,8 @@ const generateConfigName = (provider: string, serviceType: AIServiceType): strin
|
||||
'chatfire': 'ChatFire',
|
||||
'openai': 'OpenAI',
|
||||
'gemini': 'Gemini',
|
||||
'google': 'Google'
|
||||
'google': 'Google',
|
||||
'qingyun': '青云'
|
||||
}
|
||||
|
||||
const serviceNames: Record<AIServiceType, string> = {
|
||||
@@ -609,6 +646,8 @@ const handleProviderChange = () => {
|
||||
form.base_url = 'https://ark.cn-beijing.volces.com/api/v3'
|
||||
} else if (form.provider === 'openai') {
|
||||
form.base_url = 'https://api.openai.com/v1'
|
||||
} else if (form.provider === 'qingyun') {
|
||||
form.base_url = 'https://api.qingyuntop.top/v1'
|
||||
} else {
|
||||
// chatfire 和其他厂商
|
||||
form.base_url = 'https://api.chatfire.site/v1'
|
||||
|
||||
@@ -2162,7 +2162,7 @@ defineExpose({
|
||||
}
|
||||
|
||||
.media-grid {
|
||||
max-height: 450px;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 12px;
|
||||
display: grid;
|
||||
@@ -2193,7 +2193,6 @@ defineExpose({
|
||||
position: relative;
|
||||
background: var(--bg-secondary);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
cursor: move;
|
||||
border: 1px solid var(--border-primary);
|
||||
transition: all 0.3s;
|
||||
@@ -2223,6 +2222,8 @@ defineExpose({
|
||||
aspect-ratio: 16/9;
|
||||
background: var(--bg-card-hover);
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
border-radius: 6px 6px 0 0;
|
||||
|
||||
video {
|
||||
width: 100%;
|
||||
|
||||
@@ -292,12 +292,20 @@
|
||||
<el-icon :size="32">
|
||||
<Picture />
|
||||
</el-icon>
|
||||
<p>生成中...</p>
|
||||
<p>{{ img.status === 'failed' ? 'FAILED' : '生成中...' }}</p>
|
||||
</div>
|
||||
<div class="image-info">
|
||||
<el-tag :type="getStatusType(img.status)" size="small">{{ getStatusText(img.status) }}</el-tag>
|
||||
<span v-if="img.frame_type" class="frame-type-tag">{{ getFrameTypeText(img.frame_type) }}</span>
|
||||
</div>
|
||||
<el-button
|
||||
class="delete-image-btn"
|
||||
type="danger"
|
||||
size="small"
|
||||
circle
|
||||
:icon="Delete"
|
||||
@click.stop="deleteImage(img.id)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1652,7 +1660,28 @@ const extractLastFrame = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取状态标签类型
|
||||
// 删除图片生成记录
|
||||
const deleteImage = async (imageId: number) => {
|
||||
try {
|
||||
await ElMessageBox.confirm('确定要删除该图片吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
|
||||
await imageAPI.deleteImage(imageId)
|
||||
ElMessage.success('删除成功')
|
||||
|
||||
// 刷新图片列表
|
||||
if (currentStoryboard.value) {
|
||||
await loadStoryboardImages(currentStoryboard.value.id, selectedFrameType.value)
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error('删除失败: ' + (error.message || '未知错误'))
|
||||
}
|
||||
}
|
||||
}
|
||||
const getStatusType = (status: string) => {
|
||||
const statusMap: Record<string, any> = {
|
||||
pending: 'info',
|
||||
@@ -4317,4 +4346,20 @@ onBeforeUnmount(() => {
|
||||
max-height: 80px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.image-item {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.delete-image-btn {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.image-item:hover .delete-image-btn {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user