💬 Commit message: Update 2026-02-14 05:02:03, 19 files, 158 lines
📁 Files changed: 19 📝 Lines changed: 158 • tensors-3rows.png • tensors-all-sizes.png • tensors-final.png • tensors-fixed-align.png • tensors-fresh.png • tensors-labeled-rows.png • tensors-left-align.png • tensors-ratio-buttons.png • tensors-ratio-updated.png • tensors-ratio-v3.png • tensors-table-align.png • index-BPC1k--a.js • index-BvuF0jag.css • index-CP6ArsWF.css • index-CX4x_bxc.js • index.html • GenerateView.vue • app.ts • index.ts
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 54 KiB |
@@ -5,8 +5,8 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Tensors</title>
|
||||
<script type="module" crossorigin src="/assets/index-CX4x_bxc.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BvuF0jag.css">
|
||||
<script type="module" crossorigin src="/assets/index-BPC1k--a.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-CP6ArsWF.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -28,17 +28,6 @@ const loraItems = computed(() => [
|
||||
...store.loras.map(l => ({ title: l.name, value: l.path }))
|
||||
])
|
||||
|
||||
const baseSizes = [
|
||||
{ title: '512', value: 512 },
|
||||
{ title: '768', value: 768 },
|
||||
{ title: '1024', value: 1024 },
|
||||
] as const
|
||||
|
||||
const aspectRatios = [
|
||||
{ title: '3:4', value: '3:4' as const },
|
||||
{ title: '1:1', value: '1:1' as const },
|
||||
{ title: '4:3', value: '4:3' as const },
|
||||
]
|
||||
|
||||
async function handleModelChange(model: string) {
|
||||
if (model && model !== store.activeModel) {
|
||||
@@ -187,22 +176,25 @@ async function generate() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-center ga-2">
|
||||
<span class="text-caption text-grey text-uppercase">Size</span>
|
||||
<v-btn-toggle v-model="store.baseSize" mandatory density="compact" :disabled="generating">
|
||||
<v-btn v-for="s in baseSizes" :key="s.value" :value="s.value" size="small">
|
||||
{{ s.title }}
|
||||
<div class="resolution-grid rounded border pa-2">
|
||||
<div
|
||||
v-for="group in store.presetGroups"
|
||||
:key="group.label"
|
||||
class="d-flex align-center ga-2"
|
||||
>
|
||||
<span class="text-caption text-grey text-uppercase resolution-label">{{ group.label }}</span>
|
||||
<v-btn-toggle
|
||||
v-model="store.selectedPreset"
|
||||
mandatory
|
||||
density="compact"
|
||||
:disabled="generating"
|
||||
class="resolution-row"
|
||||
>
|
||||
<v-btn v-for="p in group.presets" :key="p.id" :value="p.id" size="small" class="resolution-btn">
|
||||
{{ p.label }}
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-center ga-2">
|
||||
<span class="text-caption text-grey text-uppercase">Ratio</span>
|
||||
<v-btn-toggle v-model="store.aspectRatio" mandatory density="compact" :disabled="generating">
|
||||
<v-btn v-for="r in aspectRatios" :key="r.value" :value="r.value" size="small">
|
||||
{{ r.title }}
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-center ga-2">
|
||||
@@ -262,4 +254,29 @@ async function generate() {
|
||||
.border-t {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.resolution-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
border-color: rgba(255, 255, 255, 0.12) !important;
|
||||
}
|
||||
|
||||
.resolution-label {
|
||||
width: 36px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.resolution-row {
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(3, 100px);
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.resolution-btn {
|
||||
width: 100px !important;
|
||||
min-width: 100px !important;
|
||||
max-width: 100px !important;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import type { Model, LoRA, AspectRatio, BaseSize } from '@/types'
|
||||
import type { Model, LoRA, ResolutionPreset } from '@/types'
|
||||
import * as api from '@/api/client'
|
||||
|
||||
export const useAppStore = defineStore('app', () => {
|
||||
@@ -16,23 +16,38 @@ export const useAppStore = defineStore('app', () => {
|
||||
const loraWeight = ref(0.8)
|
||||
|
||||
// Generation settings
|
||||
const baseSize = ref<BaseSize>(768)
|
||||
const aspectRatio = ref<AspectRatio>('1:1')
|
||||
const selectedPreset = ref('768-3:4')
|
||||
const steps = ref(20)
|
||||
const batchSize = ref(1)
|
||||
|
||||
// Resolution computation
|
||||
const resolutions: Record<BaseSize, Record<AspectRatio, [number, number]>> = {
|
||||
512: { '1:1': [512, 512], '4:3': [512, 384], '3:4': [384, 512] },
|
||||
768: { '1:1': [768, 768], '4:3': [768, 576], '3:4': [576, 768] },
|
||||
1024: { '1:1': [1024, 1024], '4:3': [1024, 768], '3:4': [768, 1024] },
|
||||
}
|
||||
// All resolution presets (base size × aspect ratio)
|
||||
const resolutionPresets: ResolutionPreset[] = [
|
||||
// 512 base
|
||||
{ id: '512-3:4', ratio: '3:4', width: 384, height: 512, label: '384×512' },
|
||||
{ id: '512-1:1', ratio: '1:1', width: 512, height: 512, label: '512×512' },
|
||||
{ id: '512-4:3', ratio: '4:3', width: 512, height: 384, label: '512×384' },
|
||||
// 768 base
|
||||
{ id: '768-3:4', ratio: '3:4', width: 576, height: 768, label: '576×768' },
|
||||
{ id: '768-1:1', ratio: '1:1', width: 768, height: 768, label: '768×768' },
|
||||
{ id: '768-4:3', ratio: '4:3', width: 768, height: 576, label: '768×576' },
|
||||
// 1024 base
|
||||
{ id: '1024-3:4', ratio: '3:4', width: 768, height: 1024, label: '768×1024' },
|
||||
{ id: '1024-1:1', ratio: '1:1', width: 1024, height: 1024, label: '1024×1024' },
|
||||
{ id: '1024-4:3', ratio: '4:3', width: 1024, height: 768, label: '1024×768' },
|
||||
]
|
||||
|
||||
const resolution = computed(() => {
|
||||
const [width, height] = resolutions[baseSize.value][aspectRatio.value]
|
||||
return { width, height }
|
||||
const preset = resolutionPresets.find(p => p.id === selectedPreset.value)
|
||||
return preset ? { width: preset.width, height: preset.height } : { width: 768, height: 1024 }
|
||||
})
|
||||
|
||||
// Presets grouped by base size for 3-row display
|
||||
const presetGroups = [
|
||||
{ label: 'low', presets: resolutionPresets.filter(p => p.id.startsWith('512-')) },
|
||||
{ label: 'mid', presets: resolutionPresets.filter(p => p.id.startsWith('768-')) },
|
||||
{ label: 'high', presets: resolutionPresets.filter(p => p.id.startsWith('1024-')) },
|
||||
]
|
||||
|
||||
// Loading states
|
||||
const loadingModels = ref(false)
|
||||
const switchingModel = ref(false)
|
||||
@@ -88,8 +103,9 @@ export const useAppStore = defineStore('app', () => {
|
||||
loraWeight,
|
||||
|
||||
// Generation settings
|
||||
baseSize,
|
||||
aspectRatio,
|
||||
selectedPreset,
|
||||
resolutionPresets,
|
||||
presetGroups,
|
||||
steps,
|
||||
batchSize,
|
||||
resolution,
|
||||
|
||||
@@ -77,5 +77,10 @@ export interface Resolution {
|
||||
label: string
|
||||
}
|
||||
|
||||
export type AspectRatio = '3:4' | '1:1' | '4:3'
|
||||
export type BaseSize = 512 | 768 | 1024
|
||||
export interface ResolutionPreset {
|
||||
id: string
|
||||
ratio: string
|
||||
width: number
|
||||
height: number
|
||||
label: string
|
||||
}
|
||||
|
||||