luma page, upload image and remove image function is ready

This commit is contained in:
RockYang 2024-08-26 17:59:05 +08:00
parent f71a2f5263
commit ab421f2185
7 changed files with 200 additions and 81 deletions

View File

@ -26,7 +26,6 @@ import (
"io" "io"
"net/http" "net/http"
"os" "os"
"path/filepath"
"runtime/debug" "runtime/debug"
"strings" "strings"
"time" "time"
@ -228,6 +227,7 @@ func needLogin(c *gin.Context) bool {
c.Request.URL.Path == "/api/suno/client" || c.Request.URL.Path == "/api/suno/client" ||
c.Request.URL.Path == "/api/suno/detail" || c.Request.URL.Path == "/api/suno/detail" ||
c.Request.URL.Path == "/api/suno/play" || c.Request.URL.Path == "/api/suno/play" ||
c.Request.URL.Path == "/api/download" ||
strings.HasPrefix(c.Request.URL.Path, "/api/test") || strings.HasPrefix(c.Request.URL.Path, "/api/test") ||
strings.HasPrefix(c.Request.URL.Path, "/api/user/clogin") || strings.HasPrefix(c.Request.URL.Path, "/api/user/clogin") ||
strings.HasPrefix(c.Request.URL.Path, "/api/config/") || strings.HasPrefix(c.Request.URL.Path, "/api/config/") ||
@ -316,8 +316,7 @@ func staticResourceMiddleware() gin.HandlerFunc {
url := c.Request.URL.String() url := c.Request.URL.String()
// 拦截生成缩略图请求 // 拦截生成缩略图请求
if strings.HasPrefix(url, "/static/") { if strings.HasPrefix(url, "/static/") && strings.Contains(url, "?imageView2") {
if strings.Contains(url, "?imageView2") {
r := strings.SplitAfter(url, "imageView2") r := strings.SplitAfter(url, "imageView2")
size := strings.Split(r[1], "/") size := strings.Split(r[1], "/")
if len(size) != 8 { if len(size) != 8 {
@ -369,11 +368,6 @@ func staticResourceMiddleware() gin.HandlerFunc {
// 直接输出图像数据流 // 直接输出图像数据流
c.Data(http.StatusOK, "image/jpeg", buffer.Bytes()) c.Data(http.StatusOK, "image/jpeg", buffer.Bytes())
c.Abort() // 中断请求 c.Abort() // 中断请求
} else if strings.Contains(url, "?download=true") {
filename := filepath.Base(url)
c.Header("Content-Disposition", "attachment; filename="+filename)
c.Header("Content-Type", "application/octet-stream")
}
} }
c.Next() c.Next()

View File

@ -17,19 +17,21 @@ import (
"geekai/utils/resp" "geekai/utils/resp"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm" "gorm.io/gorm"
"io"
"net/http"
"time" "time"
) )
type UploadHandler struct { type NetHandler struct {
BaseHandler BaseHandler
uploaderManager *oss.UploaderManager uploaderManager *oss.UploaderManager
} }
func NewUploadHandler(app *core.AppServer, db *gorm.DB, manager *oss.UploaderManager) *UploadHandler { func NewNetHandler(app *core.AppServer, db *gorm.DB, manager *oss.UploaderManager) *NetHandler {
return &UploadHandler{BaseHandler: BaseHandler{App: app, DB: db}, uploaderManager: manager} return &NetHandler{BaseHandler: BaseHandler{App: app, DB: db}, uploaderManager: manager}
} }
func (h *UploadHandler) Upload(c *gin.Context) { func (h *NetHandler) Upload(c *gin.Context) {
file, err := h.uploaderManager.GetUploadHandler().PutFile(c, "file") file, err := h.uploaderManager.GetUploadHandler().PutFile(c, "file")
if err != nil { if err != nil {
resp.ERROR(c, err.Error()) resp.ERROR(c, err.Error())
@ -60,7 +62,7 @@ func (h *UploadHandler) Upload(c *gin.Context) {
resp.SUCCESS(c, file) resp.SUCCESS(c, file)
} }
func (h *UploadHandler) List(c *gin.Context) { func (h *NetHandler) List(c *gin.Context) {
var data struct { var data struct {
Urls []string `json:"urls,omitempty"` Urls []string `json:"urls,omitempty"`
} }
@ -95,7 +97,7 @@ func (h *UploadHandler) List(c *gin.Context) {
} }
// Remove remove files // Remove remove files
func (h *UploadHandler) Remove(c *gin.Context) { func (h *NetHandler) Remove(c *gin.Context) {
userId := h.GetLoginUserId(c) userId := h.GetLoginUserId(c)
id := h.GetInt(c, "id", 0) id := h.GetInt(c, "id", 0)
var file model.File var file model.File
@ -119,3 +121,28 @@ func (h *UploadHandler) Remove(c *gin.Context) {
_ = h.uploaderManager.GetUploadHandler().Delete(objectKey) _ = h.uploaderManager.GetUploadHandler().Delete(objectKey)
resp.SUCCESS(c) resp.SUCCESS(c)
} }
func (h *NetHandler) Download(c *gin.Context) {
fileUrl := c.Query("url")
// 使用http工具下载文件
if fileUrl == "" {
resp.ERROR(c, types.InvalidArgs)
return
}
// 使用http.Get下载文件
r, err := http.Get(fileUrl)
if err != nil {
resp.ERROR(c, err.Error())
return
}
defer r.Body.Close()
if r.StatusCode != http.StatusOK {
resp.ERROR(c, "error status"+r.Status)
return
}
// 将下载的文件内容写入响应
c.Status(http.StatusOK)
_, _ = io.Copy(c.Writer, r.Body)
}

View File

@ -128,7 +128,7 @@ func main() {
fx.Provide(handler.NewChatRoleHandler), fx.Provide(handler.NewChatRoleHandler),
fx.Provide(handler.NewUserHandler), fx.Provide(handler.NewUserHandler),
fx.Provide(chatimpl.NewChatHandler), fx.Provide(chatimpl.NewChatHandler),
fx.Provide(handler.NewUploadHandler), fx.Provide(handler.NewNetHandler),
fx.Provide(handler.NewSmsHandler), fx.Provide(handler.NewSmsHandler),
fx.Provide(handler.NewRedeemHandler), fx.Provide(handler.NewRedeemHandler),
fx.Provide(handler.NewCaptchaHandler), fx.Provide(handler.NewCaptchaHandler),
@ -249,10 +249,11 @@ func main() {
group.POST("tokens", h.Tokens) group.POST("tokens", h.Tokens)
group.GET("stop", h.StopGenerate) group.GET("stop", h.StopGenerate)
}), }),
fx.Invoke(func(s *core.AppServer, h *handler.UploadHandler) { fx.Invoke(func(s *core.AppServer, h *handler.NetHandler) {
s.Engine.POST("/api/upload", h.Upload) s.Engine.POST("/api/upload", h.Upload)
s.Engine.POST("/api/upload/list", h.List) s.Engine.POST("/api/upload/list", h.List)
s.Engine.GET("/api/upload/remove", h.Remove) s.Engine.GET("/api/upload/remove", h.Remove)
s.Engine.GET("/api/download", h.Download)
}), }),
fx.Invoke(func(s *core.AppServer, h *handler.SmsHandler) { fx.Invoke(func(s *core.AppServer, h *handler.SmsHandler) {
group := s.Engine.Group("/api/sms/") group := s.Engine.Group("/api/sms/")

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -91,6 +91,22 @@
position relative position relative
} }
} }
.params {
display flex
justify-content right
color #e1e1e1
font-size 14px
padding 10px 30px
.item-group {
margin-left 20px
.label {
margin-right 5px
position relative
top 1px
}
}
}
} }
} }
@ -150,7 +166,16 @@
font-size 14px font-size 14px
.iconfont { .iconfont {
font-size 12px font-size 11px
position relative
margin-right 5px
top -2px
}
.el-image {
width 14px
height 14px
margin-right 5px
} }
&:hover { &:hover {

View File

@ -69,3 +69,17 @@ export function httpPost(url, data = {}, options = {}) {
}) })
}) })
} }
export function httpDownload(url) {
return new Promise((resolve, reject) => {
axios({
method: 'GET',
url: url,
responseType: 'blob' // 将响应类型设置为 `blob`
}).then(response => {
resolve(response)
}).catch(err => {
reject(err)
})
})
}

