diff --git a/CHANGELOG.md b/CHANGELOG.md index 373fdcb8..5ef712bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,20 +1,30 @@ # 更新日志 -## 4.0.2 + +## 4.0.2 + * 功能新增:支持前端菜单可以配置 -* 功能优化:手机端支持免登录预览功能 +* 功能优化:在登录和注册界面标题显示软件版本号 +* 功能优化:MJ 绘画支持 --sref 和 --cref 图片一致性参数 +* 功能优化:使用 leveldb 解决 SD 绘图进度图片预览问题 +* Bug修复:解决因为图片上传使用相对路径而导致融图失败的问题。 * 功能新增:手机端支持 Stable-Diffusion 绘画 * 功能新增:管理后台登录页面增加行为验证码,防止爆破 ## v4.0.1 -* 功能重构:重构 Stable-Diffusion 绘画实现,使用 SDAPI 替换之前的 websocket 接口,SDAPI 兼容各种 stable-diffusion 发行版,稳定性更强一些 -* 功能优化:使用 [midjouney-proxy](https://github.com/novicezk/midjourney-proxy) 项目替换内置的原生 MidJourney API,兼容 MJ-Plus 中转 + +* 功能重构:重构 Stable-Diffusion 绘画实现,使用 SDAPI 替换之前的 websocket 接口,SDAPI 兼容各种 stable-diffusion + 发行版,稳定性更强一些 +* 功能优化:使用 [midjouney-proxy](https://github.com/novicezk/midjourney-proxy) 项目替换内置的原生 MidJourney API,兼容 + MJ-Plus 中转 * 功能新增:用户算力消费日志增加统计功能,统计一段时间内用户消费的算力 * Bug修复:修复 iphone 手机无法通过图形验证码的Bug,使用滑动验证码替换 * Bug修复:修复手机端 MidJourney 绘画页面滚动条无法滚动的Bug ## v4.0.0 + 非兼容版本,重大重构,引入算力概念,将系统中所有的能力(AI对话,MJ绘画,SD绘画,DALL绘画)全部使用算力来兑换。 -只要你的算力值余额不为0,你就可以进行任何操作。比如一次 GPT3.5 对话消耗1个单位算力,一次 GPT4 对话消耗10个算力。一次 MJ 对话消耗15个算力... +只要你的算力值余额不为0,你就可以进行任何操作。比如一次 GPT3.5 对话消耗1个单位算力,一次 GPT4 对话消耗10个算力。一次 MJ +对话消耗15个算力... * 功能重构:重构整体系统,全部采用算力来进行结算 * 功能优化:SD 绘画页面采用 websocket 替换 http 轮询机制,节省带宽 @@ -29,6 +39,7 @@ * 功能新增:管理后台新增7日内新增用户和新增订单统计 ## v3.2.7 + * 功能重构:采用 Vant 重构移动页面,新增 MidJourney 功能 * 功能优化:优化 PC 端 MidJourney 页面布局,新增融图和换脸功能 * Bug修复:修复 issue [ @@ -43,6 +54,7 @@ * 功能新增:后台管理新怎对话查看和检索功能 ## v3.2.6 + * 功能优化:恢复关闭注册系统配置项,管理员可以在后台关闭用户注册,只允许内部添加账号 * 功能优化:兼用旧版本微信收款消息解析 * 功能优化:优化订单扫码支付状态轮询功能,当关闭二维码时取消轮询,节约网络资源 @@ -56,16 +68,18 @@ * 功能优化:给所有的 websocket 连接加上心跳,解决 "close 1006 (abnormal closure): unexpected EOF" Bug * 功能新增:新增短信宝短信平台发送平台集成 - ## v3.2.5 + * 功能新增:**重磅更新!!!** 新增 MidJourney-Plus API 支持,一秒配置,开箱即用,高效稳定。 -* 功能新增:**重磅更新!!!** 新增 GPT4-ALL 和 GPTs 模型支持,你只需花几块钱,可以丝滑享受 ChatGPT-Plus 会员的所有功能,无需再订阅 Plus 账号了!!! +* 功能新增:**重磅更新!!!** 新增 GPT4-ALL 和 GPTs 模型支持,你只需花几块钱,可以丝滑享受 ChatGPT-Plus 会员的所有功能,无需再订阅 + Plus 账号了!!! * 功能优化:增强 markdown 图片和引用块解析。 * 功能新增:新增用户文件管理,目前一支持上传文件跟 GPT 进行多态对话。 * 功能优化:function call 兼用中转 API。 * Bug修复:修复部分已知的 Bug。 ## v3.2.4.1 + * 功能新增:新增 PayJs 支付通道 * Bug修复:紧急修复后台添加用户失败问题 * Bug修复:紧急修复使用中转 API-KEY 无法绘图的问题 diff --git a/README.md b/README.md index 303fc242..c47877fe 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ KEY。  -另外,如果您目前还没有 OpenAI 的 API KEY的,推荐您去 https://gpt.bemore.lol 购买,**无需魔法,高速稳定,且价格还远低于 OpenAI +另外,如果您目前还没有 OpenAI 的 API KEY的,推荐您去 https://api.chat-plus.net 购买,**无需魔法,高速稳定,且价格还远低于 OpenAI 官方**。 ## 使用须知 diff --git a/api/core/types/task.go b/api/core/types/task.go index 0120c739..cd4b516e 100644 --- a/api/core/types/task.go +++ b/api/core/types/task.go @@ -25,6 +25,8 @@ type MjTask struct { Type TaskType `json:"type"` UserId int `json:"user_id"` Prompt string `json:"prompt,omitempty"` + NegPrompt string `json:"neg_prompt,omitempty"` + Params string `json:"full_prompt"` Index int `json:"index,omitempty"` MessageId string `json:"message_id,omitempty"` MessageHash string `json:"message_hash,omitempty"` @@ -41,19 +43,19 @@ type SdTask struct { } type SdTaskParams struct { - TaskId string `json:"task_id"` - Prompt string `json:"prompt"` // 提示词 - NegativePrompt string `json:"negative_prompt"` // 反向提示词 - Steps int `json:"steps"` // 迭代步数,默认20 - Sampler string `json:"sampler"` // 采样器 - FaceFix bool `json:"face_fix"` // 面部修复 - CfgScale float32 `json:"cfg_scale"` //引导系数,默认 7 - Seed int64 `json:"seed"` // 随机数种子 - Height int `json:"height"` - Width int `json:"width"` - HdFix bool `json:"hd_fix"` // 启用高清修复 - HdRedrawRate float32 `json:"hd_redraw_rate"` // 高清修复重绘幅度 - HdScale int `json:"hd_scale"` // 放大倍数 - HdScaleAlg string `json:"hd_scale_alg"` // 放大算法 - HdSteps int `json:"hd_steps"` // 高清修复迭代步数 + TaskId string `json:"task_id"` + Prompt string `json:"prompt"` // 提示词 + NegPrompt string `json:"neg_prompt"` // 反向提示词 + Steps int `json:"steps"` // 迭代步数,默认20 + Sampler string `json:"sampler"` // 采样器 + FaceFix bool `json:"face_fix"` // 面部修复 + CfgScale float32 `json:"cfg_scale"` //引导系数,默认 7 + Seed int64 `json:"seed"` // 随机数种子 + Height int `json:"height"` + Width int `json:"width"` + HdFix bool `json:"hd_fix"` // 启用高清修复 + HdRedrawRate float32 `json:"hd_redraw_rate"` // 高清修复重绘幅度 + HdScale int `json:"hd_scale"` // 放大倍数 + HdScaleAlg string `json:"hd_scale_alg"` // 放大算法 + HdSteps int `json:"hd_steps"` // 高清修复迭代步数 } diff --git a/api/go.mod b/api/go.mod index ff63a4a6..fc131837 100644 --- a/api/go.mod +++ b/api/go.mod @@ -28,10 +28,12 @@ require github.com/xxl-job/xxl-job-executor-go v1.2.0 require ( github.com/mojocn/base64Captcha v1.3.1 github.com/shopspring/decimal v1.3.1 + github.com/syndtr/goleveldb v1.0.0 ) require ( github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect golang.org/x/image v0.0.0-20190501045829-6d32002ffd75 // indirect ) diff --git a/api/go.sum b/api/go.sum index b94c92a0..e5c987ce 100644 --- a/api/go.sum +++ b/api/go.sum @@ -27,6 +27,7 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/eatmoreapple/openwechat v1.2.1 h1:ez4oqF/Y2NSEX/DbPV8lvj7JlfkYqvieeo4awx5lzfU= github.com/eatmoreapple/openwechat v1.2.1/go.mod h1:61HOzTyvLobGdgWhL68jfGNwTJEv0mhQ1miCXQrvWU8= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= @@ -67,8 +68,11 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF0 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -83,6 +87,7 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/imroc/req/v3 v3.37.2 h1:vEemuA0cq9zJ6lhe+mSRhsZm951bT0CdiSH47+KTn6I= github.com/imroc/req/v3 v3.37.2/go.mod h1:DECzjVIrj6jcUr5n6e+z0ygmCO93rx4Jy0RjOEe1YCI= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -133,9 +138,12 @@ github.com/mojocn/base64Captcha v1.3.1/go.mod h1:wAQCKEc5bDujxKRmbT6/vTnTt5CjStQ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo/v2 v2.10.0 h1:sfUl4qgLdvkChZrWCYndY2EAu9BRIw1YphNAzy1VNWs= github.com/onsi/ginkgo/v2 v2.10.0/go.mod h1:UDQOh5wbQUlMnkLfVaIUMtQ1Vus92oM+P2JX1aulgcE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A= github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU= @@ -193,6 +201,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= @@ -235,6 +245,7 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -243,11 +254,13 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -294,12 +307,15 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/api/handler/chatimpl/chat_handler.go b/api/handler/chatimpl/chat_handler.go index af69e717..c60df32e 100644 --- a/api/handler/chatimpl/chat_handler.go +++ b/api/handler/chatimpl/chat_handler.go @@ -478,7 +478,7 @@ func (h *ChatHandler) doRequest(ctx context.Context, req types.ApiRequest, platf request = request.WithContext(ctx) request.Header.Set("Content-Type", "application/json") var proxyURL string - if apiKey.ProxyURL != "" { // 使用代理 + if len(apiKey.ProxyURL) > 5 { // 使用代理 proxy, _ := url.Parse(apiKey.ProxyURL) client = &http.Client{ Transport: &http.Transport{ diff --git a/api/handler/function_handler.go b/api/handler/function_handler.go index cecbf057..e9eb57df 100644 --- a/api/handler/function_handler.go +++ b/api/handler/function_handler.go @@ -220,7 +220,7 @@ func (h *FunctionHandler) Dall3(c *gin.Context) { var res imgRes var errRes ErrRes var request *req.Request - if apiKey.ProxyURL != "" { + if len(apiKey.ProxyURL) > 5 { request = req.C().SetProxyURL(apiKey.ProxyURL).R() } else { request = req.C().R() diff --git a/api/handler/mj_handler.go b/api/handler/mj_handler.go index d2f9a107..7988a380 100644 --- a/api/handler/mj_handler.go +++ b/api/handler/mj_handler.go @@ -98,7 +98,10 @@ func (h *MidJourneyHandler) Image(c *gin.Context) { ImgArr []string `json:"img_arr"` Tile bool `json:"tile"` Quality float32 `json:"quality"` - Weight float32 `json:"weight"` + Iw float32 `json:"iw"` + CRef string `json:"cref"` //生成角色一致的图像 + SRef string `json:"sref"` //生成风格一致的图像 + Cw int `json:"cw"` // 参考程度 } if err := c.ShouldBindJSON(&data); err != nil { resp.ERROR(c, types.InvalidArgs) @@ -108,41 +111,57 @@ func (h *MidJourneyHandler) Image(c *gin.Context) { return } - var prompt = data.Prompt - if data.Rate != "" && !strings.Contains(prompt, "--ar") { - prompt += " --ar " + data.Rate + var params = "" + if data.Rate != "" && !strings.Contains(params, "--ar") { + params += " --ar " + data.Rate } - if data.Seed > 0 && !strings.Contains(prompt, "--seed") { - prompt += fmt.Sprintf(" --seed %d", data.Seed) + if data.Seed > 0 && !strings.Contains(params, "--seed") { + params += fmt.Sprintf(" --seed %d", data.Seed) } - if data.Stylize > 0 && !strings.Contains(prompt, "--s") && !strings.Contains(prompt, "--stylize") { - prompt += fmt.Sprintf(" --s %d", data.Stylize) + if data.Stylize > 0 && !strings.Contains(params, "--s") && !strings.Contains(params, "--stylize") { + params += fmt.Sprintf(" --s %d", data.Stylize) } - if data.Chaos > 0 && !strings.Contains(prompt, "--c") && !strings.Contains(prompt, "--chaos") { - prompt += fmt.Sprintf(" --c %d", data.Chaos) + if data.Chaos > 0 && !strings.Contains(params, "--c") && !strings.Contains(params, "--chaos") { + params += fmt.Sprintf(" --c %d", data.Chaos) } - if data.Weight > 0 { - prompt += fmt.Sprintf(" --iw %f", data.Weight) + if len(data.ImgArr) > 0 && data.Iw > 0 { + params += fmt.Sprintf(" --iw %f", data.Iw) } if data.Raw { - prompt += " --style raw" + params += " --style raw" } if data.Quality > 0 { - prompt += fmt.Sprintf(" --q %.2f", data.Quality) - } - if data.NegPrompt != "" { - prompt += fmt.Sprintf(" --no %s", data.NegPrompt) + params += fmt.Sprintf(" --q %.2f", data.Quality) } if data.Tile { - prompt += " --tile " + params += " --tile " } - if data.Model != "" && !strings.Contains(prompt, "--v") && !strings.Contains(prompt, "--niji") { - prompt += fmt.Sprintf(" %s", data.Model) + if data.CRef != "" { + params += fmt.Sprintf(" --cref %s", data.CRef) + if data.Cw > 0 { + params += fmt.Sprintf(" --cw %d", data.Cw) + } else { + params += " --cw 100" + } + } + + if data.SRef != "" { + params += fmt.Sprintf(" --sref %s", data.CRef) + } + if data.Model != "" && !strings.Contains(params, "--v") && !strings.Contains(params, "--niji") { + params += fmt.Sprintf(" %s", data.Model) } // 处理融图和换脸的提示词 if data.TaskType == types.TaskSwapFace.String() || data.TaskType == types.TaskBlend.String() { - prompt = fmt.Sprintf("%s:%s", data.TaskType, strings.Join(data.ImgArr, ",")) + params = fmt.Sprintf("%s:%s", data.TaskType, strings.Join(data.ImgArr, ",")) + } + + // 如果本地图片上传的是相对地址,处理成绝对地址 + for k, v := range data.ImgArr { + if !strings.HasPrefix(v, "http") { + data.ImgArr[k] = fmt.Sprintf("http://localhost:5678/%s", strings.TrimLeft(v, "/")) + } } idValue, _ := c.Get(types.LoginUserID) @@ -158,7 +177,7 @@ func (h *MidJourneyHandler) Image(c *gin.Context) { UserId: userId, TaskId: taskId, Progress: 0, - Prompt: prompt, + Prompt: fmt.Sprintf("%s %s", data.Prompt, params), Power: h.App.SysConfig.MjPower, CreatedAt: time.Now(), } @@ -181,7 +200,9 @@ func (h *MidJourneyHandler) Image(c *gin.Context) { TaskId: taskId, SessionId: data.SessionId, Type: types.TaskType(data.TaskType), - Prompt: prompt, + Prompt: data.Prompt, + NegPrompt: data.NegPrompt, + Params: params, UserId: userId, ImgArr: data.ImgArr, }) diff --git a/api/handler/payment_handler.go b/api/handler/payment_handler.go index 3f888c83..2b8f5dce 100644 --- a/api/handler/payment_handler.go +++ b/api/handler/payment_handler.go @@ -424,27 +424,21 @@ func (h *PaymentHandler) notify(orderNo string, tradeNo string) error { var opt string var power int - if user.Vip { // 已经是 VIP 用户 - if remark.Days > 0 { // 只延期 VIP,不增加调用次数 + if remark.Days > 0 { // VIP 充值 + if user.ExpiredTime >= time.Now().Unix() { user.ExpiredTime = time.Unix(user.ExpiredTime, 0).AddDate(0, 0, remark.Days).Unix() - } else { // 充值点卡,直接增加次数即可 - user.Power += remark.Power - opt = "点卡充值" - power = remark.Power - } - - } else { // 非 VIP 用户 - if remark.Days > 0 { // vip 套餐:days > 0, power == 0 + opt = "VIP充值,VIP 没到期,只延期不增加算力" + } else { user.ExpiredTime = time.Now().AddDate(0, 0, remark.Days).Unix() user.Power += h.App.SysConfig.VipMonthPower - user.Vip = true - opt = "VIP充值" power = h.App.SysConfig.VipMonthPower - } else { //点卡:days == 0, calls > 0 - user.Power += remark.Power - opt = "点卡充值" - power = remark.Power + opt = "VIP充值" } + user.Vip = true + } else { // 充值点卡,直接增加次数即可 + user.Power += remark.Power + opt = "点卡充值" + power = remark.Power } // 更新用户信息 diff --git a/api/handler/sd_handler.go b/api/handler/sd_handler.go index 09b35d49..b9c3625e 100644 --- a/api/handler/sd_handler.go +++ b/api/handler/sd_handler.go @@ -6,11 +6,11 @@ import ( "chatplus/service" "chatplus/service/oss" "chatplus/service/sd" + "chatplus/store" "chatplus/store/model" "chatplus/store/vo" "chatplus/utils" "chatplus/utils/resp" - "encoding/base64" "fmt" "net/http" "time" @@ -28,13 +28,15 @@ type SdJobHandler struct { pool *sd.ServicePool uploader *oss.UploaderManager snowflake *service.Snowflake + leveldb *store.LevelDB } -func NewSdJobHandler(app *core.AppServer, db *gorm.DB, pool *sd.ServicePool, manager *oss.UploaderManager, snowflake *service.Snowflake) *SdJobHandler { +func NewSdJobHandler(app *core.AppServer, db *gorm.DB, pool *sd.ServicePool, manager *oss.UploaderManager, snowflake *service.Snowflake, levelDB *store.LevelDB) *SdJobHandler { return &SdJobHandler{ pool: pool, uploader: manager, snowflake: snowflake, + leveldb: levelDB, BaseHandler: BaseHandler{ App: app, DB: db, @@ -125,21 +127,21 @@ func (h *SdJobHandler) Image(c *gin.Context) { return } params := types.SdTaskParams{ - TaskId: taskId, - Prompt: data.Prompt, - NegativePrompt: data.NegativePrompt, - Steps: data.Steps, - Sampler: data.Sampler, - FaceFix: data.FaceFix, - CfgScale: data.CfgScale, - Seed: data.Seed, - Height: data.Height, - Width: data.Width, - HdFix: data.HdFix, - HdRedrawRate: data.HdRedrawRate, - HdScale: data.HdScale, - HdScaleAlg: data.HdScaleAlg, - HdSteps: data.HdSteps, + TaskId: taskId, + Prompt: data.Prompt, + NegPrompt: data.NegPrompt, + Steps: data.Steps, + Sampler: data.Sampler, + FaceFix: data.FaceFix, + CfgScale: data.CfgScale, + Seed: data.Seed, + Height: data.Height, + Width: data.Width, + HdFix: data.HdFix, + HdRedrawRate: data.HdRedrawRate, + HdScale: data.HdScale, + HdScaleAlg: data.HdScaleAlg, + HdSteps: data.HdSteps, } job := model.SdJob{ @@ -257,10 +259,10 @@ func (h *SdJobHandler) getData(finish bool, userId uint, page int, pageSize int, } if item.Progress < 100 { - // 正在运行中任务使用代理访问图片 - image, err := utils.DownloadImage(item.ImgURL, "") + // 从 leveldb 中获取图片预览数据 + imageData, err := h.leveldb.Get(item.TaskId) if err == nil { - job.ImgURL = "data:image/png;base64," + base64.StdEncoding.EncodeToString(image) + job.ImgURL = "data:image/png;base64," + string(imageData) } } jobs = append(jobs, job) diff --git a/api/main.go b/api/main.go index 6d82fccb..e5b8f3cf 100644 --- a/api/main.go +++ b/api/main.go @@ -53,6 +53,10 @@ func (l *AppLifecycle) OnStop(context.Context) error { return nil } +func NewAppLifeCycle() *AppLifecycle { + return &AppLifecycle{} +} + func main() { configFile := os.Getenv("CONFIG_FILE") if configFile == "" { @@ -92,6 +96,7 @@ func main() { fx.Provide(store.NewGormConfig), fx.Provide(store.NewMysql), fx.Provide(store.NewRedisClient), + fx.Provide(store.NewLevelDB), fx.Provide(func() embed.FS { return xdbFS @@ -292,7 +297,7 @@ func main() { group.POST("save", h.Save) group.GET("list", h.List) group.POST("set", h.Set) - group.POST("remove", h.Remove) + group.GET("remove", h.Remove) }), fx.Invoke(func(s *core.AppServer, h *admin.UserHandler) { group := s.Engine.Group("/api/admin/user/") @@ -432,11 +437,14 @@ func main() { group.GET("list", h.List) }), fx.Invoke(func(s *core.AppServer, db *gorm.DB) { - err := s.Run(db) - if err != nil { - log.Fatal(err) - } + go func() { + err := s.Run(db) + if err != nil { + log.Fatal(err) + } + }() }), + fx.Provide(NewAppLifeCycle), // 注册生命周期回调函数 fx.Invoke(func(lifecycle fx.Lifecycle, lc *AppLifecycle) { lifecycle.Append(fx.Hook{ diff --git a/api/service/mj/plus_client.go b/api/service/mj/plus_client.go index 38c3265e..89bca627 100644 --- a/api/service/mj/plus_client.go +++ b/api/service/mj/plus_client.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/imroc/req/v3" "io" + "time" "github.com/gin-gonic/gin" ) @@ -16,17 +17,26 @@ import ( type PlusClient struct { Config types.MjPlusConfig apiURL string + client *req.Client } func NewPlusClient(config types.MjPlusConfig) *PlusClient { - return &PlusClient{Config: config, apiURL: config.ApiURL} + return &PlusClient{ + Config: config, + apiURL: config.ApiURL, + client: req.C().SetTimeout(time.Minute).SetUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"), + } } func (c *PlusClient) Imagine(task types.MjTask) (ImageRes, error) { apiURL := fmt.Sprintf("%s/mj-%s/mj/submit/imagine", c.apiURL, c.Config.Mode) + prompt := fmt.Sprintf("%s %s", task.Prompt, task.Params) + if task.NegPrompt != "" { + prompt += fmt.Sprintf(" --no %s", task.NegPrompt) + } body := ImageReq{ BotType: "MID_JOURNEY", - Prompt: task.Prompt, + Prompt: prompt, Base64Array: make([]string, 0), } // 生成图片 Base64 编码 @@ -42,7 +52,7 @@ func (c *PlusClient) Imagine(task types.MjTask) (ImageRes, error) { logger.Info("API URL: ", apiURL) var res ImageRes var errRes ErrRes - r, err := req.C().R(). + r, err := c.client.R(). SetHeader("Authorization", "Bearer "+c.Config.ApiKey). SetBody(body). SetSuccessResult(&res). @@ -81,7 +91,7 @@ func (c *PlusClient) Blend(task types.MjTask) (ImageRes, error) { } var res ImageRes var errRes ErrRes - r, err := req.C().R(). + r, err := c.client.R(). SetHeader("Authorization", "Bearer "+c.Config.ApiKey). SetBody(body). SetSuccessResult(&res). @@ -130,7 +140,7 @@ func (c *PlusClient) SwapFace(task types.MjTask) (ImageRes, error) { } var res ImageRes var errRes ErrRes - r, err := req.C().R(). + r, err := c.client.SetTimeout(time.Minute).R(). SetHeader("Authorization", "Bearer "+c.Config.ApiKey). SetBody(body). SetSuccessResult(&res). @@ -156,7 +166,7 @@ func (c *PlusClient) Upscale(task types.MjTask) (ImageRes, error) { apiURL := fmt.Sprintf("%s/mj/submit/action", c.apiURL) var res ImageRes var errRes ErrRes - r, err := req.C().R(). + r, err := c.client.R(). SetHeader("Authorization", "Bearer "+c.Config.ApiKey). SetBody(body). SetSuccessResult(&res). @@ -202,7 +212,7 @@ func (c *PlusClient) Variation(task types.MjTask) (ImageRes, error) { func (c *PlusClient) QueryTask(taskId string) (QueryRes, error) { 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). + r, err := c.client.R().SetHeader("Authorization", "Bearer "+c.Config.ApiKey). SetSuccessResult(&res). Get(apiURL) diff --git a/api/service/mj/proxy_client.go b/api/service/mj/proxy_client.go index c6f66c64..b8df3211 100644 --- a/api/service/mj/proxy_client.go +++ b/api/service/mj/proxy_client.go @@ -22,8 +22,12 @@ func NewProxyClient(config types.MjProxyConfig) *ProxyClient { func (c *ProxyClient) Imagine(task types.MjTask) (ImageRes, error) { apiURL := fmt.Sprintf("%s/mj/submit/imagine", c.apiURL) + prompt := fmt.Sprintf("%s %s", task.Prompt, task.Params) + if task.NegPrompt != "" { + prompt += fmt.Sprintf(" --no %s", task.NegPrompt) + } body := ImageReq{ - Prompt: task.Prompt, + Prompt: prompt, Base64Array: make([]string, 0), } // 生成图片 Base64 编码 @@ -46,8 +50,6 @@ func (c *ProxyClient) Imagine(task types.MjTask) (ImageRes, error) { SetErrorResult(&errRes). Post(apiURL) if err != nil { - all, err := io.ReadAll(r.Body) - logger.Info(string(all)) return ImageRes{}, fmt.Errorf("请求 API %s 出错:%v", apiURL, err) } diff --git a/api/service/mj/service.go b/api/service/mj/service.go index f73a9c63..3c870a17 100644 --- a/api/service/mj/service.go +++ b/api/service/mj/service.go @@ -67,8 +67,8 @@ func (s *Service) Run() { continue } - // 如果是 mj-proxy 则自动翻译提示词 - if utils.HasChinese(task.Prompt) && strings.HasPrefix(s.Name, "mj-proxy-service") { + // translate prompt + if utils.HasChinese(task.Prompt) { content, err := utils.OpenAIRequest(s.db, fmt.Sprintf(service.TranslatePromptTemplate, task.Prompt)) if err == nil { task.Prompt = content @@ -76,6 +76,15 @@ func (s *Service) Run() { 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)) + if err == nil { + task.NegPrompt = content + } else { + logger.Warnf("error with translate prompt: %v", err) + } + } var job model.MidJourneyJob tx := s.db.Where("id = ?", task.Id).First(&job) diff --git a/api/service/sd/pool.go b/api/service/sd/pool.go index 2661edd1..3033b548 100644 --- a/api/service/sd/pool.go +++ b/api/service/sd/pool.go @@ -20,7 +20,7 @@ type ServicePool struct { Clients *types.LMap[uint, *types.WsClient] // UserId => Client } -func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderManager, appConfig *types.AppConfig) *ServicePool { +func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderManager, appConfig *types.AppConfig, levelDB *store.LevelDB) *ServicePool { services := make([]*Service, 0) taskQueue := store.NewRedisQueue("StableDiffusion_Task_Queue", redisCli) notifyQueue := store.NewRedisQueue("StableDiffusion_Queue", redisCli) @@ -32,7 +32,7 @@ func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderMa // create sd service name := fmt.Sprintf("StableDifffusion Service-%s", config.Model) - service := NewService(name, config, taskQueue, notifyQueue, db, manager) + service := NewService(name, config, taskQueue, notifyQueue, db, manager, levelDB) // run sd service go func() { service.Run() diff --git a/api/service/sd/service.go b/api/service/sd/service.go index f87067a3..4f68f3e0 100644 --- a/api/service/sd/service.go +++ b/api/service/sd/service.go @@ -24,9 +24,10 @@ type Service struct { db *gorm.DB uploadManager *oss.UploaderManager name string // service name + leveldb *store.LevelDB } -func NewService(name string, config types.StableDiffusionConfig, taskQueue *store.RedisQueue, notifyQueue *store.RedisQueue, db *gorm.DB, manager *oss.UploaderManager) *Service { +func NewService(name string, config types.StableDiffusionConfig, taskQueue *store.RedisQueue, notifyQueue *store.RedisQueue, db *gorm.DB, manager *oss.UploaderManager, levelDB *store.LevelDB) *Service { config.ApiURL = strings.TrimRight(config.ApiURL, "/") return &Service{ name: name, @@ -35,6 +36,7 @@ func NewService(name string, config types.StableDiffusionConfig, taskQueue *stor taskQueue: taskQueue, notifyQueue: notifyQueue, db: db, + leveldb: levelDB, uploadManager: manager, } } @@ -47,11 +49,24 @@ func (s *Service) Run() { logger.Errorf("taking task with error: %v", err) continue } - // 翻译提示词 + + // translate prompt if utils.HasChinese(task.Params.Prompt) { content, err := utils.OpenAIRequest(s.db, fmt.Sprintf(service.RewritePromptTemplate, task.Params.Prompt)) if err == nil { task.Params.Prompt = content + } else { + logger.Warnf("error with translate prompt: %v", err) + } + } + + // translate negative prompt + if task.Params.NegPrompt != "" && utils.HasChinese(task.Params.NegPrompt) { + content, err := utils.OpenAIRequest(s.db, fmt.Sprintf(service.TranslatePromptTemplate, task.Params.NegPrompt)) + if err == nil { + task.Params.NegPrompt = content + } else { + logger.Warnf("error with translate prompt: %v", err) } } @@ -108,7 +123,7 @@ type TaskProgressResp struct { func (s *Service) Txt2Img(task types.SdTask) error { body := Txt2ImgReq{ Prompt: task.Params.Prompt, - NegativePrompt: task.Params.NegativePrompt, + NegativePrompt: task.Params.NegPrompt, Steps: task.Params.Steps, CfgScale: task.Params.CfgScale, Width: task.Params.Width, @@ -167,15 +182,20 @@ func (s *Service) Txt2Img(task types.SdTask) error { } s.db.Model(&model.SdJob{Id: uint(task.Id)}).UpdateColumn("progress", 100) s.notifyQueue.RPush(task.UserId) + // 从 leveldb 中删除预览图片数据 + _ = s.leveldb.Delete(task.Params.TaskId) return nil default: err, resp := s.checkTaskProgress() // 更新任务进度 if err == nil && resp.Progress > 0 { - logger.Debugf("Check task progress: %+v", resp.Progress) s.db.Model(&model.SdJob{Id: uint(task.Id)}).UpdateColumn("progress", int(resp.Progress*100)) // 发送更新状态信号 s.notifyQueue.RPush(task.UserId) + // 保存预览图片数据 + if resp.CurrentImage != "" { + _ = s.leveldb.Put(task.Params.TaskId, resp.CurrentImage) + } } time.Sleep(time.Second) } diff --git a/api/store/leveldb.go b/api/store/leveldb.go new file mode 100644 index 00000000..c74d4090 --- /dev/null +++ b/api/store/leveldb.go @@ -0,0 +1,110 @@ +package store + +import ( + "encoding/json" + + "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/util" +) + +type LevelDB struct { + driver *leveldb.DB +} + +func NewLevelDB() (*LevelDB, error) { + db, err := leveldb.OpenFile("data", nil) + if err != nil { + return nil, err + } + return &LevelDB{ + driver: db, + }, nil +} + +func (db *LevelDB) Put(key string, value interface{}) error { + var byteData []byte + if v, ok := value.(string); ok { + byteData = []byte(v) + } else { + b, err := json.Marshal(value) + if err != nil { + return err + } + byteData = b + } + return db.driver.Put([]byte(key), byteData, nil) +} + +func (db *LevelDB) Get(key string) ([]byte, error) { + bytes, err := db.driver.Get([]byte(key), nil) + if err != nil { + return nil, err + } + + return bytes, nil +} + +func (db *LevelDB) Search(prefix string) []string { + var items = make([]string, 0) + iter := db.driver.NewIterator(util.BytesPrefix([]byte(prefix)), nil) + defer iter.Release() + + for iter.Next() { + items = append(items, string(iter.Value())) + } + return items +} + +type PageVo struct { + Items []string + Page int + PageSize int + Total int + TotalPage int +} + +func (db *LevelDB) SearchPage(prefix string, page int, pageSize int) *PageVo { + var items = make([]string, 0) + iter := db.driver.NewIterator(util.BytesPrefix([]byte(prefix)), nil) + defer iter.Release() + + res := &PageVo{Page: page, PageSize: pageSize} + // 计算数据总数和总页数 + total := 0 + for iter.Next() { + total++ + } + res.TotalPage = (total + pageSize - 1) / pageSize + res.Total = total + + // 计算目标页码的起始和结束位置 + start := (page - 1) * pageSize + if start > total { + return nil + } + end := start + pageSize + if end > total { + end = total + } + + // 跳转到目标页码的起始位置 + count := 0 + for iter.Next() { + if count >= start { + items = append(items, string(iter.Value())) + } + count++ + } + iter.Release() + res.Items = items + return res +} + +func (db *LevelDB) Delete(key string) error { + return db.driver.Delete([]byte(key), nil) +} + +// Close release resources +func (db *LevelDB) Close() error { + return db.driver.Close() +} diff --git a/api/test/test.go b/api/test/test.go index 79058077..cc826def 100644 --- a/api/test/test.go +++ b/api/test/test.go @@ -1,5 +1,12 @@ package main -func main() { +import ( + "fmt" + "reflect" +) +func main() { + text := 1 + bytes := reflect.ValueOf(text).Bytes() + fmt.Println(bytes) } diff --git a/api/utils/openai.go b/api/utils/openai.go index 9842e07e..584f0435 100644 --- a/api/utils/openai.go +++ b/api/utils/openai.go @@ -61,7 +61,7 @@ func OpenAIRequest(db *gorm.DB, prompt string) (string, error) { var response apiRes var errRes apiErrRes client := req.C() - if apiKey.ProxyURL != "" { + if len(apiKey.ProxyURL) > 5 { client.SetProxyURL(apiKey.ApiURL) } r, err := client.R().SetHeader("Content-Type", "application/json"). diff --git a/deploy/conf/nginx/conf.d/chatgpt-plus.conf b/deploy/conf/nginx/conf.d/chatgpt-plus.conf index e4d85e3a..8442af6b 100644 --- a/deploy/conf/nginx/conf.d/chatgpt-plus.conf +++ b/deploy/conf/nginx/conf.d/chatgpt-plus.conf @@ -15,8 +15,8 @@ server { # ssl_prefer_server_ciphers on; # 日志地址 - access_log /var/log/access.log; - error_log /var/log/error.log; + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; index index.html; root /var/www/app/dist; # 这里改成前端静态页面的地址 diff --git a/deploy/docker-compose.yaml b/deploy/docker-compose.yaml index 7c74477d..2a2c2c63 100644 --- a/deploy/docker-compose.yaml +++ b/deploy/docker-compose.yaml @@ -72,6 +72,7 @@ services: - ./conf/config.toml:/var/www/app/config.toml - ./logs/app:/var/www/app/logs - ./static:/var/www/app/static + - ./data/leveldb:/var/www/app/data # 前端应用 chatgpt-plus-web: diff --git a/web/.env.development b/web/.env.development index d10ac654..330da87b 100644 --- a/web/.env.development +++ b/web/.env.development @@ -6,3 +6,4 @@ VUE_APP_ADMIN_USER=admin VUE_APP_ADMIN_PASS=admin123 VUE_APP_KEY_PREFIX=ChatPLUS_DEV_ VUE_APP_TITLE="Geek-AI 创作系统" +VUE_APP_VERSION=v4.0.2 diff --git a/web/.env.production b/web/.env.production index d558e88d..c6581695 100644 --- a/web/.env.production +++ b/web/.env.production @@ -2,3 +2,4 @@ VUE_APP_API_HOST= VUE_APP_WS_HOST= VUE_APP_KEY_PREFIX=ChatPLUS_ VUE_APP_TITLE="Geek-AI 创作系统" +VUE_APP_VERSION=v4.0.2 diff --git a/web/public/images/menu/app.png b/web/public/images/menu/app.png index 2785231c..f0307dd0 100644 Binary files a/web/public/images/menu/app.png and b/web/public/images/menu/app.png differ diff --git a/web/public/images/menu/chat.png b/web/public/images/menu/chat.png index bb484b5a..12e9f903 100644 Binary files a/web/public/images/menu/chat.png and b/web/public/images/menu/chat.png differ diff --git a/web/public/images/menu/mj.png b/web/public/images/menu/mj.png index 60f08535..97d91954 100644 Binary files a/web/public/images/menu/mj.png and b/web/public/images/menu/mj.png differ diff --git a/web/public/images/menu/sd.png b/web/public/images/menu/sd.png index 5b0d3815..fd918fbe 100644 Binary files a/web/public/images/menu/sd.png and b/web/public/images/menu/sd.png differ diff --git a/web/src/assets/css/image-mj.css b/web/src/assets/css/image-mj.css index 346f198c..f595bc43 100644 --- a/web/src/assets/css/image-mj.css +++ b/web/src/assets/css/image-mj.css @@ -182,6 +182,11 @@ .page-mj .inner .el-form .el-slider { width: 180px; } +.page-mj .inner .el-form .uploader-icon { + font-size: 24px; + position: relative; + top: 3px; +} .page-mj .inner .task-list-box { width: 100%; padding: 10px; @@ -275,6 +280,13 @@ width: 20px; height: 20px; } +.page-mj .inner .task-list-box .task-list-inner .el-row.text-info { + width: 100%; + padding: 10px 0; +} +.page-mj .inner .task-list-box .task-list-inner .el-row.text-info .el-tag { + margin-right: 10px; +} .page-mj .inner .task-list-box .task-list-inner .submit-btn { display: flex; margin: 20px 0; @@ -282,12 +294,6 @@ .page-mj .inner .task-list-box .task-list-inner .submit-btn .el-button { width: 200px; } -.page-mj .inner .task-list-box .task-list-inner .submit-btn .text-info { - width: 100%; - display: flex; - justify-content: right; - align-items: center; -} .page-mj .inner .task-list-box .task-list-inner .job-list-box .running-job-list .job-item { width: 100%; padding: 2px; diff --git a/web/src/assets/css/image-mj.styl b/web/src/assets/css/image-mj.styl index 4d16d2f5..d42935c0 100644 --- a/web/src/assets/css/image-mj.styl +++ b/web/src/assets/css/image-mj.styl @@ -225,6 +225,12 @@ .el-input, .el-slider { width 180px } + + .uploader-icon { + font-size 24px + position relative + top 3px + } } @import "task-list.styl" diff --git a/web/src/assets/css/image-sd.css b/web/src/assets/css/image-sd.css index 5ac1d564..00177432 100644 --- a/web/src/assets/css/image-sd.css +++ b/web/src/assets/css/image-sd.css @@ -53,6 +53,12 @@ padding-top: 5px; padding-bottom: 5px; } +.page-sd .inner .sd-box .sd-params .text-info { + padding: 10px; +} +.page-sd .inner .sd-box .sd-params .text-info .el-tag { + margin-right: 10px; +} .page-sd .inner .sd-box .submit-btn { padding: 10px 15px 0 15px; text-align: center; @@ -159,6 +165,13 @@ width: 20px; height: 20px; } +.page-sd .inner .task-list-box .task-list-inner .el-row.text-info { + width: 100%; + padding: 10px 0; +} +.page-sd .inner .task-list-box .task-list-inner .el-row.text-info .el-tag { + margin-right: 10px; +} .page-sd .inner .task-list-box .task-list-inner .submit-btn { display: flex; margin: 20px 0; @@ -166,12 +179,6 @@ .page-sd .inner .task-list-box .task-list-inner .submit-btn .el-button { width: 200px; } -.page-sd .inner .task-list-box .task-list-inner .submit-btn .text-info { - width: 100%; - display: flex; - justify-content: right; - align-items: center; -} .page-sd .inner .task-list-box .task-list-inner .job-list-box .running-job-list .job-item { width: 100%; padding: 2px; diff --git a/web/src/assets/css/image-sd.styl b/web/src/assets/css/image-sd.styl index edd7ef5f..904eced8 100644 --- a/web/src/assets/css/image-sd.styl +++ b/web/src/assets/css/image-sd.styl @@ -65,6 +65,14 @@ padding-top 5px padding-bottom 5px } + + .text-info { + padding 10px + + .el-tag { + margin-right 10px + } + } } .submit-btn { diff --git a/web/src/assets/css/mobile/image-mj.css b/web/src/assets/css/mobile/image-mj.css index a28c1753..15db23df 100644 --- a/web/src/assets/css/mobile/image-mj.css +++ b/web/src/assets/css/mobile/image-mj.css @@ -1,8 +1,8 @@ -.mobile-mj .content .text-line { +.mobile-mj .text-line { padding: 6px; font-size: 14px; } -.mobile-mj .content .text-line .van-row .van-col .rate { +.mobile-mj .text-line .van-row .van-col .rate { display: flex; justify-content: center; background-color: #f5f5f5; @@ -11,17 +11,17 @@ border-radius: 5px; flex-flow: column; } -.mobile-mj .content .text-line .van-row .van-col .rate .icon { +.mobile-mj .text-line .van-row .van-col .rate .icon { text-align: center; } -.mobile-mj .content .text-line .van-row .van-col .rate .icon .van-image { +.mobile-mj .text-line .van-row .van-col .rate .icon .van-image { max-width: 20px; } -.mobile-mj .content .text-line .van-row .van-col .rate .text { +.mobile-mj .text-line .van-row .van-col .rate .text { text-align: center; color: #555; } -.mobile-mj .content .text-line .van-row .van-col .model { +.mobile-mj .text-line .van-row .van-col .model { display: flex; justify-content: center; background-color: #f5f5f5; @@ -30,40 +30,45 @@ border-radius: 5px; flex-flow: column; } -.mobile-mj .content .text-line .van-row .van-col .model .icon { +.mobile-mj .text-line .van-row .van-col .model .icon { text-align: center; } -.mobile-mj .content .text-line .van-row .van-col .model .icon .van-image { +.mobile-mj .text-line .van-row .van-col .model .icon .van-image { width: 100%; height: 50px; } -.mobile-mj .content .text-line .van-row .van-col .model .text { +.mobile-mj .text-line .van-row .van-col .model .text { text-align: center; color: #555; } -.mobile-mj .content .text-line .van-row .van-col .active { +.mobile-mj .text-line .van-row .van-col .active { background-color: #e5e5e5; } -.mobile-mj .content .text-line .van-button { +.mobile-mj .text-line .van-button { position: relative; } -.mobile-mj .content .text-line .van-button .van-tag { +.mobile-mj .text-line .van-button .van-tag { position: absolute; right: 20px; } -.mobile-mj .content .text-line .align-right { +.mobile-mj .text-line .align-right { display: flex; justify-content: right; } -.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content { +.mobile-mj .tip-text { + padding: 10px; + line-height: 1.5; + color: #c1c1c1; +} +.mobile-mj .running-job-list .van-grid .van-grid-item .van-grid-item__content { padding: 0; position: relative; } -.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .van-image, -.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue { +.mobile-mj .running-job-list .van-grid .van-grid-item .van-grid-item__content .van-image, +.mobile-mj .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue { min-height: 100px; } -.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .progress { +.mobile-mj .running-job-list .van-grid .van-grid-item .van-grid-item__content .progress { display: flex; justify-content: center; align-items: center; @@ -74,36 +79,36 @@ left: 0; top: 0; } -.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .progress .van-circle__text { +.mobile-mj .running-job-list .van-grid .van-grid-item .van-grid-item__content .progress .van-circle__text { color: #fff; } -.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue { +.mobile-mj .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue { display: flex; flex-flow: column; justify-content: center; color: #c1c1c1; } -.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue .icon { +.mobile-mj .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue .icon { text-align: center; } -.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue .icon .iconfont { +.mobile-mj .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue .icon .iconfont { font-size: 24px; } -.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue .text { +.mobile-mj .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue .text { font-size: 14px; margin-top: 5px; } -.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content { +.mobile-mj .finish-job-list .van-grid .van-grid-item .van-grid-item__content { padding: 0; } -.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item { +.mobile-mj .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item { overflow: hidden; border-radius: 6px; position: relative; height: 100%; width: 100%; } -.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .opt .opt-btn { +.mobile-mj .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .opt .opt-btn { padding: 2px 0; text-align: center; border-radius: 5px; @@ -115,20 +120,20 @@ font-size: 14px; width: 100%; } -.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .van-image { +.mobile-mj .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .van-image { width: 100%; height: 200px; } -.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .upscale { +.mobile-mj .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .upscale { height: 260px; width: 100%; } -.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .remove { +.mobile-mj .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .remove { position: absolute; right: 5px; top: 5px; } -.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .remove .el-button { +.mobile-mj .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .remove .el-button { margin-left: 5px; height: auto; padding: 5px; diff --git a/web/src/assets/css/mobile/image-mj.styl b/web/src/assets/css/mobile/image-mj.styl index 948854bd..76022f0f 100644 --- a/web/src/assets/css/mobile/image-mj.styl +++ b/web/src/assets/css/mobile/image-mj.styl @@ -1,189 +1,194 @@ .mobile-mj { - .content { - .text-line { - padding 6px - font-size 14px + .text-line { + padding 6px + font-size 14px - .van-row { - .van-col { - .rate { - display: flex; - justify-content center - background-color #f5f5f5 - padding 5px 10px - margin 5px 0 - border-radius 5px - flex-flow column + .van-row { + .van-col { + .rate { + display: flex; + justify-content center + background-color #f5f5f5 + padding 5px 10px + margin 5px 0 + border-radius 5px + flex-flow column - .icon { - text-align center + .icon { + text-align center - .van-image { - max-width 20px - } - } - - .text { - text-align center - color #555555 + .van-image { + max-width 20px } } - .model { - display: flex; - justify-content center - background-color #f5f5f5 - padding 6px - margin 5px 0 - border-radius 5px - flex-flow column - - .icon { - text-align center - - .van-image { - width 100% - height 50px - } - } - - .text { - text-align center - color #555555 - } - } - - .active { - background-color #e5e5e5 + .text { + text-align center + color #555555 } } - } - .van-button { - position relative + .model { + display: flex; + justify-content center + background-color #f5f5f5 + padding 6px + margin 5px 0 + border-radius 5px + flex-flow column - .van-tag { - position absolute - right 20px - } - } + .icon { + text-align center - .align-right { - display flex - justify-content right - } - } - - .running-job-list { - .van-grid { - .van-grid-item { - .van-grid-item__content { - padding 0 - position relative - - .van-image, .task-in-queue { - min-height 100px - } - - .progress { - display flex - justify-content center - align-items center + .van-image { width 100% - height 100% - background rgba(50, 50, 50, 0.5) - position absolute - left 0 - top 0 - - .van-circle__text { - color #ffffff - } - } - - // end progress - - .task-in-queue { - display flex - flex-flow column - justify-content center - color #c1c1c1 - - .icon { - text-align center - - .iconfont { - font-size 24px - } - } - - .text { - font-size 14px - margin-top 5px - } + height 50px } } + + .text { + text-align center + color #555555 + } + } + + .active { + background-color #e5e5e5 } } } - //end running jobs + .van-button { + position relative - .finish-job-list { - .van-grid { - .van-grid-item { - .van-grid-item__content { - padding 0 + .van-tag { + position absolute + right 20px + } + } - .job-item { - overflow hidden - border-radius 6px - position relative - height 100% - width 100% + .align-right { + display flex + justify-content right + } + } - .opt { - .opt-btn { - padding 2px 0 - text-align center - border-radius 5px - margin 3px 0 - display block - cursor pointer - background-color #4E5058 - color #ffffff - font-size 14px - width 100% - } - } - .van-image { - width 100% - height 200px - } + .tip-text { + padding 10px + line-height 1.5 + color #c1c1c1 + } - .upscale { - height 260px - width 100% - } + .running-job-list { + .van-grid { + .van-grid-item { + .van-grid-item__content { + padding 0 + position relative - .remove { - position absolute - right 5px - top 5px + .van-image, .task-in-queue { + min-height 100px + } - .el-button { - margin-left 5px - height auto - padding 5px - } + .progress { + display flex + justify-content center + align-items center + width 100% + height 100% + background rgba(50, 50, 50, 0.5) + position absolute + left 0 + top 0 + + .van-circle__text { + color #ffffff + } + } + + // end progress + + .task-in-queue { + display flex + flex-flow column + justify-content center + color #c1c1c1 + + .icon { + text-align center + + .iconfont { + font-size 24px } } - + .text { + font-size 14px + margin-top 5px + } } } } } } + + //end running jobs + + .finish-job-list { + .van-grid { + .van-grid-item { + .van-grid-item__content { + padding 0 + + .job-item { + overflow hidden + border-radius 6px + position relative + height 100% + width 100% + + .opt { + .opt-btn { + padding 2px 0 + text-align center + border-radius 5px + margin 3px 0 + display block + cursor pointer + background-color #4E5058 + color #ffffff + font-size 14px + width 100% + } + } + + .van-image { + width 100% + height 200px + } + + .upscale { + height 260px + width 100% + } + + .remove { + position absolute + right 5px + top 5px + + .el-button { + margin-left 5px + height auto + padding 5px + } + } + } + + + } + } + } + } } \ No newline at end of file diff --git a/web/src/assets/css/mobile/image-sd.css b/web/src/assets/css/mobile/image-sd.css new file mode 100644 index 00000000..0189f1ac --- /dev/null +++ b/web/src/assets/css/mobile/image-sd.css @@ -0,0 +1,133 @@ +.mobile-sd .text-line { + padding: 0 6px; + font-size: 14px; +} +.mobile-sd .text-line .van-row { + width: 100%; +} +.mobile-sd .text-line .van-row .van-col .rate { + display: flex; + justify-content: center; + background-color: #f5f5f5; + padding: 5px 10px; + margin: 5px 0; + border-radius: 5px; + flex-flow: column; +} +.mobile-sd .text-line .van-row .van-col .rate .icon { + text-align: center; +} +.mobile-sd .text-line .van-row .van-col .rate .icon .van-image { + max-width: 20px; +} +.mobile-sd .text-line .van-row .van-col .rate .text { + text-align: center; + color: #555; +} +.mobile-sd .text-line .van-row .van-col .el-input__inner { + text-align: center; +} +.mobile-sd .text-line .van-row .van-col .model { + display: flex; + justify-content: center; + background-color: #f5f5f5; + padding: 6px; + margin: 5px 0; + border-radius: 5px; + flex-flow: column; +} +.mobile-sd .text-line .van-row .van-col .model .icon { + text-align: center; +} +.mobile-sd .text-line .van-row .van-col .model .icon .van-image { + width: 100%; + height: 50px; +} +.mobile-sd .text-line .van-row .van-col .model .text { + text-align: center; + color: #555; +} +.mobile-sd .text-line .van-row .van-col .active { + background-color: #e5e5e5; +} +.mobile-sd .text-line .van-button { + position: relative; +} +.mobile-sd .text-line .van-button .van-tag { + position: absolute; + right: 20px; +} +.mobile-sd .text-line .align-right { + display: flex; + justify-content: right; +} +.mobile-sd .pt-6 { + padding: 10px; +} +.mobile-sd .tip-text { + padding: 10px; + line-height: 1.5; + color: #c1c1c1; +} +.mobile-sd .running-job-list .van-grid .van-grid-item .van-grid-item__content { + padding: 0; + position: relative; +} +.mobile-sd .running-job-list .van-grid .van-grid-item .van-grid-item__content .van-image, +.mobile-sd .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue { + min-height: 100px; +} +.mobile-sd .running-job-list .van-grid .van-grid-item .van-grid-item__content .progress { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + background: rgba(50,50,50,0.5); + position: absolute; + left: 0; + top: 0; +} +.mobile-sd .running-job-list .van-grid .van-grid-item .van-grid-item__content .progress .van-circle__text { + color: #fff; +} +.mobile-sd .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue { + display: flex; + flex-flow: column; + justify-content: center; + color: #c1c1c1; +} +.mobile-sd .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue .icon { + text-align: center; +} +.mobile-sd .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue .icon .iconfont { + font-size: 24px; +} +.mobile-sd .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue .text { + font-size: 14px; + margin-top: 5px; +} +.mobile-sd .finish-job-list .van-grid .van-grid-item .van-grid-item__content { + padding: 0; +} +.mobile-sd .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item { + overflow: hidden; + border-radius: 6px; + position: relative; + height: 100%; + width: 100%; +} +.mobile-sd .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .van-image { + width: 100%; + height: 200px; +} +.mobile-sd .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .remove { + position: absolute; + right: 5px; + top: 5px; +} +.mobile-sd .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .remove .el-button { + margin-left: 5px; + height: auto; + padding: 5px; +} diff --git a/web/src/assets/css/mobile/image-sd.styl b/web/src/assets/css/mobile/image-sd.styl new file mode 100644 index 00000000..d5c1a1b8 --- /dev/null +++ b/web/src/assets/css/mobile/image-sd.styl @@ -0,0 +1,184 @@ +.mobile-sd { + .text-line { + padding 0 6px + font-size 14px + + .van-row { + width 100% + + .van-col { + .rate { + display: flex; + justify-content center + background-color #f5f5f5 + padding 5px 10px + margin 5px 0 + border-radius 5px + flex-flow column + + .icon { + text-align center + + .van-image { + max-width 20px + } + } + + .text { + text-align center + color #555555 + } + } + + .el-input__inner { + text-align center + } + + .model { + display: flex; + justify-content center + background-color #f5f5f5 + padding 6px + margin 5px 0 + border-radius 5px + flex-flow column + + .icon { + text-align center + + .van-image { + width 100% + height 50px + } + } + + .text { + text-align center + color #555555 + } + } + + .active { + background-color #e5e5e5 + } + } + } + + .van-button { + position relative + + .van-tag { + position absolute + right 20px + } + } + + .align-right { + display flex + justify-content right + } + } + + + .pt-6 { + padding 10px + } + + .tip-text { + padding 10px + line-height 1.5 + color #c1c1c1 + } + + .running-job-list { + .van-grid { + .van-grid-item { + .van-grid-item__content { + padding 0 + position relative + + .van-image, .task-in-queue { + min-height 100px + } + + .progress { + display flex + justify-content center + align-items center + width 100% + height 100% + background rgba(50, 50, 50, 0.5) + position absolute + left 0 + top 0 + + .van-circle__text { + color #ffffff + } + } + + // end progress + + .task-in-queue { + display flex + flex-flow column + justify-content center + color #c1c1c1 + + .icon { + text-align center + + .iconfont { + font-size 24px + } + } + + .text { + font-size 14px + margin-top 5px + } + } + } + } + } + } + + //end running jobs + + .finish-job-list { + .van-grid { + .van-grid-item { + .van-grid-item__content { + padding 0 + + .job-item { + overflow hidden + border-radius 6px + position relative + height 100% + width 100% + + .van-image { + width 100% + height 200px + } + + .remove { + position absolute + right 5px + top 5px + + .el-button { + margin-left 5px + height auto + padding 5px + } + } + } + + + } + } + } + } +} \ No newline at end of file diff --git a/web/src/assets/css/task-list.styl b/web/src/assets/css/task-list.styl index b836f26f..211d4830 100644 --- a/web/src/assets/css/task-list.styl +++ b/web/src/assets/css/task-list.styl @@ -116,6 +116,15 @@ } } + .el-row.text-info { + width 100% + padding 10px 0 + + .el-tag { + margin-right 10px + } + } + // 提交按钮 .submit-btn { @@ -125,13 +134,6 @@ .el-button { width 200px } - - .text-info { - width 100% - display flex - justify-content right - align-items center - } } diff --git a/web/src/components/FileSelect.vue b/web/src/components/FileSelect.vue index 74d1e0ce..7fc05d0b 100644 --- a/web/src/components/FileSelect.vue +++ b/web/src/components/FileSelect.vue @@ -120,6 +120,10 @@ const removeFile = (file) => { const insertURL = (url) => { show.value = false + // 如果是相对路径,处理成绝对路径 + if (url.indexOf("http") === -1) { + url = location.protocol + "//" + location.host + url + } emits('selected', url) } diff --git a/web/src/components/FooterBar.vue b/web/src/components/FooterBar.vue index ce5d8173..15165d69 100644 --- a/web/src/components/FooterBar.vue +++ b/web/src/components/FooterBar.vue @@ -2,7 +2,9 @@