mirror of
https://github.com/OwO-Network/DeepLX.git
synced 2025-04-15 04:33:24 +00:00
refactor: make service exportable (#183)
This commit is contained in:
parent
d1dbfcc1e5
commit
0a9ff6b582
261
main.go
261
main.go
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* @Author: Vincent Yang
|
||||
* @Date: 2023-07-01 21:45:34
|
||||
* @LastEditors: Vincent Yang
|
||||
* @LastEditTime: 2024-11-01 13:04:50
|
||||
* @LastEditors: Jason Lyu
|
||||
* @LastEditTime: 2025-04-08 13:45:00
|
||||
* @FilePath: /DeepLX/main.go
|
||||
* @Telegram: https://t.me/missuo
|
||||
* @GitHub: https://github.com/missuo
|
||||
@ -14,268 +14,21 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
translate "github.com/OwO-Network/DeepLX/translate"
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/OwO-Network/DeepLX/service"
|
||||
)
|
||||
|
||||
func authMiddleware(cfg *Config) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if cfg.Token != "" {
|
||||
providedTokenInQuery := c.Query("token")
|
||||
providedTokenInHeader := c.GetHeader("Authorization")
|
||||
|
||||
// Compatability with the Bearer token format
|
||||
if providedTokenInHeader != "" {
|
||||
parts := strings.Split(providedTokenInHeader, " ")
|
||||
if len(parts) == 2 {
|
||||
if parts[0] == "Bearer" || parts[0] == "DeepL-Auth-Key" {
|
||||
providedTokenInHeader = parts[1]
|
||||
} else {
|
||||
providedTokenInHeader = ""
|
||||
}
|
||||
} else {
|
||||
providedTokenInHeader = ""
|
||||
}
|
||||
}
|
||||
|
||||
if providedTokenInHeader != cfg.Token && providedTokenInQuery != cfg.Token {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{
|
||||
"code": http.StatusUnauthorized,
|
||||
"message": "Invalid access token",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
type PayloadFree struct {
|
||||
TransText string `json:"text"`
|
||||
SourceLang string `json:"source_lang"`
|
||||
TargetLang string `json:"target_lang"`
|
||||
TagHandling string `json:"tag_handling"`
|
||||
}
|
||||
|
||||
type PayloadAPI struct {
|
||||
Text []string `json:"text"`
|
||||
TargetLang string `json:"target_lang"`
|
||||
SourceLang string `json:"source_lang"`
|
||||
TagHandling string `json:"tag_handling"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := initConfig()
|
||||
cfg := service.InitConfig()
|
||||
|
||||
fmt.Printf("DeepL X has been successfully launched! Listening on %v:%v\n", cfg.IP, cfg.Port)
|
||||
fmt.Println("Developed by sjlleo <i@leo.moe> and missuo <me@missuo.me>.")
|
||||
|
||||
// Set Proxy
|
||||
proxyURL := os.Getenv("PROXY")
|
||||
if proxyURL == "" {
|
||||
proxyURL = cfg.Proxy
|
||||
}
|
||||
if proxyURL != "" {
|
||||
proxy, err := url.Parse(proxyURL)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse proxy URL: %v", err)
|
||||
}
|
||||
http.DefaultTransport = &http.Transport{
|
||||
Proxy: http.ProxyURL(proxy),
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.Token != "" {
|
||||
fmt.Println("Access token is set.")
|
||||
}
|
||||
|
||||
// Setting the application to release mode
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
r := gin.Default()
|
||||
r.Use(cors.Default())
|
||||
|
||||
// Defining the root endpoint which returns the project details
|
||||
r.GET("/", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": http.StatusOK,
|
||||
"message": "DeepL Free API, Developed by sjlleo and missuo. Go to /translate with POST. http://github.com/OwO-Network/DeepLX",
|
||||
})
|
||||
})
|
||||
|
||||
// Free API endpoint, No Pro Account required
|
||||
r.POST("/translate", authMiddleware(cfg), func(c *gin.Context) {
|
||||
req := PayloadFree{}
|
||||
c.BindJSON(&req)
|
||||
|
||||
sourceLang := req.SourceLang
|
||||
targetLang := req.TargetLang
|
||||
translateText := req.TransText
|
||||
tagHandling := req.TagHandling
|
||||
|
||||
proxyURL := cfg.Proxy
|
||||
|
||||
if tagHandling != "" && tagHandling != "html" && tagHandling != "xml" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": http.StatusBadRequest,
|
||||
"message": "Invalid tag_handling value. Allowed values are 'html' and 'xml'.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
result, err := translate.TranslateByDeepLX(sourceLang, targetLang, translateText, tagHandling, proxyURL, "")
|
||||
if err != nil {
|
||||
log.Fatalf("Translation failed: %s", err)
|
||||
}
|
||||
|
||||
if result.Code == http.StatusOK {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": http.StatusOK,
|
||||
"id": result.ID,
|
||||
"data": result.Data,
|
||||
"alternatives": result.Alternatives,
|
||||
"source_lang": result.SourceLang,
|
||||
"target_lang": result.TargetLang,
|
||||
"method": result.Method,
|
||||
})
|
||||
} else {
|
||||
c.JSON(result.Code, gin.H{
|
||||
"code": result.Code,
|
||||
"message": result.Message,
|
||||
})
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
// Pro API endpoint, Pro Account required
|
||||
r.POST("/v1/translate", authMiddleware(cfg), func(c *gin.Context) {
|
||||
req := PayloadFree{}
|
||||
c.BindJSON(&req)
|
||||
|
||||
sourceLang := req.SourceLang
|
||||
targetLang := req.TargetLang
|
||||
translateText := req.TransText
|
||||
tagHandling := req.TagHandling
|
||||
proxyURL := cfg.Proxy
|
||||
|
||||
dlSession := cfg.DlSession
|
||||
|
||||
if tagHandling != "" && tagHandling != "html" && tagHandling != "xml" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": http.StatusBadRequest,
|
||||
"message": "Invalid tag_handling value. Allowed values are 'html' and 'xml'.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
cookie := c.GetHeader("Cookie")
|
||||
if cookie != "" {
|
||||
dlSession = strings.Replace(cookie, "dl_session=", "", -1)
|
||||
}
|
||||
|
||||
if dlSession == "" {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{
|
||||
"code": http.StatusUnauthorized,
|
||||
"message": "No dl_session Found",
|
||||
})
|
||||
return
|
||||
} else if strings.Contains(dlSession, ".") {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{
|
||||
"code": http.StatusUnauthorized,
|
||||
"message": "Your account is not a Pro account. Please upgrade your account or switch to a different account.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
result, err := translate.TranslateByDeepLX(sourceLang, targetLang, translateText, tagHandling, proxyURL, dlSession)
|
||||
if err != nil {
|
||||
log.Fatalf("Translation failed: %s", err)
|
||||
}
|
||||
|
||||
if result.Code == http.StatusOK {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": http.StatusOK,
|
||||
"id": result.ID,
|
||||
"data": result.Data,
|
||||
"alternatives": result.Alternatives,
|
||||
"source_lang": result.SourceLang,
|
||||
"target_lang": result.TargetLang,
|
||||
"method": result.Method,
|
||||
})
|
||||
} else {
|
||||
c.JSON(result.Code, gin.H{
|
||||
"code": result.Code,
|
||||
"message": result.Message,
|
||||
})
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
// Free API endpoint, Consistent with the official API format
|
||||
r.POST("/v2/translate", authMiddleware(cfg), func(c *gin.Context) {
|
||||
proxyURL := cfg.Proxy
|
||||
|
||||
var translateText string
|
||||
var targetLang string
|
||||
|
||||
translateText = c.PostForm("text")
|
||||
targetLang = c.PostForm("target_lang")
|
||||
|
||||
if translateText == "" || targetLang == "" {
|
||||
var jsonData struct {
|
||||
Text []string `json:"text"`
|
||||
TargetLang string `json:"target_lang"`
|
||||
}
|
||||
|
||||
if err := c.BindJSON(&jsonData); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": http.StatusBadRequest,
|
||||
"message": "Invalid request payload",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
translateText = strings.Join(jsonData.Text, "\n")
|
||||
targetLang = jsonData.TargetLang
|
||||
}
|
||||
|
||||
result, err := translate.TranslateByDeepLX("", targetLang, translateText, "", proxyURL, "")
|
||||
if err != nil {
|
||||
log.Fatalf("Translation failed: %s", err)
|
||||
}
|
||||
|
||||
if result.Code == http.StatusOK {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"translations": []map[string]interface{}{
|
||||
{
|
||||
"detected_source_language": result.SourceLang,
|
||||
"text": result.Data,
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
c.JSON(result.Code, gin.H{
|
||||
"code": result.Code,
|
||||
"message": result.Message,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Catch-all route to handle undefined paths
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
c.JSON(http.StatusNotFound, gin.H{
|
||||
"code": http.StatusNotFound,
|
||||
"message": "Path not found",
|
||||
})
|
||||
})
|
||||
|
||||
r.Run(fmt.Sprintf("%v:%v", cfg.IP, cfg.Port))
|
||||
app := service.Router(cfg)
|
||||
app.Run(fmt.Sprintf("%v:%v", cfg.IP, cfg.Port))
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* @Author: Vincent Yang
|
||||
* @Date: 2024-04-23 00:39:03
|
||||
* @LastEditors: Vincent Yang
|
||||
* @LastEditTime: 2024-09-17 19:34:32
|
||||
* @LastEditors: Jason Lyu
|
||||
* @LastEditTime: 2025-04-08 13:45:00
|
||||
* @FilePath: /DeepLX/config.go
|
||||
* @Telegram: https://t.me/missuo
|
||||
* @GitHub: https://github.com/missuo
|
||||
@ -10,7 +10,7 @@
|
||||
* Copyright © 2024 by Vincent, All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package service
|
||||
|
||||
import (
|
||||
"flag"
|
||||
@ -26,7 +26,7 @@ type Config struct {
|
||||
Proxy string
|
||||
}
|
||||
|
||||
func initConfig() *Config {
|
||||
func InitConfig() *Config {
|
||||
cfg := &Config{
|
||||
IP: "0.0.0.0",
|
||||
Port: 1188,
|
275
service/service.go
Normal file
275
service/service.go
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* @Author: Vincent Yang
|
||||
* @Date: 2023-07-01 21:45:34
|
||||
* @LastEditors: Jason Lyu
|
||||
* @LastEditTime: 2025-04-08 13:45:00
|
||||
* @FilePath: /DeepLX/main.go
|
||||
* @Telegram: https://t.me/missuo
|
||||
* @GitHub: https://github.com/missuo
|
||||
*
|
||||
* Copyright © 2024 by Vincent, All Rights Reserved.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/OwO-Network/DeepLX/translate"
|
||||
)
|
||||
|
||||
func authMiddleware(cfg *Config) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if cfg.Token != "" {
|
||||
providedTokenInQuery := c.Query("token")
|
||||
providedTokenInHeader := c.GetHeader("Authorization")
|
||||
|
||||
// Compatability with the Bearer token format
|
||||
if providedTokenInHeader != "" {
|
||||
parts := strings.Split(providedTokenInHeader, " ")
|
||||
if len(parts) == 2 {
|
||||
if parts[0] == "Bearer" || parts[0] == "DeepL-Auth-Key" {
|
||||
providedTokenInHeader = parts[1]
|
||||
} else {
|
||||
providedTokenInHeader = ""
|
||||
}
|
||||
} else {
|
||||
providedTokenInHeader = ""
|
||||
}
|
||||
}
|
||||
|
||||
if providedTokenInHeader != cfg.Token && providedTokenInQuery != cfg.Token {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{
|
||||
"code": http.StatusUnauthorized,
|
||||
"message": "Invalid access token",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
type PayloadFree struct {
|
||||
TransText string `json:"text"`
|
||||
SourceLang string `json:"source_lang"`
|
||||
TargetLang string `json:"target_lang"`
|
||||
TagHandling string `json:"tag_handling"`
|
||||
}
|
||||
|
||||
type PayloadAPI struct {
|
||||
Text []string `json:"text"`
|
||||
TargetLang string `json:"target_lang"`
|
||||
SourceLang string `json:"source_lang"`
|
||||
TagHandling string `json:"tag_handling"`
|
||||
}
|
||||
|
||||
func Router(cfg *Config) *gin.Engine {
|
||||
// Set Proxy
|
||||
proxyURL := os.Getenv("PROXY")
|
||||
if proxyURL == "" {
|
||||
proxyURL = cfg.Proxy
|
||||
}
|
||||
if proxyURL != "" {
|
||||
proxy, err := url.Parse(proxyURL)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse proxy URL: %v", err)
|
||||
}
|
||||
http.DefaultTransport = &http.Transport{
|
||||
Proxy: http.ProxyURL(proxy),
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.Token != "" {
|
||||
fmt.Println("Access token is set.")
|
||||
}
|
||||
|
||||
r := gin.Default()
|
||||
r.Use(cors.Default())
|
||||
|
||||
// Defining the root endpoint which returns the project details
|
||||
r.GET("/", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": http.StatusOK,
|
||||
"message": "DeepL Free API, Developed by sjlleo and missuo. Go to /translate with POST. http://github.com/OwO-Network/DeepLX",
|
||||
})
|
||||
})
|
||||
|
||||
// Free API endpoint, No Pro Account required
|
||||
r.POST("/translate", authMiddleware(cfg), func(c *gin.Context) {
|
||||
req := PayloadFree{}
|
||||
c.BindJSON(&req)
|
||||
|
||||
sourceLang := req.SourceLang
|
||||
targetLang := req.TargetLang
|
||||
translateText := req.TransText
|
||||
tagHandling := req.TagHandling
|
||||
|
||||
proxyURL := cfg.Proxy
|
||||
|
||||
if tagHandling != "" && tagHandling != "html" && tagHandling != "xml" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": http.StatusBadRequest,
|
||||
"message": "Invalid tag_handling value. Allowed values are 'html' and 'xml'.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
result, err := translate.TranslateByDeepLX(sourceLang, targetLang, translateText, tagHandling, proxyURL, "")
|
||||
if err != nil {
|
||||
log.Fatalf("Translation failed: %s", err)
|
||||
}
|
||||
|
||||
if result.Code == http.StatusOK {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": http.StatusOK,
|
||||
"id": result.ID,
|
||||
"data": result.Data,
|
||||
"alternatives": result.Alternatives,
|
||||
"source_lang": result.SourceLang,
|
||||
"target_lang": result.TargetLang,
|
||||
"method": result.Method,
|
||||
})
|
||||
} else {
|
||||
c.JSON(result.Code, gin.H{
|
||||
"code": result.Code,
|
||||
"message": result.Message,
|
||||
})
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
// Pro API endpoint, Pro Account required
|
||||
r.POST("/v1/translate", authMiddleware(cfg), func(c *gin.Context) {
|
||||
req := PayloadFree{}
|
||||
c.BindJSON(&req)
|
||||
|
||||
sourceLang := req.SourceLang
|
||||
targetLang := req.TargetLang
|
||||
translateText := req.TransText
|
||||
tagHandling := req.TagHandling
|
||||
proxyURL := cfg.Proxy
|
||||
|
||||
dlSession := cfg.DlSession
|
||||
|
||||
if tagHandling != "" && tagHandling != "html" && tagHandling != "xml" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": http.StatusBadRequest,
|
||||
"message": "Invalid tag_handling value. Allowed values are 'html' and 'xml'.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
cookie := c.GetHeader("Cookie")
|
||||
if cookie != "" {
|
||||
dlSession = strings.Replace(cookie, "dl_session=", "", -1)
|
||||
}
|
||||
|
||||
if dlSession == "" {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{
|
||||
"code": http.StatusUnauthorized,
|
||||
"message": "No dl_session Found",
|
||||
})
|
||||
return
|
||||
} else if strings.Contains(dlSession, ".") {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{
|
||||
"code": http.StatusUnauthorized,
|
||||
"message": "Your account is not a Pro account. Please upgrade your account or switch to a different account.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
result, err := translate.TranslateByDeepLX(sourceLang, targetLang, translateText, tagHandling, proxyURL, dlSession)
|
||||
if err != nil {
|
||||
log.Fatalf("Translation failed: %s", err)
|
||||
}
|
||||
|
||||
if result.Code == http.StatusOK {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": http.StatusOK,
|
||||
"id": result.ID,
|
||||
"data": result.Data,
|
||||
"alternatives": result.Alternatives,
|
||||
"source_lang": result.SourceLang,
|
||||
"target_lang": result.TargetLang,
|
||||
"method": result.Method,
|
||||
})
|
||||
} else {
|
||||
c.JSON(result.Code, gin.H{
|
||||
"code": result.Code,
|
||||
"message": result.Message,
|
||||
})
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
// Free API endpoint, Consistent with the official API format
|
||||
r.POST("/v2/translate", authMiddleware(cfg), func(c *gin.Context) {
|
||||
proxyURL := cfg.Proxy
|
||||
|
||||
var translateText string
|
||||
var targetLang string
|
||||
|
||||
translateText = c.PostForm("text")
|
||||
targetLang = c.PostForm("target_lang")
|
||||
|
||||
if translateText == "" || targetLang == "" {
|
||||
var jsonData struct {
|
||||
Text []string `json:"text"`
|
||||
TargetLang string `json:"target_lang"`
|
||||
}
|
||||
|
||||
if err := c.BindJSON(&jsonData); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": http.StatusBadRequest,
|
||||
"message": "Invalid request payload",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
translateText = strings.Join(jsonData.Text, "\n")
|
||||
targetLang = jsonData.TargetLang
|
||||
}
|
||||
|
||||
result, err := translate.TranslateByDeepLX("", targetLang, translateText, "", proxyURL, "")
|
||||
if err != nil {
|
||||
log.Fatalf("Translation failed: %s", err)
|
||||
}
|
||||
|
||||
if result.Code == http.StatusOK {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"translations": []map[string]interface{}{
|
||||
{
|
||||
"detected_source_language": result.SourceLang,
|
||||
"text": result.Data,
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
c.JSON(result.Code, gin.H{
|
||||
"code": result.Code,
|
||||
"message": result.Message,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Catch-all route to handle undefined paths
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
c.JSON(http.StatusNotFound, gin.H{
|
||||
"code": http.StatusNotFound,
|
||||
"message": "Path not found",
|
||||
})
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
Loading…
Reference in New Issue
Block a user