diff --git a/api/core/app_server.go b/api/core/app_server.go
index 3f9f33d0..9917fc06 100644
--- a/api/core/app_server.go
+++ b/api/core/app_server.go
@@ -25,55 +25,6 @@ import (
"gorm.io/gorm"
)
-// AuthConfig 定义授权配置
-type AuthConfig struct {
- ExactPaths map[string]bool // 精确匹配的路径
- PrefixPaths map[string]bool // 前缀匹配的路径
-}
-
-var authConfig = &AuthConfig{
- ExactPaths: map[string]bool{
- "/api/user/login": false,
- "/api/user/logout": false,
- "/api/user/resetPass": false,
- "/api/user/register": false,
- "/api/user/clogin": false,
- "/api/user/clogin/callback": false,
- "/api/user/signin": false,
- "/api/admin/login": false,
- "/api/admin/logout": false,
- "/api/admin/login/captcha": false,
- "/api/app/list": false,
- "/api/app/type/list": false,
- "/api/app/list/user": false,
- "/api/model/list": false,
- "/api/mj/imgWall": false,
- "/api/mj/notify": false,
- "/api/invite/hits": false,
- "/api/sd/imgWall": false,
- "/api/dall/imgWall": false,
- "/api/product/list": false,
- "/api/menu/list": false,
- "/api/markMap/client": false,
- "/api/payment/doPay": false,
- "/api/payment/payWays": false,
- "/api/download": false,
- "/api/dall/models": false,
- "/api/chat/message": false, // 聊天接口需要特殊处理
- "/api/realtime": false, // 实时通信接口需要特殊处理
- "/api/realtime/voice": false, // 语音聊天接口需要特殊处理
- },
- PrefixPaths: map[string]bool{
- "/api/test/": false,
- "/api/payment/notify/": false,
- "/api/config/": false,
- "/api/function/": false,
- "/api/sms/": false,
- "/api/captcha/": false,
- "/static/": false,
- },
-}
-
type AppServer struct {
Config *types.AppConfig
Engine *gin.Engine
@@ -94,10 +45,10 @@ func NewServer(appConfig *types.AppConfig, redis *redis.Client, sysConfig *types
func (s *AppServer) Init(client *redis.Client) {
s.Engine.Use(middleware.ParameterHandlerMiddleware())
- s.Engine.Use(middleware.StaticMiddleware())
s.Engine.Use(errorHandler)
// 添加静态资源访问
s.Engine.Static("/static", s.Config.StaticDir)
+ s.Engine.Use(middleware.StaticMiddleware())
}
func (s *AppServer) Run(db *gorm.DB) error {
diff --git a/api/core/types/oss.go b/api/core/types/oss.go
index 434d0ddd..e22f9ef9 100644
--- a/api/core/types/oss.go
+++ b/api/core/types/oss.go
@@ -20,7 +20,6 @@ type MiniOssConfig struct {
AccessKey string `json:"access_key"`
AccessSecret string `json:"access_secret"`
Bucket string `json:"bucket"`
- SubDir string `json:"sub_dir"`
UseSSL bool `json:"use_ssl"`
Domain string `json:"domain"`
}
@@ -30,7 +29,6 @@ type QiNiuOssConfig struct {
AccessKey string `json:"access_key"`
AccessSecret string `json:"access_secret"`
Bucket string `json:"bucket"`
- SubDir string `json:"sub_dir"`
Domain string `json:"domain"`
}
diff --git a/api/core/types/sms.go b/api/core/types/sms.go
index 4d9c6504..7c95ab41 100644
--- a/api/core/types/sms.go
+++ b/api/core/types/sms.go
@@ -8,9 +8,9 @@ package types
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
type SMSConfig struct {
- Active string
- Ali SmsConfigAli
- Bao SmsConfigBao
+ Active string `json:"active"`
+ Ali SmsConfigAli `json:"aliyun"`
+ Bao SmsConfigBao `json:"bao"`
}
// SmsConfigAli 阿里云短信平台配置
diff --git a/api/handler/function_handler.go b/api/handler/function_handler.go
index ed40ae21..174c8b93 100644
--- a/api/handler/function_handler.go
+++ b/api/handler/function_handler.go
@@ -11,7 +11,6 @@ import (
"errors"
"fmt"
"geekai/core"
- "geekai/core/middleware"
"geekai/core/types"
"geekai/service"
"geekai/service/dalle"
@@ -60,12 +59,9 @@ func (h *FunctionHandler) RegisterRoutes() {
group.GET("list", h.List)
// 需要用户授权的接口
- group.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis))
- {
- group.POST("weibo", h.WeiBo)
- group.POST("zaobao", h.ZaoBao)
- group.POST("dalle3", h.Dall3)
- }
+ group.POST("weibo", h.WeiBo)
+ group.POST("zaobao", h.ZaoBao)
+ group.POST("dalle3", h.Dall3)
}
type resVo struct {
diff --git a/api/service/crawler/service.go b/api/service/crawler/service.go
deleted file mode 100644
index 39fb2fa7..00000000
--- a/api/service/crawler/service.go
+++ /dev/null
@@ -1,333 +0,0 @@
-package crawler
-
-import (
- "context"
- "errors"
- "fmt"
- "geekai/logger"
- "net/url"
- "strings"
- "time"
-
- "github.com/go-rod/rod"
- "github.com/go-rod/rod/lib/launcher"
- "github.com/go-rod/rod/lib/proto"
-)
-
-// Service 网络爬虫服务
-type Service struct {
- browser *rod.Browser
-}
-
-// NewService 创建一个新的爬虫服务
-func NewService() (*Service, error) {
- // 启动浏览器
- path, _ := launcher.LookPath()
- u := launcher.New().Bin(path).
- Headless(true). // 无头模式
- Set("disable-web-security", ""). // 禁用网络安全限制
- Set("disable-gpu", ""). // 禁用 GPU 加速
- Set("no-sandbox", ""). // 禁用沙箱模式
- Set("disable-setuid-sandbox", ""). // 禁用 setuid 沙箱
- MustLaunch()
-
- browser := rod.New().ControlURL(u).MustConnect()
-
- return &Service{
- browser: browser,
- }, nil
-}
-
-// SearchResult 搜索结果
-type SearchResult struct {
- Title string `json:"title"` // 标题
- URL string `json:"url"` // 链接
- Content string `json:"content"` // 内容摘要
-}
-
-// WebSearch 网络搜索
-func (s *Service) WebSearch(keyword string, maxPages int) ([]SearchResult, error) {
- if keyword == "" {
- return nil, errors.New("搜索关键词不能为空")
- }
-
- if maxPages <= 0 {
- maxPages = 1
- }
- if maxPages > 10 {
- maxPages = 10 // 最多搜索 10 页
- }
-
- results := make([]SearchResult, 0)
-
- // 使用百度搜索
- searchURL := fmt.Sprintf("https://www.baidu.com/s?wd=%s", url.QueryEscape(keyword))
-
- // 设置页面超时
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
- defer cancel()
-
- // 创建页面
- page := s.browser.MustPage()
- defer page.MustClose()
-
- // 设置视口大小
- err := page.SetViewport(&proto.EmulationSetDeviceMetricsOverride{
- Width: 1280,
- Height: 800,
- })
- if err != nil {
- return nil, fmt.Errorf("设置视口失败: %v", err)
- }
-
- // 导航到搜索页面
- err = page.Context(ctx).Navigate(searchURL)
- if err != nil {
- return nil, fmt.Errorf("导航到搜索页面失败: %v", err)
- }
-
- // 等待搜索结果加载完成
- err = page.WaitLoad()
- if err != nil {
- return nil, fmt.Errorf("等待页面加载完成失败: %v", err)
- }
-
- // 分析当前页面的搜索结果
- for i := 0; i < maxPages; i++ {
- if i > 0 {
- // 点击下一页按钮
- nextPage, err := page.Element("a.n")
- if err != nil || nextPage == nil {
- break // 没有下一页
- }
-
- err = nextPage.Click(proto.InputMouseButtonLeft, 1)
- if err != nil {
- break // 点击下一页失败
- }
-
- // 等待新页面加载
- err = page.WaitLoad()
- if err != nil {
- break
- }
- }
-
- // 提取搜索结果
- resultElements, err := page.Elements(".result, .c-container")
- if err != nil || resultElements == nil {
- continue
- }
-
- for _, result := range resultElements {
- // 获取标题
- titleElement, err := result.Element("h3, .t")
- if err != nil || titleElement == nil {
- continue
- }
-
- title, err := titleElement.Text()
- if err != nil {
- continue
- }
-
- // 获取 URL
- linkElement, err := titleElement.Element("a")
- if err != nil || linkElement == nil {
- continue
- }
-
- href, err := linkElement.Attribute("href")
- if err != nil || href == nil {
- continue
- }
-
- // 获取内容摘要 - 尝试多个可能的选择器
- var contentElement *rod.Element
- var content string
-
- // 尝试多个可能的选择器来适应不同版本的百度搜索结果
- selectors := []string{".content-right_8Zs40", ".c-abstract", ".content_LJ0WN", ".content"}
- for _, selector := range selectors {
- contentElement, err = result.Element(selector)
- if err == nil && contentElement != nil {
- content, _ = contentElement.Text()
- if content != "" {
- break
- }
- }
- }
-
- // 如果所有选择器都失败,尝试直接从结果块中提取文本
- if content == "" {
- // 获取结果元素的所有文本
- fullText, err := result.Text()
- if err == nil && fullText != "" {
- // 简单处理:从全文中移除标题,剩下的可能是摘要
- fullText = strings.Replace(fullText, title, "", 1)
- // 清理文本
- content = strings.TrimSpace(fullText)
- // 限制内容长度
- if len(content) > 200 {
- content = content[:200] + "..."
- }
- }
- }
-
- // 添加到结果集
- results = append(results, SearchResult{
- Title: title,
- URL: *href,
- Content: content,
- })
-
- // 限制结果数量,每页最多 10 条
- if len(results) >= 10*maxPages {
- break
- }
- }
- }
-
- // 获取真实 URL(百度搜索结果中的 URL 是短链接,需要跳转获取真实 URL)
- for i, result := range results {
- realURL, err := s.getRedirectURL(result.URL)
- if err == nil && realURL != "" {
- results[i].URL = realURL
- }
- }
-
- return results, nil
-}
-
-// 获取真实 URL
-func (s *Service) getRedirectURL(shortURL string) (string, error) {
- // 创建页面
- page, err := s.browser.Page(proto.TargetCreateTarget{URL: ""})
- if err != nil {
- return shortURL, err // 返回原始URL
- }
- defer func() {
- _ = page.Close()
- }()
-
- // 导航到短链接
- err = page.Navigate(shortURL)
- if err != nil {
- return shortURL, err // 返回原始URL
- }
-
- // 等待重定向完成
- time.Sleep(2 * time.Second)
-
- // 获取当前 URL
- info, err := page.Info()
- if err != nil {
- return shortURL, err // 返回原始URL
- }
-
- return info.URL, nil
-}
-
-// Close 关闭浏览器
-func (s *Service) Close() error {
- if s.browser != nil {
- err := s.browser.Close()
- s.browser = nil
- return err
- }
- return nil
-}
-
-// SearchWeb 封装的搜索方法
-func SearchWeb(keyword string, maxPages int) (string, error) {
- // 添加panic恢复机制
- defer func() {
- if r := recover(); r != nil {
- log := logger.GetLogger()
- log.Errorf("爬虫服务崩溃: %v", r)
- }
- }()
-
- service, err := NewService()
- if err != nil {
- return "", fmt.Errorf("创建爬虫服务失败: %v", err)
- }
- defer service.Close()
-
- // 设置超时上下文
- ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
- defer cancel()
-
- // 使用goroutine和通道来处理超时
- resultChan := make(chan []SearchResult, 1)
- errChan := make(chan error, 1)
-
- go func() {
- results, err := service.WebSearch(keyword, maxPages)
- if err != nil {
- errChan <- err
- return
- }
- resultChan <- results
- }()
-
- // 等待结果或超时
- select {
- case <-ctx.Done():
- return "", fmt.Errorf("搜索超时: %v", ctx.Err())
- case err := <-errChan:
- return "", fmt.Errorf("搜索失败: %v", err)
- case results := <-resultChan:
- if len(results) == 0 {
- return "未找到关于 \"" + keyword + "\" 的相关搜索结果", nil
- }
-
- // 格式化结果
- var builder strings.Builder
- builder.WriteString(fmt.Sprintf("为您找到关于 \"%s\" 的 %d 条搜索结果:\n\n", keyword, len(results)))
-
- for i, result := range results {
- // // 尝试打开链接获取实际内容
- // page := service.browser.MustPage()
- // defer page.MustClose()
-
- // // 设置页面超时
- // pageCtx, pageCancel := context.WithTimeout(context.Background(), 10*time.Second)
- // defer pageCancel()
-
- // // 导航到目标页面
- // err := page.Context(pageCtx).Navigate(result.URL)
- // if err == nil {
- // // 等待页面加载
- // _ = page.WaitLoad()
-
- // // 获取页面标题
- // title, err := page.Eval("() => document.title")
- // if err == nil && title.Value.String() != "" {
- // result.Title = title.Value.String()
- // }
-
- // // 获取页面主要内容
- // if content, err := page.Element("body"); err == nil {
- // if text, err := content.Text(); err == nil {
- // // 清理并截取内容
- // text = strings.TrimSpace(text)
- // if len(text) > 200 {
- // text = text[:200] + "..."
- // }
- // result.Prompt = text
- // }
- // }
- // }
-
- builder.WriteString(fmt.Sprintf("%d. **%s**\n", i+1, result.Title))
- builder.WriteString(fmt.Sprintf(" 链接: %s\n", result.URL))
- if result.Content != "" {
- builder.WriteString(fmt.Sprintf(" 摘要: %s\n", result.Content))
- }
- builder.WriteString("\n")
- }
-
- return builder.String(), nil
- }
-}
diff --git a/api/service/dalle/service.go b/api/service/dalle/service.go
index 7bad5115..dd9b66db 100644
--- a/api/service/dalle/service.go
+++ b/api/service/dalle/service.go
@@ -122,15 +122,6 @@ type ErrRes struct {
func (s *Service) Image(task types.DallTask, sync bool) (string, error) {
logger.Debugf("绘画参数:%+v", task)
- prompt := task.Prompt
- // translate prompt
- if utils.HasChinese(prompt) {
- content, err := utils.OpenAIRequest(s.db, fmt.Sprintf(service.TranslatePromptTemplate, prompt), task.TranslateModelId)
- if err == nil {
- prompt = content
- logger.Debugf("重写后提示词:%s", prompt)
- }
- }
var chatModel model.ChatModel
if task.ModelId > 0 {
@@ -160,7 +151,7 @@ func (s *Service) Image(task types.DallTask, sync bool) (string, error) {
apiURL := fmt.Sprintf("%s/v1/images/generations", apiKey.ApiURL)
reqBody := imgReq{
Model: chatModel.Value,
- Prompt: prompt,
+ Prompt: task.Prompt,
N: 1,
Size: task.Size,
Style: task.Style,
@@ -188,7 +179,7 @@ func (s *Service) Image(task types.DallTask, sync bool) (string, error) {
var imgURL string
var data = map[string]interface{}{
"progress": 100,
- "prompt": prompt,
+ "prompt": task.Prompt,
}
// 如果返回的是base64,则需要上传到oss
if res.Data[0].B64Json != "" {
@@ -214,7 +205,7 @@ func (s *Service) Image(task types.DallTask, sync bool) (string, error) {
if err != nil {
return "", fmt.Errorf("error with download image: %v", err)
}
- content = fmt.Sprintf("```\n%s\n```\n下面是我为你创作的图片:\n\n\n", prompt, imgURL)
+ content = fmt.Sprintf("```\n%s\n```\n下面是我为你创作的图片:\n\n\n", task.Prompt, imgURL)
}
return content, nil
diff --git a/api/service/migration_service.go b/api/service/migration_service.go
index cf5bb8b3..1288af95 100644
--- a/api/service/migration_service.go
+++ b/api/service/migration_service.go
@@ -13,6 +13,7 @@ import (
"geekai/core/types"
"geekai/store"
"geekai/store/model"
+ "strings"
"github.com/go-redis/redis/v8"
"gorm.io/gorm"
@@ -191,8 +192,8 @@ func (s *MigrationService) migrateCommunicationConfig(config *types.AppConfig) e
// 短信配置
smsConfig := map[string]any{
- "active": config.SMS.Active,
- "ali": map[string]any{
+ "active": strings.ToLower(config.SMS.Active),
+ "aliyun": map[string]any{
"access_key": config.SMS.Ali.AccessKey,
"access_secret": config.SMS.Ali.AccessSecret,
"sign": config.SMS.Ali.Sign,
diff --git a/api/service/mj/service.go b/api/service/mj/service.go
index 7564bda0..498d3bb2 100644
--- a/api/service/mj/service.go
+++ b/api/service/mj/service.go
@@ -67,25 +67,6 @@ func (s *Service) Run() {
continue
}
- // translate prompt
- if utils.HasChinese(task.Prompt) {
- content, err := utils.OpenAIRequest(s.db, fmt.Sprintf(service.TranslatePromptTemplate, task.Prompt), task.TranslateModelId)
- if err == nil {
- task.Prompt = content
- } else {
- logger.Warnf("error with translate prompt: %v", err)
- }
- }
- // translate negative prompt
- if task.NegPrompt != "" && utils.HasChinese(task.NegPrompt) {
- content, err := utils.OpenAIRequest(s.db, fmt.Sprintf(service.TranslatePromptTemplate, task.NegPrompt), task.TranslateModelId)
- if err == nil {
- task.NegPrompt = content
- } else {
- logger.Warnf("error with translate prompt: %v", err)
- }
- }
-
// use fast mode as default
if task.Mode == "" {
task.Mode = "fast"
diff --git a/api/service/oss/minio_oss.go b/api/service/oss/minio_oss.go
index d7f28d4b..f7465b78 100644
--- a/api/service/oss/minio_oss.go
+++ b/api/service/oss/minio_oss.go
@@ -72,7 +72,7 @@ func (s MiniOss) PutUrlFile(fileURL string, ext string, useProxy bool) (string,
if ext == "" {
ext = filepath.Ext(parse.Path)
}
- filename := fmt.Sprintf("%s/%d%s", s.config.SubDir, time.Now().UnixMicro(), ext)
+ filename := fmt.Sprintf("%d%s", time.Now().UnixMicro(), ext)
info, err := s.client.PutObject(
context.Background(),
s.config.Bucket,
@@ -99,7 +99,7 @@ func (s MiniOss) PutFile(ctx *gin.Context, name string) (File, error) {
defer fileReader.Close()
fileExt := filepath.Ext(file.Filename)
- filename := fmt.Sprintf("%s/%d%s", s.config.SubDir, time.Now().UnixMicro(), fileExt)
+ filename := fmt.Sprintf("%d%s", time.Now().UnixMicro(), fileExt)
info, err := s.client.PutObject(ctx, s.config.Bucket, filename, fileReader, file.Size, minio.PutObjectOptions{
ContentType: file.Header.Get("Body-Type"),
})
@@ -121,7 +121,7 @@ func (s MiniOss) PutBase64(base64Img string) (string, error) {
if err != nil {
return "", fmt.Errorf("error decoding base64:%v", err)
}
- objectKey := fmt.Sprintf("%s/%d.png", s.config.SubDir, time.Now().UnixMicro())
+ objectKey := fmt.Sprintf("%d.png", time.Now().UnixMicro())
info, err := s.client.PutObject(
context.Background(),
s.config.Bucket,
@@ -138,8 +138,7 @@ func (s MiniOss) PutBase64(base64Img string) (string, error) {
func (s MiniOss) Delete(fileURL string) error {
var objectKey string
if strings.HasPrefix(fileURL, "http") {
- filename := filepath.Base(fileURL)
- objectKey = fmt.Sprintf("%s/%s", s.config.SubDir, filename)
+ objectKey = filepath.Base(fileURL)
} else {
objectKey = fileURL
}
diff --git a/api/service/oss/qiniu_oss.go b/api/service/oss/qiniu_oss.go
index d99752a2..3623c648 100644
--- a/api/service/oss/qiniu_oss.go
+++ b/api/service/oss/qiniu_oss.go
@@ -75,7 +75,7 @@ func (s QiNiuOss) PutFile(ctx *gin.Context, name string) (File, error) {
defer src.Close()
fileExt := filepath.Ext(file.Filename)
- key := fmt.Sprintf("%s/%d%s", s.config.SubDir, time.Now().UnixMicro(), fileExt)
+ key := fmt.Sprintf("%d%s", time.Now().UnixMicro(), fileExt)
// 上传文件
ret := storage.PutRet{}
extra := storage.PutExtra{}
@@ -112,7 +112,7 @@ func (s QiNiuOss) PutUrlFile(fileURL string, ext string, useProxy bool) (string,
if ext == "" {
ext = filepath.Ext(parse.Path)
}
- key := fmt.Sprintf("%s/%d%s", s.config.SubDir, time.Now().UnixMicro(), ext)
+ key := fmt.Sprintf("%d%s", time.Now().UnixMicro(), ext)
ret := storage.PutRet{}
extra := storage.PutExtra{}
// 上传文件字节数据
@@ -128,7 +128,7 @@ func (s QiNiuOss) PutBase64(base64Img string) (string, error) {
if err != nil {
return "", fmt.Errorf("error decoding base64:%v", err)
}
- objectKey := fmt.Sprintf("%s/%d.png", s.config.SubDir, time.Now().UnixMicro())
+ objectKey := fmt.Sprintf("%d.png", time.Now().UnixMicro())
ret := storage.PutRet{}
extra := storage.PutExtra{}
// 上传文件字节数据
@@ -142,8 +142,7 @@ func (s QiNiuOss) PutBase64(base64Img string) (string, error) {
func (s QiNiuOss) Delete(fileURL string) error {
var objectKey string
if strings.HasPrefix(fileURL, "http") {
- filename := filepath.Base(fileURL)
- objectKey = fmt.Sprintf("%s/%s", s.config.SubDir, filename)
+ objectKey = filepath.Base(fileURL)
} else {
objectKey = fileURL
}
diff --git a/api/utils/resp/response.go b/api/utils/resp/response.go
index cc20b2bf..bc4f75ca 100644
--- a/api/utils/resp/response.go
+++ b/api/utils/resp/response.go
@@ -9,8 +9,9 @@ package resp
import (
"geekai/core/types"
- "github.com/gin-gonic/gin"
"net/http"
+
+ "github.com/gin-gonic/gin"
)
func SUCCESS(c *gin.Context, values ...interface{}) {
diff --git a/web/src/components/admin/AdminSidebar.vue b/web/src/components/admin/AdminSidebar.vue
index 9fa861a9..738c095c 100644
--- a/web/src/components/admin/AdminSidebar.vue
+++ b/web/src/components/admin/AdminSidebar.vue
@@ -223,14 +223,19 @@ const items = [
title: '存储配置',
},
{
- icon: 'log',
- index: '/admin/config/communication',
- title: '通信配置',
+ icon: 'sms',
+ index: '/admin/config/sms',
+ title: '短信配置',
},
{
- icon: 'api-key',
- index: '/admin/config/api',
- title: 'API配置',
+ icon: 'email',
+ index: '/admin/config/smtp',
+ title: '邮件配置',
+ },
+ {
+ icon: 'plugin',
+ index: '/admin/config/plugin',
+ title: '插件配置',
},
],
},
diff --git a/web/src/components/ui/Alert.vue b/web/src/components/ui/Alert.vue
new file mode 100644
index 00000000..cb187cc7
--- /dev/null
+++ b/web/src/components/ui/Alert.vue
@@ -0,0 +1,47 @@
+
+