models
This commit is contained in:
@@ -231,6 +231,18 @@ const onUseResultAsAsset = () => {
|
||||
<div class="flex flex-col gap-3 bg-black/20 p-4 rounded-xl border border-white/5">
|
||||
<!-- Grid for main params -->
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<span class="text-[10px] text-slate-500 uppercase">Model</span>
|
||||
<span class="text-xs text-violet-400 font-bold truncate" :title="previewImage.gen.model">{{ previewImage.gen.model || 'N/A' }}</span>
|
||||
</div>
|
||||
<div v-if="previewImage.gen.seed !== undefined && previewImage.gen.seed !== null" class="flex flex-col gap-0.5">
|
||||
<span class="text-[10px] text-slate-500 uppercase">Seed</span>
|
||||
<div class="flex items-center gap-1">
|
||||
<span class="text-xs text-slate-200 font-mono">{{ previewImage.gen.seed }}</span>
|
||||
<Button icon="pi pi-copy" @click="copyToClipboard(previewImage.gen.seed.toString())"
|
||||
text class="!p-0 !w-3 !h-3 !text-slate-500 hover:!text-white" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<span class="text-[10px] text-slate-500 uppercase">Quality</span>
|
||||
<span class="text-xs text-slate-200 font-semibold">{{ previewImage.gen.quality || 'N/A' }}</span>
|
||||
|
||||
@@ -516,17 +516,7 @@ const prompt = ref('')
|
||||
const isGenerating = ref(false)
|
||||
const generationStatus = ref('')
|
||||
const generationProgress = ref(0)
|
||||
const sendToTelegram = ref(false)
|
||||
const useProfileImage = ref(true)
|
||||
const telegramId = ref(localStorage.getItem('telegram_id') || '')
|
||||
const isTelegramIdSaved = ref(!!localStorage.getItem('telegram_id'))
|
||||
|
||||
const saveTelegramId = () => {
|
||||
if (telegramId.value) {
|
||||
localStorage.setItem('telegram_id', telegramId.value)
|
||||
isTelegramIdSaved.value = true
|
||||
}
|
||||
}
|
||||
const generationSuccess = ref(false)
|
||||
const generationError = ref(null)
|
||||
const generatedResult = ref(null)
|
||||
@@ -539,6 +529,12 @@ const previousPrompt = ref('')
|
||||
const isUploading = ref(false)
|
||||
const fileInput = ref(null)
|
||||
|
||||
const model = ref({ key: 'gemini-3-pro-image-preview', value: 'Pro' })
|
||||
const modelOptions = ref([
|
||||
{ key: 'gemini-3.1-flash-image-preview', value: '2' },
|
||||
{ key: 'gemini-3-pro-image-preview', value: 'Pro' }
|
||||
])
|
||||
|
||||
const selectedAssets = ref([])
|
||||
const toggleAssetSelection = (asset) => {
|
||||
const index = selectedAssets.value.findIndex(a => a.id === asset.id)
|
||||
@@ -558,9 +554,6 @@ const quality = ref({
|
||||
value: '2K'
|
||||
})
|
||||
const qualityOptions = ref([{
|
||||
key: 'ONEK',
|
||||
value: '1K'
|
||||
}, {
|
||||
key: 'TWOK',
|
||||
value: '2K'
|
||||
}, {
|
||||
@@ -729,6 +722,10 @@ const restoreGeneration = async (gen) => {
|
||||
// 1. Set prompt
|
||||
prompt.value = gen.prompt
|
||||
|
||||
// 1.1 Set Model
|
||||
const foundModel = modelOptions.value.find(opt => opt.key === gen.model)
|
||||
if (foundModel) model.value = foundModel
|
||||
|
||||
// 2. Set Quality
|
||||
const foundQuality = qualityOptions.value.find(opt => opt.key === gen.quality)
|
||||
if (foundQuality) quality.value = foundQuality
|
||||
@@ -898,25 +895,14 @@ const handleGenerate = async () => {
|
||||
generatedResult.value = null
|
||||
|
||||
try {
|
||||
if (sendToTelegram.value && !telegramId.value) {
|
||||
alert("Please enter your Telegram ID")
|
||||
isGenerating.value = false
|
||||
return
|
||||
}
|
||||
|
||||
if (telegramId.value && telegramId.value !== localStorage.getItem('telegram_id')) {
|
||||
localStorage.setItem('telegram_id', telegramId.value)
|
||||
isTelegramIdSaved.value = true
|
||||
}
|
||||
|
||||
const payload = {
|
||||
model: model.value.key,
|
||||
linked_character_id: character.value?.id,
|
||||
environment_id: selectedEnvironment.value?.id || selectedEnvironment.value?._id || null,
|
||||
aspect_ratio: aspectRatio.value.key,
|
||||
quality: quality.value.key,
|
||||
prompt: prompt.value,
|
||||
assets_list: selectedAssets.value.map(a => a.id),
|
||||
telegram_id: sendToTelegram.value ? telegramId.value : null,
|
||||
use_profile_image: useProfileImage.value,
|
||||
count: generationCount.value
|
||||
}
|
||||
@@ -1047,34 +1033,48 @@ const handleGenerate = async () => {
|
||||
<h2 class="text-sm font-bold m-0">Settings</h2>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<label
|
||||
class="text-slate-400 text-[9px] font-semibold uppercase tracking-wider">Quality</label>
|
||||
<div
|
||||
class="!flex !w-full !justify-between items-center justify-center !bg-slate-900/50 !p-1 gap-1 !rounded-lg !border !border-white/10">
|
||||
<div v-for="option in qualityOptions" :key="option.key"
|
||||
@click="quality = option"
|
||||
class="w-full items-center justify-center justify-items-center !text-center hover:bg-white/5 hover:text-white p-1 hover:rounded-lg"
|
||||
:class="quality.key === option.key ? 'bg-white/9 text-white rounded-lg' : ''">
|
||||
<span class="text-white w-full text-center">{{ option.value }}</span>
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<label
|
||||
class="text-slate-400 text-[9px] font-semibold uppercase tracking-wider">Model</label>
|
||||
<div
|
||||
class="!flex !w-full !justify-between items-center justify-center !bg-slate-900/50 !p-1 gap-1 !rounded-lg !border !border-white/10">
|
||||
<div v-for="option in modelOptions" :key="option.key"
|
||||
@click="model = option"
|
||||
class="w-full items-center justify-center justify-items-center !text-center hover:bg-white/5 hover:text-white p-1 hover:rounded-lg cursor-pointer"
|
||||
:class="model.key === option.key ? 'bg-white/10 text-white rounded-lg shadow-sm' : 'text-slate-500'">
|
||||
<span class="text-white w-full text-center text-[8px]">{{ option.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<label
|
||||
class="text-slate-400 text-[9px] font-semibold uppercase tracking-wider">Aspect</label>
|
||||
<div
|
||||
class="!flex !w-full !justify-between items-center justify-center !bg-slate-900/50 !p-1 gap-1 !rounded-lg !border !border-white/10">
|
||||
<div v-for="option in aspectRatioOptions" :key="option.key"
|
||||
@click="aspectRatio = option"
|
||||
class="w-full items-center justify-center justify-items-center !text-center hover:bg-white/5 hover:text-white p-1 hover:rounded-lg"
|
||||
:class="aspectRatio.key === option.key ? 'bg-white/9 text-white rounded-lg' : ''">
|
||||
<span class="text-white w-full text-center">{{ option.value }}</span>
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<label
|
||||
class="text-slate-400 text-[9px] font-semibold uppercase tracking-wider">Quality</label>
|
||||
<div
|
||||
class="!flex !w-full !justify-between items-center justify-center !bg-slate-900/50 !p-1 gap-1 !rounded-lg !border !border-white/10">
|
||||
<div v-for="option in qualityOptions" :key="option.key"
|
||||
@click="quality = option"
|
||||
class="w-full items-center justify-center justify-items-center !text-center hover:bg-white/5 hover:text-white p-1 hover:rounded-lg cursor-pointer"
|
||||
:class="quality.key === option.key ? 'bg-white/10 text-white rounded-lg' : ''">
|
||||
<span class="text-white w-full text-center text-[8px]">{{ option.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<label
|
||||
class="text-slate-400 text-[9px] font-semibold uppercase tracking-wider">Aspect</label>
|
||||
<div
|
||||
class="!flex !w-full !justify-between items-center justify-center !bg-slate-900/50 !p-1 gap-1 !rounded-lg !border !border-white/10">
|
||||
<div v-for="option in aspectRatioOptions" :key="option.key"
|
||||
@click="aspectRatio = option"
|
||||
class="w-full items-center justify-center justify-items-center !text-center hover:bg-white/5 hover:text-white p-1 hover:rounded-lg cursor-pointer"
|
||||
:class="aspectRatio.key === option.key ? 'bg-white/10 text-white rounded-lg' : ''">
|
||||
<span class="text-white w-full text-center text-[8px]">{{ option.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1.5">
|
||||
@@ -1162,18 +1162,6 @@ const handleGenerate = async () => {
|
||||
|
||||
<div class="flex flex-col gap-1.5 mt-auto pt-1.5 border-t border-white/5">
|
||||
<div class="flex flex-col gap-2 mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<Checkbox v-model="sendToTelegram" :binary="true"
|
||||
inputId="tg-check-char" />
|
||||
<label for="tg-check-char"
|
||||
class="text-[10px] text-slate-400 cursor-pointer select-none">Send
|
||||
result to Telegram</label>
|
||||
</div>
|
||||
<div v-if="sendToTelegram && !isTelegramIdSaved"
|
||||
class="animate-in fade-in slide-in-from-top-1 duration-200">
|
||||
<InputText v-model="telegramId" placeholder="Enter Telegram ID"
|
||||
class="w-full !text-[16px] !py-1" @blur="saveTelegramId" />
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mt-1">
|
||||
<Checkbox v-model="useProfileImage" :binary="true"
|
||||
inputId="profile-img-check" />
|
||||
|
||||
@@ -151,12 +151,14 @@ const assetPickerTab = ref('all') // 'all', 'uploaded', 'generated'
|
||||
const modalAssets = ref([])
|
||||
const isModalLoading = ref(false)
|
||||
const tempSelectedAssets = ref([])
|
||||
const model = ref({ key: 'gemini-3-pro-image-preview', value: 'Pro' })
|
||||
const modelOptions = ref([
|
||||
{ key: 'gemini-3.1-flash-image-preview', value: '2' },
|
||||
{ key: 'gemini-3-pro-image-preview', value: 'Pro' }
|
||||
])
|
||||
const quality = ref({ key: 'TWOK', value: '2K' })
|
||||
const aspectRatio = ref('NINESIXTEEN') // Default to Video (9:16)
|
||||
const generationCount = ref(1)
|
||||
const sendToTelegram = ref(false)
|
||||
const telegramId = ref('')
|
||||
const isTelegramIdSaved = ref(false)
|
||||
const useProfileImage = ref(true)
|
||||
const useEnvironment = ref(false)
|
||||
const isImprovingPrompt = ref(false)
|
||||
@@ -214,7 +216,6 @@ const onlyLiked = ref(false)
|
||||
|
||||
// Options
|
||||
const qualityOptions = ref([
|
||||
{ key: 'ONEK', value: '1K' },
|
||||
{ key: 'TWOK', value: '2K' },
|
||||
{ key: 'FOURK', value: '4K' }
|
||||
])
|
||||
@@ -225,24 +226,17 @@ const STORAGE_KEY = 'flexible_gen_settings'
|
||||
const saveSettings = () => {
|
||||
const settings = {
|
||||
prompt: prompt.value,
|
||||
model: model.value,
|
||||
selectedCharacterId: selectedCharacter.value?.id || selectedCharacter.value?._id,
|
||||
selectedEnvironmentId: selectedEnvironment.value?.id || selectedEnvironment.value?._id,
|
||||
selectedAssetIds: selectedAssets.value.map(a => a.id),
|
||||
quality: quality.value,
|
||||
aspectRatio: aspectRatio.value,
|
||||
sendToTelegram: sendToTelegram.value,
|
||||
telegramId: telegramId.value,
|
||||
useProfileImage: useProfileImage.value,
|
||||
useEnvironment: useEnvironment.value,
|
||||
generationCount: generationCount.value
|
||||
}
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(settings))
|
||||
|
||||
// Also save Telegram ID separately as it's used elsewhere
|
||||
if (telegramId.value) {
|
||||
localStorage.setItem('telegram_id', telegramId.value)
|
||||
isTelegramIdSaved.value = true
|
||||
}
|
||||
}
|
||||
|
||||
const restoreSettings = () => {
|
||||
@@ -254,6 +248,7 @@ const restoreSettings = () => {
|
||||
|
||||
// We need characters and assets loaded to fully restore objects
|
||||
// For now, we'll store IDs and restore in loadData
|
||||
if (settings.model) model.value = settings.model
|
||||
if (settings.quality) quality.value = settings.quality
|
||||
if (settings.aspectRatio) {
|
||||
// Handle legacy object format if present
|
||||
@@ -263,9 +258,6 @@ const restoreSettings = () => {
|
||||
aspectRatio.value = settings.aspectRatio
|
||||
}
|
||||
}
|
||||
sendToTelegram.value = settings.sendToTelegram || false
|
||||
telegramId.value = settings.telegramId || localStorage.getItem('telegram_id') || ''
|
||||
if (telegramId.value) isTelegramIdSaved.value = true
|
||||
if (settings.useProfileImage !== undefined) useProfileImage.value = settings.useProfileImage
|
||||
if (settings.useEnvironment !== undefined) useEnvironment.value = settings.useEnvironment
|
||||
if (settings.generationCount) generationCount.value = Math.min(settings.generationCount, 4)
|
||||
@@ -280,7 +272,7 @@ const restoreSettings = () => {
|
||||
}
|
||||
|
||||
// Watchers for auto-save
|
||||
watch([prompt, selectedCharacter, selectedEnvironment, selectedAssets, quality, aspectRatio, sendToTelegram, telegramId, useProfileImage, useEnvironment, generationCount], () => {
|
||||
watch([prompt, selectedCharacter, selectedEnvironment, selectedAssets, quality, aspectRatio, useProfileImage, useEnvironment, generationCount], () => {
|
||||
saveSettings()
|
||||
}, { deep: true })
|
||||
|
||||
@@ -412,11 +404,6 @@ const refreshHistory = async () => {
|
||||
const handleGenerate = async () => {
|
||||
if (!prompt.value.trim()) return
|
||||
|
||||
if (sendToTelegram.value && !telegramId.value) {
|
||||
alert("Please enter your Telegram ID")
|
||||
return
|
||||
}
|
||||
|
||||
isSubmitting.value = true
|
||||
|
||||
// Close settings to show gallery/progress (optional preference)
|
||||
@@ -424,13 +411,13 @@ const handleGenerate = async () => {
|
||||
|
||||
try {
|
||||
const payload = {
|
||||
model: model.value.key,
|
||||
aspect_ratio: aspectRatio.value, // Now a string
|
||||
quality: quality.value.key,
|
||||
prompt: prompt.value,
|
||||
assets_list: selectedAssets.value.map(a => a.id),
|
||||
linked_character_id: selectedCharacter.value?.id || selectedCharacter.value?._id || null,
|
||||
environment_id: (selectedCharacter.value && useEnvironment.value) ? (selectedEnvironment.value?.id || selectedEnvironment.value?._id || null) : null,
|
||||
telegram_id: sendToTelegram.value ? telegramId.value : null,
|
||||
use_profile_image: selectedCharacter.value ? useProfileImage.value : false,
|
||||
count: generationCount.value
|
||||
}
|
||||
@@ -1180,31 +1167,42 @@ const confirmAddToAlbum = async () => {
|
||||
</div>
|
||||
|
||||
<div class="w-full lg:w-80 flex flex-col gap-4">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-xs font-bold text-slate-400 uppercase tracking-wider">Quality</label>
|
||||
<Dropdown v-model="quality" :options="qualityOptions" optionLabel="value"
|
||||
class="w-full !bg-slate-800 !border-white/10 !text-white !rounded-xl"
|
||||
:pt="{ input: { class: '!text-white' }, trigger: { class: '!text-slate-400' }, panel: { class: '!bg-slate-800 !border-white/10' }, item: { class: '!text-slate-300 hover:!bg-white/10 hover:!text-white' } }" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-xs font-bold text-slate-400 uppercase tracking-wider">Format</label>
|
||||
<div class="flex items-center">
|
||||
<div class="flex-1 flex bg-slate-800 rounded-xl border border-white/10 overflow-hidden">
|
||||
<button @click="aspectRatio = 'THREEFOUR'"
|
||||
class="flex-1 py-2 text-sm font-bold transition-all flex items-center justify-center gap-1"
|
||||
:class="aspectRatio === 'THREEFOUR' ? 'bg-violet-600 text-white' : 'text-slate-400 hover:text-white hover:bg-white/5'">
|
||||
<i class="pi pi-image"></i> Photo
|
||||
</button>
|
||||
<div class="w-px bg-white/10"></div>
|
||||
<button @click="aspectRatio = 'NINESIXTEEN'"
|
||||
class="flex-1 py-2 text-sm font-bold transition-all flex items-center justify-center gap-1"
|
||||
:class="aspectRatio === 'NINESIXTEEN' ? 'bg-violet-600 text-white' : 'text-slate-400 hover:text-white hover:bg-white/5'">
|
||||
<i class="pi pi-video"></i> Video
|
||||
</button>
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Model</label>
|
||||
<div class="flex bg-slate-800 p-1 rounded-xl border border-white/10 h-[34px]">
|
||||
<div v-for="option in modelOptions" :key="option.key" @click="model = option"
|
||||
class="flex-1 flex items-center justify-center cursor-pointer rounded-md text-[10px] font-bold transition-all"
|
||||
:class="model.key === option.key ? 'bg-white/10 text-white shadow-sm' : 'text-slate-500 hover:text-slate-300'">
|
||||
{{ option.value }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Quality</label>
|
||||
<div class="flex bg-slate-800 p-1 rounded-xl border border-white/10 h-[34px]">
|
||||
<div v-for="option in qualityOptions" :key="option.key" @click="quality = option"
|
||||
class="flex-1 flex items-center justify-center cursor-pointer rounded-md text-[10px] font-bold transition-all"
|
||||
:class="quality.key === option.key ? 'bg-white/10 text-white shadow-sm' : 'text-slate-500 hover:text-slate-300'">
|
||||
{{ option.value }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Format</label>
|
||||
<div class="flex bg-slate-800 rounded-xl border border-white/10 h-[34px] p-1">
|
||||
<button @click="aspectRatio = 'THREEFOUR'"
|
||||
class="flex-1 text-[10px] font-bold transition-all flex items-center justify-center rounded-md"
|
||||
:class="aspectRatio === 'THREEFOUR' ? 'bg-white/10 text-white shadow-sm' : 'text-slate-500 hover:text-white hover:bg-white/5'">
|
||||
<i class="pi pi-image"></i>
|
||||
</button>
|
||||
<button @click="aspectRatio = 'NINESIXTEEN'"
|
||||
class="flex-1 text-[10px] font-bold transition-all flex items-center justify-center rounded-md"
|
||||
:class="aspectRatio === 'NINESIXTEEN' ? 'bg-white/10 text-white shadow-sm' : 'text-slate-500 hover:text-white hover:bg-white/5'">
|
||||
<i class="pi pi-video"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Generation Count -->
|
||||
@@ -1221,18 +1219,6 @@ const confirmAddToAlbum = async () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2 bg-slate-800/50 p-3 rounded-xl border border-white/5">
|
||||
<div class="flex items-center gap-2">
|
||||
<Checkbox v-model="sendToTelegram" :binary="true" inputId="tg-check" />
|
||||
<label for="tg-check" class="text-xs text-slate-300 cursor-pointer">Send to
|
||||
Telegram</label>
|
||||
</div>
|
||||
<div v-if="sendToTelegram" class="animate-in fade-in slide-in-from-top-1">
|
||||
<InputText v-model="telegramId" placeholder="Telegram ID"
|
||||
class="w-full !text-[16px] !bg-slate-900 !border-white/10 !text-white !py-1.5" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-auto">
|
||||
<Button :label="isSubmitting ? 'Starting...' : 'Generate'"
|
||||
:icon="isSubmitting ? 'pi pi-spin pi-spinner' : 'pi pi-sparkles'"
|
||||
|
||||
@@ -76,7 +76,12 @@ const saveName = async () => {
|
||||
|
||||
const prompt = ref('')
|
||||
const negativePrompt = ref('')
|
||||
const selectedModel = ref('flux-schnell')
|
||||
const model = ref({ key: 'gemini-3-pro-image-preview', value: 'Pro' })
|
||||
const modelOptions = ref([
|
||||
{ key: 'gemini-3.1-flash-image-preview', value: '2' },
|
||||
{ key: 'gemini-3-pro-image-preview', value: 'Pro' }
|
||||
])
|
||||
const selectedModel = ref('flux-schnell') // Keep legacy if needed elsewhere, but we will use 'model' for generation
|
||||
|
||||
// Character & Assets (declared early for settings persistence)
|
||||
const characters = ref([])
|
||||
@@ -91,8 +96,6 @@ const SETTINGS_KEY = 'idea-gen-settings'
|
||||
const quality = ref({ key: 'TWOK', value: '2K' })
|
||||
const aspectRatio = ref('NINESIXTEEN') // Default to Video (9:16)
|
||||
const imageCount = ref(1)
|
||||
const sendToTelegram = ref(false)
|
||||
const telegramId = ref('')
|
||||
const useProfileImage = ref(true)
|
||||
const useEnvironment = ref(false)
|
||||
const isImprovingPrompt = ref(false)
|
||||
@@ -135,12 +138,11 @@ watch(selectedCharacter, (newChar) => {
|
||||
const saveSettings = () => {
|
||||
const settings = {
|
||||
prompt: prompt.value,
|
||||
model: model.value,
|
||||
quality: quality.value,
|
||||
aspectRatio: aspectRatio.value,
|
||||
imageCount: imageCount.value,
|
||||
selectedModel: selectedModel.value,
|
||||
sendToTelegram: sendToTelegram.value,
|
||||
telegramId: telegramId.value,
|
||||
useProfileImage: useProfileImage.value,
|
||||
useEnvironment: useEnvironment.value,
|
||||
selectedCharacterId: selectedCharacter.value?.id || selectedCharacter.value?._id || null,
|
||||
@@ -148,9 +150,6 @@ const saveSettings = () => {
|
||||
selectedAssetIds: selectedAssets.value.map(a => a.id),
|
||||
}
|
||||
localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings))
|
||||
if (telegramId.value) {
|
||||
localStorage.setItem('telegram_id', telegramId.value)
|
||||
}
|
||||
}
|
||||
|
||||
const restoreSettings = () => {
|
||||
@@ -158,6 +157,7 @@ const restoreSettings = () => {
|
||||
if (!stored) return
|
||||
try {
|
||||
const s = JSON.parse(stored)
|
||||
if (s.model) model.value = s.model
|
||||
if (s.prompt) prompt.value = s.prompt
|
||||
if (s.quality) quality.value = s.quality
|
||||
if (s.aspectRatio) {
|
||||
@@ -170,8 +170,6 @@ const restoreSettings = () => {
|
||||
}
|
||||
if (s.imageCount) imageCount.value = Math.min(s.imageCount, 4)
|
||||
if (s.selectedModel) selectedModel.value = s.selectedModel
|
||||
sendToTelegram.value = s.sendToTelegram || false
|
||||
telegramId.value = s.telegramId || localStorage.getItem('telegram_id') || ''
|
||||
if (s.useProfileImage !== undefined) useProfileImage.value = s.useProfileImage
|
||||
if (s.useEnvironment !== undefined) useEnvironment.value = s.useEnvironment
|
||||
_savedCharacterId = s.selectedCharacterId || null
|
||||
@@ -189,7 +187,7 @@ const restoreSettings = () => {
|
||||
}
|
||||
restoreSettings()
|
||||
|
||||
watch([prompt, quality, aspectRatio, imageCount, selectedModel, sendToTelegram, telegramId, useProfileImage, useEnvironment, selectedCharacter, selectedEnvironment, selectedAssets], saveSettings, { deep: true })
|
||||
watch([prompt, quality, aspectRatio, imageCount, model, useProfileImage, useEnvironment, selectedCharacter, selectedEnvironment, selectedAssets], saveSettings, { deep: true })
|
||||
|
||||
const viewMode = ref('feed') // 'feed' or 'gallery'
|
||||
const onlyLiked = ref(false)
|
||||
@@ -203,7 +201,6 @@ watch(isSettingsVisible, (val) => {
|
||||
const API_URL = import.meta.env.VITE_API_URL
|
||||
|
||||
const qualityOptions = ref([
|
||||
{ key: 'ONEK', value: '1K' },
|
||||
{ key: 'TWOK', value: '2K' },
|
||||
{ key: 'FOURK', value: '4K' }
|
||||
])
|
||||
@@ -306,13 +303,13 @@ const handleGenerate = async () => {
|
||||
try {
|
||||
// Construct Payload
|
||||
const payload = {
|
||||
model: model.value.key,
|
||||
prompt: prompt.value,
|
||||
aspect_ratio: aspectRatio.value, // Now a string
|
||||
quality: quality.value.key,
|
||||
assets_list: selectedAssets.value.map(a => a.id),
|
||||
linked_character_id: selectedCharacter.value?.id || selectedCharacter.value?._id || null,
|
||||
environment_id: (selectedCharacter.value && useEnvironment.value) ? (selectedEnvironment.value?.id || selectedEnvironment.value?._id || null) : null,
|
||||
telegram_id: sendToTelegram.value ? telegramId.value : null,
|
||||
use_profile_image: selectedCharacter.value ? useProfileImage.value : false,
|
||||
count: imageCount.value,
|
||||
idea_id: currentIdea.value.id
|
||||
@@ -1426,31 +1423,39 @@ const markNsfw = async (gen) => {
|
||||
</div> </div>
|
||||
|
||||
<div class="w-full lg:w-72 flex flex-col gap-2">
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Model</label>
|
||||
<div class="flex bg-slate-800 p-1 rounded-xl border border-white/10">
|
||||
<div v-for="option in modelOptions" :key="option.key" @click="model = option"
|
||||
class="flex-1 text-center py-1 text-[10px] font-medium transition-all cursor-pointer rounded-md"
|
||||
:class="model.key === option.key ? 'bg-white/10 text-white shadow-sm' : 'text-slate-500 hover:text-slate-300'">
|
||||
{{ option.value }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<label
|
||||
class="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Quality</label>
|
||||
<Dropdown v-model="quality" :options="qualityOptions" optionLabel="value"
|
||||
class="w-full !bg-slate-800 !border-white/10 !text-white !rounded-xl"
|
||||
:pt="{ input: { class: '!text-white' }, trigger: { class: '!text-slate-400' }, panel: { class: '!bg-slate-800 !border-white/10' }, item: { class: '!text-slate-300 hover:!bg-white/10 hover:!text-white' } }" />
|
||||
class="w-full !bg-slate-800 !border-white/10 !text-white !rounded-xl !h-[34px]"
|
||||
:pt="{ input: { class: '!text-white !text-[10px] !py-1 !px-2' }, trigger: { class: '!text-slate-400 !w-6' }, panel: { class: '!bg-slate-800 !border-white/10' }, item: { class: '!text-slate-300 hover:!bg-white/10 hover:!text-white !text-[10px] !py-1' } }" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<label
|
||||
class="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Format</label>
|
||||
<div class="flex items-center">
|
||||
<div class="flex-1 flex bg-slate-800 rounded-lg border border-white/10 overflow-hidden">
|
||||
<button @click="aspectRatio = 'THREEFOUR'"
|
||||
class="flex-1 py-1 text-xs font-bold transition-all flex items-center justify-center gap-1"
|
||||
:class="aspectRatio === 'THREEFOUR' ? 'bg-violet-600 text-white' : 'text-slate-400 hover:text-white hover:bg-white/5'">
|
||||
<i class="pi pi-image"></i> Photo
|
||||
</button>
|
||||
<div class="w-px bg-white/10"></div>
|
||||
<button @click="aspectRatio = 'NINESIXTEEN'"
|
||||
class="flex-1 py-1 text-xs font-bold transition-all flex items-center justify-center gap-1"
|
||||
:class="aspectRatio === 'NINESIXTEEN' ? 'bg-violet-600 text-white' : 'text-slate-400 hover:text-white hover:bg-white/5'">
|
||||
<i class="pi pi-video"></i> Video
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex bg-slate-800 rounded-xl border border-white/10 overflow-hidden h-[34px]">
|
||||
<button @click="aspectRatio = 'THREEFOUR'"
|
||||
class="flex-1 text-[10px] font-bold transition-all flex items-center justify-center"
|
||||
:class="aspectRatio === 'THREEFOUR' ? 'bg-violet-600 text-white' : 'text-slate-400 hover:text-white hover:bg-white/5'">
|
||||
<i class="pi pi-image"></i>
|
||||
</button>
|
||||
<div class="w-px bg-white/10"></div>
|
||||
<button @click="aspectRatio = 'NINESIXTEEN'"
|
||||
class="flex-1 text-[10px] font-bold transition-all flex items-center justify-center"
|
||||
:class="aspectRatio === 'NINESIXTEEN' ? 'bg-violet-600 text-white' : 'text-slate-400 hover:text-white hover:bg-white/5'">
|
||||
<i class="pi pi-video"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1469,18 +1474,6 @@ const markNsfw = async (gen) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1 bg-slate-800/50 p-2 rounded-lg border border-white/5">
|
||||
<div class="flex items-center gap-2">
|
||||
<Checkbox v-model="sendToTelegram" :binary="true" inputId="idea-tg-check" />
|
||||
<label for="idea-tg-check" class="text-xs text-slate-300 cursor-pointer">Send to
|
||||
Telegram</label>
|
||||
</div>
|
||||
<div v-if="sendToTelegram" class="animate-in fade-in slide-in-from-top-1">
|
||||
<InputText v-model="telegramId" placeholder="Telegram ID"
|
||||
class="w-full !text-[16px] !bg-slate-900 !border-white/10 !text-white !py-1.5" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- NSFW Toggle -->
|
||||
<div class="flex flex-col gap-1 bg-slate-800/50 p-2 rounded-lg border border-white/5">
|
||||
<div class="flex items-center justify-between">
|
||||
|
||||
@@ -187,12 +187,15 @@ const startIdeaFromInspiration = (inspiration) => {
|
||||
|
||||
// --- Generation Settings ---
|
||||
const prompt = ref('')
|
||||
const model = ref({ key: 'gemini-3-pro-image-preview', value: 'Pro' })
|
||||
const modelOptions = ref([
|
||||
{ key: 'gemini-3.1-flash-image-preview', value: '2' },
|
||||
{ key: 'gemini-3-pro-image-preview', value: 'Pro' }
|
||||
])
|
||||
const selectedModel = ref('flux-schnell')
|
||||
const quality = ref({ key: 'TWOK', value: '2K' })
|
||||
const aspectRatio = ref({ key: 'NINESIXTEEN', value: '9:16' })
|
||||
const imageCount = ref(1)
|
||||
const sendToTelegram = ref(false)
|
||||
const telegramId = ref('')
|
||||
const useProfileImage = ref(true)
|
||||
const useEnvironment = ref(false)
|
||||
const isSubmittingGen = ref(false)
|
||||
@@ -232,7 +235,6 @@ watch(selectedCharacter, (newChar) => {
|
||||
})
|
||||
|
||||
const qualityOptions = ref([
|
||||
{ key: 'ONEK', value: '1K' },
|
||||
{ key: 'TWOK', value: '2K' },
|
||||
{ key: 'FOURK', value: '4K' }
|
||||
])
|
||||
@@ -256,13 +258,12 @@ const restoreSettings = () => {
|
||||
if (!stored) return
|
||||
try {
|
||||
const s = JSON.parse(stored)
|
||||
if (s.model) model.value = s.model
|
||||
if (s.prompt) prompt.value = s.prompt
|
||||
if (s.quality) quality.value = s.quality
|
||||
if (s.aspectRatio) aspectRatio.value = s.aspectRatio
|
||||
if (s.imageCount) imageCount.value = Math.min(s.imageCount, 4)
|
||||
if (s.selectedModel) selectedModel.value = s.selectedModel
|
||||
sendToTelegram.value = s.sendToTelegram || false
|
||||
telegramId.value = s.telegramId || localStorage.getItem('telegram_id') || ''
|
||||
if (s.useProfileImage !== undefined) useProfileImage.value = s.useProfileImage
|
||||
if (s.useEnvironment !== undefined) useEnvironment.value = s.useEnvironment
|
||||
_savedCharacterId = s.selectedCharacterId || null
|
||||
@@ -283,12 +284,11 @@ const restoreSettings = () => {
|
||||
const saveSettings = () => {
|
||||
const settings = {
|
||||
prompt: prompt.value,
|
||||
model: model.value,
|
||||
quality: quality.value,
|
||||
aspectRatio: aspectRatio.value,
|
||||
imageCount: imageCount.value,
|
||||
selectedModel: selectedModel.value,
|
||||
sendToTelegram: sendToTelegram.value,
|
||||
telegramId: telegramId.value,
|
||||
useProfileImage: useProfileImage.value,
|
||||
useEnvironment: useEnvironment.value,
|
||||
selectedCharacterId: selectedCharacter.value?.id || null,
|
||||
@@ -296,10 +296,9 @@ const saveSettings = () => {
|
||||
selectedAssetIds: selectedAssets.value.map(a => a.id),
|
||||
}
|
||||
localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings))
|
||||
if (telegramId.value) localStorage.setItem('telegram_id', telegramId.value)
|
||||
}
|
||||
|
||||
watch([prompt, quality, aspectRatio, imageCount, selectedModel, sendToTelegram, telegramId, useProfileImage, useEnvironment, selectedCharacter, selectedEnvironment, selectedAssets], saveSettings, { deep: true })
|
||||
watch([prompt, quality, aspectRatio, imageCount, model, useProfileImage, useEnvironment, selectedCharacter, selectedEnvironment, selectedAssets], saveSettings, { deep: true })
|
||||
|
||||
onMounted(async () => {
|
||||
restoreSettings()
|
||||
@@ -834,18 +833,37 @@ const handleAssetPickerUpload = async (event) => {
|
||||
|
||||
<!-- RIGHT COLUMN: Settings & Button -->
|
||||
<div class="w-full lg:w-72 flex flex-col gap-2">
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Model</label>
|
||||
<div class="flex bg-slate-800 p-1 rounded-xl border border-white/10">
|
||||
<div v-for="option in modelOptions" :key="option.key" @click="model = option"
|
||||
class="flex-1 text-center py-1 text-[10px] font-medium transition-all cursor-pointer rounded-md"
|
||||
:class="model.key === option.key ? 'bg-white/10 text-white shadow-sm' : 'text-slate-500 hover:text-slate-300'">
|
||||
{{ option.value }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Quality</label>
|
||||
<Dropdown v-model="quality" :options="qualityOptions" optionLabel="value"
|
||||
class="w-full !bg-slate-800 !border-white/10 !text-white !rounded-xl"
|
||||
:pt="{ input: { class: '!text-white' }, trigger: { class: '!text-slate-400' }, panel: { class: '!bg-slate-800 !border-white/10' }, item: { class: '!text-slate-300 hover:!bg-white/10 hover:!text-white' } }" />
|
||||
<div class="flex bg-slate-800 p-1 rounded-xl border border-white/10 h-[34px]">
|
||||
<div v-for="option in qualityOptions" :key="option.key" @click="quality = option"
|
||||
class="flex-1 flex items-center justify-center cursor-pointer rounded-md text-[10px] font-bold transition-all"
|
||||
:class="quality.key === option.key ? 'bg-white/10 text-white shadow-sm' : 'text-slate-500 hover:text-slate-300'">
|
||||
{{ option.value }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Ratio</label>
|
||||
<Dropdown v-model="aspectRatio" :options="aspectRatioOptions" optionLabel="value"
|
||||
class="w-full !bg-slate-800 !border-white/10 !text-white !rounded-xl"
|
||||
:pt="{ input: { class: '!text-white' }, trigger: { class: '!text-slate-400' }, panel: { class: '!bg-slate-800 !border-white/10' }, item: { class: '!text-slate-300 hover:!bg-white/10 hover:!text-white' } }" />
|
||||
class="w-full !bg-slate-800 !border-white/10 !text-white !rounded-xl !h-[34px]"
|
||||
:pt="{
|
||||
input: { class: '!text-white !text-[10px] !py-1 !px-2 !font-bold' },
|
||||
trigger: { class: '!text-slate-400 !w-6' },
|
||||
panel: { class: '!bg-slate-800 !border-white/10' },
|
||||
item: { class: '!text-slate-300 hover:!bg-white/10 hover:!text-white !text-[10px] !py-1' }
|
||||
}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -863,19 +881,6 @@ const handleAssetPickerUpload = async (event) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Telegram (Copied from Detail View) -->
|
||||
<div class="flex flex-col gap-1 bg-slate-800/50 p-2 rounded-lg border border-white/5">
|
||||
<div class="flex items-center gap-2">
|
||||
<Checkbox v-model="sendToTelegram" :binary="true" inputId="idea-tg-check" />
|
||||
<label for="idea-tg-check" class="text-xs text-slate-300 cursor-pointer">Send to
|
||||
Telegram</label>
|
||||
</div>
|
||||
<div v-if="sendToTelegram" class="animate-in fade-in slide-in-from-top-1">
|
||||
<InputText v-model="telegramId" placeholder="Telegram ID"
|
||||
class="w-full !text-[16px] !bg-slate-900 !border-white/10 !text-white !py-1.5" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-auto">
|
||||
<Button :label="isSubmittingGen ? 'Starting...' : 'Generate New Session'"
|
||||
|
||||
@@ -12,6 +12,7 @@ import Dialog from 'primevue/dialog'
|
||||
import Paginator from 'primevue/paginator'
|
||||
import InputText from 'primevue/inputtext'
|
||||
import Tag from 'primevue/tag'
|
||||
import Dropdown from 'primevue/dropdown'
|
||||
import GenerationPreviewModal from '../components/GenerationPreviewModal.vue'
|
||||
|
||||
const router = useRouter()
|
||||
@@ -44,22 +45,17 @@ const assetsTotalRecords = ref(0)
|
||||
const assetsRows = ref(12)
|
||||
const assetsFirst = ref(0)
|
||||
const activeAssetFilter = ref('all')
|
||||
const sendToTelegram = ref(false)
|
||||
const telegramId = ref(localStorage.getItem('telegram_id') || '')
|
||||
const isTelegramIdSaved = ref(!!localStorage.getItem('telegram_id'))
|
||||
const isUploading = ref(false)
|
||||
const fileInput = ref(null)
|
||||
|
||||
const saveTelegramId = () => {
|
||||
if (telegramId.value) {
|
||||
localStorage.setItem('telegram_id', telegramId.value)
|
||||
isTelegramIdSaved.value = true
|
||||
}
|
||||
}
|
||||
const model = ref({ key: 'gemini-3-pro-image-preview', value: 'Pro' })
|
||||
const modelOptions = ref([
|
||||
{ key: 'gemini-3.1-flash-image-preview', value: '2' },
|
||||
{ key: 'gemini-3-pro-image-preview', value: 'Pro' }
|
||||
])
|
||||
|
||||
const quality = ref({ key: 'TWOK', value: '2K' })
|
||||
const qualityOptions = ref([
|
||||
{ key: 'ONEK', value: '1K' },
|
||||
{ key: 'TWOK', value: '2K' },
|
||||
{ key: 'FOURK', value: '4K' }
|
||||
])
|
||||
@@ -186,18 +182,6 @@ const onFileSelected = async (event) => {
|
||||
const handleGenerate = async () => {
|
||||
if (!prompt.value.trim()) return
|
||||
|
||||
// Validation for Telegram
|
||||
if (sendToTelegram.value && !telegramId.value) {
|
||||
alert("Please enter your Telegram ID")
|
||||
return
|
||||
}
|
||||
|
||||
// Save ID if provided
|
||||
if (telegramId.value && telegramId.value !== localStorage.getItem('telegram_id')) {
|
||||
localStorage.setItem('telegram_id', telegramId.value)
|
||||
isTelegramIdSaved.value = true
|
||||
}
|
||||
|
||||
isGenerating.value = true
|
||||
generationSuccess.value = false
|
||||
generationError.value = null
|
||||
@@ -207,12 +191,12 @@ const handleGenerate = async () => {
|
||||
|
||||
try {
|
||||
const payload = {
|
||||
model: model.value.key,
|
||||
aspect_ratio: aspectRatio.value.key,
|
||||
quality: quality.value.key,
|
||||
prompt: prompt.value,
|
||||
assets_list: selectedAssets.value.map(a => a.id),
|
||||
linked_character_id: null, // Explicitly null for global generation
|
||||
telegram_id: sendToTelegram.value ? telegramId.value : null
|
||||
}
|
||||
|
||||
const response = await aiService.runGeneration(payload)
|
||||
@@ -294,6 +278,9 @@ const pollStatus = async (id) => {
|
||||
const restoreGeneration = async (gen) => {
|
||||
prompt.value = gen.prompt
|
||||
|
||||
const foundModel = modelOptions.value.find(opt => opt.key === gen.model)
|
||||
if (foundModel) model.value = foundModel
|
||||
|
||||
const foundQuality = qualityOptions.value.find(opt => opt.key === gen.quality)
|
||||
if (foundQuality) quality.value = foundQuality
|
||||
|
||||
@@ -461,13 +448,23 @@ onMounted(() => {
|
||||
<!-- Settings Card -->
|
||||
<div class="glass-panel p-6 rounded-2xl border border-white/5 bg-white/5 flex flex-col gap-6">
|
||||
|
||||
<!-- Quality & Aspect Ratio -->
|
||||
<div class="grid grid-cols-2 gap-6">
|
||||
<!-- Settings Row: Model, Quality & Aspect Ratio -->
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-xs font-bold text-slate-400 uppercase tracking-wider">Model</label>
|
||||
<div class="flex bg-slate-900/50 p-1 rounded-lg border border-white/10 h-[34px]">
|
||||
<div v-for="option in modelOptions" :key="option.key" @click="model = option"
|
||||
class="flex-1 flex items-center justify-center cursor-pointer rounded-md text-[10px] font-bold transition-all"
|
||||
:class="model.key === option.key ? 'bg-white/10 text-white shadow-sm' : 'text-slate-500 hover:text-slate-300'">
|
||||
{{ option.value }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-xs font-bold text-slate-400 uppercase tracking-wider">Quality</label>
|
||||
<div class="flex bg-slate-900/50 p-1 rounded-lg border border-white/10">
|
||||
<div class="flex bg-slate-900/50 p-1 rounded-lg border border-white/10 h-[34px]">
|
||||
<div v-for="option in qualityOptions" :key="option.key" @click="quality = option"
|
||||
class="flex-1 text-center py-1.5 cursor-pointer rounded-md text-xs font-medium transition-all"
|
||||
class="flex-1 flex items-center justify-center cursor-pointer rounded-md text-[10px] font-bold transition-all"
|
||||
:class="quality.key === option.key ? 'bg-white/10 text-white shadow-sm' : 'text-slate-500 hover:text-slate-300'">
|
||||
{{ option.value }}
|
||||
</div>
|
||||
@@ -476,14 +473,14 @@ onMounted(() => {
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-xs font-bold text-slate-400 uppercase tracking-wider">Aspect
|
||||
Ratio</label>
|
||||
<div class="flex bg-slate-900/50 p-1 rounded-lg border border-white/10">
|
||||
<div v-for="option in aspectRatioOptions" :key="option.key"
|
||||
@click="aspectRatio = option"
|
||||
class="flex-1 text-center py-1.5 cursor-pointer rounded-md text-xs font-medium transition-all"
|
||||
:class="aspectRatio.key === option.key ? 'bg-white/10 text-white shadow-sm' : 'text-slate-500 hover:text-slate-300'">
|
||||
{{ option.value }}
|
||||
</div>
|
||||
</div>
|
||||
<Dropdown v-model="aspectRatio" :options="aspectRatioOptions" optionLabel="value"
|
||||
class="w-full !bg-slate-900/50 !border-white/10 !text-white !rounded-lg !h-[34px]"
|
||||
:pt="{
|
||||
input: { class: '!text-white !text-[10px] !py-1 !px-2 !font-bold' },
|
||||
trigger: { class: '!text-slate-400 !w-6' },
|
||||
panel: { class: '!bg-slate-900 !border-white/10' },
|
||||
item: { class: '!text-slate-300 hover:!bg-white/10 hover:!text-white !text-[10px] !py-1' }
|
||||
}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -551,21 +548,6 @@ onMounted(() => {
|
||||
|
||||
<!-- Generate Button -->
|
||||
<div class="mt-auto">
|
||||
<div class="flex flex-col gap-2 mb-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<Checkbox v-model="sendToTelegram" :binary="true" inputId="tg-check-gen" />
|
||||
<label for="tg-check-gen"
|
||||
class="text-xs text-slate-400 cursor-pointer select-none">Send result to
|
||||
Telegram</label>
|
||||
</div>
|
||||
<div v-if="sendToTelegram && !isTelegramIdSaved"
|
||||
class="animate-in fade-in slide-in-from-top-1 duration-200">
|
||||
<InputText v-model="telegramId" placeholder="Enter Telegram ID"
|
||||
class="w-full !text-[16px] !py-1.5" @blur="saveTelegramId" />
|
||||
<small class="text-[10px] text-slate-500 block mt-0.5">ID will be saved for future
|
||||
use</small>
|
||||
</div>
|
||||
</div>
|
||||
<Button :label="isGenerating ? 'Generating...' : 'Generate Image'"
|
||||
:icon="isGenerating ? 'pi pi-spin pi-spinner' : 'pi pi-magic'" :loading="isGenerating"
|
||||
@click="handleGenerate"
|
||||
|
||||
Reference in New Issue
Block a user