init repo
This commit is contained in:
19
api/router.go
Normal file
19
api/router.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"gitea.com/bitwsd/document_ai/api/v1/formula"
|
||||
"gitea.com/bitwsd/document_ai/api/v1/oss"
|
||||
"gitea.com/bitwsd/document_ai/api/v1/task"
|
||||
"gitea.com/bitwsd/document_ai/api/v1/user"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func SetupRouter(engine *gin.RouterGroup) {
|
||||
v1 := engine.Group("/v1")
|
||||
{
|
||||
formula.SetupRouter(v1)
|
||||
oss.SetupRouter(v1)
|
||||
task.SetupRouter(v1)
|
||||
user.SetupRouter(v1)
|
||||
}
|
||||
}
|
||||
118
api/v1/formula/handler.go
Normal file
118
api/v1/formula/handler.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package formula
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
|
||||
"gitea.com/bitwsd/document_ai/internal/model/formula"
|
||||
"gitea.com/bitwsd/document_ai/internal/service"
|
||||
"gitea.com/bitwsd/document_ai/internal/storage/dao"
|
||||
"gitea.com/bitwsd/document_ai/pkg/common"
|
||||
"gitea.com/bitwsd/document_ai/pkg/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type FormulaEndpoint struct {
|
||||
recognitionService *service.RecognitionService
|
||||
}
|
||||
|
||||
func NewFormulaEndpoint() *FormulaEndpoint {
|
||||
return &FormulaEndpoint{
|
||||
recognitionService: service.NewRecognitionService(),
|
||||
}
|
||||
}
|
||||
|
||||
// CreateTask godoc
|
||||
// @Summary Create a formula recognition task
|
||||
// @Description Create a new formula recognition task from image
|
||||
// @Tags Formula
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body CreateFormulaRecognitionRequest true "Create task request"
|
||||
// @Success 200 {object} common.Response{data=CreateTaskResponse}
|
||||
// @Failure 400 {object} common.Response
|
||||
// @Failure 500 {object} common.Response
|
||||
// @Router /v1/formula/recognition [post]
|
||||
func (endpoint *FormulaEndpoint) CreateTask(ctx *gin.Context) {
|
||||
var req formula.CreateFormulaRecognitionRequest
|
||||
if err := ctx.BindJSON(&req); err != nil {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeParamError, "Invalid parameters"))
|
||||
return
|
||||
}
|
||||
|
||||
if !utils.InArray(req.TaskType, []string{string(dao.TaskTypeFormula), string(dao.TaskTypeFormula)}) {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeParamError, "Invalid task type"))
|
||||
return
|
||||
}
|
||||
|
||||
fileExt := filepath.Ext(req.FileName)
|
||||
if !utils.InArray(fileExt, []string{".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".webp"}) {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeParamError, "Invalid file type"))
|
||||
return
|
||||
}
|
||||
|
||||
task, err := endpoint.recognitionService.CreateRecognitionTask(ctx, &req)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeSystemError, "Failed to create task"))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, common.SuccessResponse(ctx, &formula.CreateTaskResponse{
|
||||
TaskNo: task.TaskUUID,
|
||||
Status: int(task.Status),
|
||||
}))
|
||||
}
|
||||
|
||||
// GetTaskStatus godoc
|
||||
// @Summary Get formula recognition task status
|
||||
// @Description Get the status and results of a formula recognition task
|
||||
// @Tags Formula
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param task_no path string true "Task No"
|
||||
// @Success 200 {object} common.Response{data=GetTaskStatusResponse}
|
||||
// @Failure 400 {object} common.Response
|
||||
// @Failure 404 {object} common.Response
|
||||
// @Failure 500 {object} common.Response
|
||||
// @Router /v1/formula/recognition/{task_no} [get]
|
||||
func (endpoint *FormulaEndpoint) GetTaskStatus(c *gin.Context) {
|
||||
var req formula.GetRecognitionStatusRequest
|
||||
if err := c.ShouldBindUri(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, common.ErrorResponse(c, common.CodeParamError, "invalid task no"))
|
||||
return
|
||||
}
|
||||
|
||||
task, err := endpoint.recognitionService.GetFormualTask(c, req.TaskNo)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, common.ErrorResponse(c, common.CodeSystemError, "failed to get task status"))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, common.SuccessResponse(c, task))
|
||||
}
|
||||
|
||||
// AI增强识别
|
||||
// @Summary AI增强识别
|
||||
// @Description AI增强识别
|
||||
// @Tags Formula
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body formula.AIEnhanceRecognitionRequest true "AI增强识别请求"
|
||||
// @Success 200 {object} common.Response{data=formula.AIEnhanceRecognitionResponse}
|
||||
// @Router /v1/formula/ai_enhance [post]
|
||||
func (endpoint *FormulaEndpoint) AIEnhanceRecognition(c *gin.Context) {
|
||||
var req formula.AIEnhanceRecognitionRequest
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusOK, common.ErrorResponse(c, common.CodeParamError, "Invalid parameters"))
|
||||
return
|
||||
}
|
||||
|
||||
_, err := endpoint.recognitionService.AIEnhanceRecognition(c, &req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, common.ErrorResponse(c, common.CodeSystemError, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, common.SuccessResponse(c, nil))
|
||||
}
|
||||
12
api/v1/formula/router.go
Normal file
12
api/v1/formula/router.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package formula
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func SetupRouter(engine *gin.RouterGroup) {
|
||||
endpoint := NewFormulaEndpoint()
|
||||
engine.POST("/formula/recognition", endpoint.CreateTask)
|
||||
engine.POST("/formula/ai_enhance", endpoint.AIEnhanceRecognition)
|
||||
engine.GET("/formula/recognition/:task_no", endpoint.GetTaskStatus)
|
||||
}
|
||||
106
api/v1/oss/handler.go
Normal file
106
api/v1/oss/handler.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package oss
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"gitea.com/bitwsd/document_ai/config"
|
||||
"gitea.com/bitwsd/document_ai/internal/storage/dao"
|
||||
"gitea.com/bitwsd/document_ai/pkg/common"
|
||||
"gitea.com/bitwsd/document_ai/pkg/constant"
|
||||
"gitea.com/bitwsd/document_ai/pkg/oss"
|
||||
"gitea.com/bitwsd/document_ai/pkg/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func GetPostObjectSignature(ctx *gin.Context) {
|
||||
policyToken, err := oss.GetPolicyToken()
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeSystemError, err.Error()))
|
||||
return
|
||||
}
|
||||
ctx.JSON(http.StatusOK, common.SuccessResponse(ctx, policyToken))
|
||||
}
|
||||
|
||||
// GetSignatureURL handles the request to generate a signed URL for a file upload.
|
||||
// @Summary Generate signed URL for file upload
|
||||
// @Description This endpoint generates a signed URL for uploading a file to the OSS (Object Storage Service).
|
||||
// @Tags file
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param hash query string true "Hash value of the file"
|
||||
// @Success 200 {object} common.Response{data=map[string]string{"sign_url":string, "repeat":bool, "path":string}} "Signed URL generated successfully"
|
||||
// @Failure 200 {object} common.Response "Error response"
|
||||
// @Router /signature_url [get]
|
||||
func GetSignatureURL(ctx *gin.Context) {
|
||||
userID := ctx.GetInt64(constant.ContextUserID)
|
||||
type Req struct {
|
||||
FileHash string `json:"file_hash" binding:"required"`
|
||||
FileName string `json:"file_name" binding:"required"`
|
||||
}
|
||||
req := Req{}
|
||||
err := ctx.BindJSON(&req)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeParamError, "param error"))
|
||||
return
|
||||
}
|
||||
taskDao := dao.NewRecognitionTaskDao()
|
||||
sess := dao.DB.WithContext(ctx)
|
||||
task, err := taskDao.GetTaskByFileURL(sess, userID, req.FileHash)
|
||||
if err != nil && err != gorm.ErrRecordNotFound {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeDBError, "failed to get task"))
|
||||
return
|
||||
}
|
||||
if task.ID != 0 {
|
||||
ctx.JSON(http.StatusOK, common.SuccessResponse(ctx, gin.H{"sign_url": "", "repeat": true, "path": task.FileURL}))
|
||||
return
|
||||
}
|
||||
extend := filepath.Ext(req.FileName)
|
||||
if extend == "" {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeParamError, "invalid file name"))
|
||||
return
|
||||
}
|
||||
if !utils.InArray(extend, []string{".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".webp"}) {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeParamError, "invalid file type"))
|
||||
return
|
||||
}
|
||||
path := filepath.Join(oss.FormulaDir, fmt.Sprintf("%s%s", utils.NewUUID(), extend))
|
||||
url, err := oss.GetPolicyURL(ctx, path)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeSystemError, err.Error()))
|
||||
return
|
||||
}
|
||||
ctx.JSON(http.StatusOK, common.SuccessResponse(ctx, gin.H{"sign_url": url, "repeat": false, "path": path}))
|
||||
}
|
||||
|
||||
func UploadFile(ctx *gin.Context) {
|
||||
if err := os.MkdirAll(config.GlobalConfig.UploadDir, 0755); err != nil {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeSystemError, "Failed to create upload directory"))
|
||||
return
|
||||
}
|
||||
|
||||
// Get file from form
|
||||
file, err := ctx.FormFile("file")
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeParamError, "File is required"))
|
||||
return
|
||||
}
|
||||
|
||||
// Generate unique filename with timestamp
|
||||
ext := filepath.Ext(file.Filename)
|
||||
filename := fmt.Sprintf("%d%s", time.Now().UnixNano(), ext)
|
||||
filepath := filepath.Join(config.GlobalConfig.UploadDir, filename)
|
||||
|
||||
// Save file
|
||||
if err := ctx.SaveUploadedFile(file, filepath); err != nil {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeSystemError, "Failed to save file"))
|
||||
return
|
||||
}
|
||||
|
||||
// Return success with file path
|
||||
ctx.JSON(http.StatusOK, common.SuccessResponse(ctx, gin.H{"sign_url": filepath}))
|
||||
}
|
||||
12
api/v1/oss/router.go
Normal file
12
api/v1/oss/router.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package oss
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
func SetupRouter(parent *gin.RouterGroup) {
|
||||
router := parent.Group("oss")
|
||||
{
|
||||
router.POST("/signature", GetPostObjectSignature)
|
||||
router.POST("/signature_url", GetSignatureURL)
|
||||
router.POST("/file/upload", UploadFile)
|
||||
}
|
||||
}
|
||||
61
api/v1/task/handler.go
Normal file
61
api/v1/task/handler.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"gitea.com/bitwsd/core/common/log"
|
||||
"gitea.com/bitwsd/document_ai/internal/model/task"
|
||||
"gitea.com/bitwsd/document_ai/internal/service"
|
||||
"gitea.com/bitwsd/document_ai/pkg/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type TaskEndpoint struct {
|
||||
taskService *service.TaskService
|
||||
}
|
||||
|
||||
func NewTaskEndpoint() *TaskEndpoint {
|
||||
return &TaskEndpoint{taskService: service.NewTaskService()}
|
||||
}
|
||||
|
||||
func (h *TaskEndpoint) EvaluateTask(c *gin.Context) {
|
||||
var req task.EvaluateTaskRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
log.Error(c, "func", "EvaluateTask", "msg", "Invalid parameters", "error", err)
|
||||
c.JSON(http.StatusOK, common.ErrorResponse(c, common.CodeParamError, "Invalid parameters"))
|
||||
return
|
||||
}
|
||||
|
||||
err := h.taskService.EvaluateTask(c, &req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, common.ErrorResponse(c, common.CodeSystemError, "评价任务失败"))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, common.SuccessResponse(c, nil))
|
||||
}
|
||||
|
||||
func (h *TaskEndpoint) GetTaskList(c *gin.Context) {
|
||||
var req task.TaskListRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
log.Error(c, "func", "GetTaskList", "msg", "Invalid parameters", "error", err)
|
||||
c.JSON(http.StatusOK, common.ErrorResponse(c, common.CodeParamError, "Invalid parameters"))
|
||||
return
|
||||
}
|
||||
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
|
||||
if req.PageSize <= 0 {
|
||||
req.PageSize = 10
|
||||
}
|
||||
|
||||
resp, err := h.taskService.GetTaskList(c, &req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, common.ErrorResponse(c, common.CodeSystemError, "获取任务列表失败"))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, common.SuccessResponse(c, resp))
|
||||
}
|
||||
11
api/v1/task/router.go
Normal file
11
api/v1/task/router.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func SetupRouter(engine *gin.RouterGroup) {
|
||||
endpoint := NewTaskEndpoint()
|
||||
engine.POST("/task/evaluate", endpoint.EvaluateTask)
|
||||
engine.GET("/task/list", endpoint.GetTaskList)
|
||||
}
|
||||
105
api/v1/user/handler.go
Normal file
105
api/v1/user/handler.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"gitea.com/bitwsd/core/common/log"
|
||||
"gitea.com/bitwsd/document_ai/config"
|
||||
model "gitea.com/bitwsd/document_ai/internal/model/user"
|
||||
"gitea.com/bitwsd/document_ai/internal/service"
|
||||
"gitea.com/bitwsd/document_ai/pkg/common"
|
||||
"gitea.com/bitwsd/document_ai/pkg/constant"
|
||||
"gitea.com/bitwsd/document_ai/pkg/jwt"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type UserEndpoint struct {
|
||||
userService *service.UserService
|
||||
}
|
||||
|
||||
func NewUserEndpoint() *UserEndpoint {
|
||||
return &UserEndpoint{
|
||||
userService: service.NewUserService(),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *UserEndpoint) SendVerificationCode(ctx *gin.Context) {
|
||||
req := model.SmsSendRequest{}
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeParamError, common.CodeParamErrorMsg))
|
||||
return
|
||||
}
|
||||
|
||||
code, err := h.userService.GetSmsCode(ctx, req.Phone)
|
||||
if err != nil {
|
||||
log.Error(ctx, "func", "SendVerificationCode", "msg", "发送验证码失败", "error", err)
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeSystemError, common.CodeSystemErrorMsg))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, common.SuccessResponse(ctx, model.SmsSendResponse{Code: code}))
|
||||
}
|
||||
|
||||
func (h *UserEndpoint) LoginByPhoneCode(ctx *gin.Context) {
|
||||
req := model.PhoneLoginRequest{}
|
||||
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeParamError, common.CodeParamErrorMsg))
|
||||
return
|
||||
}
|
||||
|
||||
if req.Code == "" || req.Phone == "" {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeParamError, common.CodeParamErrorMsg))
|
||||
return
|
||||
}
|
||||
|
||||
if config.GlobalConfig.Server.IsDebug() {
|
||||
uid := 1
|
||||
token, err := jwt.CreateToken(jwt.User{UserId: int64(uid)})
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeUnauthorized, common.CodeUnauthorizedMsg))
|
||||
return
|
||||
}
|
||||
ctx.JSON(http.StatusOK, common.SuccessResponse(ctx, model.PhoneLoginResponse{Token: token}))
|
||||
return
|
||||
}
|
||||
|
||||
uid, err := h.userService.VerifySmsCode(ctx, req.Phone, req.Code)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeUnauthorized, common.CodeSmsCodeErrorMsg))
|
||||
return
|
||||
}
|
||||
|
||||
token, err := jwt.CreateToken(jwt.User{UserId: uid})
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeUnauthorized, common.CodeUnauthorizedMsg))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, common.SuccessResponse(ctx, model.PhoneLoginResponse{Token: token}))
|
||||
}
|
||||
|
||||
func (h *UserEndpoint) GetUserInfo(ctx *gin.Context) {
|
||||
uid := ctx.GetInt64(constant.ContextUserID)
|
||||
if uid == 0 {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeUnauthorized, common.CodeUnauthorizedMsg))
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.userService.GetUserInfo(ctx, uid)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusOK, common.ErrorResponse(ctx, common.CodeSystemError, common.CodeSystemErrorMsg))
|
||||
return
|
||||
}
|
||||
|
||||
status := 0
|
||||
if user.ID > 0 {
|
||||
status = 1
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, common.SuccessResponse(ctx, model.UserInfoResponse{
|
||||
Username: user.Username,
|
||||
Phone: user.Phone,
|
||||
Status: status,
|
||||
}))
|
||||
}
|
||||
16
api/v1/user/router.go
Normal file
16
api/v1/user/router.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"gitea.com/bitwsd/document_ai/pkg/common"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func SetupRouter(router *gin.RouterGroup) {
|
||||
userEndpoint := NewUserEndpoint()
|
||||
userRouter := router.Group("/user")
|
||||
{
|
||||
userRouter.POST("/get/sms", userEndpoint.SendVerificationCode)
|
||||
userRouter.POST("/login/phone", userEndpoint.LoginByPhoneCode)
|
||||
userRouter.GET("/info", common.GetAuthMiddleware(), userEndpoint.GetUserInfo)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user