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",
|
||||
"i18next": "^23.4.6",
|
||||
"localforage": "^1.10.0",
|
||||
"lucide-react": "^0.289.0",
|
||||
"lucide-react": "^0.309.0",
|
||||
"match-sorter": "^6.3.1",
|
||||
"next-themes": "^0.2.1",
|
||||
"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
|
||||
version: 1.10.0
|
||||
lucide-react:
|
||||
specifier: ^0.289.0
|
||||
version: 0.289.0(react@18.2.0)
|
||||
specifier: ^0.309.0
|
||||
version: 0.309.0(react@18.2.0)
|
||||
match-sorter:
|
||||
specifier: ^6.3.1
|
||||
version: 6.3.1
|
||||
@ -548,6 +548,13 @@ packages:
|
||||
'@jridgewell/resolve-uri': 3.1.1
|
||||
'@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:
|
||||
resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==}
|
||||
dev: false
|
||||
@ -2092,12 +2099,12 @@ packages:
|
||||
/@types/eslint-scope@3.7.7:
|
||||
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
|
||||
dependencies:
|
||||
'@types/eslint': 8.44.8
|
||||
'@types/eslint': 8.56.2
|
||||
'@types/estree': 1.0.5
|
||||
dev: true
|
||||
|
||||
/@types/eslint@8.44.8:
|
||||
resolution: {integrity: sha512-4K8GavROwhrYl2QXDXm0Rv9epkA8GBFu0EI+XrrnnuCl7u8CWBRusX7fXJfanhZTDWSAL24gDI/UqXyUM0Injw==}
|
||||
/@types/eslint@8.56.2:
|
||||
resolution: {integrity: sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==}
|
||||
dependencies:
|
||||
'@types/estree': 1.0.5
|
||||
'@types/json-schema': 7.0.15
|
||||
@ -2152,8 +2159,8 @@ packages:
|
||||
resolution: {integrity: sha512-AuHIyzR5Hea7ij0P9q7vx7xu4z0C28ucwjAZC0ja7JhINyCnOw8/DnvAPQQ9TfOlCtZAmCERKQX9+o1mgQhuOQ==}
|
||||
dev: false
|
||||
|
||||
/@types/node@20.10.1:
|
||||
resolution: {integrity: sha512-T2qwhjWwGH81vUEx4EXmBKsTJRXFXNZTL4v0gi01+zyBmCwzE6TyHszqX01m+QHTEq+EZNo13NeJIdEqf+Myrg==}
|
||||
/@types/node@20.11.3:
|
||||
resolution: {integrity: sha512-nrlmbvGPNGaj84IJZXMPhQuCMEVTT/hXZMJJG/aIqVL9fKxqk814sGGtJA4GI6hpJSLQjpi6cn0Qx9eOf9SDVg==}
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
dev: true
|
||||
@ -2483,12 +2490,12 @@ packages:
|
||||
resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==}
|
||||
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==}
|
||||
peerDependencies:
|
||||
acorn: ^8
|
||||
dependencies:
|
||||
acorn: 8.11.2
|
||||
acorn: 8.11.3
|
||||
dev: true
|
||||
|
||||
/acorn-jsx@5.3.2(acorn@8.10.0):
|
||||
@ -2505,8 +2512,8 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/acorn@8.11.2:
|
||||
resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==}
|
||||
/acorn@8.11.3:
|
||||
resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
@ -2647,6 +2654,17 @@ packages:
|
||||
update-browserslist-db: 1.0.13(browserslist@4.22.1)
|
||||
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:
|
||||
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||
dev: true
|
||||
@ -2676,6 +2694,10 @@ packages:
|
||||
|
||||
/caniuse-lite@1.0.30001554:
|
||||
resolution: {integrity: sha512-A2E3U//MBwbJVzebddm1YfNp7Nud5Ip+IPn4BozBmn4KqVX7AvluoIDFWjsv5OkGnKUXQVmMSoMKLa3ScCblcQ==}
|
||||
dev: true
|
||||
|
||||
/caniuse-lite@1.0.30001576:
|
||||
resolution: {integrity: sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==}
|
||||
|
||||
/ccount@2.0.1:
|
||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
||||
@ -2869,19 +2891,6 @@ packages:
|
||||
/csstype@3.1.2:
|
||||
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:
|
||||
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
||||
engines: {node: '>=6.0'}
|
||||
@ -3004,6 +3013,10 @@ packages:
|
||||
resolution: {integrity: sha512-8KR114CAYQ4/r5EIEsOmOMqQ9j0MRbJZR3aXD/KFA8RuKzyoUB4XrUCg+l8RUGqTVQgKNIgTpjaG8YHRPAbX2w==}
|
||||
dev: true
|
||||
|
||||
/electron-to-chromium@1.4.631:
|
||||
resolution: {integrity: sha512-g73CJB/rMPjdxpiNJYmV1homV7mLVUNe/R0z/HhqMfpjkt58FpYmkTjbtuv3zymdbTTJ+VOEqe1c+lkTjSOhmQ==}
|
||||
dev: true
|
||||
|
||||
/enhanced-resolve@5.15.0:
|
||||
resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
@ -3689,7 +3702,7 @@ packages:
|
||||
resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
|
||||
engines: {node: '>= 10.13.0'}
|
||||
dependencies:
|
||||
'@types/node': 20.10.1
|
||||
'@types/node': 20.11.3
|
||||
merge-stream: 2.0.0
|
||||
supports-color: 8.1.1
|
||||
dev: true
|
||||
@ -3776,10 +3789,8 @@ packages:
|
||||
image-size: 0.5.5
|
||||
make-dir: 2.1.0
|
||||
mime: 1.6.0
|
||||
needle: 3.2.0
|
||||
needle: 3.3.1
|
||||
source-map: 0.6.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/levn@0.4.1:
|
||||
@ -3856,8 +3867,8 @@ packages:
|
||||
yallist: 4.0.0
|
||||
dev: true
|
||||
|
||||
/lucide-react@0.289.0(react@18.2.0):
|
||||
resolution: {integrity: sha512-D3/kt5h4KVmO9Bqlhky/szWI3puEU/KJfQWCeX8Zhvx3xx0SQ4t6vbwiK9ORBbiaqXefkBbXjoq7fOBd7s5yXQ==}
|
||||
/lucide-react@0.309.0(react@18.2.0):
|
||||
resolution: {integrity: sha512-zNVPczuwFrCfksZH3zbd1UDE6/WYhYAdbe2k7CImVyPAkXLgIwbs6eXQ4loigqDnUFjyFYCI5jZ1y10Kqal0dg==}
|
||||
peerDependencies:
|
||||
react: ^16.5.1 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
@ -4356,12 +4367,6 @@ packages:
|
||||
/ms@2.1.2:
|
||||
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:
|
||||
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
||||
dependencies:
|
||||
@ -4378,17 +4383,14 @@ packages:
|
||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||
dev: true
|
||||
|
||||
/needle@3.2.0:
|
||||
resolution: {integrity: sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==}
|
||||
/needle@3.3.1:
|
||||
resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==}
|
||||
engines: {node: '>= 4.4.x'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
iconv-lite: 0.6.3
|
||||
sax: 1.3.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
@ -4426,7 +4428,7 @@ packages:
|
||||
'@next/env': 14.0.4
|
||||
'@swc/helpers': 0.5.2
|
||||
busboy: 1.6.0
|
||||
caniuse-lite: 1.0.30001554
|
||||
caniuse-lite: 1.0.30001576
|
||||
graceful-fs: 4.2.11
|
||||
postcss: 8.4.31
|
||||
react: 18.2.0
|
||||
@ -4466,6 +4468,10 @@ packages:
|
||||
resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
|
||||
dev: true
|
||||
|
||||
/node-releases@2.0.14:
|
||||
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
|
||||
dev: true
|
||||
|
||||
/normalize-path@3.0.0:
|
||||
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -5212,8 +5218,8 @@ packages:
|
||||
lru-cache: 6.0.0
|
||||
dev: true
|
||||
|
||||
/serialize-javascript@6.0.1:
|
||||
resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==}
|
||||
/serialize-javascript@6.0.2:
|
||||
resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
|
||||
dependencies:
|
||||
randombytes: 2.1.0
|
||||
dev: true
|
||||
@ -5393,8 +5399,8 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/terser-webpack-plugin@5.3.9(webpack@5.89.0):
|
||||
resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==}
|
||||
/terser-webpack-plugin@5.3.10(webpack@5.89.0):
|
||||
resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==}
|
||||
engines: {node: '>= 10.13.0'}
|
||||
peerDependencies:
|
||||
'@swc/core': '*'
|
||||
@ -5409,11 +5415,11 @@ packages:
|
||||
uglify-js:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.20
|
||||
'@jridgewell/trace-mapping': 0.3.21
|
||||
jest-worker: 27.5.1
|
||||
schema-utils: 3.3.0
|
||||
serialize-javascript: 6.0.1
|
||||
terser: 5.24.0
|
||||
serialize-javascript: 6.0.2
|
||||
terser: 5.26.0
|
||||
webpack: 5.89.0
|
||||
dev: true
|
||||
|
||||
@ -5428,13 +5434,13 @@ packages:
|
||||
source-map-support: 0.5.21
|
||||
dev: true
|
||||
|
||||
/terser@5.24.0:
|
||||
resolution: {integrity: sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==}
|
||||
/terser@5.26.0:
|
||||
resolution: {integrity: sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@jridgewell/source-map': 0.3.5
|
||||
acorn: 8.11.2
|
||||
acorn: 8.11.3
|
||||
commander: 2.20.3
|
||||
source-map-support: 0.5.21
|
||||
dev: true
|
||||
@ -5619,6 +5625,17 @@ packages:
|
||||
picocolors: 1.0.0
|
||||
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:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
dependencies:
|
||||
@ -5817,9 +5834,9 @@ packages:
|
||||
'@webassemblyjs/ast': 1.11.6
|
||||
'@webassemblyjs/wasm-edit': 1.11.6
|
||||
'@webassemblyjs/wasm-parser': 1.11.6
|
||||
acorn: 8.11.2
|
||||
acorn-import-assertions: 1.9.0(acorn@8.11.2)
|
||||
browserslist: 4.22.1
|
||||
acorn: 8.11.3
|
||||
acorn-import-assertions: 1.9.0(acorn@8.11.3)
|
||||
browserslist: 4.22.2
|
||||
chrome-trace-event: 1.0.3
|
||||
enhanced-resolve: 5.15.0
|
||||
es-module-lexer: 1.4.1
|
||||
@ -5833,7 +5850,7 @@ packages:
|
||||
neo-async: 2.6.2
|
||||
schema-utils: 3.3.0
|
||||
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
|
||||
webpack-sources: 3.2.3
|
||||
transitivePeerDependencies:
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
setAppName,
|
||||
setBlobEndpoint,
|
||||
setDocsUrl,
|
||||
} from "@/utils/env.ts";
|
||||
} from "@/conf/env.ts";
|
||||
|
||||
export type SiteInfo = {
|
||||
title: string;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { tokenField, ws_api } from "@/conf.ts";
|
||||
import { tokenField, websocketEndpoint } from "@/conf";
|
||||
import { getMemory } from "@/utils/memory.ts";
|
||||
|
||||
export const endpoint = `${ws_api}/chat`;
|
||||
export const endpoint = `${websocketEndpoint}/chat`;
|
||||
|
||||
export type StreamMessage = {
|
||||
conversation?: number;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import axios from "axios";
|
||||
import { blobEndpoint } from "@/utils/env.ts";
|
||||
import { blobEndpoint } from "@/conf/env.ts";
|
||||
|
||||
export type BlobParserResponse = {
|
||||
status: boolean;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { tokenField, ws_api } from "@/conf.ts";
|
||||
import { tokenField, websocketEndpoint } from "@/conf";
|
||||
import { getMemory } from "@/utils/memory.ts";
|
||||
|
||||
export const endpoint = `${ws_api}/generation/create`;
|
||||
export const endpoint = `${websocketEndpoint}/generation/create`;
|
||||
|
||||
export type GenerationForm = {
|
||||
token: string;
|
||||
|
@ -42,7 +42,7 @@ export type ConversationMapper = Record<Id, Conversation>;
|
||||
export type PlanItem = {
|
||||
id: string;
|
||||
name: string;
|
||||
value: string;
|
||||
value: number;
|
||||
icon: string;
|
||||
models: string[];
|
||||
};
|
||||
@ -53,6 +53,8 @@ export type Plan = {
|
||||
items: PlanItem[];
|
||||
};
|
||||
|
||||
export type Plans = Plan[];
|
||||
|
||||
export type SubscriptionUsage = Record<
|
||||
string,
|
||||
{
|
||||
|
@ -110,6 +110,9 @@
|
||||
}
|
||||
|
||||
.model-name {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
color: hsl(var(--text));
|
||||
}
|
||||
|
||||
@ -200,13 +203,32 @@
|
||||
}
|
||||
}
|
||||
|
||||
.market-tip {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.model-name {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.badge {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
&.pro {
|
||||
p {
|
||||
// gold color gradient
|
||||
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-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.badge {
|
||||
color: rgb(164, 128, 0) !important;
|
||||
background: rgb(255, 231, 145) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.model-tag {
|
||||
|
@ -83,14 +83,6 @@
|
||||
border-color: hsl(var(--text-secondary));
|
||||
}
|
||||
|
||||
&.enterprise {
|
||||
border-color: hsl(var(--accent));
|
||||
|
||||
.desc {
|
||||
margin-top: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
@ -157,6 +149,12 @@
|
||||
gap: 6px;
|
||||
margin: 24px 0;
|
||||
|
||||
.api-tip {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
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 { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { AlertCircle, Download } from "lucide-react";
|
||||
import { withTranslation, WithTranslation } from "react-i18next";
|
||||
import { version } from "@/conf.ts";
|
||||
import { version } from "@/conf";
|
||||
import { getMemoryPerformance } from "@/utils/app.ts";
|
||||
import { Button } from "@/components/ui/button.tsx";
|
||||
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 { Button } from "@/components/ui/button.tsx";
|
||||
import { useSelector } from "react-redux";
|
||||
import { isHighContextModel } from "@/conf.ts";
|
||||
import { isHighContextModel } from "@/conf/model.ts";
|
||||
import { selectModel } from "@/store/chat.ts";
|
||||
import { ChatAction } from "@/components/home/assemblies/ChatAction.tsx";
|
||||
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 { useToast } from "./ui/use-toast.ts";
|
||||
import { getMemory, setMemory } from "@/utils/memory.ts";
|
||||
|
@ -5,21 +5,25 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip.tsx";
|
||||
import { HelpCircle } from "lucide-react";
|
||||
import React from "react";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
type TipsProps = {
|
||||
content: string;
|
||||
content?: string;
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
function Tips({ content, className }: TipsProps) {
|
||||
function Tips({ content, children, className }: TipsProps) {
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<HelpCircle className={`tips-icon ${className}`} />
|
||||
<HelpCircle className={cn("tips-icon", className)} />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>{content}</p>
|
||||
{content && <p>{content}</p>}
|
||||
{children}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
|
@ -55,7 +55,7 @@ import { useToast } from "@/components/ui/use-toast";
|
||||
import { deleteCharge, listCharge, setCharge } from "@/admin/api/charge.ts";
|
||||
import { useEffectAsync } from "@/utils/hook.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 Tips from "@/components/Tips.tsx";
|
||||
|
||||
|
@ -3,7 +3,7 @@ import { ThemeProvider } from "@/components/ThemeProvider.tsx";
|
||||
import DialogManager from "@/dialogs";
|
||||
import Broadcast from "@/components/Broadcast.tsx";
|
||||
import { useEffectAsync } from "@/utils/hook.ts";
|
||||
import { allModels, supportModels } from "@/conf.ts";
|
||||
import { allModels, supportModels } from "@/conf";
|
||||
import { channelModels } from "@/admin/channel.ts";
|
||||
import { getApiCharge, getApiMarket, getApiModels } from "@/api/v1.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 openApiDialog } from "@/store/api.ts";
|
||||
import router from "@/router.tsx";
|
||||
import { useDeeptrain } from "@/utils/env.ts";
|
||||
import { useDeeptrain } from "@/conf/env.ts";
|
||||
import React from "react";
|
||||
|
||||
type MenuBarProps = {
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
import { Button } from "@/components/ui/button.tsx";
|
||||
import { Menu } from "lucide-react";
|
||||
import { useEffect } from "react";
|
||||
import { tokenField } from "@/conf.ts";
|
||||
import { tokenField } from "@/conf";
|
||||
import { toggleMenu } from "@/store/menu.ts";
|
||||
import ProjectLink from "@/components/ProjectLink.tsx";
|
||||
import ModeToggle from "@/components/ThemeProvider.tsx";
|
||||
@ -18,7 +18,7 @@ import MenuBar from "./MenuBar.tsx";
|
||||
import { getMemory } from "@/utils/memory.ts";
|
||||
import { goAuth } from "@/utils/app.ts";
|
||||
import Avatar from "@/components/Avatar.tsx";
|
||||
import { appLogo } from "@/utils/env.ts";
|
||||
import { appLogo } from "@/conf/env.ts";
|
||||
|
||||
function NavMenu() {
|
||||
const username = useSelector(selectUsername);
|
||||
|
@ -20,7 +20,7 @@ import {
|
||||
} from "@/components/ui/dialog.tsx";
|
||||
import { getLanguage } from "@/i18n.ts";
|
||||
import { selectAuthenticated } from "@/store/auth.ts";
|
||||
import { docsEndpoint, useDeeptrain } from "@/utils/env.ts";
|
||||
import { docsEndpoint, useDeeptrain } from "@/conf/env.ts";
|
||||
|
||||
function ChatSpace() {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
@ -1,7 +1,6 @@
|
||||
import SelectGroup, { SelectItemProps } from "@/components/SelectGroup.tsx";
|
||||
import { supportModels } from "@/conf.ts";
|
||||
import { supportModels } from "@/conf";
|
||||
import {
|
||||
getPlanModels,
|
||||
openMarket,
|
||||
selectModel,
|
||||
selectModelList,
|
||||
@ -19,6 +18,7 @@ import { ToastAction } from "@/components/ui/toast.tsx";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { Sparkles } from "lucide-react";
|
||||
import { goAuth } from "@/utils/app.ts";
|
||||
import { includingModelFromPlan } from "@/conf/subscription.tsx";
|
||||
|
||||
function GetModel(name: string): Model {
|
||||
return supportModels.find((model) => model.id === name) as Model;
|
||||
@ -29,7 +29,7 @@ type ModelSelectorProps = {
|
||||
};
|
||||
|
||||
function filterModel(model: Model, level: number) {
|
||||
if (getPlanModels(level).includes(model.id)) {
|
||||
if (includingModelFromPlan(level, model.id)) {
|
||||
return {
|
||||
name: model.id,
|
||||
value: model.name,
|
||||
|
@ -11,14 +11,13 @@ import {
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { supportModels } from "@/conf.ts";
|
||||
import { supportModels } from "@/conf";
|
||||
import { isUrl, splitList } from "@/utils/base.ts";
|
||||
import { Model } from "@/api/types.ts";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
addModelList,
|
||||
closeMarket,
|
||||
getPlanModels,
|
||||
removeModelList,
|
||||
selectModel,
|
||||
selectModelList,
|
||||
@ -30,7 +29,7 @@ import { teenagerSelector } from "@/store/package.ts";
|
||||
import { ToastAction } from "@/components/ui/toast.tsx";
|
||||
import { selectAuthenticated } from "@/store/auth.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 {
|
||||
DragDropContext,
|
||||
@ -40,6 +39,16 @@ import {
|
||||
} from "react-beautiful-dnd";
|
||||
import { savePreferenceModels } from "@/utils/storage.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 = {
|
||||
value: string;
|
||||
@ -100,6 +109,8 @@ function ModelItem({
|
||||
const list = useSelector(selectModelList);
|
||||
const current = useSelector(selectModel);
|
||||
|
||||
const mobile = useMobile();
|
||||
|
||||
const level = useSelector(levelSelector);
|
||||
const student = useSelector(teenagerSelector);
|
||||
const auth = useSelector(selectAuthenticated);
|
||||
@ -111,7 +122,7 @@ function ModelItem({
|
||||
}, [model, current, list]);
|
||||
|
||||
const pro = useMemo(() => {
|
||||
return getPlanModels(level).includes(model.id);
|
||||
return includingModelFromPlan(level, model.id);
|
||||
}, [model, level, student]);
|
||||
|
||||
const avatar = useMemo(() => {
|
||||
@ -148,7 +159,32 @@ function ModelItem({
|
||||
<GripVertical className={`grip-icon h-4 w-4 translate-x-[-1rem]`} />
|
||||
<img className={`model-avatar`} src={avatar} alt={model.name} />
|
||||
<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 && (
|
||||
<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 { expiredSelector, refreshSubscription } from "@/store/subscription.ts";
|
||||
import { Plus } from "lucide-react";
|
||||
import { subscriptionPrize } from "@/conf.ts";
|
||||
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 { openDialog } from "@/store/quota.ts";
|
||||
import { getPlanPrice } from "@/conf/subscription.tsx";
|
||||
|
||||
function countPrize(base: number, month: number): number {
|
||||
const prize = subscriptionPrize[base] * month;
|
||||
function countPrice(base: number, month: number): number {
|
||||
const price = getPlanPrice(base) * month;
|
||||
if (month >= 36) {
|
||||
return prize * 0.7;
|
||||
return price * 0.7;
|
||||
} else if (month >= 12) {
|
||||
return prize * 0.8;
|
||||
return price * 0.8;
|
||||
} else if (month >= 6) {
|
||||
return prize * 0.9;
|
||||
return price * 0.9;
|
||||
}
|
||||
|
||||
return prize;
|
||||
return price;
|
||||
}
|
||||
|
||||
function countUpgradePrize(
|
||||
function countUpgradePrice(
|
||||
level: number,
|
||||
target: number,
|
||||
days: number,
|
||||
): number {
|
||||
const bias = subscriptionPrize[target] - subscriptionPrize[level];
|
||||
return (bias / 30) * days;
|
||||
const bias = getPlanPrice(target) - getPlanPrice(level);
|
||||
const v = (bias / 30) * days;
|
||||
return v > 0 ? v + 1 : 0; // time count offset
|
||||
}
|
||||
|
||||
type UpgradeProps = {
|
||||
base: number;
|
||||
level: number;
|
||||
current: number;
|
||||
};
|
||||
|
||||
async function callBuyAction(
|
||||
@ -118,7 +119,7 @@ async function callMigrateAction(
|
||||
return res.status;
|
||||
}
|
||||
|
||||
export function Upgrade({ base, level }: UpgradeProps) {
|
||||
export function Upgrade({ level, current }: UpgradeProps) {
|
||||
const { t } = useTranslation();
|
||||
const expired = useSelector(expiredSelector);
|
||||
const [open, setOpen] = React.useState(false);
|
||||
@ -126,10 +127,10 @@ export function Upgrade({ base, level }: UpgradeProps) {
|
||||
const dispatch = useDispatch();
|
||||
const { toast } = useToast();
|
||||
|
||||
const isCurrent = useMemo(() => level === base, [level, base]);
|
||||
const isUpgrade = useMemo(() => level < base, [level, base]);
|
||||
const isCurrent = useMemo(() => current === level, [current, level]);
|
||||
const isUpgrade = useMemo(() => current < level, [current, level]);
|
||||
|
||||
return level === 0 || level === base ? (
|
||||
return current === 0 || current === level ? (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button className={`action`} variant={`default`}>
|
||||
@ -169,13 +170,13 @@ export function Upgrade({ base, level }: UpgradeProps) {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className={`price`}>
|
||||
{t("sub.price", { price: countPrize(base, month).toFixed(2) })}
|
||||
{t("sub.price", { price: countPrice(level, month).toFixed(2) })}
|
||||
|
||||
{useDeeptrain && (
|
||||
<span className={`tax`}>
|
||||
(
|
||||
{t("sub.price-tax", {
|
||||
price: (countPrize(base, month) * 0.25).toFixed(1),
|
||||
price: (countPrice(level, month) * 0.25).toFixed(1),
|
||||
})}
|
||||
)
|
||||
</span>
|
||||
@ -189,7 +190,7 @@ export function Upgrade({ base, level }: UpgradeProps) {
|
||||
<Button
|
||||
className={`mb-1.5`}
|
||||
onClick={async () => {
|
||||
const res = await callBuyAction(t, toast, dispatch, month, base);
|
||||
const res = await callBuyAction(t, toast, dispatch, month, level);
|
||||
if (res) {
|
||||
setOpen(false);
|
||||
await refreshSubscription(dispatch);
|
||||
@ -222,7 +223,7 @@ export function Upgrade({ base, level }: UpgradeProps) {
|
||||
{isUpgrade && (
|
||||
<p className={`price`}>
|
||||
{t("sub.upgrade-price", {
|
||||
price: countUpgradePrize(level, base, expired).toFixed(2),
|
||||
price: countUpgradePrice(current, level, expired).toFixed(2),
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
@ -234,7 +235,7 @@ export function Upgrade({ base, level }: UpgradeProps) {
|
||||
<Button
|
||||
className={`mb-1.5`}
|
||||
onClick={async () => {
|
||||
const res = await callMigrateAction(t, toast, base);
|
||||
const res = await callMigrateAction(t, toast, level);
|
||||
if (res) {
|
||||
setOpen(false);
|
||||
await refreshSubscription(dispatch);
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { SubscriptionIcon } from "@/conf/subscription.tsx";
|
||||
import React from "react";
|
||||
import Icon from "@/components/utils/Icon.tsx";
|
||||
|
||||
type UsageProps = {
|
||||
icon: React.ReactElement;
|
||||
icon: string | React.ReactElement;
|
||||
name: string;
|
||||
usage:
|
||||
| {
|
||||
@ -17,7 +18,11 @@ function SubscriptionUsage({ icon, name, usage }: UsageProps) {
|
||||
return (
|
||||
usage && (
|
||||
<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`} />
|
||||
)}
|
||||
{name}
|
||||
<div className={`grow`} />
|
||||
{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 { useEffectAsync } from "@/utils/hook.ts";
|
||||
import { selectInit } from "@/store/auth.ts";
|
||||
import { docsEndpoint } from "@/utils/env.ts";
|
||||
import { docsEndpoint } from "@/conf/env.ts";
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogCancel,
|
||||
|
@ -23,7 +23,7 @@ import { Separator } from "@/components/ui/separator.tsx";
|
||||
import { Badge } from "@/components/ui/badge.tsx";
|
||||
import { useEffectAsync } from "@/utils/hook.ts";
|
||||
import { selectAuthenticated } from "@/store/auth.ts";
|
||||
import { deeptrainEndpoint, useDeeptrain } from "@/utils/env.ts";
|
||||
import { deeptrainEndpoint, useDeeptrain } from "@/conf/env.ts";
|
||||
|
||||
function PackageDialog() {
|
||||
const { t } = useTranslation();
|
||||
|
@ -39,7 +39,7 @@ import { useToast } from "@/components/ui/use-toast.ts";
|
||||
import { useEffectAsync } from "@/utils/hook.ts";
|
||||
import { selectAuthenticated } from "@/store/auth.ts";
|
||||
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 { cn } from "@/components/ui/lib/utils.ts";
|
||||
|
||||
|
@ -24,7 +24,7 @@ import {
|
||||
import { Checkbox } from "@/components/ui/checkbox.tsx";
|
||||
import { useEffect, useState } from "react";
|
||||
import { getMemoryPerformance } from "@/utils/app.ts";
|
||||
import { version } from "@/conf.ts";
|
||||
import { version } from "@/conf";
|
||||
import { NumberInput } from "@/components/ui/number-input.tsx";
|
||||
import {
|
||||
Select,
|
||||
|
@ -22,22 +22,68 @@ import {
|
||||
openDialog as openQuotaDialog,
|
||||
dialogSelector as quotaDialogSelector,
|
||||
} from "@/store/quota.ts";
|
||||
import {
|
||||
Award,
|
||||
BookText,
|
||||
Calendar,
|
||||
Compass,
|
||||
ImagePlus,
|
||||
LifeBuoy,
|
||||
ServerCrash,
|
||||
} from "lucide-react";
|
||||
import { Calendar } from "lucide-react";
|
||||
import { useEffectAsync } from "@/utils/hook.ts";
|
||||
import { selectAuthenticated } from "@/store/auth.ts";
|
||||
import SubscriptionUsage from "@/components/home/subscription/SubscriptionUsage.tsx";
|
||||
import Tips from "@/components/Tips.tsx";
|
||||
import { subscriptionPrize, subscriptionUsage } from "@/conf.ts";
|
||||
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() {
|
||||
const { t } = useTranslation();
|
||||
@ -49,6 +95,8 @@ function SubscriptionDialog() {
|
||||
const auth = useSelector(selectAuthenticated);
|
||||
const quota = useSelector(quotaDialogSelector);
|
||||
|
||||
const plan = useMemo(() => getPlan(level), [level]);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
useEffectAsync(async () => {
|
||||
if (!auth) return;
|
||||
@ -84,12 +132,13 @@ function SubscriptionDialog() {
|
||||
usage={expired}
|
||||
/>
|
||||
|
||||
{Object.entries(subscriptionUsage).map(
|
||||
([key, props], index) =>
|
||||
usage?.[key] && (
|
||||
{plan.items.map(
|
||||
(item, index) =>
|
||||
usage?.[item.id] && (
|
||||
<SubscriptionUsage
|
||||
{...props}
|
||||
usage={usage?.[key]}
|
||||
name={item.name}
|
||||
icon={item.icon}
|
||||
usage={usage?.[item.id]}
|
||||
key={index}
|
||||
/>
|
||||
),
|
||||
@ -97,110 +146,9 @@ function SubscriptionDialog() {
|
||||
</div>
|
||||
)}
|
||||
<div className={`plan-wrapper`}>
|
||||
<div className={`plan basic`}>
|
||||
<div className={`title`}>{t("sub.base")}</div>
|
||||
<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>
|
||||
{subscriptionData.map((item, index) => (
|
||||
<PlanItem key={index} level={item.level} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</DialogDescription>
|
||||
|
@ -1,10 +1,10 @@
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App.tsx";
|
||||
import "./conf.ts";
|
||||
import "./conf";
|
||||
import "./i18n.ts";
|
||||
import "./assets/main.less";
|
||||
import "./assets/globals.less";
|
||||
import "./conf.ts";
|
||||
import "./conf";
|
||||
import ReloadPrompt from "./components/ReloadService.tsx";
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
|
@ -92,7 +92,8 @@
|
||||
"title": "模型市场",
|
||||
"model": "探索更多模型",
|
||||
"explore": "探索",
|
||||
"search": "搜索模型名称或者简介"
|
||||
"search": "搜索模型名称或者简介",
|
||||
"model-api": "API 请求的模型 ID 名称"
|
||||
},
|
||||
"conversation": {
|
||||
"title": "对话",
|
||||
@ -181,20 +182,8 @@
|
||||
"pro": "专业版",
|
||||
"plan-price": "{{money}} 元/月",
|
||||
"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}}",
|
||||
"plan-usage": "{{name}} 每月使用 {{times}} 次",
|
||||
"plan-tip": "可调用模型",
|
||||
"enterprise": "企业版",
|
||||
"enterprise-service": "优先技术支持",
|
||||
"enterprise-sla": "SLA 保障",
|
||||
@ -446,7 +435,7 @@
|
||||
"retry-tip": "当渠道请求失败时,最多重试的次数",
|
||||
"model": "模型",
|
||||
"secret": "密钥",
|
||||
"secret-placeholder": "请输入密钥,格式:{{format}}\n多个密钥时,一行一个,请求时随机选取负载",
|
||||
"secret-placeholder": "请输入密钥,格式:{{format}} (<>不用填)\n多个密钥时,一行一个,请求时随机选取负载",
|
||||
"endpoint": "接入点",
|
||||
"endpoint-placeholder": "请输入接入点(即代理)",
|
||||
"mapper": "模型映射",
|
||||
|
@ -141,20 +141,6 @@
|
||||
"pro": "Pro",
|
||||
"plan-price": "{{money}} CNY/Month",
|
||||
"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-service": "Priority Service Support",
|
||||
"enterprise-sla": "SLA Guarantee",
|
||||
@ -190,7 +176,9 @@
|
||||
"failed": "Subscribe failed",
|
||||
"failed-prompt": "Failed to subscribe, please make sure you have enough balance.",
|
||||
"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",
|
||||
"confirm": "Confirm",
|
||||
@ -372,7 +360,7 @@
|
||||
"retry-tip": "When the channel request fails, the maximum number of retries",
|
||||
"model": "Model",
|
||||
"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-placeholder": "Please enter the endpoint (ie proxy)",
|
||||
"mapper": "Model Mapper",
|
||||
|
@ -141,20 +141,6 @@
|
||||
"pro": "プロ",
|
||||
"plan-price": "{{money}}元/月",
|
||||
"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-service": "優先技術サポート",
|
||||
"enterprise-sla": "SLA保護",
|
||||
@ -190,7 +176,9 @@
|
||||
"failed": "サブスクリプションに失敗しました",
|
||||
"failed-prompt": "サブスクリプションに失敗しました。十分な残高があることを確認してください。",
|
||||
"migrate-failed": "変更できませんでした",
|
||||
"migrate-failed-prompt": "サブスクリプションの変更に失敗しました。"
|
||||
"migrate-failed-prompt": "サブスクリプションの変更に失敗しました。",
|
||||
"plan-usage": "{{name}}は月に{{times}}回使用",
|
||||
"plan-tip": "呼び出し可能なモデル"
|
||||
},
|
||||
"cancel": "キャンセル",
|
||||
"confirm": "確認",
|
||||
|
@ -141,20 +141,6 @@
|
||||
"pro": "Профессиональный",
|
||||
"plan-price": "{{money}} CNY/месяц",
|
||||
"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-service": "Приоритетная служба поддержки",
|
||||
"enterprise-sla": "Гарантия SLA",
|
||||
@ -190,7 +176,9 @@
|
||||
"failed": "Подписка не удалась",
|
||||
"failed-prompt": "Не удалось подписаться, пожалуйста, убедитесь, что у вас достаточно баланса.",
|
||||
"migrate-failed": "Перенос подписки не удался",
|
||||
"migrate-failed-prompt": "Ваша подписка не удалась."
|
||||
"migrate-failed-prompt": "Ваша подписка не удалась.",
|
||||
"plan-usage": "{{name}} использует {{times}} раз в месяц",
|
||||
"plan-tip": "Вызываемая модель"
|
||||
},
|
||||
"cancel": "Отмена",
|
||||
"confirm": "Подтвердить",
|
||||
|
@ -8,7 +8,7 @@ import Home from "./routes/Home.tsx";
|
||||
import NotFound from "./routes/NotFound.tsx";
|
||||
import Auth from "./routes/Auth.tsx";
|
||||
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 Forgot from "@/routes/Forgot.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 { selectModel, selectWeb, setWeb } from "@/store/chat.ts";
|
||||
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 { Progress } from "@/components/ui/progress.tsx";
|
||||
import { cn } from "@/components/ui/lib/utils.ts";
|
||||
@ -76,7 +76,7 @@ function ArticleContent() {
|
||||
|
||||
function generate() {
|
||||
setProgress(true);
|
||||
const connection = new WebSocket(`${ws_api}/article/create`);
|
||||
const connection = new WebSocket(`${websocketEndpoint}/article/create`);
|
||||
|
||||
connection.onopen = () => {
|
||||
connection.send(
|
||||
@ -122,7 +122,7 @@ function ArticleContent() {
|
||||
variant={`outline`}
|
||||
className={`mt-5 w-full mr-2`}
|
||||
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`}
|
||||
className={`mt-5 w-full ml-2`}
|
||||
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 { ToastAction } from "@/components/ui/toast.tsx";
|
||||
import { tokenField } from "@/conf.ts";
|
||||
import { tokenField } from "@/conf";
|
||||
import { useEffect, useReducer } from "react";
|
||||
import Loader from "@/components/Loader.tsx";
|
||||
import "@/assets/pages/auth.less";
|
||||
@ -10,7 +10,7 @@ import router from "@/router.tsx";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getQueryParam } from "@/utils/path.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 { goAuth } from "@/utils/app.ts";
|
||||
import { Label } from "@/components/ui/label.tsx";
|
||||
|
@ -14,7 +14,7 @@ import Require, {
|
||||
import { Input } from "@/components/ui/input.tsx";
|
||||
import { Button } from "@/components/ui/button.tsx";
|
||||
import TickButton from "@/components/TickButton.tsx";
|
||||
import { appLogo } from "@/utils/env.ts";
|
||||
import { appLogo } from "@/conf/env.ts";
|
||||
|
||||
function Forgot() {
|
||||
const { t } = useTranslation();
|
||||
|
@ -3,7 +3,7 @@ import { useSelector } from "react-redux";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "@/components/ui/button.tsx";
|
||||
import { ChevronLeft, Cloud, FileDown, Send } from "lucide-react";
|
||||
import { rest_api } from "@/conf.ts";
|
||||
import { apiEndpoint } from "@/conf";
|
||||
import router from "@/router.tsx";
|
||||
import { Input } from "@/components/ui/input.tsx";
|
||||
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 { selectModel } from "@/store/chat.ts";
|
||||
import ModelFinder from "@/components/home/ModelFinder.tsx";
|
||||
import { appLogo } from "@/utils/env.ts";
|
||||
import { appLogo } from "@/conf/env.ts";
|
||||
|
||||
type WrapperProps = {
|
||||
onSend?: (value: string, model: string) => boolean;
|
||||
@ -111,14 +111,14 @@ function Wrapper({ onSend }: WrapperProps) {
|
||||
<div className={`hash-box`}>
|
||||
<a
|
||||
className={`download-box`}
|
||||
href={`${rest_api}/generation/download/tar?hash=${hash}`}
|
||||
href={`${apiEndpoint}/generation/download/tar?hash=${hash}`}
|
||||
>
|
||||
<FileDown className={`h-6 w-6`} />
|
||||
<p>{t("generate.download", { name: "tar.gz" })}</p>
|
||||
</a>
|
||||
<a
|
||||
className={`download-box`}
|
||||
href={`${rest_api}/generation/download/zip?hash=${hash}`}
|
||||
href={`${apiEndpoint}/generation/download/zip?hash=${hash}`}
|
||||
>
|
||||
<FileDown className={`h-6 w-6`} />
|
||||
<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 { validateToken } from "@/store/auth.ts";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { appLogo, appName } from "@/utils/env.ts";
|
||||
import { appLogo, appName } from "@/conf/env.ts";
|
||||
|
||||
type CompProps = {
|
||||
form: RegisterForm;
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
useState,
|
||||
} from "react";
|
||||
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 { Input } from "@/components/ui/input.tsx";
|
||||
import { GripVertical, HelpCircle, Plus, Trash2 } from "lucide-react";
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { tokenField } from "@/conf.ts";
|
||||
import { tokenField } from "@/conf";
|
||||
import { AppDispatch, RootState } from "./index.ts";
|
||||
import { forgetMemory, setMemory } from "@/utils/memory.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 { insertStart } from "@/utils/base.ts";
|
||||
import { AppDispatch, RootState } from "./index.ts";
|
||||
import { planModels, supportModels } from "@/conf.ts";
|
||||
import { supportModels } from "@/conf";
|
||||
import {
|
||||
getArrayMemory,
|
||||
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 {
|
||||
if (supportModels.length === 0) return "";
|
||||
return model && inModel(model) ? model : supportModels[0].id;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import router from "@/router.tsx";
|
||||
import { useDeeptrain } from "@/utils/env.ts";
|
||||
import { login } from "@/conf.ts";
|
||||
import { useDeeptrain } from "@/conf/env.ts";
|
||||
import { goDeepLogin } from "@/conf/deeptrain.ts";
|
||||
|
||||
export let event: BeforeInstallPromptEvent | undefined;
|
||||
|
||||
@ -52,5 +52,5 @@ export function navigate(path: string): 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();
|
||||
|
||||
window.addEventListener("resize", () => {
|
||||
@ -11,3 +14,29 @@ export function isMobile(): boolean {
|
||||
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(
|
||||
el: HTMLElement,
|
||||
el: Window | HTMLElement,
|
||||
events: string[],
|
||||
handler: EventListenerOrEventListenerObject,
|
||||
): () => void {
|
||||
|
@ -50,6 +50,10 @@ func (c *Connection) GetStack() Stack {
|
||||
|
||||
func (c *Connection) ReadWorker() {
|
||||
for {
|
||||
if c.IsClosed() {
|
||||
break
|
||||
}
|
||||
|
||||
form := utils.ReadForm[conversation.FormMessage](c.conn)
|
||||
if form == nil {
|
||||
break
|
||||
@ -61,6 +65,8 @@ func (c *Connection) ReadWorker() {
|
||||
|
||||
c.Write(form)
|
||||
}
|
||||
|
||||
c.Stop()
|
||||
}
|
||||
|
||||
func (c *Connection) Write(data *conversation.FormMessage) {
|
||||
@ -70,6 +76,14 @@ func (c *Connection) Write(data *conversation.FormMessage) {
|
||||
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 {
|
||||
form := <-c.stack
|
||||
return form
|
||||
|
@ -8,13 +8,18 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type WebSocket struct {
|
||||
Ctx *gin.Context
|
||||
Conn *websocket.Conn
|
||||
MaxTimeout time.Duration
|
||||
Closed bool
|
||||
}
|
||||
|
||||
var defaultMaxTimeout = 15 * time.Minute
|
||||
|
||||
func CheckUpgrader(c *gin.Context, strict bool) *websocket.Upgrader {
|
||||
return &websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
@ -40,10 +45,12 @@ func NewWebsocket(c *gin.Context, strict bool) *WebSocket {
|
||||
})
|
||||
return nil
|
||||
} else {
|
||||
return &WebSocket{
|
||||
instance := &WebSocket{
|
||||
Ctx: c,
|
||||
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 {
|
||||
return nil
|
||||
} else {
|
||||
return &WebSocket{
|
||||
instance := &WebSocket{
|
||||
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) {
|
||||
return w.Conn.ReadMessage()
|
||||
}
|
||||
@ -127,6 +160,14 @@ func (w *WebSocket) GetCache() *redis.Client {
|
||||
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 {
|
||||
// golang cannot use generic type in class-like struct
|
||||
// except ping
|
||||
|
Loading…
Reference in New Issue
Block a user