This commit is contained in:
toom1996
2026-09-29 19:59:30 +08:00
parent d15d2a4701
commit 361ffc01af
28 changed files with 896 additions and 47 deletions

View File

@ -40,6 +40,8 @@ type ArticleService interface {
SetCover(ctx context.Context, runwayID uint32, image string) error
// SetDeleted 上下架:deleted=1 下架(对外不可见),0 上架。
SetDeleted(ctx context.Context, id uint32, deleted uint8) error
// SumImageSize 返回某条走秀全部存活图片的原图字节数之和(供后台「图集原图总大小」展示)。
SumImageSize(ctx context.Context, runwayID uint32) (int64, error)
// PurgeGallery 彻底下架图集:级联软删图片 + 下架 + 异步入队清理S4孤儿图。
PurgeGallery(ctx context.Context, id uint32) error
}
@ -305,6 +307,11 @@ func (s *articleService) SetCover(ctx context.Context, runwayID uint32, image st
return s.articles.SetRunwayCover(ctx, runwayID, image)
}
// SumImageSize 返回某条走秀全部存活图片的原图字节数之和(供后台「图集原图总大小」展示)。
func (s *articleService) SumImageSize(ctx context.Context, runwayID uint32) (int64, error) {
return s.articles.SumImageSize(ctx, runwayID)
}
func (s *articleService) SetDeleted(ctx context.Context, id uint32, deleted uint8) error {
if deleted == 1 {
// 下架图集:软删图片 + 置下架 + 异步入队清理S4孤儿图(见 PurgeGallery)。

View File

@ -0,0 +1,43 @@
package service
import (
"context"
"net/http"
"net/http/httptest"
"testing"
)
// fakeSizeUploader 仅用于单测:返回固定 URL,不真正写存储。
type fakeSizeUploader struct{}
func (fakeSizeUploader) Upload(_ context.Context, key string, _ []byte, _ string) (string, error) {
return "http://example/" + key, nil
}
func (fakeSizeUploader) Enabled() bool { return true }
// TestDownloadAndUploadRecordsOriginalSize 校验 worker 在下载阶段记录源文件字节数
// (即 image_size 的来源:io.ReadAll 读到的原图响应体长度)。
func TestDownloadAndUploadRecordsOriginalSize(t *testing.T) {
body := []byte("fake-original-image-bytes-payload-of-known-length-1234567890")
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "image/jpeg")
_, _ = w.Write(body)
}))
defer srv.Close()
s := &IngestService{
uploader: fakeSizeUploader{},
httpClient: &http.Client{},
}
res := s.downloadAndUpload(context.Background(), srv.URL, "runway")
if res.err != nil {
t.Fatalf("downloadAndUpload 失败: %v", res.err)
}
if res.size != int64(len(body)) {
t.Fatalf("res.size = %d, want %d(源文件字节数)", res.size, len(body))
}
if res.url == "" {
t.Fatalf("res.url 不应为空(上传应成功)")
}
}

View File

@ -341,6 +341,7 @@ func (s *IngestService) processRunway(ctx context.Context, job model.IngestJob,
Phash: sqlNull(fi.phash),
IsDuplicate: fi.isDup,
DupOf: strconv.FormatUint(uint64(fi.dupID), 10),
ImageSize: fi.size,
})
}
}
@ -471,6 +472,7 @@ func (s *IngestService) fetchLookImages(ctx context.Context, looks []dto.RunwayL
Phash: sqlNull(r.phashBits),
IsDuplicate: isDup,
DupOf: strconv.FormatUint(uint64(dupID), 10),
ImageSize: r.size,
})
}
timing.images = len(rows)
@ -547,6 +549,7 @@ func (s *IngestService) processStreet(ctx context.Context, job model.IngestJob,
Phash: sqlNull(fi.phash),
IsDuplicate: fi.isDup,
DupOf: strconv.FormatUint(uint64(fi.dupID), 10),
ImageSize: fi.size,
})
}
var saveErr error
@ -609,6 +612,7 @@ func (s *IngestService) fetchImages(ctx context.Context, urls []string, prefix,
phash: r.phashBits,
dupID: dupID,
isDup: isDup,
size: r.size,
})
}
timing.images = len(out)
@ -642,6 +646,7 @@ type fetchedImage struct {
phash string // dHash 的 pgvector 二进制向量串,空串表示无法解码
dupID uint32 // 命中近重复时的参考图 id
isDup uint8 // 是否标记为近重复(供审核留痕)
size int64 // 原图源文件字节数,随结果带回供落库写入 image_size
}
// slowImageThreshold 单张图各阶段合计超过该阈值时单独打一条告警,便于从大量图里定位异常慢图。
@ -731,6 +736,7 @@ type downloadResult struct {
download time.Duration // 本张下载耗时
phash time.Duration // 本张指纹计算耗时
upload time.Duration // 本张上传耗时
size int64 // 原图源文件字节数(io.ReadAll 读到的下载响应体长度)
err error // 下载或上传失败原因(非空即该张失败)
}
@ -796,6 +802,7 @@ func (s *IngestService) downloadAndUpload(ctx context.Context, u, prefix string)
return res
}
res.download = time.Since(dlStart)
res.size = int64(len(data))
ext := path.Ext(u)
if ext == "" || len(ext) > 5 {

View File

@ -37,6 +37,8 @@ type StreetSnapService interface {
SetCover(ctx context.Context, snapID uint32, image string) error
// SetDeleted 上下架:deleted=1 下架,0 上架。
SetDeleted(ctx context.Context, id uint32, deleted uint8) error
// SumImageSize 返回某条街拍全部存活图片的原图字节数之和(供后台「图集原图总大小」展示)。
SumImageSize(ctx context.Context, snapID uint32) (int64, error)
// PurgeGallery 彻底下架街拍:级联软删图片 + 下架 + 异步入队清理S4孤儿图。
PurgeGallery(ctx context.Context, id uint32) error
}
@ -406,6 +408,11 @@ func (s *streetSnapService) SetCover(ctx context.Context, snapID uint32, image s
return s.repo.SetSnapCover(ctx, snapID, image)
}
// SumImageSize 返回某条街拍全部存活图片的原图字节数之和(供后台「图集原图总大小」展示)。
func (s *streetSnapService) SumImageSize(ctx context.Context, snapID uint32) (int64, error) {
return s.repo.SumImageSize(ctx, snapID)
}
func (s *streetSnapService) SetDeleted(ctx context.Context, id uint32, deleted uint8) error {
if deleted == 1 {
// 下架街拍:软删图片 + 置下架 + 异步入队清理S4孤儿图(见 PurgeGallery)。