ai去特征展示
This commit is contained in:
@@ -130,6 +130,7 @@ func (h *AdminReadHandler) Logs(c *gin.Context) {
|
||||
"resolution": item.Resolution,
|
||||
"duration": item.Duration,
|
||||
"refs": item.Refs,
|
||||
"deai": item.DeAI,
|
||||
"source": item.Source,
|
||||
"user_id": emptyStringNil(item.UserID),
|
||||
"user_name": userName,
|
||||
|
||||
@@ -310,6 +310,7 @@ func (h *UserGenerationHandler) Logs(c *gin.Context) {
|
||||
"resolution": item.Resolution,
|
||||
"duration": item.Duration,
|
||||
"refs": item.Refs,
|
||||
"deai": item.DeAI,
|
||||
"source": emptyStringNil(item.Source),
|
||||
"user_id": emptyStringNil(item.UserID),
|
||||
"user_name": userName,
|
||||
|
||||
@@ -93,6 +93,7 @@ type EventLog struct {
|
||||
Resolution string `gorm:"size:32"`
|
||||
Duration string `gorm:"size:32"`
|
||||
Refs int `gorm:"not null;default:0"`
|
||||
DeAI bool `gorm:"not null;default:false"` // 去AI特征 was applied (image only)
|
||||
RefFiles datatypes.JSON `gorm:"type:jsonb"` // relative paths of saved reference images, for回显 on reload
|
||||
Source string `gorm:"size:32;index"`
|
||||
// AccountID is the provider token/account chosen to fulfil this generation,
|
||||
|
||||
@@ -546,6 +546,7 @@ func (s *AdminReadService) Images(ctx context.Context, limit, offset int, kind s
|
||||
"resolution": "",
|
||||
"ratio": "",
|
||||
"duration": "",
|
||||
"deai": false,
|
||||
}
|
||||
if event, ok := index[item.Name]; ok {
|
||||
row["prompt"] = event.Prompt
|
||||
@@ -557,6 +558,7 @@ func (s *AdminReadService) Images(ctx context.Context, limit, offset int, kind s
|
||||
row["resolution"] = event.Resolution
|
||||
row["ratio"] = event.Ratio
|
||||
row["duration"] = event.Duration
|
||||
row["deai"] = event.DeAI
|
||||
}
|
||||
out = append(out, row)
|
||||
}
|
||||
|
||||
@@ -171,6 +171,7 @@ func shapeJobEvent(item *model.EventLog, modelNames map[string]string) map[strin
|
||||
"ratio": item.Ratio,
|
||||
"resolution": item.Resolution,
|
||||
"duration": item.Duration,
|
||||
"deai": item.DeAI,
|
||||
"status": status,
|
||||
"file": emptyOrNil(item.File),
|
||||
"url": emptyOrNil(url),
|
||||
|
||||
@@ -453,7 +453,7 @@ func (s *V1Service) prepareImageExecution(ctx context.Context, principal *APIPri
|
||||
if !noStore {
|
||||
fileURL, relativePath = s.allocateOutput(principal, "png", in.BaseURL)
|
||||
}
|
||||
eventID, err := s.logPendingEvent(ctx, "image", modelItem, principal, in.Prompt, aspectRatio, resolution, "", refCount, price, relativePath, source, refFiles)
|
||||
eventID, err := s.logPendingEvent(ctx, "image", modelItem, principal, in.Prompt, aspectRatio, resolution, "", refCount, price, relativePath, source, refFiles, in.DeAI)
|
||||
if err != nil {
|
||||
s.cleanupReferenceImages(ctx, "", refFiles)
|
||||
return nil, err
|
||||
@@ -703,7 +703,7 @@ func (s *V1Service) prepareVideoExecution(ctx context.Context, principal *APIPri
|
||||
if !noStore {
|
||||
fileURL, relativePath = s.allocateOutput(principal, "mp4", in.BaseURL)
|
||||
}
|
||||
eventID, err := s.logPendingEvent(ctx, "video", modelItem, principal, in.Prompt, aspectRatio, resolution, duration, refCount, price, relativePath, source, refFiles)
|
||||
eventID, err := s.logPendingEvent(ctx, "video", modelItem, principal, in.Prompt, aspectRatio, resolution, duration, refCount, price, relativePath, source, refFiles, false)
|
||||
if err != nil {
|
||||
s.cleanupReferenceImages(ctx, "", refFiles)
|
||||
return nil, err
|
||||
@@ -825,7 +825,7 @@ func (s *V1Service) StartVideoJob(ctx context.Context, principal *APIPrincipal,
|
||||
refFiles := s.saveReferenceImages(ctx, principal, in.ReferenceImages)
|
||||
// Source "v1": no output file is allocated — the result is the upstream URL,
|
||||
// stored on the event when the render completes.
|
||||
eventID, err := s.logPendingEvent(ctx, "video", modelItem, principal, in.Prompt, aspectRatio, resolution, duration, len(in.ReferenceImages), price, "", "v1", refFiles)
|
||||
eventID, err := s.logPendingEvent(ctx, "video", modelItem, principal, in.Prompt, aspectRatio, resolution, duration, len(in.ReferenceImages), price, "", "v1", refFiles, false)
|
||||
if err != nil {
|
||||
s.cleanupReferenceImages(ctx, "", refFiles)
|
||||
return nil, err
|
||||
@@ -1343,7 +1343,7 @@ func (s *V1Service) allocateOutput(principal *APIPrincipal, ext, baseURL string)
|
||||
return "/images/" + relativePath, relativePath
|
||||
}
|
||||
|
||||
func (s *V1Service) logPendingEvent(ctx context.Context, kind string, modelItem *model.ModelConfig, principal *APIPrincipal, prompt, ratio, resolution, duration string, refs int, cost float64, file, source string, refFiles []string) (string, error) {
|
||||
func (s *V1Service) logPendingEvent(ctx context.Context, kind string, modelItem *model.ModelConfig, principal *APIPrincipal, prompt, ratio, resolution, duration string, refs int, cost float64, file, source string, refFiles []string, deai bool) (string, error) {
|
||||
event := &model.EventLog{
|
||||
ID: "evt-" + randomUpper(12),
|
||||
TS: time.Now(),
|
||||
@@ -1356,6 +1356,7 @@ func (s *V1Service) logPendingEvent(ctx context.Context, kind string, modelItem
|
||||
Resolution: resolution,
|
||||
Duration: duration,
|
||||
Refs: refs,
|
||||
DeAI: deai,
|
||||
Source: source,
|
||||
Cost: cost,
|
||||
File: file,
|
||||
|
||||
@@ -328,6 +328,7 @@ onUnmounted(() => window.removeEventListener('keydown', onKey))
|
||||
<span v-if="f.resolution" class="text-emerald-300/90">{{ f.resolution }}</span>
|
||||
<span v-if="f.ratio" class="text-white/40">{{ f.ratio }}</span>
|
||||
<span v-if="f.kind === 'video' && f.duration" class="text-fuchsia-300/80">{{ f.duration }}</span>
|
||||
<span v-if="f.deai" class="text-violet-300/80">去AI</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-[10px] text-white/35 mt-0.5 tabular-nums">{{ fmtSize(f.size) }} · {{ fmtTs(f.mtime) }}</div>
|
||||
@@ -356,7 +357,7 @@ onUnmounted(() => window.removeEventListener('keydown', onKey))
|
||||
:kind="selected.kind"
|
||||
:prompt="selected.prompt"
|
||||
:meta="[selected.model, selected.name].filter(Boolean).join(' · ')"
|
||||
:meta-sub="[selected.resolution, selected.ratio, (selected.kind === 'video' ? selected.duration : ''), fmtSize(selected.size), fmtTs(selected.mtime)].filter(Boolean).join(' · ')"
|
||||
:meta-sub="[selected.resolution, selected.ratio, (selected.kind === 'video' ? selected.duration : ''), (selected.deai ? '去AI特征' : ''), fmtSize(selected.size), fmtTs(selected.mtime)].filter(Boolean).join(' · ')"
|
||||
:download-name="selected.name.split('/').pop()"
|
||||
@close="selected = null" />
|
||||
|
||||
|
||||
@@ -325,6 +325,10 @@ const sourcePill = (s) => ({
|
||||
<span class="text-white/25 mx-1.5">·</span>
|
||||
<span class="text-white/40">参考 {{ e.refs }}</span>
|
||||
</template>
|
||||
<template v-if="e.deai">
|
||||
<span class="text-white/25 mx-1.5">·</span>
|
||||
<span class="text-violet-300/70">去AI特征</span>
|
||||
</template>
|
||||
</td>
|
||||
<td class="px-3 py-3.5 text-right text-xs tabular-nums align-middle whitespace-nowrap">
|
||||
<span v-if="e.cost > 0" class="text-amber-300 font-medium">{{ e.cost }}</span>
|
||||
|
||||
@@ -471,7 +471,7 @@ async function loadHistory() {
|
||||
.map((e) => ({
|
||||
id: 'srv-' + e.id,
|
||||
prompt: e.prompt, model: e.model, kind: e.kind,
|
||||
ratio: e.ratio, resolution: e.resolution, duration: e.duration,
|
||||
ratio: e.ratio, resolution: e.resolution, duration: e.duration, deai: !!e.deai,
|
||||
status: e.status === 'success' ? 'done' : 'running',
|
||||
url: e.file ? generatedUrl(e.file) : '',
|
||||
error: '',
|
||||
@@ -834,7 +834,7 @@ onUnmounted(() => {
|
||||
<div class="pg-cap text-[11px] leading-tight font-medium line-clamp-2 transition-colors"
|
||||
:class="item.prompt ? 'pointer-events-auto cursor-pointer' : ''"
|
||||
:title="item.prompt ? '点击复制提示词' : ''" @click.stop="copyPrompt(item)">{{ item.prompt }}</div>
|
||||
<div class="pg-cap-sub text-[9px] mt-0.5 font-mono truncate">{{ item.model }}<span v-if="item.elapsed_ms"> · {{ (item.elapsed_ms / 1000).toFixed(1) }}s</span></div>
|
||||
<div class="pg-cap-sub text-[9px] mt-0.5 font-mono truncate">{{ item.model }}<span v-if="item.deai"> · 去AI</span><span v-if="item.elapsed_ms"> · {{ (item.elapsed_ms / 1000).toFixed(1) }}s</span></div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- pending / running -->
|
||||
|
||||
@@ -120,6 +120,7 @@ const params = (e) => {
|
||||
const parts = [e.ratio || '—', e.resolution || '—']
|
||||
if (e.duration) parts.push(e.duration)
|
||||
if (e.refs > 0) parts.push(`参考 ${e.refs}`)
|
||||
if (e.deai) parts.push('去AI特征')
|
||||
return parts.join(' · ')
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -360,6 +360,7 @@ onUnmounted(() => {
|
||||
<span v-if="e.resolution" class="text-emerald-300/90">{{ e.resolution }}</span>
|
||||
<span v-if="e.ratio" class="text-white/40">{{ e.ratio }}</span>
|
||||
<span v-if="e.kind === 'video' && e.duration" class="text-fuchsia-300/80">{{ e.duration }}</span>
|
||||
<span v-if="e.deai" class="text-violet-300/80">去AI</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-[10px] text-white/35 mt-0.5 tabular-nums">{{ fmtTs(e.ts) }}<span v-if="e.elapsed_ms"> · {{ fmtMs(e.elapsed_ms) }}</span></div>
|
||||
@@ -387,7 +388,7 @@ onUnmounted(() => {
|
||||
:src="generatedUrl(lightbox.file)"
|
||||
:kind="lightbox.kind"
|
||||
:prompt="lightbox.prompt"
|
||||
:meta="[lightbox.model, lightbox.ratio, lightbox.resolution, lightbox.duration, fmtMs(lightbox.elapsed_ms)].filter(Boolean).join(' · ')"
|
||||
:meta="[lightbox.model, lightbox.ratio, lightbox.resolution, lightbox.duration, (lightbox.deai ? '去AI特征' : ''), fmtMs(lightbox.elapsed_ms)].filter(Boolean).join(' · ')"
|
||||
:download-name="lightbox.file"
|
||||
@close="lightbox = null" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user