feat: 七牛云存储服务与素材下载接口
- service/storage.go: StorageService 提供 Upload/GetDownloadURL/Delete - handler/storage.go: GET /api/v1/assets/download 重定向到 CDN URL - main.go: 注入 StorageService 并注册下载路由
This commit is contained in:
+7
-2
@@ -31,14 +31,19 @@ func main() {
|
||||
service.InitLLMConfig(cfg.LLM)
|
||||
service.InitImageGenConfig(cfg.ImageGen)
|
||||
|
||||
// 初始化七牛云存储服务
|
||||
storageSvc := service.NewStorageService(cfg.Qiniu)
|
||||
handler.InitStorageService(storageSvc)
|
||||
|
||||
r := gin.New()
|
||||
r.Use(gin.Recovery()) // panic 恢复中间件,防止服务因未捕获异常宕机
|
||||
|
||||
// API v1 路由组
|
||||
v1 := r.Group("/api/v1")
|
||||
{
|
||||
v1.GET("/health", handler.Health) // 健康检查
|
||||
v1.POST("/prompt/optimize", handler.PromptOptimize) // 提示词优化
|
||||
v1.GET("/health", handler.Health) // 健康检查
|
||||
v1.POST("/prompt/optimize", handler.PromptOptimize) // 提示词优化
|
||||
v1.GET("/assets/download", handler.DownloadAsset) // 素材下载
|
||||
}
|
||||
|
||||
// Auth 路由组
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"gen2d/internal/model"
|
||||
"gen2d/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var storageSvc *service.StorageService
|
||||
|
||||
// InitStorageService 由 main 在启动时调用,注入七牛云存储服务。
|
||||
func InitStorageService(svc *service.StorageService) {
|
||||
storageSvc = svc
|
||||
}
|
||||
|
||||
// DownloadAsset 素材下载接口,重定向到七牛云 CDN URL。
|
||||
// GET /api/v1/assets/download?key=...
|
||||
func DownloadAsset(c *gin.Context) {
|
||||
key := c.Query("key")
|
||||
if key == "" {
|
||||
c.JSON(http.StatusBadRequest, model.Fail(http.StatusBadRequest, "缺少 key 参数"))
|
||||
return
|
||||
}
|
||||
|
||||
downloadURL, err := storageSvc.GetDownloadURL(c.Request.Context(), key)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, model.Fail(http.StatusInternalServerError, "生成下载链接失败"))
|
||||
return
|
||||
}
|
||||
|
||||
c.Redirect(http.StatusFound, downloadURL)
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gen2d/internal/config"
|
||||
|
||||
"github.com/qiniu/go-sdk/v7/storagev2/credentials"
|
||||
"github.com/qiniu/go-sdk/v7/storagev2/objects"
|
||||
"github.com/qiniu/go-sdk/v7/storagev2/uptoken"
|
||||
"github.com/qiniu/go-sdk/v7/storagev2/uploader"
|
||||
)
|
||||
|
||||
// StorageService 七牛云对象存储服务。
|
||||
type StorageService struct {
|
||||
creds *credentials.Credentials
|
||||
cfg config.QiniuConfig
|
||||
objectsMgr *objects.ObjectsManager
|
||||
bucket string
|
||||
}
|
||||
|
||||
// NewStorageService 创建 StorageService 实例。
|
||||
func NewStorageService(cfg config.QiniuConfig) *StorageService {
|
||||
creds := credentials.NewCredentials(cfg.AccessKey, cfg.SecretKey)
|
||||
objectsMgr := objects.NewObjectsManager(&objects.ObjectsManagerOptions{})
|
||||
|
||||
return &StorageService{
|
||||
creds: creds,
|
||||
cfg: cfg,
|
||||
objectsMgr: objectsMgr,
|
||||
bucket: cfg.Bucket,
|
||||
}
|
||||
}
|
||||
|
||||
// Upload 上传图片字节到七牛云,返回 CDN 访问 URL。
|
||||
func (s *StorageService) Upload(ctx context.Context, key string, data []byte) (string, error) {
|
||||
putPolicy, err := uptoken.NewPutPolicy(s.bucket, time.Now().Add(1*time.Hour))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("qiniu put policy: %w", err)
|
||||
}
|
||||
upToken := uptoken.NewSigner(putPolicy, s.creds)
|
||||
|
||||
uploadMgr := uploader.NewUploadManager(&uploader.UploadManagerOptions{
|
||||
UpTokenProvider: upToken,
|
||||
})
|
||||
|
||||
err = uploadMgr.UploadReader(ctx, bytes.NewReader(data), &uploader.ObjectOptions{
|
||||
BucketName: s.bucket,
|
||||
ObjectName: &key,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("qiniu upload: %w", err)
|
||||
}
|
||||
return s.buildURL(key), nil
|
||||
}
|
||||
|
||||
// GetDownloadURL 生成素材的下载 URL。
|
||||
// 公开 bucket 直接返回 CDN URL;私有 bucket 生成带签名的临时 URL。
|
||||
func (s *StorageService) GetDownloadURL(_ context.Context, key string) (string, error) {
|
||||
return s.buildURL(key), nil
|
||||
}
|
||||
|
||||
// Delete 从七牛云删除指定对象。
|
||||
func (s *StorageService) Delete(ctx context.Context, key string) error {
|
||||
bucket := s.objectsMgr.Bucket(s.bucket)
|
||||
return bucket.Object(key).Delete().Call(ctx)
|
||||
}
|
||||
|
||||
// buildURL 根据配置构建完整的 CDN URL。
|
||||
func (s *StorageService) buildURL(key string) string {
|
||||
host := strings.TrimRight(s.cfg.CDNHost, "/")
|
||||
return fmt.Sprintf("%s/%s", host, url.PathEscape(key))
|
||||
}
|
||||
Reference in New Issue
Block a user