This commit is contained in:
xds
2026-02-19 21:25:48 +03:00
parent 6de5ded2fa
commit 741857de92
5 changed files with 807 additions and 157 deletions

View File

@@ -138,6 +138,8 @@ const confirmAddToPlan = async () => {
// --- State ---
const prompt = ref('')
const selectedCharacter = ref(null)
const environments = ref([])
const selectedEnvironment = ref(null)
const selectedAssets = ref([])
// Album Picker State
const isAlbumPickerVisible = ref(false)
@@ -156,8 +158,34 @@ const sendToTelegram = ref(false)
const telegramId = ref('')
const isTelegramIdSaved = ref(false)
const useProfileImage = ref(true)
const useEnvironment = ref(false)
const isImprovingPrompt = ref(false)
const previousPrompt = ref('')
let _savedEnvironmentId = null
const loadEnvironments = async (charId) => {
if (!charId) {
environments.value = []
selectedEnvironment.value = null
return
}
try {
const response = await dataService.getEnvironments(charId)
environments.value = Array.isArray(response) ? response : (response.environments || [])
if (_savedEnvironmentId) {
selectedEnvironment.value = environments.value.find(e => (e.id === _savedEnvironmentId || e._id === _savedEnvironmentId)) || null
_savedEnvironmentId = null
}
} catch (e) {
console.error('Failed to load environments', e)
environments.value = []
}
}
watch(selectedCharacter, (newChar) => {
loadEnvironments(newChar?.id || newChar?._id)
})
const characters = ref([])
const allAssets = ref([])
@@ -195,13 +223,15 @@ const STORAGE_KEY = 'flexible_gen_settings'
const saveSettings = () => {
const settings = {
prompt: prompt.value,
selectedCharacterId: selectedCharacter.value?.id,
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))
@@ -228,7 +258,9 @@ const restoreSettings = () => {
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)
if (settings.selectedEnvironmentId) _savedEnvironmentId = settings.selectedEnvironmentId
return settings // Return to use in loadData
} catch (e) {
@@ -239,7 +271,7 @@ const restoreSettings = () => {
}
// Watchers for auto-save
watch([prompt, selectedCharacter, selectedAssets, quality, aspectRatio, sendToTelegram, telegramId, useProfileImage, generationCount], () => {
watch([prompt, selectedCharacter, selectedEnvironment, selectedAssets, quality, aspectRatio, sendToTelegram, telegramId, useProfileImage, useEnvironment, generationCount], () => {
saveSettings()
}, { deep: true })
@@ -258,7 +290,7 @@ const loadData = async () => {
const [charsRes, assetsRes, historyRes] = await Promise.all([
dataService.getCharacters(), // Assuming this exists and returns list
dataService.getAssets(100, 0, 'all'), // Load a batch of assets
aiService.getGenerations(historyRows.value, historyFirst.value, filterCharacter.value?.id)
aiService.getGenerations(historyRows.value, historyFirst.value, filterCharacter.value?.id || filterCharacter.value?._id)
])
// Characters
@@ -310,7 +342,7 @@ const loadData = async () => {
const savedSettings = restoreSettings()
if (savedSettings) {
if (savedSettings.selectedCharacterId) {
selectedCharacter.value = characters.value.find(c => c.id === savedSettings.selectedCharacterId) || null
selectedCharacter.value = characters.value.find(c => (c.id === savedSettings.selectedCharacterId || c._id === savedSettings.selectedCharacterId)) || null
}
if (savedSettings.selectedAssetIds && savedSettings.selectedAssetIds.length > 0) {
// Determine which assets to select.
@@ -328,7 +360,7 @@ const loadData = async () => {
const refreshHistory = async () => {
try {
const response = await aiService.getGenerations(historyRows.value, 0, filterCharacter.value?.id)
const response = await aiService.getGenerations(historyRows.value, 0, filterCharacter.value?.id || filterCharacter.value?._id)
if (response && response.generations) {
// Update existing items and add new ones at the top
const newGenerations = []
@@ -380,7 +412,8 @@ const handleGenerate = async () => {
quality: quality.value.key,
prompt: prompt.value,
assets_list: selectedAssets.value.map(a => a.id),
linked_character_id: selectedCharacter.value?.id || null,
linked_character_id: selectedCharacter.value?.id || selectedCharacter.value?._id || null,
environment_id: selectedEnvironment.value?.id || selectedEnvironment.value?._id || null,
telegram_id: sendToTelegram.value ? telegramId.value : null,
use_profile_image: selectedCharacter.value ? useProfileImage.value : false,
count: generationCount.value
@@ -1170,6 +1203,7 @@ const confirmAddToAlbum = async () => {
</div>
<!-- Character & Assets Row -->
<div class="flex flex-col md:flex-row gap-4">
<div class="flex-1 flex flex-col gap-2">
<label class="text-xs font-bold text-slate-400 uppercase tracking-wider">Character
@@ -1203,17 +1237,28 @@ const confirmAddToAlbum = async () => {
</Dropdown>
<div v-if="selectedCharacter"
class="flex items-center gap-2 mt-2 px-1 animate-in fade-in slide-in-from-top-1">
<Checkbox v-model="useProfileImage" :binary="true" inputId="use-profile-img"
class="!border-white/20" :pt="{
box: ({ props, state }) => ({
class: ['!bg-slate-800 !border-white/20', { '!bg-violet-600 !border-violet-600': props.modelValue }]
})
}" />
<label for="use-profile-img"
class="text-xs text-slate-300 cursor-pointer select-none">Use
Character
Photo</label>
class="flex flex-wrap items-center gap-x-4 gap-y-2 mt-2 px-1 animate-in fade-in slide-in-from-top-1">
<div class="flex items-center gap-2">
<Checkbox v-model="useProfileImage" :binary="true" inputId="use-profile-img"
class="!border-white/20" :pt="{
box: ({ props, state }) => ({
class: ['!bg-slate-800 !border-white/20', { '!bg-violet-600 !border-violet-600': props.modelValue }]
})
}" />
<label for="use-profile-img"
class="text-xs text-slate-300 cursor-pointer select-none">Use Photo</label>
</div>
<div class="flex items-center gap-2">
<Checkbox v-model="useEnvironment" :binary="true" inputId="use-env"
class="!border-white/20" :pt="{
box: ({ props, state }) => ({
class: ['!bg-slate-800 !border-white/20', { '!bg-violet-600 !border-violet-600': props.modelValue }]
})
}" />
<label for="use-env"
class="text-xs text-slate-300 cursor-pointer select-none">Use Environment</label>
</div>
</div>
</div>
@@ -1238,6 +1283,47 @@ const confirmAddToAlbum = async () => {
</div>
</div>
</div>
<!-- Environment Row (Below) -->
<div v-if="selectedCharacter && useEnvironment" class="flex flex-col gap-2 animate-in fade-in slide-in-from-top-1 mt-2">
<div class="flex justify-between items-center">
<label class="text-xs font-bold text-slate-400 uppercase tracking-wider">Environment</label>
<Button v-if="selectedEnvironment" icon="pi pi-times" @click="selectedEnvironment = null" text size="small"
class="!p-0 !h-5 !w-5 !text-[10px] text-slate-500 hover:text-white" />
</div>
<div v-if="environments.length > 0" class="flex gap-2 overflow-x-auto pb-2 custom-scrollbar no-scrollbar">
<div v-for="env in environments" :key="env.id || env._id"
@click="selectedEnvironment = env"
class="flex-shrink-0 flex items-center gap-3 px-3 py-2 rounded-xl border-2 transition-all cursor-pointer group bg-slate-800/40"
:class="[
(selectedEnvironment?.id === (env.id || env._id) || selectedEnvironment?._id === (env.id || env._id))
? 'border-violet-500 bg-violet-500/10 shadow-[0_0_20px_rgba(124,58,237,0.15)]'
: 'border-white/5 hover:border-white/20'
]"
>
<div class="w-8 h-8 rounded-lg overflow-hidden flex-shrink-0 bg-slate-900 flex items-center justify-center border border-white/5">
<img v-if="env.asset_ids?.length > 0"
:src="API_URL + '/assets/' + env.asset_ids[0] + '?thumbnail=true'"
class="w-full h-full object-cover"
/>
<i v-else class="pi pi-map-marker text-xs"
:class="(selectedEnvironment?.id === (env.id || env._id) || selectedEnvironment?._id === (env.id || env._id)) ? 'text-violet-400' : 'text-slate-500'"
></i>
</div>
<span class="text-sm whitespace-nowrap pr-1"
:class="(selectedEnvironment?.id === (env.id || env._id) || selectedEnvironment?._id === (env.id || env._id)) ? 'text-violet-300 font-bold' : 'text-slate-400 group-hover:text-slate-200'"
>
{{ env.name }}
</span>
<i v-if="(selectedEnvironment?.id === (env.id || env._id) || selectedEnvironment?._id === (env.id || env._id))"
class="pi pi-check text-violet-400 text-xs"></i>
</div>
</div>
<div v-else class="py-4 px-4 bg-slate-800/50 border border-white/5 rounded-2xl text-center">
<p class="text-xs text-slate-600 uppercase m-0">No environments for this character</p>
</div>
</div>
</div>
<div class="w-full lg:w-80 flex flex-col gap-4">