💬 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" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Tensors</title>
|
<title>Tensors</title>
|
||||||
<script type="module" crossorigin src="/assets/index-CX4x_bxc.js"></script>
|
<script type="module" crossorigin src="/assets/index-BPC1k--a.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-BvuF0jag.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-CP6ArsWF.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
@@ -28,17 +28,6 @@ const loraItems = computed(() => [
|
|||||||
...store.loras.map(l => ({ title: l.name, value: l.path }))
|
...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) {
|
async function handleModelChange(model: string) {
|
||||||
if (model && model !== store.activeModel) {
|
if (model && model !== store.activeModel) {
|
||||||
@@ -187,22 +176,25 @@ async function generate() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="d-flex align-center ga-2">
|
<div class="resolution-grid rounded border pa-2">
|
||||||
<span class="text-caption text-grey text-uppercase">Size</span>
|
<div
|
||||||
<v-btn-toggle v-model="store.baseSize" mandatory density="compact" :disabled="generating">
|
v-for="group in store.presetGroups"
|
||||||
<v-btn v-for="s in baseSizes" :key="s.value" :value="s.value" size="small">
|
:key="group.label"
|
||||||
{{ s.title }}
|
class="d-flex align-center ga-2"
|
||||||
</v-btn>
|
>
|
||||||
</v-btn-toggle>
|
<span class="text-caption text-grey text-uppercase resolution-label">{{ group.label }}</span>
|
||||||
</div>
|
<v-btn-toggle
|
||||||
|
v-model="store.selectedPreset"
|
||||||
<div class="d-flex align-center ga-2">
|
mandatory
|
||||||
<span class="text-caption text-grey text-uppercase">Ratio</span>
|
density="compact"
|
||||||
<v-btn-toggle v-model="store.aspectRatio" mandatory density="compact" :disabled="generating">
|
:disabled="generating"
|
||||||
<v-btn v-for="r in aspectRatios" :key="r.value" :value="r.value" size="small">
|
class="resolution-row"
|
||||||
{{ r.title }}
|
>
|
||||||
</v-btn>
|
<v-btn v-for="p in group.presets" :key="p.id" :value="p.id" size="small" class="resolution-btn">
|
||||||
</v-btn-toggle>
|
{{ p.label }}
|
||||||
|
</v-btn>
|
||||||
|
</v-btn-toggle>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="d-flex align-center ga-2">
|
<div class="d-flex align-center ga-2">
|
||||||
@@ -262,4 +254,29 @@ async function generate() {
|
|||||||
.border-t {
|
.border-t {
|
||||||
border-top: 1px solid rgba(255, 255, 255, 0.12);
|
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>
|
</style>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref, computed } from 'vue'
|
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'
|
import * as api from '@/api/client'
|
||||||
|
|
||||||
export const useAppStore = defineStore('app', () => {
|
export const useAppStore = defineStore('app', () => {
|
||||||
@@ -16,23 +16,38 @@ export const useAppStore = defineStore('app', () => {
|
|||||||
const loraWeight = ref(0.8)
|
const loraWeight = ref(0.8)
|
||||||
|
|
||||||
// Generation settings
|
// Generation settings
|
||||||
const baseSize = ref<BaseSize>(768)
|
const selectedPreset = ref('768-3:4')
|
||||||
const aspectRatio = ref<AspectRatio>('1:1')
|
|
||||||
const steps = ref(20)
|
const steps = ref(20)
|
||||||
const batchSize = ref(1)
|
const batchSize = ref(1)
|
||||||
|
|
||||||
// Resolution computation
|
// All resolution presets (base size × aspect ratio)
|
||||||
const resolutions: Record<BaseSize, Record<AspectRatio, [number, number]>> = {
|
const resolutionPresets: ResolutionPreset[] = [
|
||||||
512: { '1:1': [512, 512], '4:3': [512, 384], '3:4': [384, 512] },
|
// 512 base
|
||||||
768: { '1:1': [768, 768], '4:3': [768, 576], '3:4': [576, 768] },
|
{ id: '512-3:4', ratio: '3:4', width: 384, height: 512, label: '384×512' },
|
||||||
1024: { '1:1': [1024, 1024], '4:3': [1024, 768], '3:4': [768, 1024] },
|
{ 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 resolution = computed(() => {
|
||||||
const [width, height] = resolutions[baseSize.value][aspectRatio.value]
|
const preset = resolutionPresets.find(p => p.id === selectedPreset.value)
|
||||||
return { width, height }
|
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
|
// Loading states
|
||||||
const loadingModels = ref(false)
|
const loadingModels = ref(false)
|
||||||
const switchingModel = ref(false)
|
const switchingModel = ref(false)
|
||||||
@@ -88,8 +103,9 @@ export const useAppStore = defineStore('app', () => {
|
|||||||
loraWeight,
|
loraWeight,
|
||||||
|
|
||||||
// Generation settings
|
// Generation settings
|
||||||
baseSize,
|
selectedPreset,
|
||||||
aspectRatio,
|
resolutionPresets,
|
||||||
|
presetGroups,
|
||||||
steps,
|
steps,
|
||||||
batchSize,
|
batchSize,
|
||||||
resolution,
|
resolution,
|
||||||
|
|||||||
@@ -77,5 +77,10 @@ export interface Resolution {
|
|||||||
label: string
|
label: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AspectRatio = '3:4' | '1:1' | '4:3'
|
export interface ResolutionPreset {
|
||||||
export type BaseSize = 512 | 768 | 1024
|
id: string
|
||||||
|
ratio: string
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|||||||