🐳 optimized docker packaging
This commit is contained in:
4
.idea/GOHCache.xml
generated
4
.idea/GOHCache.xml
generated
@@ -1489,7 +1489,7 @@
|
|||||||
<entry key="file://$PROJECT_DIR$/app/aisvc/rpc/internal/logic/aiservice/face_recognition_logic.go">
|
<entry key="file://$PROJECT_DIR$/app/aisvc/rpc/internal/logic/aiservice/face_recognition_logic.go">
|
||||||
<value>
|
<value>
|
||||||
<ScannedPath>
|
<ScannedPath>
|
||||||
<option name="lastModified" value="1737604866085" />
|
<option name="lastModified" value="1737629887959" />
|
||||||
<option name="schema">
|
<option name="schema">
|
||||||
<list>
|
<list>
|
||||||
<option value="FaceRecognitionLogic" />
|
<option value="FaceRecognitionLogic" />
|
||||||
@@ -2117,7 +2117,7 @@
|
|||||||
<entry key="file://$PROJECT_DIR$/app/auth/api/internal/logic/storage/upload_file_logic.go">
|
<entry key="file://$PROJECT_DIR$/app/auth/api/internal/logic/storage/upload_file_logic.go">
|
||||||
<value>
|
<value>
|
||||||
<ScannedPath>
|
<ScannedPath>
|
||||||
<option name="lastModified" value="1737533110977" />
|
<option name="lastModified" value="1737629820919" />
|
||||||
<option name="schema">
|
<option name="schema">
|
||||||
<list>
|
<list>
|
||||||
<option value="UploadFileLogic" />
|
<option value="UploadFileLogic" />
|
||||||
|
|||||||
@@ -9,18 +9,14 @@ LABEL maintainer="landaiqing <<landaiqing@126.com>>"
|
|||||||
ENV TZ=Asia/Shanghai \
|
ENV TZ=Asia/Shanghai \
|
||||||
DEBIAN_FRONTEND=noninteractive
|
DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
|
||||||
|
sed -i 's|http://deb.debian.org/debian|https://mirrors.tuna.tsinghua.edu.cn/debian|g' /etc/apt/sources.list && \
|
||||||
RUN sed -i 's|http://deb.debian.org/debian|https://mirrors.tuna.tsinghua.edu.cn/debian|g' /etc/apt/sources.list && \
|
apt-get update && apt-get install -y --no-install-recommends \
|
||||||
apt-get update && apt-get install -y --no-install-recommends --fix-missing \
|
tzdata git build-essential cmake pkg-config unzip curl ca-certificates \
|
||||||
tzdata git build-essential cmake pkg-config wget unzip libgtk2.0-dev \
|
libcurl4-openssl-dev libssl-dev libturbojpeg-dev \
|
||||||
curl ca-certificates libcurl4-openssl-dev libssl-dev \
|
libpng-dev libtiff-dev nasm libblas-dev libatlas-base-dev\
|
||||||
libavcodec-dev libavformat-dev libswscale-dev libtbb2 libtbb-dev \
|
libdlib-dev libjpeg62-turbo-dev liblapack-dev && \
|
||||||
libharfbuzz-dev libfreetype6-dev \
|
rm -rf /var/lib/apt/lists/*
|
||||||
libjpeg-dev libturbojpeg-dev libpng-dev libtiff-dev libdc1394-22-dev nasm \
|
|
||||||
libdlib-dev libblas-dev libatlas-base-dev liblapack-dev \
|
|
||||||
gcc g++ musl-dev cmake && \
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
ARG OPENCV_VERSION="4.11.0"
|
ARG OPENCV_VERSION="4.11.0"
|
||||||
|
|
||||||
@@ -71,8 +67,6 @@ WORKDIR /app
|
|||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
#WORKDIR /app/app/aisvc/
|
|
||||||
|
|
||||||
ENV CGO_ENABLED=1 \
|
ENV CGO_ENABLED=1 \
|
||||||
CGO_CFLAGS="-I/usr/local/include/opencv4" \
|
CGO_CFLAGS="-I/usr/local/include/opencv4" \
|
||||||
CGO_CPPFLAGS="-I/usr/local/include" \
|
CGO_CPPFLAGS="-I/usr/local/include" \
|
||||||
@@ -81,13 +75,8 @@ ENV CGO_ENABLED=1 \
|
|||||||
GOARCH=amd64 \
|
GOARCH=amd64 \
|
||||||
GOPROXY=https://goproxy.cn,direct
|
GOPROXY=https://goproxy.cn,direct
|
||||||
|
|
||||||
RUN go mod download
|
RUN go mod download && \
|
||||||
|
go build -ldflags="-w -s" -o schisandra-ai-server ./app/aisvc/rpc/aisvc.go
|
||||||
RUN go build -ldflags="-w -s" -o schisandra-ai-server ./app/aisvc/rpc/aisvc.go
|
|
||||||
|
|
||||||
#EXPOSE 8888
|
|
||||||
#
|
|
||||||
#CMD ["./schisandra-ai-server"]
|
|
||||||
|
|
||||||
FROM debian:bullseye-slim AS runtime
|
FROM debian:bullseye-slim AS runtime
|
||||||
|
|
||||||
@@ -96,17 +85,13 @@ ENV TZ=Asia/Shanghai \
|
|||||||
|
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
|
||||||
apt-get update && apt-get install -y --no-install-recommends \
|
apt-get update && apt-get install -y --no-install-recommends \
|
||||||
tzdata libjpeg62-turbo libpng16-16 libtiff5 libturbojpeg0 \
|
tzdata libjpeg62-turbo libblas3 liblapack3 libdlib-dev libtiff5 && \
|
||||||
libharfbuzz0b libfreetype6 libavcodec58 libavformat58 libswscale5 libtbb2 \
|
|
||||||
libblas3 liblapack3 && \
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY --from=builder /usr/local/lib /usr/local/lib/
|
COPY --from=builder /usr/local/lib /usr/local/lib/
|
||||||
|
|
||||||
COPY --from=builder /usr/lib/ /usr/lib/
|
|
||||||
|
|
||||||
COPY --from=builder /usr/local/include/opencv4 /usr/local/include/opencv4/
|
COPY --from=builder /usr/local/include/opencv4 /usr/local/include/opencv4/
|
||||||
|
|
||||||
COPY --from=builder /app/schisandra-ai-server .
|
COPY --from=builder /app/schisandra-ai-server .
|
||||||
@@ -117,9 +102,6 @@ COPY --from=builder /app/app/aisvc/resources ./resources
|
|||||||
|
|
||||||
ENV LD_LIBRARY_PATH=/usr/local/lib
|
ENV LD_LIBRARY_PATH=/usr/local/lib
|
||||||
|
|
||||||
RUN echo "/usr/local/lib" > /etc/ld.so.conf.d/custom-libs.conf && ldconfig
|
|
||||||
|
|
||||||
|
|
||||||
EXPOSE 8888
|
EXPOSE 8888
|
||||||
|
|
||||||
CMD ["./schisandra-ai-server"]
|
CMD ["./schisandra-ai-server"]
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
"image"
|
"image"
|
||||||
"image/jpeg"
|
"image/jpeg"
|
||||||
|
_ "image/png"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"schisandra-album-cloud-microservices/app/aisvc/model/mysql/model"
|
"schisandra-album-cloud-microservices/app/aisvc/model/mysql/model"
|
||||||
@@ -47,6 +48,9 @@ func (l *FaceRecognitionLogic) FaceRecognition(in *pb.FaceRecognitionRequest) (*
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if toJPEG == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
// 提取人脸特征
|
// 提取人脸特征
|
||||||
faceFeatures, err := l.svcCtx.FaceRecognizer.RecognizeSingle(toJPEG)
|
faceFeatures, err := l.svcCtx.FaceRecognizer.RecognizeSingle(toJPEG)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -96,18 +100,21 @@ func (l *FaceRecognitionLogic) FaceRecognition(in *pb.FaceRecognitionRequest) (*
|
|||||||
return l.saveNewFace(in, faceFeatures, hashKey)
|
return l.saveNewFace(in, faceFeatures, hashKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertImageToJPEG 将非 JPEG 格式的图片字节数据转换为 JPEG
|
|
||||||
func (l *FaceRecognitionLogic) ConvertImageToJPEG(imageData []byte) ([]byte, error) {
|
func (l *FaceRecognitionLogic) ConvertImageToJPEG(imageData []byte) ([]byte, error) {
|
||||||
// 使用 image.Decode 解码图像数据
|
|
||||||
img, _, err := image.Decode(bytes.NewReader(imageData))
|
// 解码图片
|
||||||
|
img, format, err := image.Decode(bytes.NewReader(imageData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to decode image: %v", err)
|
return nil, fmt.Errorf("failed to decode image: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建一个缓冲区来存储 JPEG 格式的数据
|
// 如果已经是 JPEG 格式,则直接返回原数据
|
||||||
var jpegBuffer bytes.Buffer
|
if format == "jpeg" {
|
||||||
|
return imageData, nil
|
||||||
|
}
|
||||||
|
|
||||||
// 将图片编码为 JPEG 格式
|
// 如果是 PNG 格式,则转换为 JPEG
|
||||||
|
var jpegBuffer bytes.Buffer
|
||||||
err = jpeg.Encode(&jpegBuffer, img, nil)
|
err = jpeg.Encode(&jpegBuffer, img, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to encode image to JPEG: %v", err)
|
return nil, fmt.Errorf("failed to encode image to JPEG: %v", err)
|
||||||
|
|||||||
@@ -56,26 +56,29 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
var faceId int64
|
var faceId int64 = 0
|
||||||
|
var className string
|
||||||
bytes, err := io.ReadAll(file)
|
bytes, err := io.ReadAll(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
// 人脸识别
|
// 人脸识别
|
||||||
face, err := l.svcCtx.AiSvcRpc.FaceRecognition(l.ctx, &pb.FaceRecognitionRequest{Face: bytes, UserId: uid})
|
if result.FileType == "image/png" || result.FileType == "image/jpeg" {
|
||||||
if err != nil {
|
face, err := l.svcCtx.AiSvcRpc.FaceRecognition(l.ctx, &pb.FaceRecognitionRequest{Face: bytes, UserId: uid})
|
||||||
return "", err
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if face != nil {
|
||||||
|
faceId = face.GetFaceId()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图像分类
|
||||||
|
classification, err := l.svcCtx.AiSvcRpc.TfClassification(l.ctx, &pb.TfClassificationRequest{Image: bytes})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
className = classification.GetClassName()
|
||||||
}
|
}
|
||||||
if face != nil {
|
|
||||||
faceId = face.GetFaceId()
|
|
||||||
}
|
|
||||||
// 分类
|
|
||||||
classification, err := l.svcCtx.AiSvcRpc.TfClassification(l.ctx, &pb.TfClassificationRequest{Image: bytes})
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
fmt.Println(classification.ClassName)
|
|
||||||
fmt.Println(classification.Score)
|
|
||||||
|
|
||||||
// 解析 EXIF 信息
|
// 解析 EXIF 信息
|
||||||
exif, err := l.parseExifData(result.Exif)
|
exif, err := l.parseExifData(result.Exif)
|
||||||
@@ -99,12 +102,13 @@ func (l *UploadFileLogic) UploadFile(r *http.Request) (resp string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 上传文件到 OSS
|
// 上传文件到 OSS
|
||||||
if err = l.uploadFileToOSS(uid, header, file); err != nil {
|
bucket, provider, err := l.uploadFileToOSS(uid, header, file)
|
||||||
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将 EXIF 和文件信息存入数据库
|
// 将 EXIF 和文件信息存入数据库
|
||||||
if err = l.saveFileInfoToDB(uid, header, result, originalDateTime, gpsString, locationString, exif, faceId); err != nil {
|
if err = l.saveFileInfoToDB(uid, bucket, provider, header, result, originalDateTime, gpsString, locationString, exif, faceId, className); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,20 +224,20 @@ func (l *UploadFileLogic) getGeoLocation(latitude, longitude float64) (string, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 上传文件到 OSS
|
// 上传文件到 OSS
|
||||||
func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHeader, file multipart.File) error {
|
func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHeader, file multipart.File) (string, string, error) {
|
||||||
ossConfig := l.svcCtx.DB.ScaStorageConfig
|
ossConfig := l.svcCtx.DB.ScaStorageConfig
|
||||||
dbConfig, err := ossConfig.Where(ossConfig.UserID.Eq(uid)).First()
|
dbConfig, err := ossConfig.Where(ossConfig.UserID.Eq(uid)).First()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("oss config not found")
|
return "", "", errors.New("oss config not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
accessKey, err := encrypt.Decrypt(dbConfig.AccessKey, l.svcCtx.Config.Encrypt.Key)
|
accessKey, err := encrypt.Decrypt(dbConfig.AccessKey, l.svcCtx.Config.Encrypt.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("decrypt access key failed")
|
return "", "", errors.New("decrypt access key failed")
|
||||||
}
|
}
|
||||||
secretKey, err := encrypt.Decrypt(dbConfig.SecretKey, l.svcCtx.Config.Encrypt.Key)
|
secretKey, err := encrypt.Decrypt(dbConfig.SecretKey, l.svcCtx.Config.Encrypt.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("decrypt secret key failed")
|
return "", "", errors.New("decrypt secret key failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
storageConfig := &config.StorageConfig{
|
storageConfig := &config.StorageConfig{
|
||||||
@@ -247,31 +251,34 @@ func (l *UploadFileLogic) uploadFileToOSS(uid string, header *multipart.FileHead
|
|||||||
|
|
||||||
service, err := l.svcCtx.StorageManager.GetStorage(uid, storageConfig)
|
service, err := l.svcCtx.StorageManager.GetStorage(uid, storageConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("get storage failed")
|
return "", "", errors.New("get storage failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = service.UploadFileSimple(l.ctx, dbConfig.Bucket, header.Filename, file, map[string]string{})
|
_, err = service.UploadFileSimple(l.ctx, dbConfig.Bucket, header.Filename, file, map[string]string{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("upload file failed")
|
return "", "", errors.New("upload file failed")
|
||||||
}
|
}
|
||||||
return nil
|
return dbConfig.Bucket, dbConfig.Type, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将 EXIF 和文件信息存入数据库
|
// 将 EXIF 和文件信息存入数据库
|
||||||
func (l *UploadFileLogic) saveFileInfoToDB(uid string, header *multipart.FileHeader, result types.File, originalDateTime, gpsString, locationString string, exif map[string]interface{}, faceId int64) error {
|
func (l *UploadFileLogic) saveFileInfoToDB(uid, bucket, provider string, header *multipart.FileHeader, result types.File, originalDateTime, gpsString, locationString string, exif map[string]interface{}, faceId int64, className string) error {
|
||||||
exifJSON, err := json.Marshal(exif)
|
exifJSON, err := json.Marshal(exif)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("marshal exif failed")
|
return errors.New("marshal exif failed")
|
||||||
}
|
}
|
||||||
|
var landscape string
|
||||||
|
if result.Landscape != "none" {
|
||||||
|
landscape = result.Landscape
|
||||||
|
}
|
||||||
scaStorageInfo := &model.ScaStorageInfo{
|
scaStorageInfo := &model.ScaStorageInfo{
|
||||||
UserID: uid,
|
UserID: uid,
|
||||||
Provider: result.FileType,
|
Provider: provider,
|
||||||
Bucket: result.TopCategory,
|
Bucket: bucket,
|
||||||
FileName: header.Filename,
|
FileName: header.Filename,
|
||||||
FileSize: strconv.FormatInt(header.Size, 10),
|
FileSize: strconv.FormatInt(header.Size, 10),
|
||||||
FileType: result.FileType,
|
FileType: result.FileType,
|
||||||
Landscape: result.Landscape,
|
Landscape: landscape,
|
||||||
Objects: strings.Join(result.ObjectArray, ", "),
|
Objects: strings.Join(result.ObjectArray, ", "),
|
||||||
Anime: strconv.FormatBool(result.IsAnime),
|
Anime: strconv.FormatBool(result.IsAnime),
|
||||||
Category: result.TopCategory,
|
Category: result.TopCategory,
|
||||||
@@ -281,6 +288,7 @@ func (l *UploadFileLogic) saveFileInfoToDB(uid string, header *multipart.FileHea
|
|||||||
Location: locationString,
|
Location: locationString,
|
||||||
Exif: string(exifJSON),
|
Exif: string(exifJSON),
|
||||||
FaceID: faceId,
|
FaceID: faceId,
|
||||||
|
Tags: className,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = l.svcCtx.DB.ScaStorageInfo.Create(scaStorageInfo)
|
err = l.svcCtx.DB.ScaStorageInfo.Create(scaStorageInfo)
|
||||||
|
|||||||
@@ -28,9 +28,8 @@ FROM alpine:latest
|
|||||||
ENV TZ=Asia/Shanghai \
|
ENV TZ=Asia/Shanghai \
|
||||||
DEBIAN_FRONTEND=noninteractive
|
DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
|
||||||
|
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
|
||||||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
|
|
||||||
apk add --no-cache tzdata libjpeg-turbo
|
apk add --no-cache tzdata libjpeg-turbo
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|||||||
Reference in New Issue
Block a user