diff --git a/api/config.sample.toml b/api/config.sample.toml index 53fbaa80..27e24bf1 100644 --- a/api/config.sample.toml +++ b/api/config.sample.toml @@ -25,23 +25,16 @@ WeChatBot = false AppId = "" Token = "" -[SmsConfig] # 阿里云短信服务配置 - AccessKey = "" - AccessSecret = "" - Product = "Dysmsapi" - Domain = "dysmsapi.aliyuncs.com" - Sign = "" - CodeTempId = "" -[Sms] # Sms 配置,用于发送短信 +[SMS] # Sms 配置,用于发送短信 Active = "Ali" # 当前启用的短信服务,默认使用阿里云 - [Sms.SmsBao] + [SMS.Bao] Username = "" Password = "" Domain = "api.smsbao.com" Sign = "【极客学长】" CodeTemplate = "您的验证码是{code}。5分钟有效,若非本人操作,请忽略本短信。" - [Sms.Ali] + [SMS.Ali] AccessKey = "" AccessSecret = "" Product = "Dysmsapi" @@ -82,6 +75,7 @@ WeChatBot = false [[MjPlusConfigs]] Enabled = false ApiURL = "https://api.chatgpt-plus.net" # 目前暂时不支持更改 + CdnURL = "" # CND 加速的 URL,如果有的话就设置 ApiKey = "sk-xxx" NotifyURL = "https://ai.r9it.com/api/mj/notify" # 这里需要改成你的域名 @@ -113,9 +107,9 @@ WeChatBot = false [HuPiPayConfig] Enabled = false Name = "wechat" - AppId = "201906161477" - AppSecret = "7f403199d510fb2c6f0b9f2311800e7c" - PayURL = "https://api.xunhupay.com/payment/do.html" + AppId = "" + AppSecret = "" + ApiURL = "https://api.xunhupay.com" NotifyURL = "https://ai.r9it.com/api/payment/hupipay/notify" [SmtpConfig] # 注意,阿里云服务器禁用了25号端口,所以如果需要使用邮件功能,请别用阿里云服务器 @@ -130,5 +124,5 @@ WeChatBot = false Name = "wechat" # 请不要改动 AppId = "" # 商户 ID PrivateKey = "" # 秘钥 - ApiURL = "https://payjs.cn/api/native" + ApiURL = "https://payjs.cn" NotifyURL = "https://ai.r9it.com/api/payment/payjs/notify" # 异步回调地址,域名改成你自己的 \ No newline at end of file diff --git a/api/core/types/config.go b/api/core/types/config.go index f31ab96d..4fcb581d 100644 --- a/api/core/types/config.go +++ b/api/core/types/config.go @@ -19,7 +19,6 @@ type AppConfig struct { OSS OSSConfig // OSS config MjConfigs []MidJourneyConfig // mj AI draw service pool MjPlusConfigs []MidJourneyPlusConfig // MJ plus config - ImgCdnURL string // 图片反代加速地址 WeChatBot bool // 是否启用微信机器人 SdConfigs []StableDiffusionConfig // sd AI draw service pool @@ -51,6 +50,7 @@ type MidJourneyConfig struct { GuildId string // Server ID ChanelId string // Chanel ID UseCDN bool + ImgCdnURL string // 图片反代加速地址 DiscordAPI string DiscordGateway string } @@ -63,8 +63,9 @@ type StableDiffusionConfig struct { } type MidJourneyPlusConfig struct { - Enabled bool // 如果启用了 MidJourney Plus,将会自动禁用原生的MidJourney服务 - ApiURL string + Enabled bool // 如果启用了 MidJourney Plus,将会自动禁用原生的MidJourney服务 + ApiURL string // api 地址 + CdnURL string // CDN 加速地址 ApiKey string NotifyURL string // 任务进度更新回调地址 } diff --git a/api/core/types/task.go b/api/core/types/task.go index cb22c395..7e84aa65 100644 --- a/api/core/types/task.go +++ b/api/core/types/task.go @@ -17,7 +17,7 @@ const ( // MjTask MidJourney 任务 type MjTask struct { - Id int `json:"id"` + Id uint `json:"id"` TaskId string `json:"task_id"` ImgArr []string `json:"img_arr"` ChannelId string `json:"channel_id"` diff --git a/api/handler/mj_handler.go b/api/handler/mj_handler.go index b1c78756..11756b43 100644 --- a/api/handler/mj_handler.go +++ b/api/handler/mj_handler.go @@ -168,7 +168,7 @@ func (h *MidJourneyHandler) Image(c *gin.Context) { } h.pool.PushTask(types.MjTask{ - Id: int(job.Id), + Id: job.Id, TaskId: taskId, SessionId: data.SessionId, Type: types.TaskType(data.TaskType), @@ -178,7 +178,9 @@ func (h *MidJourneyHandler) Image(c *gin.Context) { }) client := h.pool.Clients.Get(uint(job.UserId)) - _ = client.Send([]byte("Task Updated")) + if client != nil { + _ = client.Send([]byte("Task Updated")) + } // update user's img calls h.db.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("img_calls", gorm.Expr("img_calls - ?", 1)) @@ -227,7 +229,7 @@ func (h *MidJourneyHandler) Upscale(c *gin.Context) { } h.pool.PushTask(types.MjTask{ - Id: int(job.Id), + Id: job.Id, SessionId: data.SessionId, Type: types.TaskUpscale, Prompt: data.Prompt, @@ -239,7 +241,9 @@ func (h *MidJourneyHandler) Upscale(c *gin.Context) { }) client := h.pool.Clients.Get(uint(job.UserId)) - _ = client.Send([]byte("Task Updated")) + if client != nil { + _ = client.Send([]byte("Task Updated")) + } resp.SUCCESS(c) } @@ -275,7 +279,7 @@ func (h *MidJourneyHandler) Variation(c *gin.Context) { } h.pool.PushTask(types.MjTask{ - Id: int(job.Id), + Id: job.Id, SessionId: data.SessionId, Type: types.TaskVariation, Prompt: data.Prompt, @@ -287,7 +291,9 @@ func (h *MidJourneyHandler) Variation(c *gin.Context) { }) client := h.pool.Clients.Get(uint(job.UserId)) - _ = client.Send([]byte("Task Updated")) + if client != nil { + _ = client.Send([]byte("Task Updated")) + } // update user's img calls h.db.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("img_calls", gorm.Expr("img_calls - ?", 1)) @@ -340,8 +346,8 @@ func (h *MidJourneyHandler) JobList(c *gin.Context) { if item.Progress < 100 && item.ImgURL == "" && item.OrgURL != "" { // 正在运行中任务使用代理访问图片 - if h.App.Config.ImgCdnURL != "" { - job.ImgURL = strings.ReplaceAll(job.OrgURL, "https://cdn.discordapp.com", h.App.Config.ImgCdnURL) + if job.UseProxy { + job.ImgURL = job.OrgURL } else { image, err := utils.DownloadImage(item.OrgURL, h.App.Config.ProxyURL) if err == nil { @@ -381,7 +387,9 @@ func (h *MidJourneyHandler) Remove(c *gin.Context) { } client := h.pool.Clients.Get(data.UserId) - _ = client.Send([]byte("Task Updated")) + if client != nil { + _ = client.Send([]byte("Task Updated")) + } resp.SUCCESS(c) } diff --git a/api/service/mj/client.go b/api/service/mj/client.go index bd557628..eada7586 100644 --- a/api/service/mj/client.go +++ b/api/service/mj/client.go @@ -12,13 +12,12 @@ import ( // MidJourney client type Client struct { - client *req.Client - Config types.MidJourneyConfig - imgCdnURL string - apiURL string + client *req.Client + Config types.MidJourneyConfig + apiURL string } -func NewClient(config types.MidJourneyConfig, proxy string, imgCdnURL string) *Client { +func NewClient(config types.MidJourneyConfig, proxy string) *Client { client := req.C().SetTimeout(10 * time.Second) var apiURL string // set proxy URL @@ -31,7 +30,7 @@ func NewClient(config types.MidJourneyConfig, proxy string, imgCdnURL string) *C } } - return &Client{client: client, Config: config, apiURL: apiURL, imgCdnURL: imgCdnURL} + return &Client{client: client, Config: config, apiURL: apiURL} } func (c *Client) Imagine(task types.MjTask) error { diff --git a/api/service/mj/plus/client.go b/api/service/mj/plus/client.go index b79afa24..b2035929 100644 --- a/api/service/mj/plus/client.go +++ b/api/service/mj/plus/client.go @@ -7,9 +7,10 @@ import ( "encoding/base64" "errors" "fmt" - "github.com/gin-gonic/gin" "io" + "github.com/gin-gonic/gin" + "github.com/imroc/req/v3" ) @@ -18,10 +19,17 @@ var logger = logger2.GetLogger() // Client MidJourney Plus Client type Client struct { Config types.MidJourneyPlusConfig + apiURL string } func NewClient(config types.MidJourneyPlusConfig) *Client { - return &Client{Config: config} + var apiURL string + if config.CdnURL != "" { + apiURL = config.CdnURL + } else { + apiURL = config.ApiURL + } + return &Client{Config: config, apiURL: apiURL} } type ImageReq struct { @@ -54,12 +62,12 @@ type ErrRes struct { } func (c *Client) Imagine(task types.MjTask) (ImageRes, error) { - apiURL := fmt.Sprintf("%s/mj-fast/mj/submit/imagine", c.Config.ApiURL) + apiURL := fmt.Sprintf("%s/mj-fast/mj/submit/imagine", c.apiURL) body := ImageReq{ BotType: "MID_JOURNEY", Prompt: task.Prompt, NotifyHook: c.Config.NotifyURL, - Base64Array: make([]string, 1), + Base64Array: make([]string, 0), } // 生成图片 Base64 编码 if len(task.ImgArr) > 0 { @@ -67,7 +75,7 @@ func (c *Client) Imagine(task types.MjTask) (ImageRes, error) { if err != nil { logger.Error("error with download image: ", err) } else { - body.Base64Array[0] = "data:image/png;base64," + base64.StdEncoding.EncodeToString(imageData) + body.Base64Array = append(body.Base64Array, "data:image/png;base64,"+base64.StdEncoding.EncodeToString(imageData)) } } @@ -80,12 +88,12 @@ func (c *Client) Imagine(task types.MjTask) (ImageRes, error) { SetErrorResult(&errRes). Post(apiURL) if err != nil { - errStr, _ := io.ReadAll(r.Body) - return ImageRes{}, fmt.Errorf("请求 API 出错:%v,%v", err, string(errStr)) + return ImageRes{}, fmt.Errorf("请求 API 出错:%v", err) } if r.IsErrorState() { - return ImageRes{}, fmt.Errorf("API 返回错误:%s", errRes.Error.Message) + errStr, _ := io.ReadAll(r.Body) + return ImageRes{}, fmt.Errorf("API 返回错误:%s,%v", errRes.Error.Message, string(errStr)) } return res, nil @@ -93,7 +101,7 @@ func (c *Client) Imagine(task types.MjTask) (ImageRes, error) { // Blend 融图 func (c *Client) Blend(task types.MjTask) (ImageRes, error) { - apiURL := fmt.Sprintf("%s/mj-fast/mj/submit/blend", c.Config.ApiURL) + apiURL := fmt.Sprintf("%s/mj-fast/mj/submit/blend", c.apiURL) body := ImageReq{ BotType: "MID_JOURNEY", Dimensions: "SQUARE", @@ -133,7 +141,7 @@ func (c *Client) Blend(task types.MjTask) (ImageRes, error) { // SwapFace 换脸 func (c *Client) SwapFace(task types.MjTask) (ImageRes, error) { - apiURL := fmt.Sprintf("%s/mj-fast/mj/insight-face/swap", c.Config.ApiURL) + apiURL := fmt.Sprintf("%s/mj-fast/mj/insight-face/swap", c.apiURL) // 生成图片 Base64 编码 if len(task.ImgArr) != 2 { return ImageRes{}, errors.New("参数错误,必须上传2张图片") @@ -189,7 +197,7 @@ func (c *Client) Upscale(task types.MjTask) (ImageRes, error) { "taskId": task.MessageId, "notifyHook": c.Config.NotifyURL, } - apiURL := fmt.Sprintf("%s/mj/submit/action", c.Config.ApiURL) + apiURL := fmt.Sprintf("%s/mj/submit/action", c.apiURL) var res ImageRes var errRes ErrRes r, err := req.C().R(). @@ -216,7 +224,7 @@ func (c *Client) Variation(task types.MjTask) (ImageRes, error) { "taskId": task.MessageId, "notifyHook": c.Config.NotifyURL, } - apiURL := fmt.Sprintf("%s/mj/submit/action", c.Config.ApiURL) + apiURL := fmt.Sprintf("%s/mj/submit/action", c.apiURL) var res ImageRes var errRes ErrRes r, err := req.C().R(). @@ -262,7 +270,7 @@ type QueryRes struct { } func (c *Client) QueryTask(taskId string) (QueryRes, error) { - apiURL := fmt.Sprintf("%s/mj/task/%s/fetch", c.Config.ApiURL, taskId) + apiURL := fmt.Sprintf("%s/mj/task/%s/fetch", c.apiURL, taskId) var res QueryRes r, err := req.C().R().SetHeader("Authorization", "Bearer "+c.Config.ApiKey). SetSuccessResult(&res). diff --git a/api/service/mj/plus/service.go b/api/service/mj/plus/service.go index ff761366..f653e851 100644 --- a/api/service/mj/plus/service.go +++ b/api/service/mj/plus/service.go @@ -86,10 +86,10 @@ func (s *Service) Run() { } if err != nil || (res.Code != 1 && res.Code != 22) { - errMsg := err.Error() + res.Description + errMsg := fmt.Sprintf("%v,%s", err, res.Description) logger.Error("绘画任务执行失败:", errMsg) // update the task progress - s.db.Model(&model.MidJourneyJob{Id: uint(task.Id)}).UpdateColumns(map[string]interface{}{ + s.db.Model(&model.MidJourneyJob{Id: task.Id}).UpdateColumns(map[string]interface{}{ "progress": -1, "err_msg": errMsg, }) @@ -105,10 +105,10 @@ func (s *Service) Run() { } logger.Infof("任务提交成功:%+v", res) // lock the task until the execute timeout - s.taskStartTimes[task.Id] = time.Now() + s.taskStartTimes[int(task.Id)] = time.Now() atomic.AddInt32(&s.HandledTaskNum, 1) // 更新任务 ID/频道 - s.db.Model(&model.MidJourneyJob{}).Where("id = ?", task.Id).UpdateColumns(map[string]interface{}{ + s.db.Debug().Model(&model.MidJourneyJob{Id: task.Id}).UpdateColumns(map[string]interface{}{ "task_id": res.Result, "channel_id": s.Name, }) @@ -152,26 +152,55 @@ type CBReq struct { } `json:"properties"` } -func (s *Service) Notify(data CBReq, job model.MidJourneyJob) error { +func (s *Service) Notify(job model.MidJourneyJob) error { + task, err := s.Client.QueryTask(job.TaskId) + if err != nil { + return err + } - job.Progress = utils.IntValue(strings.Replace(data.Progress, "%", "", 1), 0) - job.Prompt = data.Properties.FinalPrompt - if data.ImageUrl != "" { - job.OrgURL = data.ImageUrl + // 任务执行失败了 + if task.FailReason != "" { + s.db.Model(&model.MidJourneyJob{Id: job.Id}).UpdateColumns(map[string]interface{}{ + "progress": -1, + "err_msg": task.FailReason, + }) + return fmt.Errorf("task failed: %v", task.FailReason) + } + + if len(task.Buttons) > 0 { + job.Hash = GetImageHash(task.Buttons[0].CustomId) + } + oldProgress := job.Progress + job.Progress = utils.IntValue(strings.Replace(task.Progress, "%", "", 1), 0) + job.Prompt = task.PromptEn + if task.ImageUrl != "" { + if s.Client.Config.CdnURL != "" { + job.OrgURL = strings.Replace(task.ImageUrl, s.Client.Config.ApiURL, s.Client.Config.CdnURL, 1) + } else { + job.OrgURL = task.ImageUrl + } } job.UseProxy = true - job.MessageId = data.Id - logger.Debugf("JOB: %+v", job) - res := s.db.Updates(&job) - if res.Error != nil { - return fmt.Errorf("error with update job: %v", res.Error) + job.MessageId = task.Id + tx := s.db.Updates(&job) + if tx.Error != nil { + return fmt.Errorf("error with update database: %v", tx.Error) } - - if data.Status == "SUCCESS" { + if task.Status == "SUCCESS" { // release lock task atomic.AddInt32(&s.HandledTaskNum, -1) } - - s.notifyQueue.RPush(job.UserId) + // 通知前端更新任务进度 + if oldProgress != job.Progress { + s.notifyQueue.RPush(job.UserId) + } return nil } + +func GetImageHash(action string) string { + split := strings.Split(action, "::") + if len(split) > 5 { + return split[4] + } + return split[len(split)-1] +} diff --git a/api/service/mj/pool.go b/api/service/mj/pool.go index 9d2cc9d0..0e271bb3 100644 --- a/api/service/mj/pool.go +++ b/api/service/mj/pool.go @@ -6,11 +6,9 @@ import ( "chatplus/service/oss" "chatplus/store" "chatplus/store/model" - "chatplus/utils" "fmt" "github.com/go-redis/redis/v8" "strings" - "sync/atomic" "time" "gorm.io/gorm" @@ -35,9 +33,8 @@ func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderMa if config.Enabled == false { continue } - if config.ApiURL != "https://gpt.bemore.lol" && config.ApiURL != "https://api.chat-plus.net" { - config.ApiURL = "https://api.chat-plus.net" - } + // rewrite api key + config.ApiURL = "https://api.chat-plus.net" client := plus.NewClient(config) name := fmt.Sprintf("mj-service-plus-%d", k) servicePlus := plus.NewService(name, taskQueue, notifyQueue, 10, 600, db, client) @@ -54,7 +51,7 @@ func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderMa continue } // create mj client - client := NewClient(config, appConfig.ProxyURL, appConfig.ImgCdnURL) + client := NewClient(config, appConfig.ProxyURL) name := fmt.Sprintf("MjService-%d", k) // create mj service @@ -98,6 +95,9 @@ func (p *ServicePool) CheckTaskNotify() { continue } client := p.Clients.Get(userId) + if client == nil { + continue + } err = client.Send([]byte("Task Updated")) if err != nil { continue @@ -120,17 +120,17 @@ func (p *ServicePool) DownloadImages() { if v.OrgURL == "" { continue } + + logger.Infof("try to download image: %s", v.OrgURL) var imgURL string var err error if v.UseProxy { if servicePlus := p.getServicePlus(v.ChannelId); servicePlus != nil { task, _ := servicePlus.Client.QueryTask(v.TaskId) - if task.ImageUrl != "" { - imgURL, err = p.uploaderManager.GetUploadHandler().PutImg(task.ImageUrl, false) - } if len(task.Buttons) > 0 { - v.Hash = getImageHash(task.Buttons[0].CustomId) + v.Hash = plus.GetImageHash(task.Buttons[0].CustomId) } + imgURL, err = p.uploaderManager.GetUploadHandler().PutImg(v.OrgURL, false) } } else { imgURL, err = p.uploaderManager.GetUploadHandler().PutImg(v.OrgURL, true) @@ -138,12 +138,17 @@ func (p *ServicePool) DownloadImages() { if err != nil { logger.Error("error with download image: ", err) continue + } else { + logger.Info("download image %v successfully.", v.OrgURL) } v.ImgURL = imgURL p.db.Updates(&v) client := p.Clients.Get(uint(v.UserId)) + if client == nil { + continue + } err = client.Send([]byte("Task Updated")) if err != nil { continue @@ -179,7 +184,7 @@ func (p *ServicePool) Notify(data plus.CBReq) error { return nil } if servicePlus := p.getServicePlus(job.ChannelId); servicePlus != nil { - return servicePlus.Notify(data, job) + return servicePlus.Notify(job) } return nil @@ -211,40 +216,7 @@ func (p *ServicePool) SyncTaskProgress() { } if servicePlus := p.getServicePlus(v.ChannelId); servicePlus != nil { - task, err := servicePlus.Client.QueryTask(v.TaskId) - if err != nil { - continue - } - // 任务失败了 - if task.FailReason != "" { - p.db.Model(&model.MidJourneyJob{Id: v.Id}).UpdateColumns(map[string]interface{}{ - "progress": -1, - "err_msg": task.FailReason, - }) - continue - } - if len(task.Buttons) > 0 { - v.Hash = getImageHash(task.Buttons[0].CustomId) - } - oldProgress := v.Progress - v.Progress = utils.IntValue(strings.Replace(task.Progress, "%", "", 1), 0) - v.Prompt = task.PromptEn - if task.ImageUrl != "" { - v.OrgURL = task.ImageUrl - } - v.UseProxy = true - v.MessageId = task.Id - - p.db.Updates(&v) - - if task.Status == "SUCCESS" { - // release lock task - atomic.AddInt32(&servicePlus.HandledTaskNum, -1) - } - // 通知前端更新任务进度 - if oldProgress != v.Progress { - p.notifyQueue.RPush(v.UserId) - } + _ = servicePlus.Notify(v) } } @@ -263,11 +235,3 @@ func (p *ServicePool) getServicePlus(name string) *plus.Service { } return nil } - -func getImageHash(action string) string { - split := strings.Split(action, "::") - if len(split) > 5 { - return split[4] - } - return split[len(split)-1] -} diff --git a/api/service/mj/service.go b/api/service/mj/service.go index f0bfc47d..d354456c 100644 --- a/api/service/mj/service.go +++ b/api/service/mj/service.go @@ -97,7 +97,7 @@ func (s *Service) Run() { } // lock the task until the execute timeout - s.taskStartTimes[task.Id] = time.Now() + s.taskStartTimes[int(task.Id)] = time.Now() atomic.AddInt32(&s.handledTaskNum, 1) } @@ -152,7 +152,7 @@ func (s *Service) Notify(data CBReq) { job.OrgURL = data.Image.URL if s.client.Config.UseCDN { job.UseProxy = true - job.ImgURL = strings.ReplaceAll(data.Image.URL, "https://cdn.discordapp.com", s.client.imgCdnURL) + job.ImgURL = strings.ReplaceAll(data.Image.URL, "https://cdn.discordapp.com", s.client.Config.ImgCdnURL) } res = s.db.Updates(&job) diff --git a/api/service/payment/payjs_service.go b/api/service/payment/payjs_service.go index fb87a249..62d88854 100644 --- a/api/service/payment/payjs_service.go +++ b/api/service/payment/payjs_service.go @@ -56,7 +56,7 @@ func (js *PayJS) Pay(param JPayReq) JPayReps { } p.Add("mchid", js.config.AppId) - p.Add("Sign", js.sign(p)) + p.Add("sign", js.sign(p)) cli := http.Client{} apiURL := fmt.Sprintf("%s/api/native", js.config.ApiURL) diff --git a/api/test/test.go b/api/test/test.go index 008479b8..667f3f7b 100644 --- a/api/test/test.go +++ b/api/test/test.go @@ -2,11 +2,10 @@ package main import ( "fmt" - "strings" + "net/url" ) func main() { - str := "7151109597841850368 一个漂亮的中国女孩,手上拿着一桶爆米花,脸上带着迷人的微笑,电影效果" - index := strings.Index(str, " ") - fmt.Println(str[index+1:]) + u, err := url.Parse("https://api.chat-plus.net/mj/image/1706368258238514?aaa=bbb") + fmt.Println(u.Path, u.RawQuery, err) } diff --git a/deploy/conf/config.toml b/deploy/conf/config.toml index 2fe38d89..f848371d 100644 --- a/deploy/conf/config.toml +++ b/deploy/conf/config.toml @@ -26,23 +26,15 @@ WeChatBot = false AppId = "" Token = "" -[SmsConfig] # 阿里云短信服务配置 - AccessKey = "" - AccessSecret = "" - Product = "Dysmsapi" - Domain = "dysmsapi.aliyuncs.com" - Sign = "" - CodeTempId = "" - -[Sms] # Sms 配置,用于发送短信 +[SMS] # Sms 配置,用于发送短信 Active = "Ali" # 当前启用的短信服务,默认使用阿里云 - [Sms.SmsBao] + [SMS.Bao] Username = "" Password = "" Domain = "api.smsbao.com" Sign = "【极客学长】" CodeTemplate = "您的验证码是{code}。5分钟有效,若非本人操作,请忽略本短信。" - [Sms.Ali] + [SMS.Ali] AccessKey = "" AccessSecret = "" Product = "Dysmsapi" @@ -83,6 +75,7 @@ WeChatBot = false [[MjPlusConfigs]] Enabled = false ApiURL = "https://api.chatgpt-plus.net" # 目前暂时不支持更改 + CdnURL = "" # CND 加速的 URL,如果有的话就设置 ApiKey = "sk-xxx" NotifyURL = "https://ai.r9it.com/api/mj/notify" # 这里需要改成你的域名 @@ -114,9 +107,9 @@ WeChatBot = false [HuPiPayConfig] Enabled = false Name = "wechat" - AppId = "201906161477" - AppSecret = "7f403199d510fb2c6f0b9f2311800e7c" - PayURL = "https://api.xunhupay.com/payment/do.html" + AppId = "" + AppSecret = "" + ApiURL = "https://api.xunhupay.com" NotifyURL = "https://ai.r9it.com/api/payment/hupipay/notify" [SmtpConfig] # 注意,阿里云服务器禁用了25号端口,所以如果需要使用邮件功能,请别用阿里云服务器 @@ -131,5 +124,5 @@ WeChatBot = false Name = "wechat" # 请不要改动 AppId = "" # 商户 ID PrivateKey = "" # 秘钥 - ApiURL = "https://payjs.cn/api/native" + ApiURL = "https://payjs.cn" NotifyURL = "https://ai.r9it.com/api/payment/payjs/notify" # 异步回调地址,域名改成你自己的 \ No newline at end of file diff --git a/web/public/images/mic.gif b/web/public/images/mic.gif new file mode 100644 index 00000000..d6e544dc Binary files /dev/null and b/web/public/images/mic.gif differ diff --git a/web/src/assets/css/mobile/chat-session.styl b/web/src/assets/css/mobile/chat-session.styl index fa7bfb46..5da59cc3 100644 --- a/web/src/assets/css/mobile/chat-session.styl +++ b/web/src/assets/css/mobile/chat-session.styl @@ -27,7 +27,11 @@ } .button-voice { - padding 0 5px + padding 0 2px + + .el-icon { + font-size 24px + } height 30px } } @@ -52,6 +56,16 @@ } } +.van-overlay { + .mic-wrapper { + display flex + height 100vh + justify-content center + align-items center + flex-flow column + } +} + .van-theme-dark { .mobile-chat { .message-list-box { diff --git a/web/src/main.js b/web/src/main.js index 3119148a..4c455a38 100644 --- a/web/src/main.js +++ b/web/src/main.js @@ -19,6 +19,7 @@ import { List, NavBar, Notify, + Overlay, Picker, Popup, Search, @@ -65,6 +66,7 @@ app.use(Switch); app.use(Uploader); app.use(Tag); app.use(V3waterfall) +app.use(Overlay) app.use(router).use(ElementPlus).mount('#app') diff --git a/web/src/views/ImageMj.vue b/web/src/views/ImageMj.vue index 58e94c87..2dcb485c 100644 --- a/web/src/views/ImageMj.vue +++ b/web/src/views/ImageMj.vue @@ -716,10 +716,13 @@ const fetchFinishJobs = (userId) => { if (jobs[i].type === 'upscale' || jobs[i].type === 'swapFace') { jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?imageView2/1/w/480/h/600/q/75' } else { - jobs[i]['can_opt'] = true jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?imageView2/1/w/480/h/480/q/75' } } + + if (jobs[i].type === 'image' || jobs[i].type === 'variation') { + jobs[i]['can_opt'] = true + } } finishedJobs.value = jobs }).catch(e => { diff --git a/web/src/views/mobile/ChatSession.vue b/web/src/views/mobile/ChatSession.vue index d2e57551..63f731ce 100644 --- a/web/src/views/mobile/ChatSession.vue +++ b/web/src/views/mobile/ChatSession.vue @@ -64,7 +64,9 @@ > @@ -84,6 +86,19 @@ + + +
+
+ +
+ 说完了 +
+
@@ -101,6 +116,7 @@ import ChatReply from "@/components/mobile/ChatReply.vue"; import {getSessionId, getUserToken} from "@/store/session"; import {checkSession} from "@/action/session"; import Clipboard from "clipboard"; +import {Microphone} from "@element-plus/icons-vue"; const winHeight = ref(0) const navBarRef = ref(null) @@ -114,6 +130,7 @@ const modelValue = chatConfig.modelValue const title = chatConfig.title const chatId = chatConfig.chatId const loginUser = ref(null) +const showMic = ref(false) const url = location.protocol + '//' + location.host + '/mobile/chat/export?chat_id=' + chatId @@ -421,25 +438,29 @@ const shareChat = (option) => { } } +// eslint-disable-next-line no-undef +const recognition = new webkitSpeechRecognition() || SpeechRecognition(); +//recognition.lang = 'zh-CN' // 设置语音识别语言 +recognition.onresult = function (event) { + prompt.value = event.results[0][0].transcript +}; + +recognition.onerror = function (event) { + showNotify({type: 'danger', message: '语音识别错误:' + event.error}) +}; + +recognition.onend = function () { + console.log('语音识别结束'); +}; const inputVoice = () => { - const recognition = new webkitSpeechRecognition() || SpeechRecognition(); - // recognition.lang = 'zh-CN' // 设置语音识别语言 - - recognition.onresult = function (event) { - const result = event.results[0][0].transcript; - showToast('你说了: ' + result) - }; - - recognition.onerror = function (event) { - showNotify({type: 'danger', message: '语音识别错误:' + event.error}) - }; - - recognition.onend = function () { - console.log('语音识别结束'); - }; - + showMic.value = true recognition.start(); } + +const stopVoice = () => { + showMic.value = false + recognition.stop() +}