mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-18 01:06:39 +08:00
feat: 为大图片生成缩略图,加快前端图片加载速度
This commit is contained in:
parent
6f39f639bd
commit
a7265c4251
@ -12,9 +12,14 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-redis/redis/v8"
|
"github.com/go-redis/redis/v8"
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"github.com/nfnt/resize"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"image"
|
||||||
|
"image/jpeg"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -58,6 +63,7 @@ func (s *AppServer) Init(debug bool, client *redis.Client) {
|
|||||||
logger.Info("Enabled debug mode")
|
logger.Info("Enabled debug mode")
|
||||||
}
|
}
|
||||||
s.Engine.Use(corsMiddleware())
|
s.Engine.Use(corsMiddleware())
|
||||||
|
s.Engine.Use(staticResourceMiddleware())
|
||||||
s.Engine.Use(authorizeMiddleware(s, client))
|
s.Engine.Use(authorizeMiddleware(s, client))
|
||||||
s.Engine.Use(parameterHandlerMiddleware())
|
s.Engine.Use(parameterHandlerMiddleware())
|
||||||
s.Engine.Use(errorHandler)
|
s.Engine.Use(errorHandler)
|
||||||
@ -274,3 +280,52 @@ func trimJSONStrings(data interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 静态资源中间件
|
||||||
|
func staticResourceMiddleware() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
|
||||||
|
url := c.Request.URL.String()
|
||||||
|
// 拦截生成缩略图请求
|
||||||
|
if strings.HasPrefix(url, "/static/") && strings.Contains(url, "?imageView2") {
|
||||||
|
r := strings.SplitAfter(url, "imageView2")
|
||||||
|
size := strings.Split(r[1], "/")
|
||||||
|
if len(size) != 8 {
|
||||||
|
c.String(http.StatusNotFound, "invalid thumb args")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
with := utils.IntValue(size[3], 0)
|
||||||
|
height := utils.IntValue(size[5], 0)
|
||||||
|
quality := utils.IntValue(size[7], 75)
|
||||||
|
|
||||||
|
// 打开图片文件
|
||||||
|
filePath := strings.TrimLeft(c.Request.URL.Path, "/")
|
||||||
|
file, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
c.String(http.StatusNotFound, "Image not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// 解码图片
|
||||||
|
img, _, err := image.Decode(file)
|
||||||
|
if err != nil {
|
||||||
|
c.String(http.StatusInternalServerError, "Error decoding image")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成缩略图
|
||||||
|
resizedImg := resize.Thumbnail(uint(with), uint(height), img, resize.Lanczos3)
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
err = jpeg.Encode(&buffer, resizedImg, &jpeg.Options{Quality: quality})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直接输出图像数据流
|
||||||
|
c.Data(http.StatusOK, "image/jpeg", buffer.Bytes())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -72,11 +72,17 @@ func (s *Service) Run() {
|
|||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("绘画任务执行失败:", err)
|
logger.Error("绘画任务执行失败:", err)
|
||||||
if task.RetryCount <= 5 {
|
// 推送任务到前端
|
||||||
s.taskQueue.RPush(task)
|
client := s.Clients.Get(task.SessionId)
|
||||||
|
if client != nil {
|
||||||
|
utils.ReplyChunkMessage(client, vo.MidJourneyJob{
|
||||||
|
Type: task.Type.String(),
|
||||||
|
UserId: task.UserId,
|
||||||
|
MessageId: task.MessageId,
|
||||||
|
Progress: -1,
|
||||||
|
Prompt: task.Prompt,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
task.RetryCount += 1
|
|
||||||
time.Sleep(time.Second * 3)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,42 +1,5 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
|
||||||
"chatplus/store/model"
|
|
||||||
"chatplus/utils"
|
|
||||||
"fmt"
|
|
||||||
"gorm.io/driver/mysql"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
MysqlDns := "root:12345678@tcp(localhost:3306)/chatgpt_plus?charset=utf8mb4&collation=utf8mb4_unicode_ci&parseTime=True&loc=Local"
|
|
||||||
db, err := gorm.Open(mysql.Open(MysqlDns), &gorm.Config{})
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
_ = os.MkdirAll("static/upload/images", 0755)
|
|
||||||
var jobs []model.MidJourneyJob
|
|
||||||
db.Find(&jobs)
|
|
||||||
for _, job := range jobs {
|
|
||||||
basename := path.Base(job.ImgURL)
|
|
||||||
imageData, err := utils.DownloadImage(job.ImgURL, "")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("图片下载失败:" + job.ImgURL)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
newImagePath := fmt.Sprintf("static/upload/images/%s", basename)
|
|
||||||
err = os.WriteFile(newImagePath, imageData, 0644)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error writing image file:", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Println("图片保存成功!", newImagePath)
|
|
||||||
// 更新数据库
|
|
||||||
job.ImgURL = fmt.Sprintf("http://localhost:5678/%s", newImagePath)
|
|
||||||
db.Updates(&job)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -354,12 +354,14 @@ import {onMounted, ref} from "vue"
|
|||||||
import {ChromeFilled, DeleteFilled, DocumentCopy, InfoFilled, Picture, Plus} from "@element-plus/icons-vue";
|
import {ChromeFilled, DeleteFilled, DocumentCopy, InfoFilled, Picture, Plus} from "@element-plus/icons-vue";
|
||||||
import Compressor from "compressorjs";
|
import Compressor from "compressorjs";
|
||||||
import {httpGet, httpPost} from "@/utils/http";
|
import {httpGet, httpPost} from "@/utils/http";
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage, ElNotification} from "element-plus";
|
||||||
import ItemList from "@/components/ItemList.vue";
|
import ItemList from "@/components/ItemList.vue";
|
||||||
import Clipboard from "clipboard";
|
import Clipboard from "clipboard";
|
||||||
import {checkSession} from "@/action/session";
|
import {checkSession} from "@/action/session";
|
||||||
import {useRouter} from "vue-router";
|
import {useRouter} from "vue-router";
|
||||||
import {getSessionId, getUserToken} from "@/store/session";
|
import {getSessionId, getUserToken} from "@/store/session";
|
||||||
|
import {removeArrayItem} from "@/utils/libs";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
const listBoxHeight = ref(window.innerHeight - 40)
|
const listBoxHeight = ref(window.innerHeight - 40)
|
||||||
const mjBoxHeight = ref(window.innerHeight - 150)
|
const mjBoxHeight = ref(window.innerHeight - 150)
|
||||||
@ -432,6 +434,14 @@ const connect = () => {
|
|||||||
if (isNew) {
|
if (isNew) {
|
||||||
finishedJobs.value.unshift(data)
|
finishedJobs.value.unshift(data)
|
||||||
}
|
}
|
||||||
|
} else if (data.progress === -1) { // 任务执行失败
|
||||||
|
ElNotification({
|
||||||
|
title: '任务执行失败',
|
||||||
|
message: "提示词:" + data['prompt'],
|
||||||
|
type: 'error',
|
||||||
|
})
|
||||||
|
runningJobs.value = removeArrayItem(runningJobs.value, data, (v1, v2) => v1.id === v2.id)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < runningJobs.value.length; i++) {
|
for (let i = 0; i < runningJobs.value.length; i++) {
|
||||||
if (runningJobs.value[i].id === data.id) {
|
if (runningJobs.value[i].id === data.id) {
|
||||||
@ -463,7 +473,7 @@ onMounted(() => {
|
|||||||
ElMessage.error("获取任务失败:" + e.message)
|
ElMessage.error("获取任务失败:" + e.message)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 获取运行中的任务
|
// 获取已完成的任务
|
||||||
httpGet(`/api/mj/jobs?status=1&user_id=${user['id']}`).then(res => {
|
httpGet(`/api/mj/jobs?status=1&user_id=${user['id']}`).then(res => {
|
||||||
finishedJobs.value = res.data
|
finishedJobs.value = res.data
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
@ -516,19 +526,6 @@ const afterRead = (file) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTaskType = (type) => {
|
|
||||||
switch (type) {
|
|
||||||
case "image":
|
|
||||||
return "绘画任务"
|
|
||||||
case "upscale":
|
|
||||||
return "放大任务"
|
|
||||||
case "variation":
|
|
||||||
return "变化任务"
|
|
||||||
}
|
|
||||||
return "未知任务"
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建绘图任务
|
// 创建绘图任务
|
||||||
const promptRef = ref(null)
|
const promptRef = ref(null)
|
||||||
const generate = () => {
|
const generate = () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user