mirror of
https://github.com/coaidev/coai.git
synced 2025-05-20 05:20:15 +09:00
feat: update plan config and websocket connection deadline feature
This commit is contained in:
parent
7f1c8fad99
commit
5dc965992a
@ -39,7 +39,7 @@
|
|||||||
"cmdk": "^0.2.0",
|
"cmdk": "^0.2.0",
|
||||||
"i18next": "^23.4.6",
|
"i18next": "^23.4.6",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"lucide-react": "^0.289.0",
|
"lucide-react": "^0.309.0",
|
||||||
"match-sorter": "^6.3.1",
|
"match-sorter": "^6.3.1",
|
||||||
"next-themes": "^0.2.1",
|
"next-themes": "^0.2.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
129
app/pnpm-lock.yaml
generated
129
app/pnpm-lock.yaml
generated
@ -87,8 +87,8 @@ dependencies:
|
|||||||
specifier: ^1.10.0
|
specifier: ^1.10.0
|
||||||
version: 1.10.0
|
version: 1.10.0
|
||||||
lucide-react:
|
lucide-react:
|
||||||
specifier: ^0.289.0
|
specifier: ^0.309.0
|
||||||
version: 0.289.0(react@18.2.0)
|
version: 0.309.0(react@18.2.0)
|
||||||
match-sorter:
|
match-sorter:
|
||||||
specifier: ^6.3.1
|
specifier: ^6.3.1
|
||||||
version: 6.3.1
|
version: 6.3.1
|
||||||
@ -548,6 +548,13 @@ packages:
|
|||||||
'@jridgewell/resolve-uri': 3.1.1
|
'@jridgewell/resolve-uri': 3.1.1
|
||||||
'@jridgewell/sourcemap-codec': 1.4.15
|
'@jridgewell/sourcemap-codec': 1.4.15
|
||||||
|
|
||||||
|
/@jridgewell/trace-mapping@0.3.21:
|
||||||
|
resolution: {integrity: sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==}
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/resolve-uri': 3.1.1
|
||||||
|
'@jridgewell/sourcemap-codec': 1.4.15
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@kurkle/color@0.3.2:
|
/@kurkle/color@0.3.2:
|
||||||
resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==}
|
resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==}
|
||||||
dev: false
|
dev: false
|
||||||
@ -2092,12 +2099,12 @@ packages:
|
|||||||
/@types/eslint-scope@3.7.7:
|
/@types/eslint-scope@3.7.7:
|
||||||
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
|
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/eslint': 8.44.8
|
'@types/eslint': 8.56.2
|
||||||
'@types/estree': 1.0.5
|
'@types/estree': 1.0.5
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/eslint@8.44.8:
|
/@types/eslint@8.56.2:
|
||||||
resolution: {integrity: sha512-4K8GavROwhrYl2QXDXm0Rv9epkA8GBFu0EI+XrrnnuCl7u8CWBRusX7fXJfanhZTDWSAL24gDI/UqXyUM0Injw==}
|
resolution: {integrity: sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/estree': 1.0.5
|
'@types/estree': 1.0.5
|
||||||
'@types/json-schema': 7.0.15
|
'@types/json-schema': 7.0.15
|
||||||
@ -2152,8 +2159,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-AuHIyzR5Hea7ij0P9q7vx7xu4z0C28ucwjAZC0ja7JhINyCnOw8/DnvAPQQ9TfOlCtZAmCERKQX9+o1mgQhuOQ==}
|
resolution: {integrity: sha512-AuHIyzR5Hea7ij0P9q7vx7xu4z0C28ucwjAZC0ja7JhINyCnOw8/DnvAPQQ9TfOlCtZAmCERKQX9+o1mgQhuOQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@types/node@20.10.1:
|
/@types/node@20.11.3:
|
||||||
resolution: {integrity: sha512-T2qwhjWwGH81vUEx4EXmBKsTJRXFXNZTL4v0gi01+zyBmCwzE6TyHszqX01m+QHTEq+EZNo13NeJIdEqf+Myrg==}
|
resolution: {integrity: sha512-nrlmbvGPNGaj84IJZXMPhQuCMEVTT/hXZMJJG/aIqVL9fKxqk814sGGtJA4GI6hpJSLQjpi6cn0Qx9eOf9SDVg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 5.26.5
|
undici-types: 5.26.5
|
||||||
dev: true
|
dev: true
|
||||||
@ -2483,12 +2490,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==}
|
resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/acorn-import-assertions@1.9.0(acorn@8.11.2):
|
/acorn-import-assertions@1.9.0(acorn@8.11.3):
|
||||||
resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==}
|
resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
acorn: ^8
|
acorn: ^8
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.11.2
|
acorn: 8.11.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/acorn-jsx@5.3.2(acorn@8.10.0):
|
/acorn-jsx@5.3.2(acorn@8.10.0):
|
||||||
@ -2505,8 +2512,8 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/acorn@8.11.2:
|
/acorn@8.11.3:
|
||||||
resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==}
|
resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
@ -2647,6 +2654,17 @@ packages:
|
|||||||
update-browserslist-db: 1.0.13(browserslist@4.22.1)
|
update-browserslist-db: 1.0.13(browserslist@4.22.1)
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/browserslist@4.22.2:
|
||||||
|
resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==}
|
||||||
|
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||||
|
hasBin: true
|
||||||
|
dependencies:
|
||||||
|
caniuse-lite: 1.0.30001576
|
||||||
|
electron-to-chromium: 1.4.631
|
||||||
|
node-releases: 2.0.14
|
||||||
|
update-browserslist-db: 1.0.13(browserslist@4.22.2)
|
||||||
|
dev: true
|
||||||
|
|
||||||
/buffer-from@1.1.2:
|
/buffer-from@1.1.2:
|
||||||
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||||
dev: true
|
dev: true
|
||||||
@ -2676,6 +2694,10 @@ packages:
|
|||||||
|
|
||||||
/caniuse-lite@1.0.30001554:
|
/caniuse-lite@1.0.30001554:
|
||||||
resolution: {integrity: sha512-A2E3U//MBwbJVzebddm1YfNp7Nud5Ip+IPn4BozBmn4KqVX7AvluoIDFWjsv5OkGnKUXQVmMSoMKLa3ScCblcQ==}
|
resolution: {integrity: sha512-A2E3U//MBwbJVzebddm1YfNp7Nud5Ip+IPn4BozBmn4KqVX7AvluoIDFWjsv5OkGnKUXQVmMSoMKLa3ScCblcQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/caniuse-lite@1.0.30001576:
|
||||||
|
resolution: {integrity: sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==}
|
||||||
|
|
||||||
/ccount@2.0.1:
|
/ccount@2.0.1:
|
||||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
||||||
@ -2869,19 +2891,6 @@ packages:
|
|||||||
/csstype@3.1.2:
|
/csstype@3.1.2:
|
||||||
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
|
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
|
||||||
|
|
||||||
/debug@3.2.7:
|
|
||||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
|
||||||
requiresBuild: true
|
|
||||||
peerDependencies:
|
|
||||||
supports-color: '*'
|
|
||||||
peerDependenciesMeta:
|
|
||||||
supports-color:
|
|
||||||
optional: true
|
|
||||||
dependencies:
|
|
||||||
ms: 2.1.3
|
|
||||||
dev: true
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
/debug@4.3.4:
|
/debug@4.3.4:
|
||||||
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
||||||
engines: {node: '>=6.0'}
|
engines: {node: '>=6.0'}
|
||||||
@ -3004,6 +3013,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-8KR114CAYQ4/r5EIEsOmOMqQ9j0MRbJZR3aXD/KFA8RuKzyoUB4XrUCg+l8RUGqTVQgKNIgTpjaG8YHRPAbX2w==}
|
resolution: {integrity: sha512-8KR114CAYQ4/r5EIEsOmOMqQ9j0MRbJZR3aXD/KFA8RuKzyoUB4XrUCg+l8RUGqTVQgKNIgTpjaG8YHRPAbX2w==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/electron-to-chromium@1.4.631:
|
||||||
|
resolution: {integrity: sha512-g73CJB/rMPjdxpiNJYmV1homV7mLVUNe/R0z/HhqMfpjkt58FpYmkTjbtuv3zymdbTTJ+VOEqe1c+lkTjSOhmQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/enhanced-resolve@5.15.0:
|
/enhanced-resolve@5.15.0:
|
||||||
resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==}
|
resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
@ -3689,7 +3702,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
|
resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
|
||||||
engines: {node: '>= 10.13.0'}
|
engines: {node: '>= 10.13.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.10.1
|
'@types/node': 20.11.3
|
||||||
merge-stream: 2.0.0
|
merge-stream: 2.0.0
|
||||||
supports-color: 8.1.1
|
supports-color: 8.1.1
|
||||||
dev: true
|
dev: true
|
||||||
@ -3776,10 +3789,8 @@ packages:
|
|||||||
image-size: 0.5.5
|
image-size: 0.5.5
|
||||||
make-dir: 2.1.0
|
make-dir: 2.1.0
|
||||||
mime: 1.6.0
|
mime: 1.6.0
|
||||||
needle: 3.2.0
|
needle: 3.3.1
|
||||||
source-map: 0.6.1
|
source-map: 0.6.1
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/levn@0.4.1:
|
/levn@0.4.1:
|
||||||
@ -3856,8 +3867,8 @@ packages:
|
|||||||
yallist: 4.0.0
|
yallist: 4.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/lucide-react@0.289.0(react@18.2.0):
|
/lucide-react@0.309.0(react@18.2.0):
|
||||||
resolution: {integrity: sha512-D3/kt5h4KVmO9Bqlhky/szWI3puEU/KJfQWCeX8Zhvx3xx0SQ4t6vbwiK9ORBbiaqXefkBbXjoq7fOBd7s5yXQ==}
|
resolution: {integrity: sha512-zNVPczuwFrCfksZH3zbd1UDE6/WYhYAdbe2k7CImVyPAkXLgIwbs6eXQ4loigqDnUFjyFYCI5jZ1y10Kqal0dg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.5.1 || ^17.0.0 || ^18.0.0
|
react: ^16.5.1 || ^17.0.0 || ^18.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -4356,12 +4367,6 @@ packages:
|
|||||||
/ms@2.1.2:
|
/ms@2.1.2:
|
||||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||||
|
|
||||||
/ms@2.1.3:
|
|
||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
|
||||||
requiresBuild: true
|
|
||||||
dev: true
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
/mz@2.7.0:
|
/mz@2.7.0:
|
||||||
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -4378,17 +4383,14 @@ packages:
|
|||||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/needle@3.2.0:
|
/needle@3.3.1:
|
||||||
resolution: {integrity: sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==}
|
resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==}
|
||||||
engines: {node: '>= 4.4.x'}
|
engines: {node: '>= 4.4.x'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 3.2.7
|
|
||||||
iconv-lite: 0.6.3
|
iconv-lite: 0.6.3
|
||||||
sax: 1.3.0
|
sax: 1.3.0
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@ -4426,7 +4428,7 @@ packages:
|
|||||||
'@next/env': 14.0.4
|
'@next/env': 14.0.4
|
||||||
'@swc/helpers': 0.5.2
|
'@swc/helpers': 0.5.2
|
||||||
busboy: 1.6.0
|
busboy: 1.6.0
|
||||||
caniuse-lite: 1.0.30001554
|
caniuse-lite: 1.0.30001576
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
postcss: 8.4.31
|
postcss: 8.4.31
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
@ -4466,6 +4468,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
|
resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/node-releases@2.0.14:
|
||||||
|
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/normalize-path@3.0.0:
|
/normalize-path@3.0.0:
|
||||||
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -5212,8 +5218,8 @@ packages:
|
|||||||
lru-cache: 6.0.0
|
lru-cache: 6.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/serialize-javascript@6.0.1:
|
/serialize-javascript@6.0.2:
|
||||||
resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==}
|
resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
|
||||||
dependencies:
|
dependencies:
|
||||||
randombytes: 2.1.0
|
randombytes: 2.1.0
|
||||||
dev: true
|
dev: true
|
||||||
@ -5393,8 +5399,8 @@ packages:
|
|||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/terser-webpack-plugin@5.3.9(webpack@5.89.0):
|
/terser-webpack-plugin@5.3.10(webpack@5.89.0):
|
||||||
resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==}
|
resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==}
|
||||||
engines: {node: '>= 10.13.0'}
|
engines: {node: '>= 10.13.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@swc/core': '*'
|
'@swc/core': '*'
|
||||||
@ -5409,11 +5415,11 @@ packages:
|
|||||||
uglify-js:
|
uglify-js:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/trace-mapping': 0.3.20
|
'@jridgewell/trace-mapping': 0.3.21
|
||||||
jest-worker: 27.5.1
|
jest-worker: 27.5.1
|
||||||
schema-utils: 3.3.0
|
schema-utils: 3.3.0
|
||||||
serialize-javascript: 6.0.1
|
serialize-javascript: 6.0.2
|
||||||
terser: 5.24.0
|
terser: 5.26.0
|
||||||
webpack: 5.89.0
|
webpack: 5.89.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
@ -5428,13 +5434,13 @@ packages:
|
|||||||
source-map-support: 0.5.21
|
source-map-support: 0.5.21
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/terser@5.24.0:
|
/terser@5.26.0:
|
||||||
resolution: {integrity: sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==}
|
resolution: {integrity: sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/source-map': 0.3.5
|
'@jridgewell/source-map': 0.3.5
|
||||||
acorn: 8.11.2
|
acorn: 8.11.3
|
||||||
commander: 2.20.3
|
commander: 2.20.3
|
||||||
source-map-support: 0.5.21
|
source-map-support: 0.5.21
|
||||||
dev: true
|
dev: true
|
||||||
@ -5619,6 +5625,17 @@ packages:
|
|||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/update-browserslist-db@1.0.13(browserslist@4.22.2):
|
||||||
|
resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
browserslist: '>= 4.21.0'
|
||||||
|
dependencies:
|
||||||
|
browserslist: 4.22.2
|
||||||
|
escalade: 3.1.1
|
||||||
|
picocolors: 1.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/uri-js@4.4.1:
|
/uri-js@4.4.1:
|
||||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -5817,9 +5834,9 @@ packages:
|
|||||||
'@webassemblyjs/ast': 1.11.6
|
'@webassemblyjs/ast': 1.11.6
|
||||||
'@webassemblyjs/wasm-edit': 1.11.6
|
'@webassemblyjs/wasm-edit': 1.11.6
|
||||||
'@webassemblyjs/wasm-parser': 1.11.6
|
'@webassemblyjs/wasm-parser': 1.11.6
|
||||||
acorn: 8.11.2
|
acorn: 8.11.3
|
||||||
acorn-import-assertions: 1.9.0(acorn@8.11.2)
|
acorn-import-assertions: 1.9.0(acorn@8.11.3)
|
||||||
browserslist: 4.22.1
|
browserslist: 4.22.2
|
||||||
chrome-trace-event: 1.0.3
|
chrome-trace-event: 1.0.3
|
||||||
enhanced-resolve: 5.15.0
|
enhanced-resolve: 5.15.0
|
||||||
es-module-lexer: 1.4.1
|
es-module-lexer: 1.4.1
|
||||||
@ -5833,7 +5850,7 @@ packages:
|
|||||||
neo-async: 2.6.2
|
neo-async: 2.6.2
|
||||||
schema-utils: 3.3.0
|
schema-utils: 3.3.0
|
||||||
tapable: 2.2.1
|
tapable: 2.2.1
|
||||||
terser-webpack-plugin: 5.3.9(webpack@5.89.0)
|
terser-webpack-plugin: 5.3.10(webpack@5.89.0)
|
||||||
watchpack: 2.4.0
|
watchpack: 2.4.0
|
||||||
webpack-sources: 3.2.3
|
webpack-sources: 3.2.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
setAppName,
|
setAppName,
|
||||||
setBlobEndpoint,
|
setBlobEndpoint,
|
||||||
setDocsUrl,
|
setDocsUrl,
|
||||||
} from "@/utils/env.ts";
|
} from "@/conf/env.ts";
|
||||||
|
|
||||||
export type SiteInfo = {
|
export type SiteInfo = {
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { tokenField, ws_api } from "@/conf.ts";
|
import { tokenField, websocketEndpoint } from "@/conf";
|
||||||
import { getMemory } from "@/utils/memory.ts";
|
import { getMemory } from "@/utils/memory.ts";
|
||||||
|
|
||||||
export const endpoint = `${ws_api}/chat`;
|
export const endpoint = `${websocketEndpoint}/chat`;
|
||||||
|
|
||||||
export type StreamMessage = {
|
export type StreamMessage = {
|
||||||
conversation?: number;
|
conversation?: number;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { blobEndpoint } from "@/utils/env.ts";
|
import { blobEndpoint } from "@/conf/env.ts";
|
||||||
|
|
||||||
export type BlobParserResponse = {
|
export type BlobParserResponse = {
|
||||||
status: boolean;
|
status: boolean;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { tokenField, ws_api } from "@/conf.ts";
|
import { tokenField, websocketEndpoint } from "@/conf";
|
||||||
import { getMemory } from "@/utils/memory.ts";
|
import { getMemory } from "@/utils/memory.ts";
|
||||||
|
|
||||||
export const endpoint = `${ws_api}/generation/create`;
|
export const endpoint = `${websocketEndpoint}/generation/create`;
|
||||||
|
|
||||||
export type GenerationForm = {
|
export type GenerationForm = {
|
||||||
token: string;
|
token: string;
|
||||||
|
@ -42,7 +42,7 @@ export type ConversationMapper = Record<Id, Conversation>;
|
|||||||
export type PlanItem = {
|
export type PlanItem = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
value: number;
|
||||||
icon: string;
|
icon: string;
|
||||||
models: string[];
|
models: string[];
|
||||||
};
|
};
|
||||||
@ -53,6 +53,8 @@ export type Plan = {
|
|||||||
items: PlanItem[];
|
items: PlanItem[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Plans = Plan[];
|
||||||
|
|
||||||
export type SubscriptionUsage = Record<
|
export type SubscriptionUsage = Record<
|
||||||
string,
|
string,
|
||||||
{
|
{
|
||||||
|
@ -110,6 +110,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.model-name {
|
.model-name {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
color: hsl(var(--text));
|
color: hsl(var(--text));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,13 +203,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.market-tip {
|
||||||
|
transform: translateY(1px);
|
||||||
|
}
|
||||||
|
|
||||||
.model-name {
|
.model-name {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
&.pro {
|
&.pro {
|
||||||
|
p {
|
||||||
// gold color gradient
|
// gold color gradient
|
||||||
background: linear-gradient(to right, hsl(45, 100%, 70%) 0%, hsl(46, 100%, 58%) 50%, hsl(46, 100%, 50%) 100%);
|
background: linear-gradient(to right, hsl(45, 100%, 70%) 0%, hsl(46, 100%, 58%) 50%, hsl(46, 100%, 50%) 100%);
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
color: rgb(164, 128, 0) !important;
|
||||||
|
background: rgb(255, 231, 145) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.model-tag {
|
.model-tag {
|
||||||
|
@ -83,14 +83,6 @@
|
|||||||
border-color: hsl(var(--text-secondary));
|
border-color: hsl(var(--text-secondary));
|
||||||
}
|
}
|
||||||
|
|
||||||
&.enterprise {
|
|
||||||
border-color: hsl(var(--accent));
|
|
||||||
|
|
||||||
.desc {
|
|
||||||
margin-top: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@ -157,6 +149,12 @@
|
|||||||
gap: 6px;
|
gap: 6px;
|
||||||
margin: 24px 0;
|
margin: 24px 0;
|
||||||
|
|
||||||
|
.api-tip {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
div {
|
div {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { deeptrainApiEndpoint, useDeeptrain } from "@/utils/env.ts";
|
import { deeptrainApiEndpoint, useDeeptrain } from "@/conf/env.ts";
|
||||||
import { ImgHTMLAttributes, useMemo } from "react";
|
import { ImgHTMLAttributes, useMemo } from "react";
|
||||||
import { cn } from "@/components/ui/lib/utils.ts";
|
import { cn } from "@/components/ui/lib/utils.ts";
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { AlertCircle, Download } from "lucide-react";
|
import { AlertCircle, Download } from "lucide-react";
|
||||||
import { withTranslation, WithTranslation } from "react-i18next";
|
import { withTranslation, WithTranslation } from "react-i18next";
|
||||||
import { version } from "@/conf.ts";
|
import { version } from "@/conf";
|
||||||
import { getMemoryPerformance } from "@/utils/app.ts";
|
import { getMemoryPerformance } from "@/utils/app.ts";
|
||||||
import { Button } from "@/components/ui/button.tsx";
|
import { Button } from "@/components/ui/button.tsx";
|
||||||
import { saveAsFile } from "@/utils/dom.ts";
|
import { saveAsFile } from "@/utils/dom.ts";
|
||||||
|
@ -24,7 +24,7 @@ import { useDraggableInput } from "@/utils/dom.ts";
|
|||||||
import { FileObject, FileArray, blobParser } from "@/api/file.ts";
|
import { FileObject, FileArray, blobParser } from "@/api/file.ts";
|
||||||
import { Button } from "@/components/ui/button.tsx";
|
import { Button } from "@/components/ui/button.tsx";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { isHighContextModel } from "@/conf.ts";
|
import { isHighContextModel } from "@/conf/model.ts";
|
||||||
import { selectModel } from "@/store/chat.ts";
|
import { selectModel } from "@/store/chat.ts";
|
||||||
import { ChatAction } from "@/components/home/assemblies/ChatAction.tsx";
|
import { ChatAction } from "@/components/home/assemblies/ChatAction.tsx";
|
||||||
import { cn } from "@/components/ui/lib/utils.ts";
|
import { cn } from "@/components/ui/lib/utils.ts";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { version } from "@/conf.ts";
|
import { version } from "@/conf";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useToast } from "./ui/use-toast.ts";
|
import { useToast } from "./ui/use-toast.ts";
|
||||||
import { getMemory, setMemory } from "@/utils/memory.ts";
|
import { getMemory, setMemory } from "@/utils/memory.ts";
|
||||||
|
@ -5,21 +5,25 @@ import {
|
|||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip.tsx";
|
} from "@/components/ui/tooltip.tsx";
|
||||||
import { HelpCircle } from "lucide-react";
|
import { HelpCircle } from "lucide-react";
|
||||||
|
import React from "react";
|
||||||
|
import { cn } from "@/components/ui/lib/utils.ts";
|
||||||
|
|
||||||
type TipsProps = {
|
type TipsProps = {
|
||||||
content: string;
|
content?: string;
|
||||||
|
children?: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function Tips({ content, className }: TipsProps) {
|
function Tips({ content, children, className }: TipsProps) {
|
||||||
return (
|
return (
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<HelpCircle className={`tips-icon ${className}`} />
|
<HelpCircle className={cn("tips-icon", className)} />
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>{content}</p>
|
{content && <p>{content}</p>}
|
||||||
|
{children}
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
|
@ -55,7 +55,7 @@ import { useToast } from "@/components/ui/use-toast";
|
|||||||
import { deleteCharge, listCharge, setCharge } from "@/admin/api/charge.ts";
|
import { deleteCharge, listCharge, setCharge } from "@/admin/api/charge.ts";
|
||||||
import { useEffectAsync } from "@/utils/hook.ts";
|
import { useEffectAsync } from "@/utils/hook.ts";
|
||||||
import { cn } from "@/components/ui/lib/utils.ts";
|
import { cn } from "@/components/ui/lib/utils.ts";
|
||||||
import { allModels } from "@/conf.ts";
|
import { allModels } from "@/conf";
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert.tsx";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert.tsx";
|
||||||
import Tips from "@/components/Tips.tsx";
|
import Tips from "@/components/Tips.tsx";
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { ThemeProvider } from "@/components/ThemeProvider.tsx";
|
|||||||
import DialogManager from "@/dialogs";
|
import DialogManager from "@/dialogs";
|
||||||
import Broadcast from "@/components/Broadcast.tsx";
|
import Broadcast from "@/components/Broadcast.tsx";
|
||||||
import { useEffectAsync } from "@/utils/hook.ts";
|
import { useEffectAsync } from "@/utils/hook.ts";
|
||||||
import { allModels, supportModels } from "@/conf.ts";
|
import { allModels, supportModels } from "@/conf";
|
||||||
import { channelModels } from "@/admin/channel.ts";
|
import { channelModels } from "@/admin/channel.ts";
|
||||||
import { getApiCharge, getApiMarket, getApiModels } from "@/api/v1.ts";
|
import { getApiCharge, getApiMarket, getApiModels } from "@/api/v1.ts";
|
||||||
import { loadPreferenceModels } from "@/utils/storage.ts";
|
import { loadPreferenceModels } from "@/utils/storage.ts";
|
||||||
|
@ -27,7 +27,7 @@ import { openDialog as openInvitationDialog } from "@/store/invitation.ts";
|
|||||||
import { openDialog as openSharingDialog } from "@/store/sharing.ts";
|
import { openDialog as openSharingDialog } from "@/store/sharing.ts";
|
||||||
import { openDialog as openApiDialog } from "@/store/api.ts";
|
import { openDialog as openApiDialog } from "@/store/api.ts";
|
||||||
import router from "@/router.tsx";
|
import router from "@/router.tsx";
|
||||||
import { useDeeptrain } from "@/utils/env.ts";
|
import { useDeeptrain } from "@/conf/env.ts";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
type MenuBarProps = {
|
type MenuBarProps = {
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
import { Button } from "@/components/ui/button.tsx";
|
import { Button } from "@/components/ui/button.tsx";
|
||||||
import { Menu } from "lucide-react";
|
import { Menu } from "lucide-react";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { tokenField } from "@/conf.ts";
|
import { tokenField } from "@/conf";
|
||||||
import { toggleMenu } from "@/store/menu.ts";
|
import { toggleMenu } from "@/store/menu.ts";
|
||||||
import ProjectLink from "@/components/ProjectLink.tsx";
|
import ProjectLink from "@/components/ProjectLink.tsx";
|
||||||
import ModeToggle from "@/components/ThemeProvider.tsx";
|
import ModeToggle from "@/components/ThemeProvider.tsx";
|
||||||
@ -18,7 +18,7 @@ import MenuBar from "./MenuBar.tsx";
|
|||||||
import { getMemory } from "@/utils/memory.ts";
|
import { getMemory } from "@/utils/memory.ts";
|
||||||
import { goAuth } from "@/utils/app.ts";
|
import { goAuth } from "@/utils/app.ts";
|
||||||
import Avatar from "@/components/Avatar.tsx";
|
import Avatar from "@/components/Avatar.tsx";
|
||||||
import { appLogo } from "@/utils/env.ts";
|
import { appLogo } from "@/conf/env.ts";
|
||||||
|
|
||||||
function NavMenu() {
|
function NavMenu() {
|
||||||
const username = useSelector(selectUsername);
|
const username = useSelector(selectUsername);
|
||||||
|
@ -20,7 +20,7 @@ import {
|
|||||||
} from "@/components/ui/dialog.tsx";
|
} from "@/components/ui/dialog.tsx";
|
||||||
import { getLanguage } from "@/i18n.ts";
|
import { getLanguage } from "@/i18n.ts";
|
||||||
import { selectAuthenticated } from "@/store/auth.ts";
|
import { selectAuthenticated } from "@/store/auth.ts";
|
||||||
import { docsEndpoint, useDeeptrain } from "@/utils/env.ts";
|
import { docsEndpoint, useDeeptrain } from "@/conf/env.ts";
|
||||||
|
|
||||||
function ChatSpace() {
|
function ChatSpace() {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import SelectGroup, { SelectItemProps } from "@/components/SelectGroup.tsx";
|
import SelectGroup, { SelectItemProps } from "@/components/SelectGroup.tsx";
|
||||||
import { supportModels } from "@/conf.ts";
|
import { supportModels } from "@/conf";
|
||||||
import {
|
import {
|
||||||
getPlanModels,
|
|
||||||
openMarket,
|
openMarket,
|
||||||
selectModel,
|
selectModel,
|
||||||
selectModelList,
|
selectModelList,
|
||||||
@ -19,6 +18,7 @@ import { ToastAction } from "@/components/ui/toast.tsx";
|
|||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { Sparkles } from "lucide-react";
|
import { Sparkles } from "lucide-react";
|
||||||
import { goAuth } from "@/utils/app.ts";
|
import { goAuth } from "@/utils/app.ts";
|
||||||
|
import { includingModelFromPlan } from "@/conf/subscription.tsx";
|
||||||
|
|
||||||
function GetModel(name: string): Model {
|
function GetModel(name: string): Model {
|
||||||
return supportModels.find((model) => model.id === name) as Model;
|
return supportModels.find((model) => model.id === name) as Model;
|
||||||
@ -29,7 +29,7 @@ type ModelSelectorProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function filterModel(model: Model, level: number) {
|
function filterModel(model: Model, level: number) {
|
||||||
if (getPlanModels(level).includes(model.id)) {
|
if (includingModelFromPlan(level, model.id)) {
|
||||||
return {
|
return {
|
||||||
name: model.id,
|
name: model.id,
|
||||||
value: model.name,
|
value: model.name,
|
||||||
|
@ -11,14 +11,13 @@ import {
|
|||||||
X,
|
X,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import { supportModels } from "@/conf.ts";
|
import { supportModels } from "@/conf";
|
||||||
import { isUrl, splitList } from "@/utils/base.ts";
|
import { isUrl, splitList } from "@/utils/base.ts";
|
||||||
import { Model } from "@/api/types.ts";
|
import { Model } from "@/api/types.ts";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import {
|
import {
|
||||||
addModelList,
|
addModelList,
|
||||||
closeMarket,
|
closeMarket,
|
||||||
getPlanModels,
|
|
||||||
removeModelList,
|
removeModelList,
|
||||||
selectModel,
|
selectModel,
|
||||||
selectModelList,
|
selectModelList,
|
||||||
@ -30,7 +29,7 @@ import { teenagerSelector } from "@/store/package.ts";
|
|||||||
import { ToastAction } from "@/components/ui/toast.tsx";
|
import { ToastAction } from "@/components/ui/toast.tsx";
|
||||||
import { selectAuthenticated } from "@/store/auth.ts";
|
import { selectAuthenticated } from "@/store/auth.ts";
|
||||||
import { useToast } from "@/components/ui/use-toast.ts";
|
import { useToast } from "@/components/ui/use-toast.ts";
|
||||||
import { docsEndpoint } from "@/utils/env.ts";
|
import { docsEndpoint } from "@/conf/env.ts";
|
||||||
import { goAuth } from "@/utils/app.ts";
|
import { goAuth } from "@/utils/app.ts";
|
||||||
import {
|
import {
|
||||||
DragDropContext,
|
DragDropContext,
|
||||||
@ -40,6 +39,16 @@ import {
|
|||||||
} from "react-beautiful-dnd";
|
} from "react-beautiful-dnd";
|
||||||
import { savePreferenceModels } from "@/utils/storage.ts";
|
import { savePreferenceModels } from "@/utils/storage.ts";
|
||||||
import { cn } from "@/components/ui/lib/utils.ts";
|
import { cn } from "@/components/ui/lib/utils.ts";
|
||||||
|
import { Badge } from "@/components/ui/badge.tsx";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip.tsx";
|
||||||
|
import { useMobile } from "@/utils/device.ts";
|
||||||
|
import Tips from "@/components/Tips.tsx";
|
||||||
|
import { includingModelFromPlan } from "@/conf/subscription.tsx";
|
||||||
|
|
||||||
type SearchBarProps = {
|
type SearchBarProps = {
|
||||||
value: string;
|
value: string;
|
||||||
@ -100,6 +109,8 @@ function ModelItem({
|
|||||||
const list = useSelector(selectModelList);
|
const list = useSelector(selectModelList);
|
||||||
const current = useSelector(selectModel);
|
const current = useSelector(selectModel);
|
||||||
|
|
||||||
|
const mobile = useMobile();
|
||||||
|
|
||||||
const level = useSelector(levelSelector);
|
const level = useSelector(levelSelector);
|
||||||
const student = useSelector(teenagerSelector);
|
const student = useSelector(teenagerSelector);
|
||||||
const auth = useSelector(selectAuthenticated);
|
const auth = useSelector(selectAuthenticated);
|
||||||
@ -111,7 +122,7 @@ function ModelItem({
|
|||||||
}, [model, current, list]);
|
}, [model, current, list]);
|
||||||
|
|
||||||
const pro = useMemo(() => {
|
const pro = useMemo(() => {
|
||||||
return getPlanModels(level).includes(model.id);
|
return includingModelFromPlan(level, model.id);
|
||||||
}, [model, level, student]);
|
}, [model, level, student]);
|
||||||
|
|
||||||
const avatar = useMemo(() => {
|
const avatar = useMemo(() => {
|
||||||
@ -148,7 +159,32 @@ function ModelItem({
|
|||||||
<GripVertical className={`grip-icon h-4 w-4 translate-x-[-1rem]`} />
|
<GripVertical className={`grip-icon h-4 w-4 translate-x-[-1rem]`} />
|
||||||
<img className={`model-avatar`} src={avatar} alt={model.name} />
|
<img className={`model-avatar`} src={avatar} alt={model.name} />
|
||||||
<div className={`model-info`}>
|
<div className={`model-info`}>
|
||||||
<p className={cn("model-name", pro && "pro")}>{model.name}</p>
|
<div className={cn("model-name", pro && "pro")}>
|
||||||
|
<p>{model.name}</p>
|
||||||
|
{mobile ? (
|
||||||
|
<Tips className={`market-tip`}>
|
||||||
|
<div className={`flex flex-col items-center justify-center`}>
|
||||||
|
<p>{t("market.model-api")}</p>
|
||||||
|
<Badge className={`badge whitespace-nowrap mt-2`}>
|
||||||
|
{model.id}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</Tips>
|
||||||
|
) : (
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger>
|
||||||
|
<Badge
|
||||||
|
className={`badge whitespace-nowrap inline-block ml-2`}
|
||||||
|
>
|
||||||
|
{model.id}
|
||||||
|
</Badge>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>{t("market.model-api")}</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
{model.description && (
|
{model.description && (
|
||||||
<p className={`model-description`}>{model.description}</p>
|
<p className={`model-description`}>{model.description}</p>
|
||||||
)}
|
)}
|
||||||
|
@ -23,37 +23,38 @@ import { DialogClose } from "@radix-ui/react-dialog";
|
|||||||
import { Button } from "@/components/ui/button.tsx";
|
import { Button } from "@/components/ui/button.tsx";
|
||||||
import { expiredSelector, refreshSubscription } from "@/store/subscription.ts";
|
import { expiredSelector, refreshSubscription } from "@/store/subscription.ts";
|
||||||
import { Plus } from "lucide-react";
|
import { Plus } from "lucide-react";
|
||||||
import { subscriptionPrize } from "@/conf.ts";
|
|
||||||
import { ToastAction } from "@/components/ui/toast.tsx";
|
import { ToastAction } from "@/components/ui/toast.tsx";
|
||||||
import { deeptrainEndpoint, useDeeptrain } from "@/utils/env.ts";
|
import { deeptrainEndpoint, useDeeptrain } from "@/conf/env.ts";
|
||||||
import { AppDispatch } from "@/store";
|
import { AppDispatch } from "@/store";
|
||||||
import { openDialog } from "@/store/quota.ts";
|
import { openDialog } from "@/store/quota.ts";
|
||||||
|
import { getPlanPrice } from "@/conf/subscription.tsx";
|
||||||
|
|
||||||
function countPrize(base: number, month: number): number {
|
function countPrice(base: number, month: number): number {
|
||||||
const prize = subscriptionPrize[base] * month;
|
const price = getPlanPrice(base) * month;
|
||||||
if (month >= 36) {
|
if (month >= 36) {
|
||||||
return prize * 0.7;
|
return price * 0.7;
|
||||||
} else if (month >= 12) {
|
} else if (month >= 12) {
|
||||||
return prize * 0.8;
|
return price * 0.8;
|
||||||
} else if (month >= 6) {
|
} else if (month >= 6) {
|
||||||
return prize * 0.9;
|
return price * 0.9;
|
||||||
}
|
}
|
||||||
|
|
||||||
return prize;
|
return price;
|
||||||
}
|
}
|
||||||
|
|
||||||
function countUpgradePrize(
|
function countUpgradePrice(
|
||||||
level: number,
|
level: number,
|
||||||
target: number,
|
target: number,
|
||||||
days: number,
|
days: number,
|
||||||
): number {
|
): number {
|
||||||
const bias = subscriptionPrize[target] - subscriptionPrize[level];
|
const bias = getPlanPrice(target) - getPlanPrice(level);
|
||||||
return (bias / 30) * days;
|
const v = (bias / 30) * days;
|
||||||
|
return v > 0 ? v + 1 : 0; // time count offset
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpgradeProps = {
|
type UpgradeProps = {
|
||||||
base: number;
|
|
||||||
level: number;
|
level: number;
|
||||||
|
current: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function callBuyAction(
|
async function callBuyAction(
|
||||||
@ -118,7 +119,7 @@ async function callMigrateAction(
|
|||||||
return res.status;
|
return res.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Upgrade({ base, level }: UpgradeProps) {
|
export function Upgrade({ level, current }: UpgradeProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const expired = useSelector(expiredSelector);
|
const expired = useSelector(expiredSelector);
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
@ -126,10 +127,10 @@ export function Upgrade({ base, level }: UpgradeProps) {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
const isCurrent = useMemo(() => level === base, [level, base]);
|
const isCurrent = useMemo(() => current === level, [current, level]);
|
||||||
const isUpgrade = useMemo(() => level < base, [level, base]);
|
const isUpgrade = useMemo(() => current < level, [current, level]);
|
||||||
|
|
||||||
return level === 0 || level === base ? (
|
return current === 0 || current === level ? (
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button className={`action`} variant={`default`}>
|
<Button className={`action`} variant={`default`}>
|
||||||
@ -169,13 +170,13 @@ export function Upgrade({ base, level }: UpgradeProps) {
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<p className={`price`}>
|
<p className={`price`}>
|
||||||
{t("sub.price", { price: countPrize(base, month).toFixed(2) })}
|
{t("sub.price", { price: countPrice(level, month).toFixed(2) })}
|
||||||
|
|
||||||
{useDeeptrain && (
|
{useDeeptrain && (
|
||||||
<span className={`tax`}>
|
<span className={`tax`}>
|
||||||
(
|
(
|
||||||
{t("sub.price-tax", {
|
{t("sub.price-tax", {
|
||||||
price: (countPrize(base, month) * 0.25).toFixed(1),
|
price: (countPrice(level, month) * 0.25).toFixed(1),
|
||||||
})}
|
})}
|
||||||
)
|
)
|
||||||
</span>
|
</span>
|
||||||
@ -189,7 +190,7 @@ export function Upgrade({ base, level }: UpgradeProps) {
|
|||||||
<Button
|
<Button
|
||||||
className={`mb-1.5`}
|
className={`mb-1.5`}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const res = await callBuyAction(t, toast, dispatch, month, base);
|
const res = await callBuyAction(t, toast, dispatch, month, level);
|
||||||
if (res) {
|
if (res) {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
await refreshSubscription(dispatch);
|
await refreshSubscription(dispatch);
|
||||||
@ -222,7 +223,7 @@ export function Upgrade({ base, level }: UpgradeProps) {
|
|||||||
{isUpgrade && (
|
{isUpgrade && (
|
||||||
<p className={`price`}>
|
<p className={`price`}>
|
||||||
{t("sub.upgrade-price", {
|
{t("sub.upgrade-price", {
|
||||||
price: countUpgradePrize(level, base, expired).toFixed(2),
|
price: countUpgradePrice(current, level, expired).toFixed(2),
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@ -234,7 +235,7 @@ export function Upgrade({ base, level }: UpgradeProps) {
|
|||||||
<Button
|
<Button
|
||||||
className={`mb-1.5`}
|
className={`mb-1.5`}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const res = await callMigrateAction(t, toast, base);
|
const res = await callMigrateAction(t, toast, level);
|
||||||
if (res) {
|
if (res) {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
await refreshSubscription(dispatch);
|
await refreshSubscription(dispatch);
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
import { SubscriptionIcon } from "@/conf/subscription.tsx";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Icon from "@/components/utils/Icon.tsx";
|
import Icon from "@/components/utils/Icon.tsx";
|
||||||
|
|
||||||
type UsageProps = {
|
type UsageProps = {
|
||||||
icon: React.ReactElement;
|
icon: string | React.ReactElement;
|
||||||
name: string;
|
name: string;
|
||||||
usage:
|
usage:
|
||||||
| {
|
| {
|
||||||
@ -17,7 +18,11 @@ function SubscriptionUsage({ icon, name, usage }: UsageProps) {
|
|||||||
return (
|
return (
|
||||||
usage && (
|
usage && (
|
||||||
<div className={`sub-column`}>
|
<div className={`sub-column`}>
|
||||||
|
{typeof icon === "string" ? (
|
||||||
|
<SubscriptionIcon type={icon} className={`h-4 w-4 mr-1`} />
|
||||||
|
) : (
|
||||||
<Icon icon={icon} className={`h-4 w-4 mr-1`} />
|
<Icon icon={icon} className={`h-4 w-4 mr-1`} />
|
||||||
|
)}
|
||||||
{name}
|
{name}
|
||||||
<div className={`grow`} />
|
<div className={`grow`} />
|
||||||
{typeof usage === "number" ? (
|
{typeof usage === "number" ? (
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
import axios from "axios";
|
|
||||||
import { Model, PlanModel, SubscriptionUsage } from "@/api/types.ts";
|
|
||||||
import {
|
|
||||||
deeptrainAppName,
|
|
||||||
deeptrainEndpoint,
|
|
||||||
getDev,
|
|
||||||
getRestApi,
|
|
||||||
getTokenField,
|
|
||||||
getWebsocketApi,
|
|
||||||
} from "@/utils/env.ts";
|
|
||||||
import { getMemory } from "@/utils/memory.ts";
|
|
||||||
import { Compass, Image, Newspaper } from "lucide-react";
|
|
||||||
import React from "react";
|
|
||||||
import { syncSiteInfo } from "@/admin/api/info.ts";
|
|
||||||
import { getOfflineModels, loadPreferenceModels } from "@/utils/storage.ts";
|
|
||||||
|
|
||||||
export const version = "3.8.6";
|
|
||||||
export const dev: boolean = getDev();
|
|
||||||
export const deploy: boolean = true;
|
|
||||||
export let rest_api: string = getRestApi(deploy);
|
|
||||||
export let ws_api: string = getWebsocketApi(deploy);
|
|
||||||
export const tokenField = getTokenField(deploy);
|
|
||||||
|
|
||||||
export let supportModels: Model[] = loadPreferenceModels(getOfflineModels());
|
|
||||||
|
|
||||||
export let allModels: string[] = supportModels.map((model) => model.id);
|
|
||||||
|
|
||||||
export const planModels: PlanModel[] = [
|
|
||||||
{ id: "gpt-4-0613", level: 1 },
|
|
||||||
{ id: "gpt-4-1106-preview", level: 1 },
|
|
||||||
{ id: "gpt-4-vision-preview", level: 1 },
|
|
||||||
{ id: "gpt-4-v", level: 1 },
|
|
||||||
{ id: "gpt-4-all", level: 1 },
|
|
||||||
{ id: "gpt-4-dalle", level: 1 },
|
|
||||||
{ id: "claude-2", level: 1 },
|
|
||||||
{ id: "claude-2.1", level: 1 },
|
|
||||||
{ id: "claude-2-100k", level: 1 },
|
|
||||||
{ id: "midjourney-fast", level: 1 },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const subscriptionPrize: Record<number, number> = {
|
|
||||||
1: 42,
|
|
||||||
2: 76,
|
|
||||||
3: 148,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const subscriptionUsage: SubscriptionUsage = {
|
|
||||||
midjourney: { name: "Midjourney", icon: React.createElement(Image) },
|
|
||||||
"gpt-4": { name: "GPT-4", icon: React.createElement(Compass) },
|
|
||||||
"claude-100k": { name: "Claude 100k", icon: React.createElement(Newspaper) },
|
|
||||||
};
|
|
||||||
|
|
||||||
export function getModelFromId(id: string): Model | undefined {
|
|
||||||
return supportModels.find((model) => model.id === id);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isHighContextModel(id: string): boolean {
|
|
||||||
const model = getModelFromId(id);
|
|
||||||
return !!model && model.high_context;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function login() {
|
|
||||||
location.href = `${deeptrainEndpoint}/login?app=${
|
|
||||||
dev ? "dev" : deeptrainAppName
|
|
||||||
}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
axios.defaults.baseURL = rest_api;
|
|
||||||
axios.defaults.headers.post["Content-Type"] = "application/json";
|
|
||||||
axios.defaults.headers.common["Authorization"] = getMemory(tokenField);
|
|
||||||
|
|
||||||
syncSiteInfo();
|
|
13
app/src/conf/api.ts
Normal file
13
app/src/conf/api.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import { getMemory } from "@/utils/memory.ts";
|
||||||
|
|
||||||
|
type AxiosConfig = {
|
||||||
|
endpoint: string;
|
||||||
|
token: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function setAxiosConfig(config: AxiosConfig) {
|
||||||
|
axios.defaults.baseURL = config.endpoint;
|
||||||
|
axios.defaults.headers.post["Content-Type"] = "application/json";
|
||||||
|
axios.defaults.headers.common["Authorization"] = getMemory(config.token);
|
||||||
|
}
|
8
app/src/conf/deeptrain.ts
Normal file
8
app/src/conf/deeptrain.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { deeptrainAppName, deeptrainEndpoint } from "@/conf/env.ts";
|
||||||
|
import { dev } from "@/conf/index.ts";
|
||||||
|
|
||||||
|
export function goDeepLogin() {
|
||||||
|
location.href = `${deeptrainEndpoint}/login?app=${
|
||||||
|
dev ? "dev" : deeptrainAppName
|
||||||
|
}`;
|
||||||
|
}
|
125
app/src/conf/index.ts
Normal file
125
app/src/conf/index.ts
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
import { Model, PlanModel, Plans } from "@/api/types.ts";
|
||||||
|
import {
|
||||||
|
getDev,
|
||||||
|
getRestApi,
|
||||||
|
getTokenField,
|
||||||
|
getWebsocketApi,
|
||||||
|
} from "@/conf/env.ts";
|
||||||
|
import { syncSiteInfo } from "@/admin/api/info.ts";
|
||||||
|
import { getOfflineModels, loadPreferenceModels } from "@/utils/storage.ts";
|
||||||
|
import { setAxiosConfig } from "@/conf/api.ts";
|
||||||
|
|
||||||
|
export const version = "3.8.6"; // version of the current build
|
||||||
|
export const dev: boolean = getDev(); // is in development mode (for debugging, in localhost origin)
|
||||||
|
export const deploy: boolean = true; // is production environment (for api endpoint)
|
||||||
|
|
||||||
|
export let apiEndpoint: string = getRestApi(deploy); // api endpoint for rest api calls
|
||||||
|
export let websocketEndpoint: string = getWebsocketApi(deploy); // api endpoint for websocket calls
|
||||||
|
export const tokenField = getTokenField(deploy); // token field name for storing token
|
||||||
|
|
||||||
|
export let supportModels: Model[] = loadPreferenceModels(getOfflineModels()); // support models in model market of the current site
|
||||||
|
export let allModels: string[] = supportModels.map((model) => model.id); // all support model id list of the current site
|
||||||
|
|
||||||
|
const GPT4Array = [
|
||||||
|
"gpt-4",
|
||||||
|
"gpt-4-0314",
|
||||||
|
"gpt-4-0613",
|
||||||
|
"gpt-4-1106-preview",
|
||||||
|
"gpt-4-vision-preview",
|
||||||
|
"gpt-4-v",
|
||||||
|
"gpt-4-dalle",
|
||||||
|
"gpt-4-all",
|
||||||
|
];
|
||||||
|
const Claude100kArray = ["claude-1.3", "claude-2", "claude-2.1"];
|
||||||
|
const MidjourneyArray = ["midjourney-fast"];
|
||||||
|
|
||||||
|
export const subscriptionData: Plans = [
|
||||||
|
{
|
||||||
|
level: 1,
|
||||||
|
price: 42,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: "gpt-4",
|
||||||
|
icon: "compass",
|
||||||
|
name: "GPT-4",
|
||||||
|
value: 150,
|
||||||
|
models: GPT4Array,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "midjourney",
|
||||||
|
icon: "image-plus",
|
||||||
|
name: "Midjourney",
|
||||||
|
value: 50,
|
||||||
|
models: MidjourneyArray,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "claude-100k",
|
||||||
|
icon: "book-text",
|
||||||
|
name: "Claude 100k",
|
||||||
|
value: 300,
|
||||||
|
models: Claude100kArray,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
level: 2,
|
||||||
|
price: 76,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: "gpt-4",
|
||||||
|
icon: "compass",
|
||||||
|
name: "GPT-4",
|
||||||
|
value: 300,
|
||||||
|
models: GPT4Array,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "midjourney",
|
||||||
|
icon: "image-plus",
|
||||||
|
name: "Midjourney",
|
||||||
|
value: 100,
|
||||||
|
models: MidjourneyArray,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "claude-100k",
|
||||||
|
icon: "book-text",
|
||||||
|
name: "Claude 100k",
|
||||||
|
value: 600,
|
||||||
|
models: Claude100kArray,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
level: 3,
|
||||||
|
price: 148,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: "gpt-4",
|
||||||
|
icon: "compass",
|
||||||
|
name: "GPT-4",
|
||||||
|
value: 600,
|
||||||
|
models: GPT4Array,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "midjourney",
|
||||||
|
icon: "image-plus",
|
||||||
|
name: "Midjourney",
|
||||||
|
value: 200,
|
||||||
|
models: MidjourneyArray,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "claude-100k",
|
||||||
|
icon: "book-text",
|
||||||
|
name: "Claude 100k",
|
||||||
|
value: 1200,
|
||||||
|
models: Claude100kArray,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
setAxiosConfig({
|
||||||
|
endpoint: apiEndpoint,
|
||||||
|
token: tokenField,
|
||||||
|
});
|
||||||
|
|
||||||
|
syncSiteInfo();
|
11
app/src/conf/model.ts
Normal file
11
app/src/conf/model.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { Model } from "@/api/types.ts";
|
||||||
|
import { supportModels } from "@/conf/index.ts";
|
||||||
|
|
||||||
|
export function getModelFromId(id: string): Model | undefined {
|
||||||
|
return supportModels.find((model) => model.id === id);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isHighContextModel(id: string): boolean {
|
||||||
|
const model = getModelFromId(id);
|
||||||
|
return !!model && model.high_context;
|
||||||
|
}
|
61
app/src/conf/subscription.tsx
Normal file
61
app/src/conf/subscription.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import {
|
||||||
|
BookText,
|
||||||
|
Compass,
|
||||||
|
Image,
|
||||||
|
ImagePlus,
|
||||||
|
Video,
|
||||||
|
AudioLines,
|
||||||
|
} from "lucide-react";
|
||||||
|
import React, { useMemo } from "react";
|
||||||
|
import { subscriptionData } from "@/conf/index.ts";
|
||||||
|
import { Plan } from "@/api/types.ts";
|
||||||
|
import Icon from "@/components/utils/Icon.tsx";
|
||||||
|
|
||||||
|
export const subscriptionIcons: Record<string, React.ReactElement> = {
|
||||||
|
compass: <Compass />,
|
||||||
|
image: <Image />,
|
||||||
|
imageplus: <ImagePlus />,
|
||||||
|
booktext: <BookText />,
|
||||||
|
video: <Video />,
|
||||||
|
audio: <AudioLines />,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const subscriptionType: Record<number, string> = {
|
||||||
|
1: "basic",
|
||||||
|
2: "standard",
|
||||||
|
3: "pro",
|
||||||
|
};
|
||||||
|
|
||||||
|
type SubscriptionIconProps = {
|
||||||
|
type: string;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function SubscriptionIcon({ type, className }: SubscriptionIconProps) {
|
||||||
|
const icon = useMemo(() => {
|
||||||
|
return subscriptionIcons[type.toLowerCase()] || subscriptionIcons.compass;
|
||||||
|
}, [type]);
|
||||||
|
|
||||||
|
return <Icon icon={icon} className={className} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPlan(level: number): Plan {
|
||||||
|
const raw = subscriptionData.filter((item) => item.level === level);
|
||||||
|
return raw.length > 0 ? raw[0] : subscriptionData[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPlanModels(level: number): string[] {
|
||||||
|
return getPlan(level).items.flatMap((item) => item.models);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function includingModelFromPlan(level: number, model: string): boolean {
|
||||||
|
return getPlanModels(level).includes(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPlanPrice(level: number): number {
|
||||||
|
return getPlan(level).price;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPlanName(level: number): string {
|
||||||
|
return subscriptionType[level] || "none";
|
||||||
|
}
|
@ -24,7 +24,7 @@ import { useToast } from "@/components/ui/use-toast.ts";
|
|||||||
import { copyClipboard } from "@/utils/dom.ts";
|
import { copyClipboard } from "@/utils/dom.ts";
|
||||||
import { useEffectAsync } from "@/utils/hook.ts";
|
import { useEffectAsync } from "@/utils/hook.ts";
|
||||||
import { selectInit } from "@/store/auth.ts";
|
import { selectInit } from "@/store/auth.ts";
|
||||||
import { docsEndpoint } from "@/utils/env.ts";
|
import { docsEndpoint } from "@/conf/env.ts";
|
||||||
import {
|
import {
|
||||||
AlertDialog,
|
AlertDialog,
|
||||||
AlertDialogCancel,
|
AlertDialogCancel,
|
||||||
|
@ -23,7 +23,7 @@ import { Separator } from "@/components/ui/separator.tsx";
|
|||||||
import { Badge } from "@/components/ui/badge.tsx";
|
import { Badge } from "@/components/ui/badge.tsx";
|
||||||
import { useEffectAsync } from "@/utils/hook.ts";
|
import { useEffectAsync } from "@/utils/hook.ts";
|
||||||
import { selectAuthenticated } from "@/store/auth.ts";
|
import { selectAuthenticated } from "@/store/auth.ts";
|
||||||
import { deeptrainEndpoint, useDeeptrain } from "@/utils/env.ts";
|
import { deeptrainEndpoint, useDeeptrain } from "@/conf/env.ts";
|
||||||
|
|
||||||
function PackageDialog() {
|
function PackageDialog() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -39,7 +39,7 @@ import { useToast } from "@/components/ui/use-toast.ts";
|
|||||||
import { useEffectAsync } from "@/utils/hook.ts";
|
import { useEffectAsync } from "@/utils/hook.ts";
|
||||||
import { selectAuthenticated } from "@/store/auth.ts";
|
import { selectAuthenticated } from "@/store/auth.ts";
|
||||||
import { ToastAction } from "@/components/ui/toast.tsx";
|
import { ToastAction } from "@/components/ui/toast.tsx";
|
||||||
import { deeptrainEndpoint, docsEndpoint, useDeeptrain } from "@/utils/env.ts";
|
import { deeptrainEndpoint, docsEndpoint, useDeeptrain } from "@/conf/env.ts";
|
||||||
import { useRedeem } from "@/api/redeem.ts";
|
import { useRedeem } from "@/api/redeem.ts";
|
||||||
import { cn } from "@/components/ui/lib/utils.ts";
|
import { cn } from "@/components/ui/lib/utils.ts";
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ import {
|
|||||||
import { Checkbox } from "@/components/ui/checkbox.tsx";
|
import { Checkbox } from "@/components/ui/checkbox.tsx";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { getMemoryPerformance } from "@/utils/app.ts";
|
import { getMemoryPerformance } from "@/utils/app.ts";
|
||||||
import { version } from "@/conf.ts";
|
import { version } from "@/conf";
|
||||||
import { NumberInput } from "@/components/ui/number-input.tsx";
|
import { NumberInput } from "@/components/ui/number-input.tsx";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
|
@ -22,22 +22,68 @@ import {
|
|||||||
openDialog as openQuotaDialog,
|
openDialog as openQuotaDialog,
|
||||||
dialogSelector as quotaDialogSelector,
|
dialogSelector as quotaDialogSelector,
|
||||||
} from "@/store/quota.ts";
|
} from "@/store/quota.ts";
|
||||||
import {
|
import { Calendar } from "lucide-react";
|
||||||
Award,
|
|
||||||
BookText,
|
|
||||||
Calendar,
|
|
||||||
Compass,
|
|
||||||
ImagePlus,
|
|
||||||
LifeBuoy,
|
|
||||||
ServerCrash,
|
|
||||||
} from "lucide-react";
|
|
||||||
import { useEffectAsync } from "@/utils/hook.ts";
|
import { useEffectAsync } from "@/utils/hook.ts";
|
||||||
import { selectAuthenticated } from "@/store/auth.ts";
|
import { selectAuthenticated } from "@/store/auth.ts";
|
||||||
import SubscriptionUsage from "@/components/home/subscription/SubscriptionUsage.tsx";
|
import SubscriptionUsage from "@/components/home/subscription/SubscriptionUsage.tsx";
|
||||||
import Tips from "@/components/Tips.tsx";
|
import Tips from "@/components/Tips.tsx";
|
||||||
import { subscriptionPrize, subscriptionUsage } from "@/conf.ts";
|
|
||||||
import { Upgrade } from "@/components/home/subscription/BuyDialog.tsx";
|
import { Upgrade } from "@/components/home/subscription/BuyDialog.tsx";
|
||||||
import { useDeeptrain } from "@/utils/env.ts";
|
import { useDeeptrain } from "@/conf/env.ts";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import {
|
||||||
|
getPlan,
|
||||||
|
getPlanName,
|
||||||
|
SubscriptionIcon,
|
||||||
|
} from "@/conf/subscription.tsx";
|
||||||
|
import { cn } from "@/components/ui/lib/utils.ts";
|
||||||
|
import { subscriptionData } from "@/conf";
|
||||||
|
import { Badge } from "@/components/ui/badge.tsx";
|
||||||
|
|
||||||
|
type PlanItemProps = {
|
||||||
|
level: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
function PlanItem({ level }: PlanItemProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const current = useSelector(levelSelector);
|
||||||
|
const plan = useMemo(() => getPlan(level), [level]);
|
||||||
|
const name = useMemo(() => getPlanName(level), [level]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cn("plan", name)}>
|
||||||
|
<div className={`title`}>{t(`sub.${name}`)}</div>
|
||||||
|
<div className={`price-wrapper`}>
|
||||||
|
<div className={`price`}>
|
||||||
|
{t("sub.plan-price", { money: plan.price })}
|
||||||
|
</div>
|
||||||
|
{useDeeptrain && <p className={`annotate`}>({t("sub.include-tax")})</p>}
|
||||||
|
</div>
|
||||||
|
<div className={`desc`}>
|
||||||
|
{plan.items.map((item, index) => (
|
||||||
|
<div key={index}>
|
||||||
|
<SubscriptionIcon type={item.icon} className={`h-4 w-4 mr-1`} />
|
||||||
|
{t("sub.plan-usage", { name: item.name, times: item.value })}
|
||||||
|
<Tips>
|
||||||
|
<div className={`api-tip`}>
|
||||||
|
<p>{t("sub.plan-tip")}</p>
|
||||||
|
<div
|
||||||
|
className={`flex flex-row gap-2 mt-2 flex-wrap justify-center items-center max-w-[40vw]`}
|
||||||
|
>
|
||||||
|
{item.models.map((model, index) => (
|
||||||
|
<Badge key={index} className={`whitespace-nowrap`}>
|
||||||
|
{model}
|
||||||
|
</Badge>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tips>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<Upgrade level={level} current={current} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function SubscriptionDialog() {
|
function SubscriptionDialog() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -49,6 +95,8 @@ function SubscriptionDialog() {
|
|||||||
const auth = useSelector(selectAuthenticated);
|
const auth = useSelector(selectAuthenticated);
|
||||||
const quota = useSelector(quotaDialogSelector);
|
const quota = useSelector(quotaDialogSelector);
|
||||||
|
|
||||||
|
const plan = useMemo(() => getPlan(level), [level]);
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
useEffectAsync(async () => {
|
useEffectAsync(async () => {
|
||||||
if (!auth) return;
|
if (!auth) return;
|
||||||
@ -84,12 +132,13 @@ function SubscriptionDialog() {
|
|||||||
usage={expired}
|
usage={expired}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{Object.entries(subscriptionUsage).map(
|
{plan.items.map(
|
||||||
([key, props], index) =>
|
(item, index) =>
|
||||||
usage?.[key] && (
|
usage?.[item.id] && (
|
||||||
<SubscriptionUsage
|
<SubscriptionUsage
|
||||||
{...props}
|
name={item.name}
|
||||||
usage={usage?.[key]}
|
icon={item.icon}
|
||||||
|
usage={usage?.[item.id]}
|
||||||
key={index}
|
key={index}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
@ -97,110 +146,9 @@ function SubscriptionDialog() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={`plan-wrapper`}>
|
<div className={`plan-wrapper`}>
|
||||||
<div className={`plan basic`}>
|
{subscriptionData.map((item, index) => (
|
||||||
<div className={`title`}>{t("sub.base")}</div>
|
<PlanItem key={index} level={item.level} />
|
||||||
<div className={`price-wrapper`}>
|
))}
|
||||||
<div className={`price`}>
|
|
||||||
{t("sub.plan-price", { money: subscriptionPrize[1] })}
|
|
||||||
</div>
|
|
||||||
{useDeeptrain && (
|
|
||||||
<p className={`annotate`}>({t("sub.include-tax")})</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className={`desc`}>
|
|
||||||
<div>
|
|
||||||
<Compass className={`h-4 w-4 mr-1`} />
|
|
||||||
{t("sub.plan-gpt4", { times: 150 })}
|
|
||||||
<Tips content={t("sub.plan-gpt4-desc")} />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<ImagePlus className={`h-4 w-4 mr-1`} />
|
|
||||||
{t("sub.plan-midjourney", { times: 50 })}
|
|
||||||
<Tips content={t("sub.plan-midjourney-desc")} />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<BookText className={`h-4 w-4 mr-1`} />
|
|
||||||
{t("sub.plan-claude", { times: 300 })}
|
|
||||||
<Tips content={t("sub.plan-claude-desc")} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Upgrade base={1} level={level} />
|
|
||||||
</div>
|
|
||||||
<div className={`plan standard`}>
|
|
||||||
<div className={`title`}>{t("sub.standard")}</div>
|
|
||||||
<div className={`price-wrapper`}>
|
|
||||||
<div className={`price`}>
|
|
||||||
{t("sub.plan-price", { money: subscriptionPrize[2] })}
|
|
||||||
</div>
|
|
||||||
{useDeeptrain && (
|
|
||||||
<p className={`annotate`}>({t("sub.include-tax")})</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className={`desc`}>
|
|
||||||
<div>
|
|
||||||
<LifeBuoy className={`h-4 w-4 mr-1`} />
|
|
||||||
{t("sub.pro-service")}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Compass className={`h-4 w-4 mr-1`} />
|
|
||||||
{t("sub.plan-gpt4", { times: 300 })}
|
|
||||||
<Tips content={t("sub.plan-gpt4-desc")} />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<ImagePlus className={`h-4 w-4 mr-1`} />
|
|
||||||
{t("sub.plan-midjourney", { times: 100 })}
|
|
||||||
<Tips content={t("sub.plan-midjourney-desc")} />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<BookText className={`h-4 w-4 mr-1`} />
|
|
||||||
{t("sub.plan-claude", { times: 600 })}
|
|
||||||
<Tips content={t("sub.plan-claude-desc")} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Upgrade base={2} level={level} />
|
|
||||||
</div>
|
|
||||||
<div className={`plan pro`}>
|
|
||||||
<div className={`title`}>{t("sub.pro")}</div>
|
|
||||||
<div className={`price-wrapper`}>
|
|
||||||
<div className={`price`}>
|
|
||||||
{t("sub.plan-price", { money: subscriptionPrize[3] })}
|
|
||||||
</div>
|
|
||||||
{useDeeptrain && (
|
|
||||||
<p className={`annotate`}>({t("sub.include-tax")})</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className={`desc`}>
|
|
||||||
<div>
|
|
||||||
<ServerCrash className={`h-4 w-4 mr-1`} />
|
|
||||||
{t("sub.pro-thread")}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Compass className={`h-4 w-4 mr-1`} />
|
|
||||||
{t("sub.plan-gpt4", { times: 600 })}
|
|
||||||
<Tips content={t("sub.plan-gpt4-desc")} />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<ImagePlus className={`h-4 w-4 mr-1`} />
|
|
||||||
{t("sub.plan-midjourney", { times: 200 })}
|
|
||||||
<Tips content={t("sub.plan-midjourney-desc")} />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<BookText className={`h-4 w-4 mr-1`} />
|
|
||||||
{t("sub.plan-claude", { times: 1200 })}
|
|
||||||
<Tips content={t("sub.plan-claude-desc")} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={`award`}>
|
|
||||||
<Award className={`h-3 w-3 mb-1`} />
|
|
||||||
<div className={`mb-1`}>
|
|
||||||
{t("sub.pro-award", {
|
|
||||||
content:
|
|
||||||
"Poe Pro ($20)\n x \nMidjourney Base Plan ($10)",
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Upgrade base={3} level={level} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import ReactDOM from "react-dom/client";
|
import ReactDOM from "react-dom/client";
|
||||||
import App from "./App.tsx";
|
import App from "./App.tsx";
|
||||||
import "./conf.ts";
|
import "./conf";
|
||||||
import "./i18n.ts";
|
import "./i18n.ts";
|
||||||
import "./assets/main.less";
|
import "./assets/main.less";
|
||||||
import "./assets/globals.less";
|
import "./assets/globals.less";
|
||||||
import "./conf.ts";
|
import "./conf";
|
||||||
import ReloadPrompt from "./components/ReloadService.tsx";
|
import ReloadPrompt from "./components/ReloadService.tsx";
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||||
|
@ -92,7 +92,8 @@
|
|||||||
"title": "模型市场",
|
"title": "模型市场",
|
||||||
"model": "探索更多模型",
|
"model": "探索更多模型",
|
||||||
"explore": "探索",
|
"explore": "探索",
|
||||||
"search": "搜索模型名称或者简介"
|
"search": "搜索模型名称或者简介",
|
||||||
|
"model-api": "API 请求的模型 ID 名称"
|
||||||
},
|
},
|
||||||
"conversation": {
|
"conversation": {
|
||||||
"title": "对话",
|
"title": "对话",
|
||||||
@ -181,20 +182,8 @@
|
|||||||
"pro": "专业版",
|
"pro": "专业版",
|
||||||
"plan-price": "{{money}} 元/月",
|
"plan-price": "{{money}} 元/月",
|
||||||
"include-tax": "含税",
|
"include-tax": "含税",
|
||||||
"free-models": "免费模型永久免费",
|
"plan-usage": "{{name}} 每月使用 {{times}} 次",
|
||||||
"free-web": "联网搜索功能",
|
"plan-tip": "可调用模型",
|
||||||
"free-conversation": "对话存储记录",
|
|
||||||
"free-sharing": "对话分享功能",
|
|
||||||
"free-api": "API 调用",
|
|
||||||
"plan-midjourney": "Midjourney 每月绘图 {{times}} 次",
|
|
||||||
"plan-midjourney-desc": "Midjourney 快速出图模式",
|
|
||||||
"plan-gpt4": "GPT-4 每月配额 {{times}} 次",
|
|
||||||
"plan-gpt4-desc": "包含 GPT 4 Turbo, GPT 4V, GPT 4 DALLE",
|
|
||||||
"plan-claude": "Claude 100k 每月配额 {{times}} 次",
|
|
||||||
"plan-claude-desc": "包含 Claude 2 (100k), Claude 2.1 (200k)",
|
|
||||||
"pro-service": "优先服务支持",
|
|
||||||
"pro-thread": "并发数提升",
|
|
||||||
"pro-award": "等价于 {{content}}",
|
|
||||||
"enterprise": "企业版",
|
"enterprise": "企业版",
|
||||||
"enterprise-service": "优先技术支持",
|
"enterprise-service": "优先技术支持",
|
||||||
"enterprise-sla": "SLA 保障",
|
"enterprise-sla": "SLA 保障",
|
||||||
@ -446,7 +435,7 @@
|
|||||||
"retry-tip": "当渠道请求失败时,最多重试的次数",
|
"retry-tip": "当渠道请求失败时,最多重试的次数",
|
||||||
"model": "模型",
|
"model": "模型",
|
||||||
"secret": "密钥",
|
"secret": "密钥",
|
||||||
"secret-placeholder": "请输入密钥,格式:{{format}}\n多个密钥时,一行一个,请求时随机选取负载",
|
"secret-placeholder": "请输入密钥,格式:{{format}} (<>不用填)\n多个密钥时,一行一个,请求时随机选取负载",
|
||||||
"endpoint": "接入点",
|
"endpoint": "接入点",
|
||||||
"endpoint-placeholder": "请输入接入点(即代理)",
|
"endpoint-placeholder": "请输入接入点(即代理)",
|
||||||
"mapper": "模型映射",
|
"mapper": "模型映射",
|
||||||
|
@ -141,20 +141,6 @@
|
|||||||
"pro": "Pro",
|
"pro": "Pro",
|
||||||
"plan-price": "{{money}} CNY/Month",
|
"plan-price": "{{money}} CNY/Month",
|
||||||
"include-tax": "Include Tax",
|
"include-tax": "Include Tax",
|
||||||
"free-models": "Free Models Free Forever",
|
|
||||||
"free-web": "web searching feature",
|
|
||||||
"free-conversation": "conversation storage",
|
|
||||||
"free-sharing": "conversation sharing",
|
|
||||||
"free-api": "API calls",
|
|
||||||
"plan-midjourney": "Midjourney {{times}} image generation per month",
|
|
||||||
"plan-midjourney-desc": "Midjourney Quick Image Generation",
|
|
||||||
"plan-gpt4": "GPT-4 {{times}} requests per month",
|
|
||||||
"plan-gpt4-desc": "including GPT 4 Turbo, GPT 4V, GPT 4 DALLE",
|
|
||||||
"plan-claude": "Claude 100k {{times}} requests per month",
|
|
||||||
"plan-claude-desc": "including Claude 2 (100k), Claude 2.1 (200k)",
|
|
||||||
"pro-service": "Priority Service Support",
|
|
||||||
"pro-thread": "Concurrency Increase",
|
|
||||||
"pro-award": "Equivalent to {{content}}",
|
|
||||||
"enterprise": "Enterprise",
|
"enterprise": "Enterprise",
|
||||||
"enterprise-service": "Priority Service Support",
|
"enterprise-service": "Priority Service Support",
|
||||||
"enterprise-sla": "SLA Guarantee",
|
"enterprise-sla": "SLA Guarantee",
|
||||||
@ -190,7 +176,9 @@
|
|||||||
"failed": "Subscribe failed",
|
"failed": "Subscribe failed",
|
||||||
"failed-prompt": "Failed to subscribe, please make sure you have enough balance.",
|
"failed-prompt": "Failed to subscribe, please make sure you have enough balance.",
|
||||||
"migrate-failed": "Migrate failed",
|
"migrate-failed": "Migrate failed",
|
||||||
"migrate-failed-prompt": "Your subscription migration failed."
|
"migrate-failed-prompt": "Your subscription migration failed.",
|
||||||
|
"plan-usage": "{{name}} uses {{times}} times per month",
|
||||||
|
"plan-tip": "Callable Model"
|
||||||
},
|
},
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
@ -372,7 +360,7 @@
|
|||||||
"retry-tip": "When the channel request fails, the maximum number of retries",
|
"retry-tip": "When the channel request fails, the maximum number of retries",
|
||||||
"model": "Model",
|
"model": "Model",
|
||||||
"secret": "Secret",
|
"secret": "Secret",
|
||||||
"secret-placeholder": "Please enter the secret, format: {{format}}\nWhen there are multiple secrets, one line is selected randomly when requesting the load",
|
"secret-placeholder": "Please enter the secret, format: {{format}} (<> not filled)\nWhen there are multiple secrets, one line is selected randomly when requesting the load",
|
||||||
"endpoint": "Endpoint",
|
"endpoint": "Endpoint",
|
||||||
"endpoint-placeholder": "Please enter the endpoint (ie proxy)",
|
"endpoint-placeholder": "Please enter the endpoint (ie proxy)",
|
||||||
"mapper": "Model Mapper",
|
"mapper": "Model Mapper",
|
||||||
|
@ -141,20 +141,6 @@
|
|||||||
"pro": "プロ",
|
"pro": "プロ",
|
||||||
"plan-price": "{{money}}元/月",
|
"plan-price": "{{money}}元/月",
|
||||||
"include-tax": "(税込)",
|
"include-tax": "(税込)",
|
||||||
"free-models": "フリーモデルライフタイムフリー",
|
|
||||||
"free-web": "ネットワーク検索機能",
|
|
||||||
"free-conversation": "会話ストレージレコード",
|
|
||||||
"free-sharing": "会話の共有",
|
|
||||||
"free-api": "API呼び出し",
|
|
||||||
"plan-midjourney": "ミッドジャーニーは月に{{times}}回抽選されます",
|
|
||||||
"plan-midjourney-desc": "ミッドジャーニー・クイックプロットモード",
|
|
||||||
"plan-gpt4": "GPT -4ノルマ{{times}}回/月",
|
|
||||||
"plan-gpt4-desc": "GPT 4 Turbo、GPT 4 V、GPT 4 DALLEを含む",
|
|
||||||
"plan-claude": "クロード10万回の月間ノルマ{{times}}回",
|
|
||||||
"plan-claude-desc": "クロード2 ( 100 k )、クロード2.1 ( 200 k )が含まれています",
|
|
||||||
"pro-service": "優先サービスサポート",
|
|
||||||
"pro-thread": "同時実行数の増加",
|
|
||||||
"pro-award": "{{content}}相当",
|
|
||||||
"enterprise": "エンタープライズ版",
|
"enterprise": "エンタープライズ版",
|
||||||
"enterprise-service": "優先技術サポート",
|
"enterprise-service": "優先技術サポート",
|
||||||
"enterprise-sla": "SLA保護",
|
"enterprise-sla": "SLA保護",
|
||||||
@ -190,7 +176,9 @@
|
|||||||
"failed": "サブスクリプションに失敗しました",
|
"failed": "サブスクリプションに失敗しました",
|
||||||
"failed-prompt": "サブスクリプションに失敗しました。十分な残高があることを確認してください。",
|
"failed-prompt": "サブスクリプションに失敗しました。十分な残高があることを確認してください。",
|
||||||
"migrate-failed": "変更できませんでした",
|
"migrate-failed": "変更できませんでした",
|
||||||
"migrate-failed-prompt": "サブスクリプションの変更に失敗しました。"
|
"migrate-failed-prompt": "サブスクリプションの変更に失敗しました。",
|
||||||
|
"plan-usage": "{{name}}は月に{{times}}回使用",
|
||||||
|
"plan-tip": "呼び出し可能なモデル"
|
||||||
},
|
},
|
||||||
"cancel": "キャンセル",
|
"cancel": "キャンセル",
|
||||||
"confirm": "確認",
|
"confirm": "確認",
|
||||||
|
@ -141,20 +141,6 @@
|
|||||||
"pro": "Профессиональный",
|
"pro": "Профессиональный",
|
||||||
"plan-price": "{{money}} CNY/месяц",
|
"plan-price": "{{money}} CNY/месяц",
|
||||||
"include-tax": "Включая налог",
|
"include-tax": "Включая налог",
|
||||||
"free-models": "Бесплатные модели бесплатно навсегда",
|
|
||||||
"free-web": "веб-поиск",
|
|
||||||
"free-conversation": "хранение разговоров",
|
|
||||||
"free-sharing": "общий доступ к разговорам",
|
|
||||||
"free-api": "API вызовы",
|
|
||||||
"plan-midjourney": "Midjourney {{times}} генерация изображений в месяц",
|
|
||||||
"plan-midjourney-desc": "Быстрая генерация изображений Midjourney",
|
|
||||||
"plan-gpt4": "GPT-4 {{times}} запросов в месяц",
|
|
||||||
"plan-gpt4-desc": "включая GPT 4 Turbo, GPT 4V, GPT 4 DALLE",
|
|
||||||
"plan-claude": "Claude 100k {{times}} запросов в месяц",
|
|
||||||
"plan-claude-desc": "включая Claude 2 (100k), Claude 2.1 (200k)",
|
|
||||||
"pro-service": "Приоритетная служба поддержки",
|
|
||||||
"pro-thread": "Увеличение параллелизма",
|
|
||||||
"pro-award": "Эквивалент {{content}}",
|
|
||||||
"enterprise": "Корпоративный",
|
"enterprise": "Корпоративный",
|
||||||
"enterprise-service": "Приоритетная служба поддержки",
|
"enterprise-service": "Приоритетная служба поддержки",
|
||||||
"enterprise-sla": "Гарантия SLA",
|
"enterprise-sla": "Гарантия SLA",
|
||||||
@ -190,7 +176,9 @@
|
|||||||
"failed": "Подписка не удалась",
|
"failed": "Подписка не удалась",
|
||||||
"failed-prompt": "Не удалось подписаться, пожалуйста, убедитесь, что у вас достаточно баланса.",
|
"failed-prompt": "Не удалось подписаться, пожалуйста, убедитесь, что у вас достаточно баланса.",
|
||||||
"migrate-failed": "Перенос подписки не удался",
|
"migrate-failed": "Перенос подписки не удался",
|
||||||
"migrate-failed-prompt": "Ваша подписка не удалась."
|
"migrate-failed-prompt": "Ваша подписка не удалась.",
|
||||||
|
"plan-usage": "{{name}} использует {{times}} раз в месяц",
|
||||||
|
"plan-tip": "Вызываемая модель"
|
||||||
},
|
},
|
||||||
"cancel": "Отмена",
|
"cancel": "Отмена",
|
||||||
"confirm": "Подтвердить",
|
"confirm": "Подтвердить",
|
||||||
|
@ -8,7 +8,7 @@ import Home from "./routes/Home.tsx";
|
|||||||
import NotFound from "./routes/NotFound.tsx";
|
import NotFound from "./routes/NotFound.tsx";
|
||||||
import Auth from "./routes/Auth.tsx";
|
import Auth from "./routes/Auth.tsx";
|
||||||
import React, { Suspense, useEffect } from "react";
|
import React, { Suspense, useEffect } from "react";
|
||||||
import { useDeeptrain } from "@/utils/env.ts";
|
import { useDeeptrain } from "@/conf/env.ts";
|
||||||
import Register from "@/routes/Register.tsx";
|
import Register from "@/routes/Register.tsx";
|
||||||
import Forgot from "@/routes/Forgot.tsx";
|
import Forgot from "@/routes/Forgot.tsx";
|
||||||
import { lazyFactor } from "@/utils/loader.tsx";
|
import { lazyFactor } from "@/utils/loader.tsx";
|
||||||
|
@ -17,7 +17,7 @@ import ModelFinder from "@/components/home/ModelFinder.tsx";
|
|||||||
import { Toggle } from "@/components/ui/toggle.tsx";
|
import { Toggle } from "@/components/ui/toggle.tsx";
|
||||||
import { selectModel, selectWeb, setWeb } from "@/store/chat.ts";
|
import { selectModel, selectWeb, setWeb } from "@/store/chat.ts";
|
||||||
import { Label } from "@/components/ui/label.tsx";
|
import { Label } from "@/components/ui/label.tsx";
|
||||||
import { rest_api, tokenField, ws_api } from "@/conf.ts";
|
import { apiEndpoint, tokenField, websocketEndpoint } from "@/conf";
|
||||||
import { getMemory } from "@/utils/memory.ts";
|
import { getMemory } from "@/utils/memory.ts";
|
||||||
import { Progress } from "@/components/ui/progress.tsx";
|
import { Progress } from "@/components/ui/progress.tsx";
|
||||||
import { cn } from "@/components/ui/lib/utils.ts";
|
import { cn } from "@/components/ui/lib/utils.ts";
|
||||||
@ -76,7 +76,7 @@ function ArticleContent() {
|
|||||||
|
|
||||||
function generate() {
|
function generate() {
|
||||||
setProgress(true);
|
setProgress(true);
|
||||||
const connection = new WebSocket(`${ws_api}/article/create`);
|
const connection = new WebSocket(`${websocketEndpoint}/article/create`);
|
||||||
|
|
||||||
connection.onopen = () => {
|
connection.onopen = () => {
|
||||||
connection.send(
|
connection.send(
|
||||||
@ -122,7 +122,7 @@ function ArticleContent() {
|
|||||||
variant={`outline`}
|
variant={`outline`}
|
||||||
className={`mt-5 w-full mr-2`}
|
className={`mt-5 w-full mr-2`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
location.href = `${rest_api}/article/download/zip?hash=${hash}`;
|
location.href = `${apiEndpoint}/article/download/zip?hash=${hash}`;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{" "}
|
{" "}
|
||||||
@ -133,7 +133,7 @@ function ArticleContent() {
|
|||||||
variant={`outline`}
|
variant={`outline`}
|
||||||
className={`mt-5 w-full ml-2`}
|
className={`mt-5 w-full ml-2`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
location.href = `${rest_api}/article/download/tar?hash=${hash}`;
|
location.href = `${apiEndpoint}/article/download/tar?hash=${hash}`;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{" "}
|
{" "}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useToast } from "@/components/ui/use-toast.ts";
|
import { useToast } from "@/components/ui/use-toast.ts";
|
||||||
import { ToastAction } from "@/components/ui/toast.tsx";
|
import { ToastAction } from "@/components/ui/toast.tsx";
|
||||||
import { tokenField } from "@/conf.ts";
|
import { tokenField } from "@/conf";
|
||||||
import { useEffect, useReducer } from "react";
|
import { useEffect, useReducer } from "react";
|
||||||
import Loader from "@/components/Loader.tsx";
|
import Loader from "@/components/Loader.tsx";
|
||||||
import "@/assets/pages/auth.less";
|
import "@/assets/pages/auth.less";
|
||||||
@ -10,7 +10,7 @@ import router from "@/router.tsx";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { getQueryParam } from "@/utils/path.ts";
|
import { getQueryParam } from "@/utils/path.ts";
|
||||||
import { setMemory } from "@/utils/memory.ts";
|
import { setMemory } from "@/utils/memory.ts";
|
||||||
import { appLogo, appName, useDeeptrain } from "@/utils/env.ts";
|
import { appLogo, appName, useDeeptrain } from "@/conf/env.ts";
|
||||||
import { Card, CardContent } from "@/components/ui/card.tsx";
|
import { Card, CardContent } from "@/components/ui/card.tsx";
|
||||||
import { goAuth } from "@/utils/app.ts";
|
import { goAuth } from "@/utils/app.ts";
|
||||||
import { Label } from "@/components/ui/label.tsx";
|
import { Label } from "@/components/ui/label.tsx";
|
||||||
|
@ -14,7 +14,7 @@ import Require, {
|
|||||||
import { Input } from "@/components/ui/input.tsx";
|
import { Input } from "@/components/ui/input.tsx";
|
||||||
import { Button } from "@/components/ui/button.tsx";
|
import { Button } from "@/components/ui/button.tsx";
|
||||||
import TickButton from "@/components/TickButton.tsx";
|
import TickButton from "@/components/TickButton.tsx";
|
||||||
import { appLogo } from "@/utils/env.ts";
|
import { appLogo } from "@/conf/env.ts";
|
||||||
|
|
||||||
function Forgot() {
|
function Forgot() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -3,7 +3,7 @@ import { useSelector } from "react-redux";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Button } from "@/components/ui/button.tsx";
|
import { Button } from "@/components/ui/button.tsx";
|
||||||
import { ChevronLeft, Cloud, FileDown, Send } from "lucide-react";
|
import { ChevronLeft, Cloud, FileDown, Send } from "lucide-react";
|
||||||
import { rest_api } from "@/conf.ts";
|
import { apiEndpoint } from "@/conf";
|
||||||
import router from "@/router.tsx";
|
import router from "@/router.tsx";
|
||||||
import { Input } from "@/components/ui/input.tsx";
|
import { Input } from "@/components/ui/input.tsx";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
@ -12,7 +12,7 @@ import { useToast } from "@/components/ui/use-toast.ts";
|
|||||||
import { handleGenerationData } from "@/utils/processor.ts";
|
import { handleGenerationData } from "@/utils/processor.ts";
|
||||||
import { selectModel } from "@/store/chat.ts";
|
import { selectModel } from "@/store/chat.ts";
|
||||||
import ModelFinder from "@/components/home/ModelFinder.tsx";
|
import ModelFinder from "@/components/home/ModelFinder.tsx";
|
||||||
import { appLogo } from "@/utils/env.ts";
|
import { appLogo } from "@/conf/env.ts";
|
||||||
|
|
||||||
type WrapperProps = {
|
type WrapperProps = {
|
||||||
onSend?: (value: string, model: string) => boolean;
|
onSend?: (value: string, model: string) => boolean;
|
||||||
@ -111,14 +111,14 @@ function Wrapper({ onSend }: WrapperProps) {
|
|||||||
<div className={`hash-box`}>
|
<div className={`hash-box`}>
|
||||||
<a
|
<a
|
||||||
className={`download-box`}
|
className={`download-box`}
|
||||||
href={`${rest_api}/generation/download/tar?hash=${hash}`}
|
href={`${apiEndpoint}/generation/download/tar?hash=${hash}`}
|
||||||
>
|
>
|
||||||
<FileDown className={`h-6 w-6`} />
|
<FileDown className={`h-6 w-6`} />
|
||||||
<p>{t("generate.download", { name: "tar.gz" })}</p>
|
<p>{t("generate.download", { name: "tar.gz" })}</p>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
className={`download-box`}
|
className={`download-box`}
|
||||||
href={`${rest_api}/generation/download/zip?hash=${hash}`}
|
href={`${apiEndpoint}/generation/download/zip?hash=${hash}`}
|
||||||
>
|
>
|
||||||
<FileDown className={`h-6 w-6`} />
|
<FileDown className={`h-6 w-6`} />
|
||||||
<p>{t("generate.download", { name: "zip" })}</p>
|
<p>{t("generate.download", { name: "zip" })}</p>
|
||||||
|
@ -16,7 +16,7 @@ import { useToast } from "@/components/ui/use-toast.ts";
|
|||||||
import TickButton from "@/components/TickButton.tsx";
|
import TickButton from "@/components/TickButton.tsx";
|
||||||
import { validateToken } from "@/store/auth.ts";
|
import { validateToken } from "@/store/auth.ts";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { appLogo, appName } from "@/utils/env.ts";
|
import { appLogo, appName } from "@/conf/env.ts";
|
||||||
|
|
||||||
type CompProps = {
|
type CompProps = {
|
||||||
form: RegisterForm;
|
form: RegisterForm;
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { Model as RawModel } from "@/api/types.ts";
|
import { Model as RawModel } from "@/api/types.ts";
|
||||||
import { supportModels } from "@/conf.ts";
|
import { supportModels } from "@/conf";
|
||||||
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
|
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
|
||||||
import { Input } from "@/components/ui/input.tsx";
|
import { Input } from "@/components/ui/input.tsx";
|
||||||
import { GripVertical, HelpCircle, Plus, Trash2 } from "lucide-react";
|
import { GripVertical, HelpCircle, Plus, Trash2 } from "lucide-react";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createSlice } from "@reduxjs/toolkit";
|
import { createSlice } from "@reduxjs/toolkit";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { tokenField } from "@/conf.ts";
|
import { tokenField } from "@/conf";
|
||||||
import { AppDispatch, RootState } from "./index.ts";
|
import { AppDispatch, RootState } from "./index.ts";
|
||||||
import { forgetMemory, setMemory } from "@/utils/memory.ts";
|
import { forgetMemory, setMemory } from "@/utils/memory.ts";
|
||||||
import { doState } from "@/api/auth.ts";
|
import { doState } from "@/api/auth.ts";
|
||||||
|
@ -3,7 +3,7 @@ import { ConversationInstance, Model } from "@/api/types.ts";
|
|||||||
import { Message } from "@/api/types.ts";
|
import { Message } from "@/api/types.ts";
|
||||||
import { insertStart } from "@/utils/base.ts";
|
import { insertStart } from "@/utils/base.ts";
|
||||||
import { AppDispatch, RootState } from "./index.ts";
|
import { AppDispatch, RootState } from "./index.ts";
|
||||||
import { planModels, supportModels } from "@/conf.ts";
|
import { supportModels } from "@/conf";
|
||||||
import {
|
import {
|
||||||
getArrayMemory,
|
getArrayMemory,
|
||||||
getBooleanMemory,
|
getBooleanMemory,
|
||||||
@ -31,12 +31,6 @@ export function inModel(model: string): boolean {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPlanModels(level: number): string[] {
|
|
||||||
return planModels
|
|
||||||
.filter((item) => item.level <= level)
|
|
||||||
.map((item) => item.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getModel(model: string | undefined | null): string {
|
export function getModel(model: string | undefined | null): string {
|
||||||
if (supportModels.length === 0) return "";
|
if (supportModels.length === 0) return "";
|
||||||
return model && inModel(model) ? model : supportModels[0].id;
|
return model && inModel(model) ? model : supportModels[0].id;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import router from "@/router.tsx";
|
import router from "@/router.tsx";
|
||||||
import { useDeeptrain } from "@/utils/env.ts";
|
import { useDeeptrain } from "@/conf/env.ts";
|
||||||
import { login } from "@/conf.ts";
|
import { goDeepLogin } from "@/conf/deeptrain.ts";
|
||||||
|
|
||||||
export let event: BeforeInstallPromptEvent | undefined;
|
export let event: BeforeInstallPromptEvent | undefined;
|
||||||
|
|
||||||
@ -52,5 +52,5 @@ export function navigate(path: string): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function goAuth(): void {
|
export function goAuth(): void {
|
||||||
useDeeptrain ? login() : navigate("/login");
|
useDeeptrain ? goDeepLogin() : navigate("/login");
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { addEventListeners } from "@/utils/dom.ts";
|
||||||
|
|
||||||
export let mobile = isMobile();
|
export let mobile = isMobile();
|
||||||
|
|
||||||
window.addEventListener("resize", () => {
|
window.addEventListener("resize", () => {
|
||||||
@ -11,3 +14,29 @@ export function isMobile(): boolean {
|
|||||||
navigator.userAgent.includes("Mobile")
|
navigator.userAgent.includes("Mobile")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useMobile(): boolean {
|
||||||
|
const [mobile, setMobile] = useState<boolean>(isMobile);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = () => setMobile(isMobile);
|
||||||
|
|
||||||
|
return addEventListeners(
|
||||||
|
window,
|
||||||
|
[
|
||||||
|
"resize",
|
||||||
|
"orientationchange",
|
||||||
|
"touchstart",
|
||||||
|
"touchmove",
|
||||||
|
"touchend",
|
||||||
|
"touchcancel",
|
||||||
|
"gesturestart",
|
||||||
|
"gesturechange",
|
||||||
|
"gestureend",
|
||||||
|
],
|
||||||
|
handler,
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return mobile;
|
||||||
|
}
|
||||||
|
@ -186,7 +186,7 @@ export function addEventListener(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function addEventListeners(
|
export function addEventListeners(
|
||||||
el: HTMLElement,
|
el: Window | HTMLElement,
|
||||||
events: string[],
|
events: string[],
|
||||||
handler: EventListenerOrEventListenerObject,
|
handler: EventListenerOrEventListenerObject,
|
||||||
): () => void {
|
): () => void {
|
||||||
|
@ -50,6 +50,10 @@ func (c *Connection) GetStack() Stack {
|
|||||||
|
|
||||||
func (c *Connection) ReadWorker() {
|
func (c *Connection) ReadWorker() {
|
||||||
for {
|
for {
|
||||||
|
if c.IsClosed() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
form := utils.ReadForm[conversation.FormMessage](c.conn)
|
form := utils.ReadForm[conversation.FormMessage](c.conn)
|
||||||
if form == nil {
|
if form == nil {
|
||||||
break
|
break
|
||||||
@ -61,6 +65,8 @@ func (c *Connection) ReadWorker() {
|
|||||||
|
|
||||||
c.Write(form)
|
c.Write(form)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Connection) Write(data *conversation.FormMessage) {
|
func (c *Connection) Write(data *conversation.FormMessage) {
|
||||||
@ -70,6 +76,14 @@ func (c *Connection) Write(data *conversation.FormMessage) {
|
|||||||
c.stack <- data
|
c.stack <- data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Connection) IsClosed() bool {
|
||||||
|
return c.conn.IsClosed()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) Stop() {
|
||||||
|
c.Write(nil)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Connection) Read() *conversation.FormMessage {
|
func (c *Connection) Read() *conversation.FormMessage {
|
||||||
form := <-c.stack
|
form := <-c.stack
|
||||||
return form
|
return form
|
||||||
|
@ -8,13 +8,18 @@ import (
|
|||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebSocket struct {
|
type WebSocket struct {
|
||||||
Ctx *gin.Context
|
Ctx *gin.Context
|
||||||
Conn *websocket.Conn
|
Conn *websocket.Conn
|
||||||
|
MaxTimeout time.Duration
|
||||||
|
Closed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var defaultMaxTimeout = 15 * time.Minute
|
||||||
|
|
||||||
func CheckUpgrader(c *gin.Context, strict bool) *websocket.Upgrader {
|
func CheckUpgrader(c *gin.Context, strict bool) *websocket.Upgrader {
|
||||||
return &websocket.Upgrader{
|
return &websocket.Upgrader{
|
||||||
CheckOrigin: func(r *http.Request) bool {
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
@ -40,10 +45,12 @@ func NewWebsocket(c *gin.Context, strict bool) *WebSocket {
|
|||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
return &WebSocket{
|
instance := &WebSocket{
|
||||||
Ctx: c,
|
Ctx: c,
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
}
|
}
|
||||||
|
instance.Init()
|
||||||
|
return instance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,12 +58,38 @@ func NewWebsocketClient(url string) *WebSocket {
|
|||||||
if conn, _, err := websocket.DefaultDialer.Dial(url, nil); err != nil {
|
if conn, _, err := websocket.DefaultDialer.Dial(url, nil); err != nil {
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
return &WebSocket{
|
instance := &WebSocket{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
}
|
}
|
||||||
|
instance.Init()
|
||||||
|
return instance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *WebSocket) Init() {
|
||||||
|
w.Closed = false
|
||||||
|
|
||||||
|
w.Conn.SetCloseHandler(func(code int, text string) error {
|
||||||
|
w.Closed = true
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
w.Conn.SetPongHandler(func(appData string) error {
|
||||||
|
return w.Conn.SetReadDeadline(time.Now().Add(w.GetMaxTimeout()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WebSocket) SetMaxTimeout(timeout time.Duration) {
|
||||||
|
w.MaxTimeout = timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WebSocket) GetMaxTimeout() time.Duration {
|
||||||
|
if w.MaxTimeout <= 0 {
|
||||||
|
return defaultMaxTimeout
|
||||||
|
}
|
||||||
|
return w.MaxTimeout
|
||||||
|
}
|
||||||
|
|
||||||
func (w *WebSocket) Read() (int, []byte, error) {
|
func (w *WebSocket) Read() (int, []byte, error) {
|
||||||
return w.Conn.ReadMessage()
|
return w.Conn.ReadMessage()
|
||||||
}
|
}
|
||||||
@ -127,6 +160,14 @@ func (w *WebSocket) GetCache() *redis.Client {
|
|||||||
return GetCacheFromContext(w.Ctx)
|
return GetCacheFromContext(w.Ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *WebSocket) GetConn() *websocket.Conn {
|
||||||
|
return w.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WebSocket) IsClosed() bool {
|
||||||
|
return w.Closed
|
||||||
|
}
|
||||||
|
|
||||||
func ReadForm[T interface{}](w *WebSocket) *T {
|
func ReadForm[T interface{}](w *WebSocket) *T {
|
||||||
// golang cannot use generic type in class-like struct
|
// golang cannot use generic type in class-like struct
|
||||||
// except ping
|
// except ping
|
||||||
|
Loading…
Reference in New Issue
Block a user