View File

@ -2,15 +2,24 @@
<div class="page-luma"> <div class="page-luma">
<div class="prompt-box"> <div class="prompt-box">
<div class="images"> <div class="images">
<div v-for="img in images" class="item"> <div v-for="img in images" :key="img" class="item">
<el-image :src="img" fit="cover"/> <el-image :src="img" fit="cover"/>
<el-icon><CircleCloseFilled /></el-icon> <el-icon @click="remove(img)"><CircleCloseFilled /></el-icon>
</div> </div>
</div> </div>
<div class="prompt-container"> <div class="prompt-container">
<div class="input-container"> <div class="input-container">
<div class="upload-icon"> <div class="upload-icon">
<el-upload
class="avatar-uploader"
:auto-upload="true"
:show-file-list="false"
:http-request="upload"
accept=".jpg,.png,.jpeg"
>
<i class="iconfont icon-image"></i> <i class="iconfont icon-image"></i>
</el-upload>
</div> </div>
<textarea <textarea
class="prompt-input" class="prompt-input"
@ -24,6 +33,16 @@
</div> </div>
</div> </div>
<div class="params">
<div class="item-group">
<span class="label">循环</span>
<el-switch v-model="loop" size="small" style="--el-switch-on-color:#BF78BF;" />
</div>
<div class="item-group">
<span class="label">提示词优化</span>
<el-switch v-model="promptExtend" size="small" style="--el-switch-on-color:#BF78BF;" />
</div>
</div>
</div> </div>
</div> </div>
@ -40,12 +59,11 @@
</div> </div>
<div class="video-name">{{item.name}}</div> <div class="video-name">{{item.name}}</div>
<div class="opts"> <div class="opts">
<a :href="item.url+'?download=true'" download="video.mp4"> <button class="btn" @click="download(item)" :disabled="item.downloading">
<button class="btn"> <i class="iconfont icon-download" v-if="!item.downloading"></i>
<i class="iconfont icon-download"></i> <el-image src="/images/loading.gif" fit="cover" v-else />
<span>下载</span> <span>下载</span>
</button> </button>
</a>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
@ -56,19 +74,21 @@
<script setup> <script setup>
import {ref} from "vue"; import {ref} from "vue";
import {CircleCloseFilled} from "@element-plus/icons-vue"; import {CircleCloseFilled} from "@element-plus/icons-vue";
import {httpDownload, httpPost} from "@/utils/http";
import {showMessageError} from "@/utils/dialog";
import {ElMessage} from "element-plus";
const row = ref(1) const row = ref(1)
const prompt = ref('') const prompt = ref('')
const images = ref([ const loop = ref(false)
"http://nk.img.r9it.com/chatgpt-plus/1719371605709871.jpg", const promptExtend = ref(false)
"http://nk.img.r9it.com/chatgpt-plus/1719371605709871.jpg" const images = ref([])
])
const videos = ref([ const videos = ref([
{ {
id: 1, id: 1,
name: 'a dancing girl', name: 'a dancing girl',
url: 'http://localhost:5678/static/upload/2024/8/1724574661747320.mp4', url: 'https://storage.cdn-luma.com/dream_machine/d133794f-3124-4059-a9f2-e5fed79f0d5b/watermarked_video01944f69966f14d33b6c4486a8cfb8dde.mp4',
cover: 'https://storage.cdn-luma.com/dream_machine/d133794f-3124-4059-a9f2-e5fed79f0d5b/video_0_thumb.jpg', cover: 'https://storage.cdn-luma.com/dream_machine/d133794f-3124-4059-a9f2-e5fed79f0d5b/video_0_thumb.jpg',
playing: false playing: false
}, },
@ -102,6 +122,44 @@ const videos = ref([
}, },
]) ])
const download = (item) => {
const downloadURL = `${process.env.VUE_APP_API_HOST}/api/download?url=${item.url}`
// parse filename
const urlObj = new URL(item.url);
const fileName = urlObj.pathname.split('/').pop();
item.downloading = true
httpDownload(downloadURL).then(response => {
const blob = new Blob([response.data]);
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(link.href);
item.downloading = false
}).catch(() => {
showMessageError("下载失败")
item.downloading = false
})
}
const upload = (file) => {
const formData = new FormData();
formData.append('file', file.file, file.name);
//
httpPost('/api/upload', formData).then((res) => {
images.value.push(res.data.url)
ElMessage.success({message: "上传成功", duration: 500})
}).catch((e) => {
ElMessage.error('图片上传失败:' + e.message)
})
};
const remove = (img) => {
images.value = images.value.filter(item => item !== img)
}
</script> </script>