feat: initial commit - Go + CGO captcha recognition service
Build and Deploy / build-frontend (push) Failing after 2s
Build and Deploy / build-backend (push) Has been skipped
Build and Deploy / build-docker (push) Has been skipped
Build and Deploy / deploy (push) Has been skipped

Features:
- Go + CGO ONNX/OpenCV wrapper for high performance
- SQLite (default) / MySQL database support
- Optional Redis caching
- JWT authentication system
- Multiple captcha recognition APIs:
  - OCR text recognition
  - Slider captcha matching
  - Image similarity comparison
  - Rotation captcha detection
  - Object detection
- React frontend with install wizard
- Docker and docker-compose support
- Gitea CI/CD pipeline

Project structure:
- cmd/server: Main entry point
- internal/: Core business logic
- pkg/onnx: ONNX Runtime CGO wrapper
- pkg/opencv: OpenCV CGO wrapper
- web/: React frontend
- deploy/: Deployment configs
- scripts/: Utility scripts
This commit is contained in:
2026-07-16 08:56:38 +00:00
commit 524c404194
32 changed files with 2971 additions and 0 deletions
+112
View File
@@ -0,0 +1,112 @@
package config
import (
"fmt"
"os"
"github.com/spf13/viper"
)
type Config struct {
Server ServerConfig
Database DatabaseConfig
Redis RedisConfig
JWT JWTConfig
Captcha CaptchaConfig
}
type ServerConfig struct {
Host string
Port int
Mode string
}
type DatabaseConfig struct {
Type string // sqlite or mysql
Host string
Port int
User string
Password string
Database string
SQLite SQLiteConfig
}
type SQLiteConfig struct {
Path string
}
type RedisConfig struct {
Enabled bool
Host string
Port int
Password string
DB int
}
type JWTConfig struct {
Secret string
ExpireTime int // hours
}
type CaptchaConfig struct {
ModelPath string
}
var Cfg *Config
func Load(configPath string) error {
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.AddConfigPath("./data")
viper.AddConfigPath(configPath)
// 默认值
viper.SetDefault("server.host", "0.0.0.0")
viper.SetDefault("server.port", 6688)
viper.SetDefault("server.mode", "release")
viper.SetDefault("database.type", "sqlite")
viper.SetDefault("database.sqlite.path", "./data/app.db")
viper.SetDefault("database.host", "localhost")
viper.SetDefault("database.port", 3306)
viper.SetDefault("redis.enabled", false)
viper.SetDefault("redis.host", "localhost")
viper.SetDefault("redis.port", 6379)
viper.SetDefault("redis.db", 0)
viper.SetDefault("jwt.expire_time", 1440) // 60 days
viper.SetDefault("captcha.model_path", "./models")
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
return fmt.Errorf("配置文件未找到,请先运行安装向导")
}
return err
}
Cfg = &Config{}
if err := viper.Unmarshal(Cfg); err != nil {
return err
}
// 从环境变量读取 JWT Secret
if secret := os.Getenv("JWT_SECRET"); secret != "" {
Cfg.JWT.Secret = secret
}
return nil
}
func Save(cfg *Config) error {
viper.Set("server", cfg.Server)
viper.Set("database", cfg.Database)
viper.Set("redis", cfg.Redis)
viper.Set("jwt", cfg.JWT)
viper.Set("captcha", cfg.Captcha)
return viper.WriteConfig()
}
func IsInstalled() bool {
_, err := os.Stat("./data/config.yaml")
return err == nil
}