ai去特征增加开关
This commit is contained in:
@@ -51,6 +51,7 @@ type CreditSettings struct {
|
|||||||
// DeAISettings is the per-tier surcharge (积分) for the 去AI特征 option on the
|
// DeAISettings is the per-tier surcharge (积分) for the 去AI特征 option on the
|
||||||
// 画图台 — charged on top of the model's image price when the toggle is on.
|
// 画图台 — charged on top of the model's image price when the toggle is on.
|
||||||
type DeAISettings struct {
|
type DeAISettings struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
Price1K int `json:"price_1k"`
|
Price1K int `json:"price_1k"`
|
||||||
Price2K int `json:"price_2k"`
|
Price2K int `json:"price_2k"`
|
||||||
Price4K int `json:"price_4k"`
|
Price4K int `json:"price_4k"`
|
||||||
@@ -343,6 +344,10 @@ func (s *AppSettingsService) TestProxy(ctx context.Context, proxy string) (map[s
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *AppSettingsService) DeAI(ctx context.Context) (*DeAISettings, error) {
|
func (s *AppSettingsService) DeAI(ctx context.Context) (*DeAISettings, error) {
|
||||||
|
enabledRaw, err := s.settings.GetValue(ctx, "deai.enabled")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
p1Raw, err := s.settings.GetValue(ctx, "deai.price_1k")
|
p1Raw, err := s.settings.GetValue(ctx, "deai.price_1k")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -356,6 +361,7 @@ func (s *AppSettingsService) DeAI(ctx context.Context) (*DeAISettings, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &DeAISettings{
|
return &DeAISettings{
|
||||||
|
Enabled: parseBoolSetting(enabledRaw, false),
|
||||||
Price1K: clampNonNegative(parseIntSetting(p1Raw, 1)),
|
Price1K: clampNonNegative(parseIntSetting(p1Raw, 1)),
|
||||||
Price2K: clampNonNegative(parseIntSetting(p2Raw, 2)),
|
Price2K: clampNonNegative(parseIntSetting(p2Raw, 2)),
|
||||||
Price4K: clampNonNegative(parseIntSetting(p4Raw, 3)),
|
Price4K: clampNonNegative(parseIntSetting(p4Raw, 3)),
|
||||||
@@ -364,6 +370,7 @@ func (s *AppSettingsService) DeAI(ctx context.Context) (*DeAISettings, error) {
|
|||||||
|
|
||||||
func (s *AppSettingsService) SaveDeAI(ctx context.Context, in DeAISettings) (*DeAISettings, error) {
|
func (s *AppSettingsService) SaveDeAI(ctx context.Context, in DeAISettings) (*DeAISettings, error) {
|
||||||
if err := s.settings.UpsertValues(ctx, map[string]string{
|
if err := s.settings.UpsertValues(ctx, map[string]string{
|
||||||
|
"deai.enabled": strconv.FormatBool(in.Enabled),
|
||||||
"deai.price_1k": strconv.Itoa(clampNonNegative(in.Price1K)),
|
"deai.price_1k": strconv.Itoa(clampNonNegative(in.Price1K)),
|
||||||
"deai.price_2k": strconv.Itoa(clampNonNegative(in.Price2K)),
|
"deai.price_2k": strconv.Itoa(clampNonNegative(in.Price2K)),
|
||||||
"deai.price_4k": strconv.Itoa(clampNonNegative(in.Price4K)),
|
"deai.price_4k": strconv.Itoa(clampNonNegative(in.Price4K)),
|
||||||
|
|||||||
@@ -418,6 +418,11 @@ func (s *V1Service) prepareImageExecution(ctx context.Context, principal *APIPri
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 去AI特征 is gated by a system-settings switch (default off) — drop the
|
||||||
|
// flag when disabled so no surcharge is charged and no processing runs.
|
||||||
|
if in.DeAI && !s.deaiEnabled(ctx) {
|
||||||
|
in.DeAI = false
|
||||||
|
}
|
||||||
genCtx, cancel := context.WithTimeout(ctx, 8*time.Minute)
|
genCtx, cancel := context.WithTimeout(ctx, 8*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@@ -2879,6 +2884,19 @@ func guessRatio(w, h int) string {
|
|||||||
// firstPricedResolution returns the model's lowest priced image tier (1K/2K/4K
|
// firstPricedResolution returns the model's lowest priced image tier (1K/2K/4K
|
||||||
// order), or "" if none is priced. Used to rescue a request whose resolution
|
// order), or "" if none is priced. Used to rescue a request whose resolution
|
||||||
// the model doesn't support.
|
// the model doesn't support.
|
||||||
|
// deaiEnabled reports whether the 去AI特征 feature is switched on in system
|
||||||
|
// settings (default off). When off, an incoming deai flag is ignored entirely.
|
||||||
|
func (s *V1Service) deaiEnabled(ctx context.Context) bool {
|
||||||
|
if s.settings == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
raw, err := s.settings.GetValue(ctx, "deai.enabled")
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return parseBoolSetting(raw, false)
|
||||||
|
}
|
||||||
|
|
||||||
// deaiSurcharge returns the 去AI特征 surcharge (积分) for an image resolution
|
// deaiSurcharge returns the 去AI特征 surcharge (积分) for an image resolution
|
||||||
// tier, from site settings (defaults: 1K=1, 2K=2, 4K=3).
|
// tier, from site settings (defaults: 1K=1, 2K=2, 4K=3).
|
||||||
func (s *V1Service) deaiSurcharge(ctx context.Context, resolution string) float64 {
|
func (s *V1Service) deaiSurcharge(ctx context.Context, resolution string) float64 {
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ const credits = reactive({ checkin_enabled: true, checkin_reward: 3, invite_enab
|
|||||||
const credBusy = ref(false); const credSaved = ref(false)
|
const credBusy = ref(false); const credSaved = ref(false)
|
||||||
|
|
||||||
// ---- deai (去AI特征 附加价格) ----
|
// ---- deai (去AI特征 附加价格) ----
|
||||||
const deaiCfg = reactive({ price_1k: 1, price_2k: 2, price_4k: 3 })
|
const deaiCfg = reactive({ enabled: false, price_1k: 1, price_2k: 2, price_4k: 3 })
|
||||||
const deaiBusy = ref(false); const deaiSaved = ref(false)
|
const deaiBusy = ref(false); const deaiSaved = ref(false)
|
||||||
async function loadDeai() {
|
async function loadDeai() {
|
||||||
const r = await api('/settings/deai')
|
const r = await api('/settings/deai')
|
||||||
@@ -130,6 +130,7 @@ async function loadDeai() {
|
|||||||
async function saveDeai() {
|
async function saveDeai() {
|
||||||
deaiBusy.value = true; deaiSaved.value = false
|
deaiBusy.value = true; deaiSaved.value = false
|
||||||
const r = await api('/settings/deai', jsonBody('PUT', {
|
const r = await api('/settings/deai', jsonBody('PUT', {
|
||||||
|
enabled: !!deaiCfg.enabled,
|
||||||
price_1k: Number(deaiCfg.price_1k) || 0,
|
price_1k: Number(deaiCfg.price_1k) || 0,
|
||||||
price_2k: Number(deaiCfg.price_2k) || 0,
|
price_2k: Number(deaiCfg.price_2k) || 0,
|
||||||
price_4k: Number(deaiCfg.price_4k) || 0,
|
price_4k: Number(deaiCfg.price_4k) || 0,
|
||||||
@@ -489,14 +490,18 @@ onMounted(() => { loadSite(); loadReg(); loadSmtp(); loadCredits(); loadAnnounce
|
|||||||
<p class="text-xs text-slate-400 mb-4">画图台开启「去AI特征」后,按画质档位在模型价格之上额外扣除的积分。仅对图片生成生效。</p>
|
<p class="text-xs text-slate-400 mb-4">画图台开启「去AI特征」后,按画质档位在模型价格之上额外扣除的积分。仅对图片生成生效。</p>
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<label class="row">
|
<label class="row">
|
||||||
|
<span><span class="lbl">开启去AI特征</span><span class="hint">关闭后画图台不显示该选项,也不会加价。默认关闭。</span></span>
|
||||||
|
<input type="checkbox" v-model="deaiCfg.enabled" class="sw" />
|
||||||
|
</label>
|
||||||
|
<label class="row" :class="!deaiCfg.enabled && 'opacity-50'">
|
||||||
<span><span class="lbl">1K 附加价格</span><span class="hint">默认 1 积分。</span></span>
|
<span><span class="lbl">1K 附加价格</span><span class="hint">默认 1 积分。</span></span>
|
||||||
<input type="number" min="0" v-model.number="deaiCfg.price_1k" class="num" />
|
<input type="number" min="0" v-model.number="deaiCfg.price_1k" class="num" />
|
||||||
</label>
|
</label>
|
||||||
<label class="row">
|
<label class="row" :class="!deaiCfg.enabled && 'opacity-50'">
|
||||||
<span><span class="lbl">2K 附加价格</span><span class="hint">默认 2 积分。</span></span>
|
<span><span class="lbl">2K 附加价格</span><span class="hint">默认 2 积分。</span></span>
|
||||||
<input type="number" min="0" v-model.number="deaiCfg.price_2k" class="num" />
|
<input type="number" min="0" v-model.number="deaiCfg.price_2k" class="num" />
|
||||||
</label>
|
</label>
|
||||||
<label class="row">
|
<label class="row" :class="!deaiCfg.enabled && 'opacity-50'">
|
||||||
<span><span class="lbl">4K 附加价格</span><span class="hint">默认 3 积分。</span></span>
|
<span><span class="lbl">4K 附加价格</span><span class="hint">默认 3 积分。</span></span>
|
||||||
<input type="number" min="0" v-model.number="deaiCfg.price_4k" class="num" />
|
<input type="number" min="0" v-model.number="deaiCfg.price_4k" class="num" />
|
||||||
</label>
|
</label>
|
||||||
@@ -678,7 +683,8 @@ html.dark .num, html.dark .txt, html.dark .field {
|
|||||||
box-shadow: 0 0 0 3px rgb(167 139 250 / 0.15);
|
box-shadow: 0 0 0 3px rgb(167 139 250 / 0.15);
|
||||||
}
|
}
|
||||||
.num:disabled, .txt:disabled, .field:disabled { opacity: 0.45; cursor: not-allowed; }
|
.num:disabled, .txt:disabled, .field:disabled { opacity: 0.45; cursor: not-allowed; }
|
||||||
.num { width: 6rem; padding: 0.4rem 0.55rem; font-size: 0.8rem; text-align: right; }
|
.num { width: 6rem; padding: 0.4rem 0.55rem; font-size: 0.8rem; text-align: right; -moz-appearance: textfield; appearance: textfield; }
|
||||||
|
.num::-webkit-outer-spin-button, .num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
|
||||||
.txt { width: 16rem; max-width: 60%; padding: 0.4rem 0.65rem; font-size: 0.8rem; }
|
.txt { width: 16rem; max-width: 60%; padding: 0.4rem 0.65rem; font-size: 0.8rem; }
|
||||||
.field { width: 100%; padding: 0.55rem 0.75rem; font-size: 0.85rem; }
|
.field { width: 100%; padding: 0.55rem 0.75rem; font-size: 0.85rem; }
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,8 @@ function tierPrice(normalMap, agentMap, key) {
|
|||||||
return Number(n)
|
return Number(n)
|
||||||
}
|
}
|
||||||
// 去AI特征 per-tier surcharge (loaded from /deai-pricing; defaults 1/2/3 分).
|
// 去AI特征 per-tier surcharge (loaded from /deai-pricing; defaults 1/2/3 分).
|
||||||
const deaiPricing = ref({ price_1k: 1, price_2k: 2, price_4k: 3 })
|
const deaiPricing = ref({ enabled: false, price_1k: 1, price_2k: 2, price_4k: 3 })
|
||||||
|
const deaiEnabled = computed(() => !!deaiPricing.value.enabled)
|
||||||
const deaiSurcharge = computed(() => {
|
const deaiSurcharge = computed(() => {
|
||||||
const key = { '1K': 'price_1k', '2K': 'price_2k', '4K': 'price_4k' }[resolution.value] || 'price_1k'
|
const key = { '1K': 'price_1k', '2K': 'price_2k', '4K': 'price_4k' }[resolution.value] || 'price_1k'
|
||||||
return Number(deaiPricing.value[key] ?? 0)
|
return Number(deaiPricing.value[key] ?? 0)
|
||||||
@@ -155,7 +156,7 @@ const price = computed(() => {
|
|||||||
}
|
}
|
||||||
const base = tierPrice(m.prices, m.prices_agent, resolution.value)
|
const base = tierPrice(m.prices, m.prices_agent, resolution.value)
|
||||||
if (base == null) return null
|
if (base == null) return null
|
||||||
return base + (deai.value ? deaiSurcharge.value : 0)
|
return base + (deaiEnabled.value && deai.value ? deaiSurcharge.value : 0)
|
||||||
})
|
})
|
||||||
const priceLabel = computed(() => price.value == null ? '—' : pointsLabel(price.value))
|
const priceLabel = computed(() => price.value == null ? '—' : pointsLabel(price.value))
|
||||||
const canAfford = computed(() => price.value == null || credits.value >= price.value)
|
const canAfford = computed(() => price.value == null || credits.value >= price.value)
|
||||||
@@ -402,7 +403,7 @@ async function fireOne() {
|
|||||||
ratio: ratio.value,
|
ratio: ratio.value,
|
||||||
resolution: resolution.value,
|
resolution: resolution.value,
|
||||||
duration: mode.value === 'video' ? duration.value : '',
|
duration: mode.value === 'video' ? duration.value : '',
|
||||||
deai: mode.value === 'image' ? deai.value : false,
|
deai: mode.value === 'image' && deaiEnabled.value ? deai.value : false,
|
||||||
status: 'pending',
|
status: 'pending',
|
||||||
url: '',
|
url: '',
|
||||||
error: '',
|
error: '',
|
||||||
@@ -697,7 +698,7 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 去AI特征 (image only): opt-in post-processing with a per-tier surcharge -->
|
<!-- 去AI特征 (image only): opt-in post-processing with a per-tier surcharge -->
|
||||||
<div v-if="mode === 'image'" class="flex items-center justify-between">
|
<div v-if="mode === 'image' && deaiEnabled" class="flex items-center justify-between">
|
||||||
<label class="text-xs font-medium text-slate-500">
|
<label class="text-xs font-medium text-slate-500">
|
||||||
去AI特征
|
去AI特征
|
||||||
<span class="text-slate-400 font-normal">(+{{ deaiSurcharge }} 积分)</span>
|
<span class="text-slate-400 font-normal">(+{{ deaiSurcharge }} 积分)</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user