mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-11-06 17:23:42 +08:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f943669e18 | ||
|
|
3b26735998 | ||
|
|
79d25769ee | ||
|
|
1dd6800987 | ||
|
|
5e673a9ee0 | ||
|
|
92eb67a2af |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,5 +1,16 @@
|
||||
# 更新日志
|
||||
|
||||
## v3.1.2
|
||||
1. 功能新增:新增七牛云 OSS 实现,目前已支持三种文件上传服务:Local, Minio, QiNiu OSS。
|
||||
2. 功能新增:新增桌面版,使用 electron 套壳网页版。
|
||||
3. Bug修复:自动去除众筹核销时候转账单号中的空格,防止复制的时候多复制了空格。
|
||||
4. 功能优化:ChatPlus.vue 页面支持通过 chat_id path variable 来定位到指定的聊天。
|
||||
5. 功能优化:取消导出聊天页面的授权验证
|
||||
6. 功能优化:所有路由跳转都使用绝对路径
|
||||
|
||||
## v3.1.1
|
||||
紧急修复版本,采用弹窗的方式显示验证码,解决验证码在低分辨率下被掩盖的Bug
|
||||
|
||||
## v3.1.0(大版本更新)
|
||||
1. 功能重构:将聊天模型独立拆分,以便支持多平台模型,目前已经内置支持 OPenAI,Azure 以及 ChatGLM,用户可以在这两个平台的模型中随意切换,体验不同的模型聊天。
|
||||
2. 功能重构:重写系统 API 授权机制,使用 JWT 替换传统的 session 会话授权,使得 API 授权变得更加灵活。
|
||||
|
||||
@@ -169,7 +169,7 @@ MysqlDns = "root:12345678@tcp(172.22.11.200:3307)/chatgpt_plus?charset=utf8&pars
|
||||
Token = "插件扩展 API Token" # 这个 token 随便填,只要确保跟 chatgpt-plus-exts 项目的 token 一样就行
|
||||
|
||||
[OSS] # OSS 配置,用于存储 MJ 绘画图片
|
||||
Active = "local" # 默认使用本地文件存储
|
||||
Active = "local" # 默认使用本地文件存储引擎
|
||||
[OSS.Local]
|
||||
BasePath = "./static/upload" # 本地文件上传根路径
|
||||
BaseURL = "http://localhost:5678/static/upload" # 本地上传文件根 URL 如果是线上,则直接设置为 /static/upload 即可
|
||||
@@ -180,6 +180,12 @@ MysqlDns = "root:12345678@tcp(172.22.11.200:3307)/chatgpt_plus?charset=utf8&pars
|
||||
Bucket = "chatgpt-plus" # 替换为你自己创建的 Bucket,注意要给 Bucket 设置公开的读权限,否则会出现图片无法显示。
|
||||
UseSSL = false
|
||||
Domain = "minio 文件公开访问地址" # 地址必须是能够通过公网访问的,否则会出现图片无法显示。
|
||||
[OSS.QiNiu] # 七牛云 OSS 配置
|
||||
Zone = "z2" # 区域,z0:华东,z1: 华北,na0:北美,as0:新加坡
|
||||
AccessKey = "七牛云 OSS AccessKey"
|
||||
AccessSecret = "七牛云 OSS AccessSecret"
|
||||
Bucket = "七牛云 OSS Bucket"
|
||||
Domain = "OSS Bucket 所绑定的域名,如 https://img.r9it.com"
|
||||
```
|
||||
|
||||
> 如果要启用微信收款服务和 MidJourney
|
||||
|
||||
@@ -42,6 +42,12 @@ AesEncryptKey = "{YOUR_AES_KEY}"
|
||||
Endpoint = "IP:端口"
|
||||
AccessKey = "minio oss access key"
|
||||
AccessSecret = "minio oss access secret"
|
||||
Bucket = "chatgpt-plus"
|
||||
Bucket = "minio oss bucket"
|
||||
UseSSL = false
|
||||
Domain = "minio 文件公开访问地址"
|
||||
[OSS.QiNiu] # 七牛云 OSS 配置
|
||||
Zone = "z2" # 区域,z0:华东,z1: 华北,na0:北美,as0:新加坡
|
||||
AccessKey = "七牛云 OSS AccessKey"
|
||||
AccessSecret = "七牛云 OSS AccessSecret"
|
||||
Bucket = "七牛云 OSS Bucket"
|
||||
Domain = "OSS Bucket 所绑定的域名,如 https://img.r9it.com"
|
||||
|
||||
@@ -145,6 +145,8 @@ func authorizeMiddleware(s *AppServer, client *redis.Client) gin.HandlerFunc {
|
||||
c.Request.URL.Path == "/api/user/register" ||
|
||||
c.Request.URL.Path == "/api/reward/notify" ||
|
||||
c.Request.URL.Path == "/api/mj/notify" ||
|
||||
c.Request.URL.Path == "/api/chat/history" ||
|
||||
c.Request.URL.Path == "/api/chat/detail" ||
|
||||
strings.HasPrefix(c.Request.URL.Path, "/api/sms/") ||
|
||||
strings.HasPrefix(c.Request.URL.Path, "/api/captcha/") ||
|
||||
strings.HasPrefix(c.Request.URL.Path, "/static/") ||
|
||||
|
||||
@@ -44,6 +44,7 @@ type OSSConfig struct {
|
||||
Active string
|
||||
Local LocalStorageConfig
|
||||
Minio MinioConfig
|
||||
QiNiu QiNiuConfig
|
||||
}
|
||||
type MinioConfig struct {
|
||||
Endpoint string
|
||||
@@ -54,6 +55,14 @@ type MinioConfig struct {
|
||||
Domain string
|
||||
}
|
||||
|
||||
type QiNiuConfig struct {
|
||||
Zone string
|
||||
AccessKey string
|
||||
AccessSecret string
|
||||
Bucket string
|
||||
Domain string
|
||||
}
|
||||
|
||||
type LocalStorageConfig struct {
|
||||
BasePath string
|
||||
BaseURL string
|
||||
@@ -76,14 +85,6 @@ type Manager struct {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type SessionDriver string
|
||||
|
||||
const (
|
||||
SessionDriverMem = SessionDriver("mem")
|
||||
SessionDriverRedis = SessionDriver("redis")
|
||||
SessionDriverCookie = SessionDriver("cookie")
|
||||
)
|
||||
|
||||
// ChatConfig 系统默认的聊天配置
|
||||
type ChatConfig struct {
|
||||
OpenAI ModelAPIConfig `json:"open_ai"`
|
||||
|
||||
@@ -13,6 +13,7 @@ require (
|
||||
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20230415042440-a5e3d8259ae0
|
||||
github.com/minio/minio-go/v7 v7.0.62
|
||||
github.com/pkoukk/tiktoken-go v0.1.1-0.20230418101013-cae809389480
|
||||
github.com/qiniu/go-sdk/v7 v7.17.1
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
go.uber.org/zap v1.23.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
@@ -60,6 +61,7 @@ require (
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
||||
golang.org/x/mod v0.11.0 // indirect
|
||||
golang.org/x/net v0.14.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/text v0.12.0 // indirect
|
||||
golang.org/x/tools v0.10.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
|
||||
50
api/go.sum
50
api/go.sum
@@ -13,6 +13,7 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -33,11 +34,17 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk=
|
||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
@@ -92,11 +99,15 @@ github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20230415042440-a5e3d8259ae0 h1:LgmjED/yQILqmUED4GaXjrINWe7YJh4HM6z2EvEINPs=
|
||||
@@ -127,12 +138,17 @@ github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:Ff
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkoukk/tiktoken-go v0.1.1-0.20230418101013-cae809389480 h1:IFhPCcB0/HtnEN+ZoUGDT55YgFCymbFJ15kXqs3nv5w=
|
||||
github.com/pkoukk/tiktoken-go v0.1.1-0.20230418101013-cae809389480/go.mod h1:BijIqAP84FMYC4XbdJgjyMpiSjusU8x0Y0W9K2t0QtU=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk=
|
||||
github.com/qiniu/go-sdk/v7 v7.17.1 h1:UoQv7fBKtzAiD1qZPIvTy62Se48YLKxcCYP9nAwWMa0=
|
||||
github.com/qiniu/go-sdk/v7 v7.17.1/go.mod h1:nqoYCNo53ZlGA521RvRethvxUDvXKt4gtYXOwye868w=
|
||||
github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U=
|
||||
@@ -143,6 +159,9 @@ github.com/quic-go/quic-go v0.35.1 h1:b0kzj6b/cQAf05cT0CkQubHM31wiA+xH3IBkxP62po
|
||||
github.com/quic-go/quic-go v0.35.1/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
|
||||
github.com/refraction-networking/utls v1.3.2 h1:o+AkWB57mkcoW36ET7uJ002CpBWHu0KPxi6vzxvPnv8=
|
||||
github.com/refraction-networking/utls v1.3.2/go.mod h1:fmoaOww2bxzzEpIKOebIsnBvjQpqP7L2vcm/9KUfm/E=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
@@ -170,6 +189,7 @@ github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
@@ -187,41 +207,63 @@ golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
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=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
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=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -232,8 +274,10 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
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=
|
||||
|
||||
@@ -35,14 +35,9 @@ func (h *ChatHandler) Update(c *gin.Context) {
|
||||
// History 获取聊天历史记录
|
||||
func (h *ChatHandler) History(c *gin.Context) {
|
||||
chatId := c.Query("chat_id") // 会话 ID
|
||||
user, err := utils.GetLoginUser(c, h.db)
|
||||
if err != nil {
|
||||
resp.NotAuth(c)
|
||||
return
|
||||
}
|
||||
var items []model.HistoryMessage
|
||||
var messages = make([]vo.HistoryMessage, 0)
|
||||
res := h.db.Where("chat_id = ? AND user_id = ?", chatId, user.Id).Find(&items)
|
||||
res := h.db.Where("chat_id = ?", chatId).Find(&items)
|
||||
if res.Error != nil {
|
||||
resp.ERROR(c, "No history message")
|
||||
return
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"chatplus/utils/resp"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RewardHandler struct {
|
||||
@@ -75,6 +76,9 @@ func (h *RewardHandler) Verify(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 移除转账单号中间的空格,防止有人复制的时候多复制了空格
|
||||
data.TxId = strings.ReplaceAll(data.TxId, " ", "")
|
||||
|
||||
var item model.Reward
|
||||
res := h.db.Where("tx_id = ?", data.TxId).First(&item)
|
||||
if res.Error != nil {
|
||||
|
||||
@@ -3,7 +3,6 @@ package handler
|
||||
import (
|
||||
"chatplus/core"
|
||||
"chatplus/core/types"
|
||||
"chatplus/service/oss"
|
||||
"chatplus/store"
|
||||
"chatplus/store/model"
|
||||
"chatplus/store/vo"
|
||||
@@ -22,11 +21,10 @@ import (
|
||||
|
||||
type UserHandler struct {
|
||||
BaseHandler
|
||||
db *gorm.DB
|
||||
searcher *xdb.Searcher
|
||||
leveldb *store.LevelDB
|
||||
redis *redis.Client
|
||||
uploadManager *oss.UploaderManager
|
||||
db *gorm.DB
|
||||
searcher *xdb.Searcher
|
||||
leveldb *store.LevelDB
|
||||
redis *redis.Client
|
||||
}
|
||||
|
||||
func NewUserHandler(
|
||||
@@ -34,9 +32,8 @@ func NewUserHandler(
|
||||
db *gorm.DB,
|
||||
searcher *xdb.Searcher,
|
||||
levelDB *store.LevelDB,
|
||||
client *redis.Client,
|
||||
manager *oss.UploaderManager) *UserHandler {
|
||||
handler := &UserHandler{db: db, searcher: searcher, leveldb: levelDB, redis: client, uploadManager: manager}
|
||||
client *redis.Client) *UserHandler {
|
||||
handler := &UserHandler{db: db, searcher: searcher, leveldb: levelDB, redis: client}
|
||||
handler.App = app
|
||||
return handler
|
||||
}
|
||||
@@ -259,7 +256,6 @@ func (h *UserHandler) ProfileUpdate(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
h.db.First(&user, user.Id)
|
||||
oldAvatar := user.Avatar
|
||||
user.Avatar = data.Avatar
|
||||
user.ChatConfig = utils.JsonEncode(data.ChatConfig)
|
||||
res := h.db.Updates(&user)
|
||||
@@ -268,13 +264,6 @@ func (h *UserHandler) ProfileUpdate(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// remove the old avatar image file
|
||||
if oldAvatar != data.Avatar {
|
||||
err = h.uploadManager.GetActiveService().Delete(oldAvatar)
|
||||
if err != nil {
|
||||
logger.Error("error with delete image: ", err)
|
||||
}
|
||||
}
|
||||
resp.SUCCESS(c)
|
||||
}
|
||||
|
||||
|
||||
98
api/service/oss/qiniu_service.go
Normal file
98
api/service/oss/qiniu_service.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package oss
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"chatplus/core/types"
|
||||
"chatplus/utils"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/qiniu/go-sdk/v7/auth/qbox"
|
||||
"github.com/qiniu/go-sdk/v7/storage"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
type QiNiuService struct {
|
||||
config *types.QiNiuConfig
|
||||
token string
|
||||
uploader *storage.FormUploader
|
||||
manager *storage.BucketManager
|
||||
proxyURL string
|
||||
dir string
|
||||
}
|
||||
|
||||
func NewQiNiuService(appConfig *types.AppConfig) QiNiuService {
|
||||
config := &appConfig.OSS.QiNiu
|
||||
// build storage uploader
|
||||
zone, ok := storage.GetRegionByID(storage.RegionID(config.Zone))
|
||||
if !ok {
|
||||
zone = storage.ZoneHuanan
|
||||
}
|
||||
storeConfig := storage.Config{Zone: &zone}
|
||||
formUploader := storage.NewFormUploader(&storeConfig)
|
||||
// generate token
|
||||
mac := qbox.NewMac(config.AccessKey, config.AccessSecret)
|
||||
putPolicy := storage.PutPolicy{
|
||||
Scope: config.Bucket,
|
||||
}
|
||||
return QiNiuService{
|
||||
config: config,
|
||||
token: putPolicy.UploadToken(mac),
|
||||
uploader: formUploader,
|
||||
manager: storage.NewBucketManager(mac, &storeConfig),
|
||||
proxyURL: appConfig.ProxyURL,
|
||||
dir: "chatgpt-plus",
|
||||
}
|
||||
}
|
||||
|
||||
func (s QiNiuService) PutFile(ctx *gin.Context, name string) (string, error) {
|
||||
// 解析表单
|
||||
file, err := ctx.FormFile(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// 打开上传文件
|
||||
src, err := file.Open()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
fileExt := filepath.Ext(file.Filename)
|
||||
key := fmt.Sprintf("%s/%d%s", s.dir, time.Now().UnixMicro(), fileExt)
|
||||
// 上传文件
|
||||
ret := storage.PutRet{}
|
||||
extra := storage.PutExtra{}
|
||||
err = s.uploader.Put(ctx, &ret, s.token, key, src, file.Size, &extra)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s/%s", s.config.Domain, ret.Key), nil
|
||||
}
|
||||
|
||||
func (s QiNiuService) PutImg(imageURL string) (string, error) {
|
||||
imageData, err := utils.DownloadImage(imageURL, s.proxyURL)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error with download image: %v", err)
|
||||
}
|
||||
fileExt := filepath.Ext(filepath.Base(imageURL))
|
||||
key := fmt.Sprintf("%s/%d%s", s.dir, time.Now().UnixMicro(), fileExt)
|
||||
ret := storage.PutRet{}
|
||||
extra := storage.PutExtra{}
|
||||
// 上传文件字节数据
|
||||
err = s.uploader.Put(context.Background(), &ret, s.token, key, bytes.NewReader(imageData), int64(len(imageData)), &extra)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%s/%s", s.config.Domain, ret.Key), nil
|
||||
}
|
||||
|
||||
func (s QiNiuService) Delete(fileURL string) error {
|
||||
objectName := filepath.Base(fileURL)
|
||||
key := fmt.Sprintf("%s/%s", s.dir, objectName)
|
||||
return s.manager.Delete(s.config.Bucket, key)
|
||||
}
|
||||
|
||||
var _ Uploader = QiNiuService{}
|
||||
@@ -10,8 +10,9 @@ type UploaderManager struct {
|
||||
uploadServices map[string]Uploader
|
||||
}
|
||||
|
||||
const uploaderLocal = "LOCAL"
|
||||
const uploaderMinio = "MINIO"
|
||||
const Local = "LOCAL"
|
||||
const Minio = "MINIO"
|
||||
const QiNiu = "QINIU"
|
||||
|
||||
func NewUploaderManager(config *types.AppConfig) (*UploaderManager, error) {
|
||||
services := make(map[string]Uploader)
|
||||
@@ -20,12 +21,15 @@ func NewUploaderManager(config *types.AppConfig) (*UploaderManager, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
services[uploaderMinio] = minioService
|
||||
services[Minio] = minioService
|
||||
}
|
||||
if config.OSS.Local.BasePath != "" {
|
||||
services[uploaderLocal] = NewLocalStorageService(config)
|
||||
services[Local] = NewLocalStorageService(config)
|
||||
}
|
||||
active := uploaderLocal
|
||||
if config.OSS.QiNiu.AccessKey != "" {
|
||||
services[QiNiu] = NewQiNiuService(config)
|
||||
}
|
||||
active := Local
|
||||
if config.OSS.Active != "" {
|
||||
active = strings.ToUpper(config.OSS.Active)
|
||||
}
|
||||
|
||||
2
desktop/.gitignore
vendored
Normal file
2
desktop/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
dist
|
||||
BIN
desktop/icons/logo.icns
Normal file
BIN
desktop/icons/logo.icns
Normal file
Binary file not shown.
BIN
desktop/icons/logo.ico
Executable file
BIN
desktop/icons/logo.ico
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
desktop/icons/logo.png
Normal file
BIN
desktop/icons/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
29
desktop/index.js
Executable file
29
desktop/index.js
Executable file
@@ -0,0 +1,29 @@
|
||||
const { app, BrowserWindow, Menu } = require('electron');
|
||||
|
||||
app.on('ready', () => {
|
||||
|
||||
const loadingWindow = new BrowserWindow({ width: 400, height: 300, frame: false });
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 1,
|
||||
height: 1,
|
||||
});
|
||||
|
||||
// 先隐藏主窗口
|
||||
mainWindow.hide()
|
||||
// 加载第三方网站
|
||||
mainWindow.loadURL('https://ai.r9it.com');
|
||||
// 加载 loading.html 文件
|
||||
loadingWindow.loadFile('loading.html');
|
||||
// 隐藏菜单
|
||||
Menu.setApplicationMenu(null);
|
||||
|
||||
// 监听 loading.html 窗口的 'show-main-window' 事件
|
||||
mainWindow.webContents.on('did-finish-load', () => {
|
||||
// 最大化窗口
|
||||
mainWindow.maximize();
|
||||
// 显示主窗口
|
||||
mainWindow.show();
|
||||
// 关闭加载窗口
|
||||
loadingWindow.close();
|
||||
});
|
||||
});
|
||||
31
desktop/loading.html
Executable file
31
desktop/loading.html
Executable file
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.loader {
|
||||
border: 4px solid #f3f3f3;
|
||||
border-top: 4px solid #3498db;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="loader"></div>
|
||||
</body>
|
||||
</html>
|
||||
40
desktop/package.json
Executable file
40
desktop/package.json
Executable file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "chatgpt-plus-desktop",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "electron .",
|
||||
"package": "electron-builder",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"build": {
|
||||
"appId": "ai.r9it.com",
|
||||
"productName": "ChatGPT-Plus",
|
||||
"directories": {
|
||||
"output": "dist"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"package.json"
|
||||
],
|
||||
"linux": {
|
||||
"target": "AppImage",
|
||||
"icon": "icons/logo.png"
|
||||
},
|
||||
"mac": {
|
||||
"target": "dmg",
|
||||
"icon": "icons/logo.icns"
|
||||
},
|
||||
"win": {
|
||||
"target": "nsis",
|
||||
"icon": "icons/logo.ico"
|
||||
}
|
||||
},
|
||||
|
||||
"author": "geekmaster",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"electron": "^26.1.0"
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,12 @@ AesEncryptKey = "{YOUR_AES_KEY}"
|
||||
Endpoint = "IP:端口"
|
||||
AccessKey = "minio oss access key"
|
||||
AccessSecret = "minio oss access secret"
|
||||
Bucket = "chatgpt-plus"
|
||||
Bucket = "minio oss bucket"
|
||||
UseSSL = false
|
||||
Domain = "minio 文件公开访问地址"
|
||||
[OSS.QiNiu] # 七牛云 OSS 配置
|
||||
Zone = "z2" # 区域,z0:华东,z1: 华北,na0:北美,as0:新加坡
|
||||
AccessKey = "七牛云 OSS AccessKey"
|
||||
AccessSecret = "七牛云 OSS AccessSecret"
|
||||
Bucket = "七牛云 OSS Bucket"
|
||||
Domain = "OSS Bucket 所绑定的域名,如 https://img.r9it.com"
|
||||
|
||||
307
web/src/assets/css/chat-plus.css
Normal file
307
web/src/assets/css/chat-plus.css
Normal file
@@ -0,0 +1,307 @@
|
||||
#app {
|
||||
height: 100%;
|
||||
}
|
||||
#app .common-layout {
|
||||
height: 100%;
|
||||
}
|
||||
#app .common-layout .el-aside {
|
||||
background-color: #252526;
|
||||
}
|
||||
#app .common-layout .el-aside .title-box {
|
||||
padding: 6px 10px;
|
||||
display: flex;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
}
|
||||
#app .common-layout .el-aside .title-box .logo {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
#app .common-layout .el-aside .title-box span {
|
||||
padding-top: 5px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
#app .common-layout .el-aside .chat-list {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
background-color: #28292a;
|
||||
border-top: 1px solid #2f3032;
|
||||
border-right: 1px solid #2f3032;
|
||||
}
|
||||
#app .common-layout .el-aside .chat-list .search-box {
|
||||
flex-wrap: wrap;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
#app .common-layout .el-aside .chat-list .search-box .el-input__wrapper {
|
||||
background-color: #363535;
|
||||
box-shadow: none;
|
||||
}
|
||||
#app .common-layout .el-aside .chat-list ::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
#app .common-layout .el-aside .chat-list .content {
|
||||
width: 100%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
#app .common-layout .el-aside .chat-list .content .chat-list-item {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#app .common-layout .el-aside .chat-list .content .chat-list-item:hover {
|
||||
background-color: #343540;
|
||||
}
|
||||
#app .common-layout .el-aside .chat-list .content .chat-list-item .avatar {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
#app .common-layout .el-aside .chat-list .content .chat-list-item .chat-title-input {
|
||||
font-size: 14px;
|
||||
margin-top: 4px;
|
||||
margin-left: 10px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
width: 210px;
|
||||
}
|
||||
#app .common-layout .el-aside .chat-list .content .chat-list-item .chat-title {
|
||||
color: #c1c1c1;
|
||||
padding: 5px 10px;
|
||||
max-width: 220px;
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
#app .common-layout .el-aside .chat-list .content .chat-list-item .btn {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
top: 16px;
|
||||
color: #fff;
|
||||
}
|
||||
#app .common-layout .el-aside .chat-list .content .chat-list-item .btn .el-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
#app .common-layout .el-aside .chat-list .content .chat-list-item.active {
|
||||
background-color: #343540;
|
||||
}
|
||||
#app .common-layout .el-aside .chat-list .content .chat-list-item.active .btn {
|
||||
display: inline;
|
||||
}
|
||||
#app .common-layout .el-aside .tool-box {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding: 0 20px 10px 20px;
|
||||
border-top: 1px solid #3c3c3c;
|
||||
}
|
||||
#app .common-layout .el-aside .tool-box .user-info {
|
||||
width: 100%;
|
||||
padding-top: 10px;
|
||||
}
|
||||
#app .common-layout .el-aside .tool-box .user-info .el-dropdown-link {
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
}
|
||||
#app .common-layout .el-aside .tool-box .user-info .el-dropdown-link .el-image {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
#app .common-layout .el-aside .tool-box .user-info .el-dropdown-link .username {
|
||||
display: flex;
|
||||
line-height: 22px;
|
||||
width: 230px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
#app .common-layout .el-aside .tool-box .user-info .el-dropdown-link .el-icon {
|
||||
color: #ccc;
|
||||
line-height: 24px;
|
||||
}
|
||||
#app .common-layout .el-main {
|
||||
overflow: hidden;
|
||||
--el-main-padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
#app .common-layout .el-main .chat-head {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background-color: #28292a;
|
||||
}
|
||||
#app .common-layout .el-main .chat-head .chat-config {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-top: 10px;
|
||||
}
|
||||
#app .common-layout .el-main .chat-head .chat-config .role-select-label {
|
||||
color: #fff;
|
||||
}
|
||||
#app .common-layout .el-main .chat-head .chat-config .el-select {
|
||||
margin-right: 10px;
|
||||
}
|
||||
#app .common-layout .el-main .chat-head .chat-config .role-select {
|
||||
max-width: 130px;
|
||||
}
|
||||
#app .common-layout .el-main .chat-head .chat-config .el-button .el-icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
#app .common-layout .el-main .chat-head .iconfont {
|
||||
margin-right: 5px;
|
||||
}
|
||||
#app .common-layout .el-main .right-box {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
background-color: #fff;
|
||||
border-left: 1px solid #4f4f4f;
|
||||
}
|
||||
#app .common-layout .el-main .right-box #container {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
#app .common-layout .el-main .right-box #container ::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
#app .common-layout .el-main .right-box #container .chat-box {
|
||||
overflow-y: scroll;
|
||||
--content-font-size: 16px;
|
||||
--content-color: #c1c1c1;
|
||||
font-family: 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
|
||||
padding: 0 0 50px 0;
|
||||
}
|
||||
#app .common-layout .el-main .right-box #container .chat-box .chat-line {
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
#app .common-layout .el-main .right-box #container .re-generate {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
#app .common-layout .el-main .right-box #container .re-generate .btn-box {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
}
|
||||
#app .common-layout .el-main .right-box #container .re-generate .btn-box .el-button .el-icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
#app .common-layout .el-main .right-box #container .input-box {
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: 0 2px 15px rgba(0,0,0,0.1);
|
||||
padding: 0 15px;
|
||||
}
|
||||
#app .common-layout .el-main .right-box #container .input-box .input-container {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
border: none;
|
||||
padding: 10px 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
#app .common-layout .el-main .right-box #container .input-box .input-container .el-textarea .el-textarea__inner::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
#app .common-layout .el-main .right-box #container .input-box .input-container .send-btn {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 20px;
|
||||
}
|
||||
#app .common-layout .el-main .right-box #container .input-box .input-container .send-btn .el-button {
|
||||
padding: 8px 5px;
|
||||
border-radius: 6px;
|
||||
background: #19c37d;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
}
|
||||
#app .common-layout .el-main .right-box #container::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
#app .el-message-box {
|
||||
width: 90%;
|
||||
max-width: 420px;
|
||||
}
|
||||
#app .el-message {
|
||||
min-width: 100px;
|
||||
max-width: 600px;
|
||||
}
|
||||
.el-select-dropdown__wrap .el-select-dropdown__item .role-option {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.el-select-dropdown__wrap .el-select-dropdown__item .role-option .el-image {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.el-select-dropdown__wrap .el-select-dropdown__item .role-option span {
|
||||
margin-left: 5px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
}
|
||||
.account {
|
||||
display: flex;
|
||||
background-color: #90ffc2;
|
||||
color: #000;
|
||||
width: 100%;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
.account .vip-logo .el-image {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
.account .vip-info {
|
||||
padding: 0 10px 0 10px;
|
||||
}
|
||||
.account .vip-info h4,
|
||||
.account .vip-info p {
|
||||
margin: 0;
|
||||
}
|
||||
.account .vip-info h4 {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
.account .vip-info p {
|
||||
color: #333;
|
||||
}
|
||||
.account .pay-btn {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
align-items: center;
|
||||
}
|
||||
.notice {
|
||||
background-color: #f6deff;
|
||||
width: 100%;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
color: #cf49ff;
|
||||
}
|
||||
.dialog-service {
|
||||
text-align: center;
|
||||
}
|
||||
.dialog-service .el-image {
|
||||
width: 360px;
|
||||
}
|
||||
404
web/src/assets/css/chat-plus.styl
Normal file
404
web/src/assets/css/chat-plus.styl
Normal file
@@ -0,0 +1,404 @@
|
||||
$sideBgColor = #252526;
|
||||
$borderColor = #4676d0;
|
||||
#app {
|
||||
|
||||
height: 100%;
|
||||
|
||||
.common-layout {
|
||||
height: 100%;
|
||||
|
||||
// left side
|
||||
|
||||
.el-aside {
|
||||
background-color: $sideBgColor;
|
||||
|
||||
.title-box {
|
||||
padding: 6px 10px;
|
||||
display: flex;
|
||||
color: #ffffff;
|
||||
font-size: 20px;
|
||||
|
||||
.logo {
|
||||
background-color: #ffffff
|
||||
border-radius: 8px;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
span {
|
||||
padding-top: 5px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-list {
|
||||
display: flex
|
||||
flex-flow: column
|
||||
background-color: #28292A
|
||||
border-top: 1px solid #2F3032
|
||||
border-right: 1px solid #2F3032
|
||||
|
||||
.search-box {
|
||||
flex-wrap: wrap
|
||||
padding: 10px 15px;
|
||||
|
||||
.el-input__wrapper {
|
||||
background-color: #363535;
|
||||
box-shadow: none
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏滚动条
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.content {
|
||||
//display flex
|
||||
//flex-wrap: wrap;
|
||||
//flex-direction column
|
||||
width: 100%
|
||||
overflow-y: scroll
|
||||
|
||||
.chat-list-item {
|
||||
display: flex
|
||||
width: 100%
|
||||
justify-content: flex-start
|
||||
padding: 8px 12px
|
||||
//border-bottom: 1px solid #3c3c3c
|
||||
cursor: pointer
|
||||
|
||||
&:hover {
|
||||
background-color #343540
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.chat-title-input {
|
||||
font-size: 14px;
|
||||
margin-top: 4px;
|
||||
margin-left: 10px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
width: 210px;
|
||||
}
|
||||
|
||||
.chat-title {
|
||||
color: #c1c1c1
|
||||
padding: 5px 10px;
|
||||
max-width 220px;
|
||||
font-size 14px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display none
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
top: 16px;
|
||||
color #ffffff
|
||||
|
||||
.el-icon {
|
||||
margin-right 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-list-item.active {
|
||||
background-color: #343540;
|
||||
|
||||
.btn {
|
||||
display inline
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.tool-box {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding 0 20px 10px 20px;
|
||||
border-top 1px solid #3c3c3c;
|
||||
|
||||
.user-info {
|
||||
width 100%
|
||||
padding-top 10px;
|
||||
|
||||
.el-dropdown-link {
|
||||
width 100%;
|
||||
cursor: pointer
|
||||
display flex
|
||||
|
||||
.el-image {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.username {
|
||||
display flex
|
||||
line-height 22px;
|
||||
width 230px;
|
||||
padding-left 10px;
|
||||
|
||||
}
|
||||
|
||||
.el-icon {
|
||||
color: #cccccc;
|
||||
line-height 24px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-main {
|
||||
overflow: hidden;
|
||||
--el-main-padding: 0;
|
||||
margin: 0;
|
||||
|
||||
.chat-head {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background-color: #28292A
|
||||
|
||||
.chat-config {
|
||||
display flex
|
||||
flex-direction row
|
||||
align-items: center;
|
||||
justify-content center;
|
||||
padding-top 10px;
|
||||
|
||||
.role-select-label {
|
||||
color #ffffff
|
||||
}
|
||||
|
||||
.el-select {
|
||||
//max-width 150px;
|
||||
margin-right 10px;
|
||||
}
|
||||
|
||||
.role-select {
|
||||
max-width 130px;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
.el-icon {
|
||||
margin-right 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
margin-right 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.right-box {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
background-color: #ffffff
|
||||
border-left: 1px solid #4f4f4f
|
||||
|
||||
#container {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.chat-box {
|
||||
overflow-y: scroll;
|
||||
//border-bottom: 1px solid #4f4f4f
|
||||
|
||||
// 变量定义
|
||||
--content-font-size: 16px;
|
||||
--content-color: #c1c1c1;
|
||||
|
||||
font-family: 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
|
||||
padding: 0 0 50px 0;
|
||||
|
||||
.chat-line {
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.re-generate {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.btn-box {
|
||||
position: absolute
|
||||
bottom: 10px;
|
||||
|
||||
.el-button {
|
||||
.el-icon {
|
||||
margin-right 5px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.input-box {
|
||||
background-color: #ffffff
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1);
|
||||
padding 0 15px;
|
||||
|
||||
.input-container {
|
||||
width 100%
|
||||
margin: 0;
|
||||
border: none;
|
||||
padding: 10px 0;
|
||||
display flex
|
||||
justify-content center
|
||||
position relative
|
||||
|
||||
.el-textarea {
|
||||
|
||||
.el-textarea__inner::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.send-btn {
|
||||
position absolute;
|
||||
right 12px;
|
||||
top 20px;
|
||||
|
||||
.el-button {
|
||||
padding 8px 5px;
|
||||
border-radius 6px;
|
||||
background: rgb(25, 195, 125)
|
||||
color #ffffff;
|
||||
font-size 20px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#container::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-message-box {
|
||||
width: 90%;
|
||||
max-width: 420px;
|
||||
}
|
||||
|
||||
.el-message {
|
||||
min-width: 100px;
|
||||
max-width: 600px;
|
||||
}
|
||||
}
|
||||
|
||||
.el-select-dropdown__wrap {
|
||||
.el-select-dropdown__item {
|
||||
.role-option {
|
||||
display flex
|
||||
flex-flow row
|
||||
margin-top 8px;
|
||||
|
||||
.el-image {
|
||||
width 20px
|
||||
height 20px
|
||||
border-radius 50%
|
||||
}
|
||||
|
||||
span {
|
||||
margin-left 5px;
|
||||
height 20px;
|
||||
line-height 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.account {
|
||||
display flex
|
||||
background-color #90FFC2
|
||||
color #000000
|
||||
width 100%
|
||||
border-radius 10px
|
||||
padding 10px
|
||||
|
||||
.vip-logo {
|
||||
.el-image {
|
||||
width 40px
|
||||
height 40px
|
||||
border-radius 100%
|
||||
background-color #ffffff
|
||||
}
|
||||
}
|
||||
|
||||
.vip-info {
|
||||
padding: 0 10px 0 10px
|
||||
|
||||
h4, p {
|
||||
margin 0
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-weight bold
|
||||
font-size 16px;
|
||||
}
|
||||
|
||||
p {
|
||||
color #333333
|
||||
}
|
||||
}
|
||||
|
||||
.pay-btn {
|
||||
width 100%
|
||||
display flex
|
||||
justify-content right
|
||||
align-items center
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.notice {
|
||||
background-color #F6DEFF
|
||||
width 100%
|
||||
padding 5px 10px;
|
||||
border-radius 5px;
|
||||
color #CF49FF
|
||||
}
|
||||
|
||||
.dialog-service {
|
||||
text-align center
|
||||
|
||||
.el-image {
|
||||
width 360px;
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ export default defineComponent({
|
||||
default: 0,
|
||||
},
|
||||
model: {
|
||||
type: String,
|
||||
type: Number,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -58,7 +58,7 @@ const save = () => {
|
||||
ElMessage.success({
|
||||
message: '核销成功',
|
||||
duration: 1000,
|
||||
onClose: () => emits('hide', false)
|
||||
onClose: () => location.reload()
|
||||
})
|
||||
}).catch(e => {
|
||||
ElMessage.error({message: "核销失败:" + e.message});
|
||||
|
||||
@@ -21,11 +21,18 @@ const routes = [
|
||||
component: () => import('@/views/Register.vue'),
|
||||
},
|
||||
{
|
||||
name: 'plus',
|
||||
name: 'chat',
|
||||
path: '/chat',
|
||||
meta: {title: '创作中心'},
|
||||
component: () => import('@/views/ChatPlus.vue'),
|
||||
},
|
||||
{
|
||||
name: 'chat-id',
|
||||
path: '/chat/:id',
|
||||
meta: {title: '创作中心'},
|
||||
component: () => import('@/views/ChatPlus.vue'),
|
||||
props: true // 将路由参数传递给组件的 props
|
||||
},
|
||||
{
|
||||
name: 'chat-export',
|
||||
path: '/chat/export',
|
||||
|
||||
@@ -102,7 +102,7 @@ const exportChat = () => {
|
||||
justify-content center
|
||||
|
||||
.chat-box {
|
||||
max-width 800px;
|
||||
width 800px;
|
||||
// 变量定义
|
||||
--content-font-size: 16px;
|
||||
--content-color: #c1c1c1;
|
||||
|
||||
@@ -235,13 +235,14 @@
|
||||
title="参与众筹"
|
||||
>
|
||||
<el-alert type="info" :closable="false">
|
||||
<p>您好,ChatGPT-Plus 项目目前已经运行了快半年了,一直免费给大家使用的。然而免费服务始终难以维持,服务器即将到期,免费的
|
||||
API KEY 也全部用完了,因此我们准备开启众筹模式,只需要打赏9.9元,就可以兑换 100 次对话,以此来覆盖我们的 OpenAI
|
||||
账单和服务器的费用。</p>
|
||||
<div style="font-size: 14px">您好,众筹 9.9元,就可以兑换 100 次对话,以此来覆盖我们的 OpenAI
|
||||
账单和服务器的费用。<strong
|
||||
style="color: #f56c6c">由于本人没有开通微信支付,付款后请凭借转账单号进入核销【众筹核销】菜单手动核销。</strong>
|
||||
</div>
|
||||
</el-alert>
|
||||
<p style="text-align: center">
|
||||
<div style="text-align: center;padding-top: 10px;">
|
||||
<el-image :src="rewardImg"/>
|
||||
</p>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
@@ -284,8 +285,8 @@ import Welcome from "@/components/Welcome.vue";
|
||||
import ChatMidJourney from "@/components/ChatMidJourney.vue";
|
||||
|
||||
const title = ref('ChatGPT-智能助手');
|
||||
const logo = 'images/logo.png';
|
||||
const rewardImg = ref('images/reward.png')
|
||||
const logo = '/images/logo.png';
|
||||
const rewardImg = ref('/images/reward.png')
|
||||
const models = ref([])
|
||||
const modelID = ref(0)
|
||||
const chatData = ref([]);
|
||||
@@ -319,26 +320,43 @@ onMounted(() => {
|
||||
checkSession().then((user) => {
|
||||
loginUser.value = user
|
||||
isLogin.value = true
|
||||
// 加载角色列表
|
||||
httpGet(`/api/role/list?user_id=${user.id}`).then((res) => {
|
||||
roles.value = res.data;
|
||||
roleId.value = roles.value[0]['id'];
|
||||
// 获取会话列表
|
||||
loadChats();
|
||||
// 获取会话列表
|
||||
httpGet("/api/chat/list?user_id=" + loginUser.value.id).then((res) => {
|
||||
if (res.data) {
|
||||
chatList.value = res.data;
|
||||
allChats.value = res.data;
|
||||
}
|
||||
// 加载模型
|
||||
httpGet('/api/model/list?enable=1').then(res => {
|
||||
models.value = res.data
|
||||
modelID.value = models.value[0].id
|
||||
// 创建新的对话
|
||||
newChat();
|
||||
|
||||
// 加载角色列表
|
||||
httpGet(`/api/role/list?user_id=${user.id}`).then((res) => {
|
||||
roles.value = res.data;
|
||||
roleId.value = roles.value[0]['id'];
|
||||
const chatId = router.currentRoute.value.params['id']
|
||||
const chat = getChatById(chatId)
|
||||
if (chat === null) {
|
||||
// 创建新的对话
|
||||
newChat();
|
||||
} else {
|
||||
// 加载对话
|
||||
loadChat(chat)
|
||||
}
|
||||
}).catch((e) => {
|
||||
ElMessage.error('获取聊天角色失败: ' + e.messages)
|
||||
})
|
||||
}).catch(e => {
|
||||
ElMessage.error("加载模型失败: " + e.message)
|
||||
})
|
||||
}).catch((e) => {
|
||||
ElMessage.error('获取聊天角色失败: ' + e.messages)
|
||||
|
||||
}).catch(() => {
|
||||
// TODO: 增加重试按钮
|
||||
ElMessage.error("加载会话列表失败!")
|
||||
})
|
||||
}).catch(() => {
|
||||
router.push('login')
|
||||
router.push('/login')
|
||||
});
|
||||
|
||||
const clipboard = new Clipboard('.copy-reply');
|
||||
@@ -349,20 +367,9 @@ onMounted(() => {
|
||||
clipboard.on('error', () => {
|
||||
ElMessage.error('复制失败!');
|
||||
})
|
||||
});
|
||||
|
||||
// 加载会话
|
||||
const loadChats = function () {
|
||||
httpGet("/api/chat/list?user_id=" + loginUser.value.id).then((res) => {
|
||||
if (res.data) {
|
||||
chatList.value = res.data;
|
||||
allChats.value = res.data;
|
||||
}
|
||||
}).catch(() => {
|
||||
// TODO: 增加重试按钮
|
||||
ElMessage.error("加载会话列表失败!")
|
||||
})
|
||||
}
|
||||
window.onresize = () => resizeElement();
|
||||
});
|
||||
|
||||
const getRoleById = function (rid) {
|
||||
for (let i = 0; i < roles.value.length; i++) {
|
||||
@@ -409,7 +416,12 @@ const newChat = function () {
|
||||
}
|
||||
|
||||
// 切换会话
|
||||
const changeChat = function (chat) {
|
||||
const changeChat = (chat) => {
|
||||
router.push("/chat/" + chat.chat_id)
|
||||
loadChat(chat)
|
||||
}
|
||||
|
||||
const loadChat = function (chat) {
|
||||
if (activeChat.value['chat_id'] === chat.chat_id) {
|
||||
return;
|
||||
}
|
||||
@@ -738,7 +750,7 @@ const logout = function () {
|
||||
activelyClose.value = true;
|
||||
httpGet('/api/user/logout').then(() => {
|
||||
removeUserToken();
|
||||
router.push('login');
|
||||
router.push('/login');
|
||||
}).catch(() => {
|
||||
ElMessage.error('注销失败!');
|
||||
})
|
||||
@@ -838,353 +850,18 @@ const exportChat = () => {
|
||||
// console.log(url)
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
|
||||
const getChatById = (chatId) => {
|
||||
for (let index in chatList.value) {
|
||||
if (chatList.value[index].chat_id === chatId) {
|
||||
return chatList.value[index]
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
@import '@/assets/iconfont/iconfont.css';
|
||||
$sideBgColor = #252526;
|
||||
$borderColor = #4676d0;
|
||||
#app {
|
||||
|
||||
height: 100%;
|
||||
|
||||
.common-layout {
|
||||
height: 100%;
|
||||
|
||||
// left side
|
||||
|
||||
.el-aside {
|
||||
background-color: $sideBgColor;
|
||||
|
||||
.title-box {
|
||||
padding: 6px 10px;
|
||||
display: flex;
|
||||
color: #ffffff;
|
||||
font-size: 20px;
|
||||
|
||||
.logo {
|
||||
background-color: #ffffff
|
||||
border-radius: 8px;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
span {
|
||||
padding-top: 5px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-list {
|
||||
display: flex
|
||||
flex-flow: column
|
||||
background-color: #28292A
|
||||
border-top: 1px solid #2F3032
|
||||
border-right: 1px solid #2F3032
|
||||
|
||||
.search-box {
|
||||
flex-wrap: wrap
|
||||
padding: 10px 15px;
|
||||
|
||||
.el-input__wrapper {
|
||||
background-color: #363535;
|
||||
box-shadow: none
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏滚动条
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.content {
|
||||
//display flex
|
||||
//flex-wrap: wrap;
|
||||
//flex-direction column
|
||||
width: 100%
|
||||
overflow-y: scroll
|
||||
|
||||
.chat-list-item {
|
||||
display: flex
|
||||
width: 100%
|
||||
justify-content: flex-start
|
||||
padding: 8px 12px
|
||||
//border-bottom: 1px solid #3c3c3c
|
||||
cursor: pointer
|
||||
|
||||
&:hover {
|
||||
background-color #343540
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.chat-title-input {
|
||||
font-size: 14px;
|
||||
margin-top: 4px;
|
||||
margin-left: 10px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
width: 210px;
|
||||
}
|
||||
|
||||
.chat-title {
|
||||
color: #c1c1c1
|
||||
padding: 5px 10px;
|
||||
max-width 220px;
|
||||
font-size 14px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display none
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
top: 16px;
|
||||
color #ffffff
|
||||
|
||||
.el-icon {
|
||||
margin-right 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-list-item.active {
|
||||
background-color: #343540;
|
||||
|
||||
.btn {
|
||||
display inline
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.tool-box {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding 0 20px 10px 20px;
|
||||
border-top 1px solid #3c3c3c;
|
||||
|
||||
.user-info {
|
||||
width 100%
|
||||
padding-top 10px;
|
||||
|
||||
.el-dropdown-link {
|
||||
width 100%;
|
||||
cursor: pointer
|
||||
display flex
|
||||
|
||||
.el-image {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.username {
|
||||
display flex
|
||||
line-height 22px;
|
||||
width 230px;
|
||||
padding-left 10px;
|
||||
|
||||
}
|
||||
|
||||
.el-icon {
|
||||
color: #cccccc;
|
||||
line-height 24px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-main {
|
||||
overflow: hidden;
|
||||
--el-main-padding: 0;
|
||||
margin: 0;
|
||||
|
||||
.chat-head {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background-color: #28292A
|
||||
|
||||
.chat-config {
|
||||
display flex
|
||||
flex-direction row
|
||||
align-items: center;
|
||||
justify-content center;
|
||||
padding-top 10px;
|
||||
|
||||
.role-select-label {
|
||||
color #ffffff
|
||||
}
|
||||
|
||||
.el-select {
|
||||
//max-width 150px;
|
||||
margin-right 10px;
|
||||
}
|
||||
|
||||
.role-select {
|
||||
max-width 130px;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
.el-icon {
|
||||
margin-right 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
margin-right 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.right-box {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
background-color: #ffffff
|
||||
border-left: 1px solid #4f4f4f
|
||||
|
||||
#container {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.chat-box {
|
||||
overflow-y: scroll;
|
||||
//border-bottom: 1px solid #4f4f4f
|
||||
|
||||
// 变量定义
|
||||
--content-font-size: 16px;
|
||||
--content-color: #c1c1c1;
|
||||
|
||||
font-family: 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
|
||||
padding: 0 0 50px 0;
|
||||
|
||||
.chat-line {
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.re-generate {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.btn-box {
|
||||
position: absolute
|
||||
bottom: 10px;
|
||||
|
||||
.el-button {
|
||||
.el-icon {
|
||||
margin-right 5px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.input-box {
|
||||
background-color: #ffffff
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1);
|
||||
padding 0 15px;
|
||||
|
||||
.input-container {
|
||||
width 100%
|
||||
margin: 0;
|
||||
border: none;
|
||||
padding: 10px 0;
|
||||
display flex
|
||||
justify-content center
|
||||
position relative
|
||||
|
||||
.el-textarea {
|
||||
|
||||
.el-textarea__inner::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.send-btn {
|
||||
position absolute;
|
||||
right 12px;
|
||||
top 20px;
|
||||
|
||||
.el-button {
|
||||
padding 8px 5px;
|
||||
border-radius 6px;
|
||||
background: rgb(25, 195, 125)
|
||||
color #ffffff;
|
||||
font-size 20px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#container::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-message-box {
|
||||
width: 90%;
|
||||
max-width: 420px;
|
||||
}
|
||||
|
||||
.el-message {
|
||||
min-width: 100px;
|
||||
max-width: 600px;
|
||||
}
|
||||
}
|
||||
|
||||
.el-select-dropdown__wrap {
|
||||
.el-select-dropdown__item {
|
||||
.role-option {
|
||||
display flex
|
||||
flex-flow row
|
||||
margin-top 8px;
|
||||
|
||||
.el-image {
|
||||
width 20px
|
||||
height 20px
|
||||
border-radius 50%
|
||||
}
|
||||
|
||||
span {
|
||||
margin-left 5px;
|
||||
height 20px;
|
||||
line-height 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@import "@/assets/css/chat-plus.styl"
|
||||
</style>
|
||||
@@ -17,7 +17,7 @@ checkSession().then(() => {
|
||||
router.push("/chat")
|
||||
}
|
||||
}).catch(() => {
|
||||
router.push("login")
|
||||
router.push("/login")
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
<el-row class="text-line">
|
||||
还没有账号?
|
||||
<el-link type="primary" @click="router.push('register')">注册新账号</el-link>
|
||||
<el-link type="primary" @click="router.push('/register')">注册新账号</el-link>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
@@ -66,9 +66,9 @@ const password = ref(process.env.VUE_APP_PASS);
|
||||
|
||||
checkSession().then(() => {
|
||||
if (isMobile()) {
|
||||
router.push('mobile')
|
||||
router.push('/mobile')
|
||||
} else {
|
||||
router.push('chat')
|
||||
router.push('/chat')
|
||||
}
|
||||
}).catch(() => {
|
||||
})
|
||||
@@ -94,7 +94,7 @@ const login = function () {
|
||||
if (isMobile()) {
|
||||
router.push('/mobile')
|
||||
} else {
|
||||
router.push('chat')
|
||||
router.push('/chat')
|
||||
}
|
||||
}).catch((e) => {
|
||||
ElMessage.error('登录失败,' + e.message)
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
<el-row class="text-line">
|
||||
已经有账号?
|
||||
<el-link type="primary" @click="router.push('login')">登录</el-link>
|
||||
<el-link type="primary" @click="router.push('/login')">登录</el-link>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
@@ -144,7 +144,7 @@ const register = function () {
|
||||
return ElMessage.error('请输入短信验证码');
|
||||
}
|
||||
httpPost('/api/user/register', formData.value).then(() => {
|
||||
ElMessage.success({"message": "注册成功,即将跳转到登录页...", onClose: () => router.push("login")})
|
||||
ElMessage.success({"message": "注册成功,即将跳转到登录页...", onClose: () => router.push("/login")})
|
||||
}).catch((e) => {
|
||||
ElMessage.error('注册失败,' + e.message)
|
||||
})
|
||||
|
||||
@@ -55,7 +55,7 @@ const username = ref(process.env.VUE_APP_ADMIN_USER);
|
||||
const password = ref(process.env.VUE_APP_ADMIN_PASS);
|
||||
|
||||
checkAdminSession().then(() => {
|
||||
router.push("admin")
|
||||
router.push("/admin")
|
||||
}).catch(() => {
|
||||
})
|
||||
onMounted(() => {
|
||||
@@ -76,7 +76,7 @@ const login = function () {
|
||||
|
||||
httpPost('/api/admin/login', {username: username.value.trim(), password: password.value.trim()}).then(res => {
|
||||
setAdminToken(res.data)
|
||||
router.push("admin")
|
||||
router.push("/admin")
|
||||
}).catch((e) => {
|
||||
ElMessage.error('登录失败,' + e.message)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user