{{ status }}
+{{ status }}
+diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d40fa88 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +logs/stability/ +logs/conversation/ diff --git a/frontend-admin/src/views/ModelsView.vue b/frontend-admin/src/views/ModelsView.vue index 74a9914..2284ac2 100644 --- a/frontend-admin/src/views/ModelsView.vue +++ b/frontend-admin/src/views/ModelsView.vue @@ -159,6 +159,18 @@ +
默认 0.45;越低越保留原图,越高变化越明显。
+默认 0.72;仅作用于白色遮罩区域。
+
必须使用 Save (API Format) 导出的 JSON(节点含 class_type)。
UI Format(含 nodes/links)导入后会秒结束且不出图。
@@ -310,6 +322,8 @@ const form = reactive({
workflow_json: '',
prompt_node: '',
seed_node: '',
+ img2img_denoise: 0.45,
+ inpaint_denoise: 0.72,
refine_prompt: true,
system_prompt: ''
})
@@ -385,14 +399,16 @@ function onProviderChange() {
}
function parseExtraConfig(extra) {
- if (!extra) return { workflow_json: '', prompt_node: '', seed_node: '', refine_prompt: true, system_prompt: '' }
+ if (!extra) return { workflow_json: '', prompt_node: '', seed_node: '', img2img_denoise: 0.45, inpaint_denoise: 0.72, refine_prompt: true, system_prompt: '' }
if (typeof extra === 'string') {
- try { extra = JSON.parse(extra) } catch { return { workflow_json: '', prompt_node: '', seed_node: '', refine_prompt: true, system_prompt: '' } }
+ try { extra = JSON.parse(extra) } catch { return { workflow_json: '', prompt_node: '', seed_node: '', img2img_denoise: 0.45, inpaint_denoise: 0.72, refine_prompt: true, system_prompt: '' } }
}
return {
workflow_json: extra.workflow ? JSON.stringify(extra.workflow, null, 2) : '',
prompt_node: extra.prompt_node || '',
seed_node: extra.seed_node || '',
+ img2img_denoise: Number(extra.img2img_denoise ?? 0.45),
+ inpaint_denoise: Number(extra.inpaint_denoise ?? 0.72),
refine_prompt: extra.refine_prompt === undefined ? true : !!extra.refine_prompt,
system_prompt: extra.system_prompt || ''
}
@@ -437,6 +453,8 @@ function buildExtraConfig() {
}
if ((form.prompt_node || '').trim()) config.prompt_node = form.prompt_node.trim()
if ((form.seed_node || '').trim()) config.seed_node = form.seed_node.trim()
+ config.img2img_denoise = Math.max(0.01, Math.min(1, Number(form.img2img_denoise) || 0.45))
+ config.inpaint_denoise = Math.max(0.01, Math.min(1, Number(form.inpaint_denoise) || 0.72))
if ((form.system_prompt || '').trim()) config.system_prompt = form.system_prompt.trim()
config.refine_prompt = !!form.refine_prompt
return config
@@ -485,7 +503,7 @@ function openCreate() {
name: '', provider: 'openai', model_id: '', api_base_url: 'https://api.openai.com/v1',
api_key: '', max_tokens: 4096, temperature: 0.7, is_default: false, enabled: true, support_context: true, support_image: true,
frequency_penalty: 0, presence_penalty: 0,
- workflow_json: '', prompt_node: '', seed_node: '', refine_prompt: true, system_prompt: ''
+ workflow_json: '', prompt_node: '', seed_node: '', img2img_denoise: 0.45, inpaint_denoise: 0.72, refine_prompt: true, system_prompt: ''
})
showModal.value = true
}
@@ -510,6 +528,8 @@ function openEdit(m) {
workflow_json: extra.workflow_json,
prompt_node: extra.prompt_node,
seed_node: extra.seed_node,
+ img2img_denoise: extra.img2img_denoise,
+ inpaint_denoise: extra.inpaint_denoise,
refine_prompt: extra.refine_prompt,
system_prompt: extra.system_prompt
})
@@ -540,6 +560,8 @@ async function saveModel() {
delete payload.workflow_json
delete payload.prompt_node
delete payload.seed_node
+ delete payload.img2img_denoise
+ delete payload.inpaint_denoise
delete payload.refine_prompt
delete payload.system_prompt
diff --git a/frontend/src/components/ChatInput.vue b/frontend/src/components/ChatInput.vue
index 91ff904..75d98b8 100644
--- a/frontend/src/components/ChatInput.vue
+++ b/frontend/src/components/ChatInput.vue
@@ -39,87 +39,7 @@
-
Agent 会为当前请求加入稳定的分析步骤和输出规范。
-正在上传 {{ uploadingFiles.length }} 个文件
-- 当前工作流仅支持文生图,请移除附件后输入图片描述 +
+ 第一张为原图;需要局部重绘时,第二张请上传同尺寸黑白遮罩(白色区域会被修改) +
+可直接文生图,也可上传原图进行 img2img / inpaint 图片处理
++ Agent 会自动识别任务,并调用合适的语言或图片生成模型
-当前是图片生成模式,发送提示词后会在对话中返回图片
游客模式不支持发送图片,登录后即可上传
@@ -266,7 +189,7 @@ @@ -1033,324 +945,6 @@ async function handleSend() { transition: border-color 0.18s ease, box-shadow 0.18s ease; } -.agent-panel { - position: absolute; - right: 0; - bottom: calc(100% + 10px); - left: 0; - z-index: 40; - max-height: min(58dvh, 430px); - padding: 18px; - overflow-y: auto; - overscroll-behavior: contain; - border: 1px solid #dce3ec; - border-radius: 22px; - background: rgba(255, 255, 255, 0.98); - box-shadow: 0 24px 64px rgba(31, 49, 78, 0.17), 0 2px 8px rgba(31, 49, 78, 0.06); - backdrop-filter: blur(16px); -} - -.agent-panel-header { - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: 20px; - padding: 2px 2px 14px; -} - -.agent-eyebrow { - display: block; - margin-bottom: 5px; - color: var(--accent); - font-size: 10px; - font-weight: 700; - letter-spacing: 0.09em; - text-transform: uppercase; -} - -.agent-panel-header h3 { - color: var(--text-primary); - font-size: 18px; - font-weight: 680; - letter-spacing: -0.025em; - line-height: 1.35; -} - -.agent-panel-header p { - margin-top: 4px; - color: var(--text-muted); - font-size: 12px; - line-height: 1.55; -} - -.agent-panel-close, -.active-agent-remove { - display: inline-flex; - align-items: center; - justify-content: center; - flex-shrink: 0; - color: var(--text-muted); - transition: color 0.16s ease, background 0.16s ease, transform 0.16s ease; -} - -.agent-panel-close { - width: 34px; - height: 34px; - border-radius: 50%; -} - -.agent-panel-close:hover, -.active-agent-remove:hover { - background: #edf1f6; - color: var(--text-primary); -} - -.agent-panel-close:active, -.active-agent-remove:active { - transform: scale(0.94); -} - -.agent-options { - overflow: hidden; - border-top: 1px solid #e8edf3; - border-bottom: 1px solid #e8edf3; -} - -.agent-option { - position: relative; - display: flex; - align-items: center; - gap: 12px; - width: 100%; - min-height: 72px; - padding: 10px 10px 10px 8px; - color: var(--text-primary); - text-align: left; - transition: background 0.16s ease, transform 0.16s ease; -} - -.agent-option + .agent-option { - border-top: 1px solid #edf1f5; -} - -.agent-option::before { - position: absolute; - top: 13px; - bottom: 13px; - left: 0; - width: 3px; - border-radius: 3px; - background: var(--accent); - content: ''; - opacity: 0; - transform: scaleY(0.55); - transition: opacity 0.16s ease, transform 0.18s ease; -} - -.agent-option:hover { - background: #f8fafc; -} - -.agent-option:active { - transform: scale(0.995); -} - -.agent-option.selected { - background: #f2f6fc; -} - -.agent-option.selected::before { - opacity: 1; - transform: scaleY(1); -} - -.agent-option-icon, -.active-agent-icon { - display: inline-flex; - align-items: center; - justify-content: center; - flex-shrink: 0; - background: #eaf1ff; - color: #2d66da; -} - -.agent-option-icon { - width: 42px; - height: 42px; - border-radius: 13px; -} - -.agent-option-icon[data-accent='teal'], -.active-agent-icon[data-accent='teal'] { - background: #e7f5f1; - color: #177565; -} - -.agent-option-icon[data-accent='amber'], -.active-agent-icon[data-accent='amber'] { - background: #fff3dd; - color: #94600b; -} - -.agent-option-icon[data-accent='slate'], -.active-agent-icon[data-accent='slate'] { - background: #edf0f4; - color: #4b5b70; -} - -.agent-option-copy { - display: flex; - flex: 1; - flex-direction: column; - min-width: 0; -} - -.agent-option-heading { - display: flex; - align-items: center; - gap: 6px; - min-width: 0; -} - -.agent-option-heading strong { - margin-right: 3px; - font-size: 14px; - font-weight: 650; -} - -.agent-option-copy small { - margin-top: 5px; - overflow: hidden; - color: var(--text-muted); - font-size: 12px; - line-height: 1.4; - text-overflow: ellipsis; - white-space: nowrap; -} - -.agent-tag { - padding: 2px 6px; - border: 1px solid #e0e6ee; - border-radius: 5px; - background: #fff; - color: #67758a; - font-size: 10px; - line-height: 1.4; -} - -.agent-option-check { - flex-shrink: 0; - color: var(--accent); -} - -.agent-panel-footer { - display: flex; - align-items: flex-end; - gap: 18px; - padding: 14px 2px 1px; -} - -.agent-starters { - display: flex; - flex: 1; - flex-wrap: wrap; - gap: 7px; - min-width: 0; -} - -.agent-starters > span { - width: 100%; - color: var(--text-muted); - font-size: 10px; - font-weight: 650; - letter-spacing: 0.05em; -} - -.agent-starters button { - max-width: 100%; - padding: 6px 9px; - overflow: hidden; - border: 1px solid #dfe6ef; - border-radius: 8px; - background: #f8fafc; - color: var(--text-secondary); - font-size: 11px; - text-overflow: ellipsis; - white-space: nowrap; - transition: background 0.16s ease, border-color 0.16s ease, color 0.16s ease; -} - -.agent-starters button:hover { - border-color: #c9d7ed; - background: #f1f6fd; - color: var(--accent); -} - -.agent-disable { - flex-shrink: 0; - padding: 7px 4px; - color: var(--text-muted); - font-size: 11px; -} - -.agent-disable:hover { - color: var(--danger); -} - -.active-agent-strip { - display: flex; - align-items: center; - gap: 9px; - min-height: 48px; - margin: 9px 10px 0; - padding: 6px 7px; - border: 1px solid #e1e7ef; - border-radius: 12px; - background: #f7f9fc; -} - -.active-agent-icon { - width: 34px; - height: 34px; - border-radius: 10px; -} - -.active-agent-copy { - display: flex; - flex: 1; - flex-direction: column; - min-width: 0; -} - -.active-agent-copy strong { - color: var(--text-primary); - font-size: 12px; - font-weight: 650; - line-height: 1.35; -} - -.active-agent-copy small { - margin-top: 2px; - overflow: hidden; - color: var(--text-muted); - font-size: 10px; - text-overflow: ellipsis; - white-space: nowrap; -} - -.active-agent-adjust { - padding: 5px 7px; - color: var(--accent); - font-size: 11px; - font-weight: 600; -} - -.active-agent-remove { - width: 28px; - height: 28px; - border-radius: 50%; -} - .agent-trigger { position: relative; display: inline-flex; @@ -1393,18 +987,6 @@ async function handleSend() { box-shadow: 0 0 0 3px rgba(47, 141, 115, 0.1); } -.agent-panel-enter-active, -.agent-panel-leave-active { - transition: opacity 0.18s ease, transform 0.22s cubic-bezier(0.16, 1, 0.3, 1); - transform-origin: center bottom; -} - -.agent-panel-enter-from, -.agent-panel-leave-to { - opacity: 0; - transform: translateY(8px) scale(0.985); -} - .input-wrapper:focus-within { border-color: rgba(45, 102, 218, 0.54); box-shadow: 0 0 0 3px rgba(45, 102, 218, 0.09), var(--shadow-composer); @@ -1652,89 +1234,6 @@ async function handleSend() { border-radius: 18px; } - .agent-panel { - bottom: calc(100% + 8px); - max-height: min(57dvh, 460px); - padding: 14px; - border-radius: 18px; - } - - .agent-panel-header { - gap: 12px; - padding-bottom: 11px; - } - - .agent-panel-header h3 { - font-size: 16px; - } - - .agent-panel-header p { - max-width: 270px; - font-size: 11px; - } - - .agent-option { - min-height: 64px; - gap: 10px; - padding: 8px 7px 8px 6px; - } - - .agent-option-icon { - width: 38px; - height: 38px; - border-radius: 11px; - } - - .agent-option-copy small { - margin-top: 3px; - font-size: 11px; - } - - .agent-tag { - display: none; - } - - .agent-panel-footer { - align-items: stretch; - flex-direction: column; - gap: 6px; - padding-top: 11px; - } - - .agent-starters { - flex-wrap: nowrap; - overflow-x: auto; - scrollbar-width: none; - } - - .agent-starters > span { - display: none; - } - - .agent-starters button { - flex: 0 0 auto; - max-width: 86%; - } - - .agent-disable { - align-self: flex-end; - } - - .active-agent-strip { - min-height: 44px; - margin: 7px 8px 0; - padding: 5px 6px; - } - - .active-agent-icon { - width: 32px; - height: 32px; - } - - .active-agent-copy small { - max-width: 42vw; - } - .input-textarea { min-height: 66px; padding: 14px 12px 8px; @@ -1841,8 +1340,6 @@ async function handleSend() { .mode-tab, .model-picker, .send-btn, - .agent-panel, - .agent-option, .agent-trigger, .upload-progress-fill { transition: none; diff --git a/frontend/src/components/ImageWorkbench.vue b/frontend/src/components/ImageWorkbench.vue new file mode 100644 index 0000000..d3320de --- /dev/null +++ b/frontend/src/components/ImageWorkbench.vue @@ -0,0 +1,1085 @@ + +{{ status }}
+{{ status }}
+