feat(ui): add prompt garden guide for image-to-image
This commit is contained in:
1 parent
e1e9e9a8d4
commit
bf675c3cdd
4 files changed
+168
No files matched your search
@@ -146,6 +146,56 @@
|
||||
:disabled="isOptimizing"
|
||||
/>
|
||||
|
||||
<div
|
||||
v-if="showPromptGardenEmptyGuide"
|
||||
class="prompt-garden-empty-guide"
|
||||
data-testid="image-image2image-prompt-garden-guide"
|
||||
>
|
||||
<div class="prompt-garden-empty-guide__icon">
|
||||
<NIcon>
|
||||
<Plant2 />
|
||||
</NIcon>
|
||||
</div>
|
||||
<div class="prompt-garden-empty-guide__copy">
|
||||
<NText strong>
|
||||
{{ t('common.promptGarden.image2ImageGuideTitle') }}
|
||||
</NText>
|
||||
<NText depth="3" class="prompt-garden-empty-guide__hint">
|
||||
{{ t('common.promptGarden.image2ImageGuideHint') }}
|
||||
</NText>
|
||||
</div>
|
||||
<div class="prompt-garden-empty-guide__actions">
|
||||
<NButton
|
||||
size="small"
|
||||
secondary
|
||||
:disabled="isPromptGardenGuideDisabled"
|
||||
data-testid="image-image2image-prompt-garden-discover"
|
||||
@click="handlePromptGardenDiscover"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon>
|
||||
<ExternalLink />
|
||||
</NIcon>
|
||||
</template>
|
||||
{{ t('common.promptGarden.discoverShort') }}
|
||||
</NButton>
|
||||
<NButton
|
||||
size="small"
|
||||
secondary
|
||||
:disabled="isPromptGardenGuideDisabled"
|
||||
data-testid="image-image2image-prompt-garden-import"
|
||||
@click="showPromptGardenImport = true"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon>
|
||||
<FileImport />
|
||||
</NIcon>
|
||||
</template>
|
||||
{{ t('common.promptGarden.importShort') }}
|
||||
</NButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 图片上传区域 - Image2Image 模式始终显示 -->
|
||||
<NSpace
|
||||
vertical
|
||||
@@ -712,12 +762,18 @@
|
||||
:renderPhase="previewRenderPhase"
|
||||
/>
|
||||
|
||||
<PromptGardenImportDialog
|
||||
v-model:show="showPromptGardenImport"
|
||||
@confirm="handlePromptGardenImportConfirm"
|
||||
/>
|
||||
|
||||
<!-- 模板管理器由 App 统一管理,这里不再渲染 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, inject, ref, reactive, computed, watch, nextTick, type Ref } from 'vue'
|
||||
import { useRouter, type LocationQueryRaw } from 'vue-router'
|
||||
|
||||
import {
|
||||
NCard,
|
||||
@@ -742,9 +798,11 @@ import {
|
||||
NTooltip,
|
||||
type UploadFileInfo,
|
||||
} from "naive-ui";
|
||||
import { ExternalLink, FileImport, Plant2 } from '@vicons/tabler'
|
||||
import { useI18n } from "vue-i18n";
|
||||
import PromptPanelUI from "../PromptPanel.vue";
|
||||
import WorkspaceUtilityMenu from '../common/WorkspaceUtilityMenu.vue'
|
||||
import PromptGardenImportDialog from '../common/PromptGardenImportDialog.vue'
|
||||
import PromptPreviewPanel from "../PromptPreviewPanel.vue";
|
||||
import SelectWithConfig from "../SelectWithConfig.vue";
|
||||
import TestPanelVersionSelect from '../TestPanelVersionSelect.vue'
|
||||
@@ -759,6 +817,8 @@ import { getI18nErrorMessage } from '../../utils/error'
|
||||
import { withHistorySourceBindingMetadata } from '../../utils/history-source-binding'
|
||||
import { resolveSourceAssetRef } from '../../utils/source-asset'
|
||||
import { downloadImageSource } from '../../utils/image-download'
|
||||
import { openExternalUrl } from '../../utils/open-external-url'
|
||||
import type { PromptGardenImportRequest } from '../../utils/prompt-garden-import'
|
||||
import { VariableAwareInput } from '../variable-extraction'
|
||||
import TemporaryVariablesPanel from '../variable/TemporaryVariablesPanel.vue'
|
||||
import VariableValuePreviewDialog from '../variable/VariableValuePreviewDialog.vue'
|
||||
@@ -792,6 +852,7 @@ import { useWorkspaceTextModelSelection } from '../../composables/workspaces/use
|
||||
import { useElementSize } from '@vueuse/core'
|
||||
import { runTasksWithExecutionMode } from '../../utils/runTasksSequentially'
|
||||
import {
|
||||
getEnvVar,
|
||||
type ContextMode,
|
||||
type ImageModelConfig,
|
||||
type Image2ImageRequest,
|
||||
@@ -807,6 +868,7 @@ import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
// 国际化
|
||||
const { t } = useI18n();
|
||||
const router = useRouter()
|
||||
|
||||
interface VariantInputImageInfo {
|
||||
width?: number
|
||||
@@ -961,6 +1023,56 @@ const templateSelection = useWorkspaceTemplateSelection(
|
||||
const selectedTemplateId = templateSelection.selectedTemplateId
|
||||
const templateOptions = templateSelection.templateOptions
|
||||
|
||||
const showPromptGardenImport = ref(false)
|
||||
|
||||
const isPromptGardenEnabled = computed(() => {
|
||||
const value = getEnvVar('VITE_ENABLE_PROMPT_GARDEN_IMPORT').trim().toLowerCase()
|
||||
return value === '1' || value === 'true'
|
||||
})
|
||||
|
||||
const promptGardenBaseUrl = computed(() =>
|
||||
getEnvVar('VITE_PROMPT_GARDEN_BASE_URL').trim().replace(/\/$/, ''),
|
||||
)
|
||||
|
||||
const showPromptGardenEmptyGuide = computed(() =>
|
||||
isPromptGardenEnabled.value && !originalPrompt.value.trim(),
|
||||
)
|
||||
|
||||
const isPromptGardenGuideDisabled = computed(() =>
|
||||
isOptimizing.value || isIterating.value || isAnyVariantRunning.value,
|
||||
)
|
||||
|
||||
const handlePromptGardenDiscover = () => {
|
||||
void openExternalUrl(promptGardenBaseUrl.value, { logPrefix: 'PromptGarden' })
|
||||
}
|
||||
|
||||
const handlePromptGardenImportConfirm = async (request: PromptGardenImportRequest) => {
|
||||
if (!request.importCode) return false
|
||||
|
||||
const currentRoute = router.currentRoute.value
|
||||
const query: LocationQueryRaw = {
|
||||
...currentRoute.query,
|
||||
importCode: request.importCode,
|
||||
}
|
||||
if (request.exampleId) {
|
||||
query.exampleId = request.exampleId
|
||||
} else {
|
||||
delete query.exampleId
|
||||
}
|
||||
if (request.subModeKey) {
|
||||
query.subModeKey = request.subModeKey
|
||||
} else {
|
||||
delete query.subModeKey
|
||||
}
|
||||
|
||||
await router.push({
|
||||
path: currentRoute.path,
|
||||
query,
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
const isCompareMode = computed<boolean>({
|
||||
get: () => !!session.isCompareMode,
|
||||
set: (value) => session.toggleCompareMode(!!value),
|
||||
@@ -2509,4 +2621,54 @@ onUnmounted(() => {
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.prompt-garden-empty-guide {
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr) auto;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid color-mix(in srgb, var(--n-success-color) 10%, var(--n-border-color));
|
||||
border-radius: 8px;
|
||||
background: color-mix(in srgb, var(--n-success-color) 3%, var(--n-color));
|
||||
}
|
||||
|
||||
.prompt-garden-empty-guide__icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
color: color-mix(in srgb, var(--n-success-color) 76%, var(--n-text-color-3));
|
||||
border-radius: 999px;
|
||||
background: color-mix(in srgb, var(--n-success-color) 7%, transparent);
|
||||
}
|
||||
|
||||
.prompt-garden-empty-guide__copy {
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.prompt-garden-empty-guide__hint {
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.prompt-garden-empty-guide__actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.prompt-garden-empty-guide {
|
||||
grid-template-columns: auto minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.prompt-garden-empty-guide__actions {
|
||||
grid-column: 1 / -1;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -49,6 +49,8 @@ const messages = {
|
||||
"importPlaceholder": "Enter import code",
|
||||
"text2ImageGuideTitle": "Discover text-to-image prompts in Prompt Garden",
|
||||
"text2ImageGuideHint": "When you need a starting point, browse Garden prompts or paste an import code into this workspace.",
|
||||
"image2ImageGuideTitle": "Discover image-to-image prompts in Prompt Garden",
|
||||
"image2ImageGuideHint": "When you need an editing direction, browse Garden prompts or paste an import code into this workspace.",
|
||||
"discoverShort": "Discover",
|
||||
"importShort": "Paste code",
|
||||
"importingStatus": "Importing prompt and image resources from Prompt Garden..."
|
||||
|
||||
@@ -47,6 +47,8 @@ const messages = {
|
||||
"importPlaceholder": "输入导入码",
|
||||
"text2ImageGuideTitle": "从 Prompt Garden 发现文生图提示词",
|
||||
"text2ImageGuideHint": "没有灵感时,可以先去花园挑一个提示词,或粘贴导入码直接带入当前工作区。",
|
||||
"image2ImageGuideTitle": "从 Prompt Garden 发现图生图提示词",
|
||||
"image2ImageGuideHint": "没有改图思路时,可以先去花园挑一个图生图提示词,或粘贴导入码带入当前工作区。",
|
||||
"discoverShort": "去发现",
|
||||
"importShort": "粘贴导入码",
|
||||
"importingStatus": "正在从 Prompt Garden 获取提示词和图片资源..."
|
||||
|
||||
@@ -47,6 +47,8 @@ const messages = {
|
||||
"importPlaceholder": "輸入匯入碼",
|
||||
"text2ImageGuideTitle": "從 Prompt Garden 發現文生圖提示詞",
|
||||
"text2ImageGuideHint": "沒有靈感時,可以先去花園挑一個提示詞,或貼上匯入碼直接帶入目前工作區。",
|
||||
"image2ImageGuideTitle": "從 Prompt Garden 發現圖生圖提示詞",
|
||||
"image2ImageGuideHint": "沒有改圖思路時,可以先去花園挑一個圖生圖提示詞,或貼上匯入碼帶入目前工作區。",
|
||||
"discoverShort": "去發現",
|
||||
"importShort": "貼上匯入碼",
|
||||
"importingStatus": "正在從 Prompt Garden 取得提示詞和圖片資源..."
|
||||
|
||||
Reference in new issue
Block a user