init
This commit is contained in:
94
utils/ai_request.go
Normal file
94
utils/ai_request.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
)
|
||||
|
||||
type AiReqeust struct{}
|
||||
|
||||
type DeepseekResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Created int64 `json:"created"`
|
||||
Model string `json:"model"`
|
||||
Choices []struct {
|
||||
Index int `json:"index"`
|
||||
Message struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
} `json:"message"`
|
||||
Logprobs interface{} `json:"logprobs"` // 可能是null或复杂结构
|
||||
FinishReason string `json:"finish_reason"`
|
||||
} `json:"choices"`
|
||||
Usage struct {
|
||||
PromptTokens int `json:"prompt_tokens"`
|
||||
CompletionTokens int `json:"completion_tokens"`
|
||||
TotalTokens int `json:"total_tokens"`
|
||||
PromptTokensDetails struct {
|
||||
CachedTokens int `json:"cached_tokens"`
|
||||
} `json:"prompt_tokens_details"`
|
||||
PromptCacheHitTokens int `json:"prompt_cache_hit_tokens"`
|
||||
PromptCacheMissTokens int `json:"prompt_cache_miss_tokens"`
|
||||
} `json:"usage"`
|
||||
SystemFingerprint string `json:"system_fingerprint"`
|
||||
}
|
||||
|
||||
func (*AiReqeust) Deepseek(text string) string {
|
||||
// 定义结构体
|
||||
type Message struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
type ChatRequest struct {
|
||||
Model string `json:"model"`
|
||||
Messages []Message `json:"messages"`
|
||||
}
|
||||
// 创建 resty 客户端
|
||||
client := resty.New()
|
||||
|
||||
// 目标URL
|
||||
url := "https://api.deepseek.com/v1/chat/completions"
|
||||
|
||||
request := ChatRequest{
|
||||
Model: "deepseek-chat",
|
||||
Messages: []Message{
|
||||
{
|
||||
Role: "user",
|
||||
Content: text,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// 发送 POST 请求
|
||||
resp, err := client.R().
|
||||
SetHeader("Content-Type", "application/json"). // 必填头
|
||||
SetHeader("Authorization", "Bearer sk-9ca769cb45c249559276b979a2e1a2cd"). // 认证头
|
||||
SetBody(request). // 设置JSON体
|
||||
Post(url)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("请求失败:", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
// 解析响应
|
||||
var response DeepseekResponse
|
||||
if err := json.Unmarshal(resp.Body(), &response); err != nil {
|
||||
fmt.Println("解析失败:", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
// 提取关键信息
|
||||
if len(response.Choices) > 0 {
|
||||
firstChoice := response.Choices[0]
|
||||
// fmt.Printf("\nAI回复 (%s):\n%s\n",
|
||||
// firstChoice.Message.Role,
|
||||
// firstChoice.Message.Content)
|
||||
return firstChoice.Message.Content
|
||||
}
|
||||
return ""
|
||||
}
|
||||
60
utils/db.go
Normal file
60
utils/db.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go-account-register/config"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var DB *gorm.DB
|
||||
|
||||
func Connect() (*gorm.DB, error) {
|
||||
appConfig, dberr := config.LoadConfig()
|
||||
if dberr != nil {
|
||||
fmt.Println("读取配置失败")
|
||||
}
|
||||
|
||||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
appConfig.Database.Username,
|
||||
appConfig.Database.Password,
|
||||
appConfig.Database.Host,
|
||||
appConfig.Database.Port,
|
||||
appConfig.Database.Database)
|
||||
|
||||
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to database: %w", err)
|
||||
}
|
||||
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get sql.DB: %w", err)
|
||||
}
|
||||
|
||||
sqlDB.SetMaxIdleConns(10)
|
||||
sqlDB.SetMaxOpenConns(100)
|
||||
sqlDB.SetConnMaxLifetime(time.Hour)
|
||||
|
||||
log.Println("Database connection established")
|
||||
DB = db
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func GetDB() *gorm.DB {
|
||||
if DB == nil {
|
||||
panic("database connection is not initialized")
|
||||
}
|
||||
return DB
|
||||
}
|
||||
|
||||
func Close() error {
|
||||
sqlDB, err := DB.DB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sqlDB.Close()
|
||||
}
|
||||
69
utils/external/index.go
vendored
Normal file
69
utils/external/index.go
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package external
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go-account-register/models"
|
||||
"go-account-register/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetIpInfo(ip string) models.Ip {
|
||||
db := utils.GetDB()
|
||||
var ipInfo models.Ip
|
||||
if ip == "" {
|
||||
var ipRequest utils.IpRequest
|
||||
res, err := ipRequest.IpApi(ip)
|
||||
if err != nil {
|
||||
}
|
||||
resIp := db.Model(&models.Ip{}).Where("query = ?", res.Query).First(&ipInfo)
|
||||
if resIp.Error != nil {
|
||||
createIp(res)
|
||||
db.Model(&models.Ip{}).Where("query = ?", res.Query).First(&ipInfo)
|
||||
return ipInfo
|
||||
}
|
||||
return ipInfo
|
||||
}
|
||||
resIp := db.Model(&models.Ip{}).Where("query = ?", ip).First(&ipInfo)
|
||||
if resIp.Error != nil {
|
||||
var ipRequest utils.IpRequest
|
||||
res, err := ipRequest.IpApi(ip)
|
||||
if err != nil {
|
||||
}
|
||||
createIp(res)
|
||||
db.Model(&models.Ip{}).Where("query = ?", ip).First(&ipInfo)
|
||||
return ipInfo
|
||||
}
|
||||
|
||||
return ipInfo
|
||||
}
|
||||
|
||||
func createIp(res utils.IPAPIResponse) {
|
||||
db := utils.GetDB()
|
||||
|
||||
db.Model(&models.Ip{}).Create(&models.Ip{
|
||||
As: res.As,
|
||||
Asname: res.Asname,
|
||||
City: res.City,
|
||||
Continent: res.Continent,
|
||||
ContinentCode: res.ContinentCode,
|
||||
Country: res.Country,
|
||||
CountryCode: res.CountryCode,
|
||||
Currency: res.Currency,
|
||||
District: res.District,
|
||||
Hosting: utils.BoolToInt(res.Hosting),
|
||||
Isp: res.Isp,
|
||||
Lat: fmt.Sprint(res.Lat),
|
||||
Lon: fmt.Sprint(res.Lon),
|
||||
Mobile: utils.BoolToInt(res.Mobile),
|
||||
Offset: fmt.Sprint(res.Offset),
|
||||
Org: res.Org,
|
||||
Proxy: utils.BoolToInt(res.Proxy),
|
||||
Query: res.Query,
|
||||
Region: res.Region,
|
||||
RegionName: res.RegionName,
|
||||
Timezone: res.Timezone,
|
||||
Zip: res.Zip,
|
||||
UpdateTime: time.Now().Unix(),
|
||||
CreateTime: time.Now().Unix(),
|
||||
})
|
||||
}
|
||||
75
utils/index.go
Normal file
75
utils/index.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
type RandDateParams struct {
|
||||
Year int
|
||||
Month int
|
||||
Day int
|
||||
}
|
||||
|
||||
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
const (
|
||||
letterBits = 6 // 52个字母需6位(2^6=64)
|
||||
letterMask = 1<<letterBits - 1 // 二进制掩码(63个1)
|
||||
)
|
||||
|
||||
func BoolToInt(b bool) int64 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func RandString(n int) string {
|
||||
b := make([]byte, n)
|
||||
for i := 0; i < n; {
|
||||
if idx := int(rand.Int63() & letterMask); idx < len(letters) {
|
||||
b[i] = letters[idx]
|
||||
i++
|
||||
} // 丢弃无效索引,重试
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func RandDate(minAge, maxAge int) RandDateParams {
|
||||
// 创建本地随机生成器(避免全局 rand.Seed 弃用问题)
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
// 计算年份范围(当前年-100岁 到 当前年-18岁)
|
||||
currentTime := time.Now()
|
||||
currentYear := currentTime.Year()
|
||||
minYear := currentYear - maxAge
|
||||
maxYear := currentYear - minAge
|
||||
|
||||
// 生成随机年份
|
||||
year := minYear + r.Intn(maxYear-minYear+1)
|
||||
|
||||
// 生成随机月份(1-12)
|
||||
month := r.Intn(12) + 1
|
||||
|
||||
// 动态计算当月最大天数(考虑闰年)
|
||||
daysInMonth := 31
|
||||
switch month {
|
||||
case 2: // 二月特殊处理
|
||||
if (year%4 == 0 && year%100 != 0) || year%400 == 0 {
|
||||
daysInMonth = 29 // 闰年
|
||||
} else {
|
||||
daysInMonth = 28 // 平年
|
||||
}
|
||||
case 4, 6, 9, 11: // 30 天的月份
|
||||
daysInMonth = 30
|
||||
}
|
||||
|
||||
// 生成随机日期(1 ~ daysInMonth)
|
||||
day := r.Intn(daysInMonth) + 1
|
||||
|
||||
return RandDateParams{
|
||||
Year: year,
|
||||
Month: month,
|
||||
Day: day,
|
||||
}
|
||||
}
|
||||
84
utils/ip_request.go
Normal file
84
utils/ip_request.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
)
|
||||
|
||||
type IpRequest struct {
|
||||
}
|
||||
|
||||
type IPAPIResponse struct {
|
||||
As string `json:"as"`
|
||||
Asname string `json:"asname"`
|
||||
City string `json:"city"`
|
||||
Continent string `json:"continent"`
|
||||
ContinentCode string `json:"continentCode"`
|
||||
Country string `json:"country"`
|
||||
CountryCode string `json:"countryCode"`
|
||||
Currency string `json:"currency"`
|
||||
District string `json:"district"`
|
||||
Hosting bool `json:"hosting"`
|
||||
Isp string `json:"isp"`
|
||||
Lat float64 `json:"lat"`
|
||||
Lon float64 `json:"lon"`
|
||||
Mobile bool `json:"mobile"`
|
||||
Offset float64 `json:"offset"`
|
||||
Org string `json:"org"`
|
||||
Proxy bool `json:"proxy"`
|
||||
Query string `json:"query"`
|
||||
Region string `json:"region"`
|
||||
RegionName string `json:"regionName"`
|
||||
Timezone string `json:"timezone"`
|
||||
Zip string `json:"zip"`
|
||||
}
|
||||
|
||||
func (*IpRequest) IpApi(targetIP string) (IPAPIResponse, error) {
|
||||
// 创建Resty客户端
|
||||
client := resty.New()
|
||||
|
||||
// 构建请求URL
|
||||
// targetIP := "103.142.140.235"
|
||||
var url string = "http://demo.ip-api.com/json?fields=66842623&lang=en"
|
||||
if targetIP != "" {
|
||||
url = fmt.Sprintf("http://demo.ip-api.com/json/%s?fields=66842623&lang=en", targetIP)
|
||||
}
|
||||
|
||||
// 创建响应结构体实例
|
||||
var result IPAPIResponse
|
||||
|
||||
// 发送GET请求(不设置任何请求头)
|
||||
resp, err := client.R().
|
||||
SetResult(&result). // 自动解析JSON到结构体
|
||||
Get(url)
|
||||
|
||||
// 错误处理
|
||||
if err != nil {
|
||||
fmt.Printf("请求失败: %v\n", err)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// 检查HTTP状态码
|
||||
if resp.StatusCode() != 200 {
|
||||
fmt.Printf("API返回错误状态码: %d\n", resp.StatusCode())
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (*IpRequest) GetIPAddress() {
|
||||
// 创建Resty客户端
|
||||
client := resty.New()
|
||||
var url string = "http://icanhazip.com/"
|
||||
// 发送GET请求(不设置任何请求头)
|
||||
resp, err := client.R().
|
||||
Get(url)
|
||||
// 错误处理
|
||||
if err != nil {
|
||||
fmt.Printf("请求失败: %v\n", err)
|
||||
}
|
||||
log.Println(resp)
|
||||
}
|
||||
42
utils/proxy_handle.go
Normal file
42
utils/proxy_handle.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ProxyHandle struct {
|
||||
}
|
||||
|
||||
func (ProxyHandle) ParseProxy(proxyStr string) (protocol, username, password, ip, port string, err error) {
|
||||
// 清理字符串中的多余字符(如末尾的 \n)
|
||||
proxyStr = strings.TrimSpace(proxyStr)
|
||||
|
||||
// 解析 URL
|
||||
proxyURL, err := url.Parse(proxyStr)
|
||||
if err != nil {
|
||||
return "", "", "", "", "", err
|
||||
}
|
||||
|
||||
// 提取协议(http/https)
|
||||
protocol = proxyURL.Scheme
|
||||
|
||||
// 提取 IP 和端口
|
||||
host := proxyURL.Host
|
||||
if strings.Contains(host, ":") {
|
||||
parts := strings.Split(host, ":")
|
||||
ip = parts[0]
|
||||
port = parts[1]
|
||||
} else {
|
||||
ip = host
|
||||
port = "8080" // 默认端口
|
||||
}
|
||||
|
||||
// 提取用户名和密码
|
||||
if proxyURL.User != nil {
|
||||
username = proxyURL.User.Username()
|
||||
password, _ = proxyURL.User.Password()
|
||||
}
|
||||
|
||||
return protocol, username, password, ip, port, nil
|
||||
}
|
||||
34
utils/redis.go
Normal file
34
utils/redis.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
// Redis 封装结构体
|
||||
type Redis struct {
|
||||
rdb *redis.Client
|
||||
}
|
||||
|
||||
// 初始化Redis连接
|
||||
func InitRedis() (*Redis, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
// 创建 Redis 客户端
|
||||
rdb := redis.NewClient(&redis.Options{
|
||||
Addr: "localhost:6379", // Redis 服务器地址
|
||||
Password: "", // 密码,没有则为空
|
||||
DB: 0, // 默认数据库
|
||||
})
|
||||
|
||||
// 测试连接
|
||||
if _, err := rdb.Ping(ctx).Result(); err != nil {
|
||||
return nil, fmt.Errorf("redis连接失败: %w", err)
|
||||
}
|
||||
|
||||
log.Println("✅ Redis连接成功")
|
||||
return &Redis{rdb: rdb}, nil
|
||||
}
|
||||
85
utils/verify_image_plugin.go
Normal file
85
utils/verify_image_plugin.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
_ "image/jpeg"
|
||||
"image/png"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/golang/freetype"
|
||||
"golang.org/x/image/font"
|
||||
)
|
||||
|
||||
type VerifyImagePlugin struct{}
|
||||
|
||||
func (*VerifyImagePlugin) DrawText(originalImage, newImage, text, fontPath string) (string, error) {
|
||||
srcFile, err := os.Open(originalImage) // 替换为你的图片路径
|
||||
if err != nil {
|
||||
log.Fatal("图片打开失败:", err)
|
||||
return "", err
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
// 解码原始图片
|
||||
img, _, err := image.Decode(srcFile)
|
||||
if err != nil {
|
||||
log.Fatal("图片解码失败,只支持jpg、png:", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
rgba := image.NewRGBA(img.Bounds())
|
||||
draw.Draw(rgba, rgba.Bounds(), img, image.Point{}, draw.Src)
|
||||
var fontStr string = fontPath
|
||||
if fontPath == "" {
|
||||
fontStr = "fonts/AlibabaPuHuiTi-3-115-Black.ttf"
|
||||
}
|
||||
fontBytes, err := os.ReadFile(fontStr) // 替换为你的字体路径
|
||||
if err != nil {
|
||||
log.Fatal("字体加载失败:", err)
|
||||
return "", err
|
||||
}
|
||||
fontObj, err := freetype.ParseFont(fontBytes)
|
||||
if err != nil {
|
||||
log.Fatal("字体解析失败:", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
c := freetype.NewContext()
|
||||
c.SetDPI(72) // 屏幕分辨率
|
||||
c.SetFont(fontObj) // 设置中文字体
|
||||
c.SetFontSize(40) // 字体大小(磅)
|
||||
c.SetClip(rgba.Bounds()) // 绘制区域
|
||||
c.SetDst(rgba) // 目标画布
|
||||
c.SetSrc(image.NewUniform(color.RGBA{ // 文字颜色
|
||||
R: 255,
|
||||
G: 255,
|
||||
B: 255,
|
||||
A: 255,
|
||||
}))
|
||||
c.SetHinting(font.HintingFull) // 增强小字清晰度
|
||||
|
||||
x := 150 // 水平起始位置
|
||||
y := 250 // 垂直起始位置
|
||||
yBase := y + int(c.PointToFixed(40)>>6) // 关键:修正垂直偏移
|
||||
pt := freetype.Pt(x, yBase)
|
||||
|
||||
if _, err := c.DrawString(text, pt); err != nil {
|
||||
log.Fatal("文字绘制失败:", err)
|
||||
}
|
||||
|
||||
outFile, err := os.Create(newImage)
|
||||
if err != nil {
|
||||
log.Fatal("输出文件创建失败:", err)
|
||||
return "", err
|
||||
}
|
||||
defer outFile.Close()
|
||||
if err := png.Encode(outFile, rgba); err != nil {
|
||||
log.Fatal("图片保存失败:", err)
|
||||
return "", err
|
||||
}
|
||||
log.Println("成功生成:output.png")
|
||||
return newImage, nil
|
||||
}
|
||||
Reference in New Issue
Block a user