Skip to content

Commit

Permalink
Merge branch 'chatgpt-web-dev:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
InternetBugs committed May 18, 2024
2 parents 48aa1a2 + c8b71c8 commit 8bb765f
Show file tree
Hide file tree
Showing 20 changed files with 61 additions and 177 deletions.
10 changes: 0 additions & 10 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
module.exports = {
root: true,
extends: ['@antfu'],
rules: {
'antfu/top-level-function': 'off',
'@typescript-eslint/consistent-type-imports': 'off',
'@stylistic/ts/member-delimiter-style': 'off',
'@stylistic/ts/indent': 'off',
'@stylistic/js/no-tabs': 'off',
'vue/no-unused-refs': 'off',
'import/newline-after-import': 'off',
'unicorn/prefer-number-properties': 'off',
},
ignorePatterns: [
'vite.config.ts',
'tsconfig.json',
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ coverage

# Environment variables files
/service/.env
/docker-compose/nginx/html
/docker-compose/nginx/html
106 changes: 0 additions & 106 deletions service/src/chatgpt/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as console from 'node:console'
import * as dotenv from 'dotenv'
import 'isomorphic-fetch'
import type { ChatGPTAPIOptions, ChatMessage, SendMessageOptions } from 'chatgpt'
Expand All @@ -7,7 +6,6 @@ import { SocksProxyAgent } from 'socks-proxy-agent'
import httpsProxyAgent from 'https-proxy-agent'
import fetch from 'node-fetch'
import jwt_decode from 'jwt-decode'
import dayjs from 'dayjs'
import type { AuditConfig, KeyConfig, UserInfo } from '../storage/model'
import { Status } from '../storage/model'
import { convertImageUrl } from '../utils/image'
Expand Down Expand Up @@ -253,112 +251,8 @@ async function containsSensitiveWords(audit: AuditConfig, text: string): Promise
return false
}

async function fetchAccessTokenExpiredTime() {
const config = await getCacheConfig()
const jwt = jwt_decode(config.accessToken) as JWT
if (jwt.exp)
return dayjs.unix(jwt.exp).format('YYYY-MM-DD HH:mm:ss')
return '-'
}

let cachedBalance: number | undefined
let cacheExpiration = 0

async function fetchBalance() {
const now = new Date().getTime()
if (cachedBalance && cacheExpiration > now)
return Promise.resolve(cachedBalance.toFixed(3))

// 计算起始日期和结束日期
const startDate = new Date(now - 90 * 24 * 60 * 60 * 1000)
const endDate = new Date(now + 24 * 60 * 60 * 1000)

const config = await getCacheConfig()
const OPENAI_API_KEY = config.apiKey
const OPENAI_API_BASE_URL = config.apiBaseUrl

if (!isNotEmptyString(OPENAI_API_KEY))
return Promise.resolve('-')

const API_BASE_URL = isNotEmptyString(OPENAI_API_BASE_URL)
? OPENAI_API_BASE_URL
: 'https://api.openai.com'

// 查是否订阅
const urlSubscription = `${API_BASE_URL}/v1/dashboard/billing/subscription`
// 查普通账单
// const urlBalance = `${API_BASE_URL}/dashboard/billing/credit_grants`
// 查使用量
const urlUsage = `${API_BASE_URL}/v1/dashboard/billing/usage?start_date=${formatDate(startDate)}&end_date=${formatDate(endDate)}`

const headers = {
'Authorization': `Bearer ${OPENAI_API_KEY}`,
'Content-Type': 'application/json',
}
let socksAgent
let httpsAgent
if (isNotEmptyString(config.socksProxy)) {
socksAgent = new SocksProxyAgent({
hostname: config.socksProxy.split(':')[0],
port: Number.parseInt(config.socksProxy.split(':')[1]),
userId: isNotEmptyString(config.socksAuth) ? config.socksAuth.split(':')[0] : undefined,
password: isNotEmptyString(config.socksAuth) ? config.socksAuth.split(':')[1] : undefined,
})
}
else if (isNotEmptyString(config.httpsProxy)) {
httpsAgent = new HttpsProxyAgent(config.httpsProxy)
}

try {
// 获取API限额
let response = await fetch(urlSubscription, { agent: socksAgent === undefined ? httpsAgent : socksAgent, headers })
if (!response.ok) {
console.error('您的账户已被封禁,请登录OpenAI进行查看。')
return
}
interface SubscriptionData {
hard_limit_usd?: number
// 这里可以添加其他可能的属性
}
const subscriptionData: SubscriptionData = await response.json()
const totalAmount = subscriptionData.hard_limit_usd

interface UsageData {
total_usage?: number
// 这里可以添加其他可能的属性
}

// 获取已使用量
response = await fetch(urlUsage, { agent: socksAgent === undefined ? httpsAgent : socksAgent, headers })
const usageData: UsageData = await response.json()
const totalUsage = usageData.total_usage / 100

// 计算剩余额度
cachedBalance = totalAmount - totalUsage
cacheExpiration = now + 60 * 60 * 1000

return Promise.resolve(cachedBalance.toFixed(3))
}
catch (error) {
globalThis.console.error(error)
return Promise.resolve('-')
}
}

function formatDate(date) {
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')

return `${year}-${month}-${day}`
}

async function chatConfig() {
const config = await getOriginConfig() as ModelConfig
// if (config.apiModel === 'ChatGPTAPI')
// config.balance = await fetchBalance()
// else
// config.accessTokenExpiredTime = await fetchAccessTokenExpiredTime()
return sendResponse<ModelConfig>({
type: 'Success',
data: config,
Expand Down
22 changes: 11 additions & 11 deletions src/components/common/PromptStore/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const modalMode = ref('')
const tempModifiedItem = ref<any>({})
// 添加修改导入都使用一个Modal, 临时修改内容占用tempPromptKey,切换状态前先将内容都清楚
const changeShowModal = (mode: 'add' | 'modify' | 'local_import', selected = { key: '', value: '' }) => {
function changeShowModal(mode: 'add' | 'modify' | 'local_import', selected = { key: '', value: '' }) {
if (mode === 'add') {
tempPromptKey.value = ''
tempPromptValue.value = ''
Expand All @@ -82,15 +82,15 @@ const changeShowModal = (mode: 'add' | 'modify' | 'local_import', selected = { k
// 在线导入相关
const downloadURL = ref('')
const downloadDisabled = computed(() => downloadURL.value.trim().length < 1)
const setDownloadURL = (url: string) => {
function setDownloadURL(url: string) {
downloadURL.value = url
}
// 控制 input 按钮
const inputStatus = computed (() => tempPromptKey.value.trim().length < 1 || tempPromptValue.value.trim().length < 1)
// Prompt模板相关操作
const addPromptTemplate = () => {
function addPromptTemplate() {
for (const i of promptList.value) {
if (i.key === tempPromptKey.value) {
message.error(t('store.addRepeatTitleTips'))
Expand All @@ -106,7 +106,7 @@ const addPromptTemplate = () => {
changeShowModal('add')
}
const modifyPromptTemplate = () => {
function modifyPromptTemplate() {
let index = 0
// 通过临时索引把待修改项摘出来
Expand Down Expand Up @@ -135,19 +135,19 @@ const modifyPromptTemplate = () => {
changeShowModal('modify')
}
const deletePromptTemplate = (row: { key: string; value: string }) => {
function deletePromptTemplate(row: { key: string; value: string }) {
promptList.value = [
...promptList.value.filter((item: { key: string; value: string }) => item.key !== row.key),
] as never
message.success(t('common.deleteSuccess'))
}
const clearPromptTemplate = () => {
function clearPromptTemplate() {
promptList.value = []
message.success(t('common.clearSuccess'))
}
const importPromptTemplate = (from = 'online') => {
function importPromptTemplate(from = 'online') {
try {
const jsonData = JSON.parse(tempPromptValue.value)
let key = ''
Expand Down Expand Up @@ -196,7 +196,7 @@ const importPromptTemplate = (from = 'online') => {
}
// 模板导出
const exportPromptTemplate = () => {
function exportPromptTemplate() {
exportLoading.value = true
const jsonDataStr = JSON.stringify(promptList.value)
const blob = new Blob([jsonDataStr], { type: 'application/json' })
Expand All @@ -210,7 +210,7 @@ const exportPromptTemplate = () => {
}
// 模板在线导入
const downloadPromptTemplate = async () => {
async function downloadPromptTemplate() {
try {
importLoading.value = true
const response = await fetch(downloadURL.value)
Expand Down Expand Up @@ -239,7 +239,7 @@ const downloadPromptTemplate = async () => {
}
// 移动端自适应相关
const renderTemplate = () => {
function renderTemplate() {
const [keyLimit, valueLimit] = isMobile.value ? [10, 30] : [15, 50]
return promptList.value.map((item: { key: string; value: string }) => {
Expand All @@ -260,7 +260,7 @@ const pagination = computed(() => {
})
// table相关
const createColumns = (): DataTableColumns<DataProps> => {
function createColumns(): DataTableColumns<DataProps> {
return [
{
title: t('store.title'),
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/Setting/Anonuncement.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang='ts'>
import { onMounted, ref } from 'vue'
import { NButton, NInput, NSpin, NSwitch, useMessage } from 'naive-ui'
import { AnnounceConfig, ConfigState } from './model'
import type { AnnounceConfig, ConfigState } from './model'
import { fetchChatConfig, fetchUpdateAnnounce } from '@/api'
import { t } from '@/locales'
Expand Down
3 changes: 1 addition & 2 deletions src/components/common/Setting/Audit.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<script setup lang='ts'>
import { onMounted, ref } from 'vue'
import { NButton, NInput, NSelect, NSpin, NSwitch, useMessage } from 'naive-ui'
import type { AuditConfig, ConfigState } from './model'
import { TextAuditServiceProvider } from './model'
import type { AuditConfig, ConfigState, TextAuditServiceProvider } from './model'
import { fetchChatConfig, fetchTestAudit, fetchUpdateAudit } from '@/api'
import { t } from '@/locales'
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/Setting/Gift.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ function parseCSV(content: string) {
return giftCards
}
function handleUploadChange(data: { file: UploadFileInfo, fileList: Array<UploadFileInfo>, event?: Event }) {
function handleUploadChange(data: { file: UploadFileInfo; fileList: Array<UploadFileInfo>; event?: Event }) {
fileListRef.value = data.fileList
csvData.value = []
if (data.event) {
Expand Down
3 changes: 1 addition & 2 deletions src/components/common/Setting/Keys.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const handleSaving = ref(false)
const keyConfig = ref(new KeyConfig('', 'ChatGPTAPI', [], [], ''))
const keys = ref([])
const createColumns = (): DataTableColumns => {
function createColumns(): DataTableColumns {
return [
{
title: 'Key',
Expand Down Expand Up @@ -226,7 +226,6 @@ onMounted(async () => {
</NButton>
</NSpace>
<NDataTable
ref="table"
remote
:loading="loading"
:row-key="(rowData) => rowData._id"
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/Setting/Site.vue
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ onMounted(() => {
/>
</div>
</div>
<!-- 增加新注册用户的全局数量设置 -->
<!-- 增加新注册用户的全局数量设置 -->
<div class="flex items-center space-x-4">
<span class="flex-shrink-0 w-[100px]">{{ $t('setting.globalAmount') }}</span>
<div class="flex-1">
Expand Down
3 changes: 1 addition & 2 deletions src/components/common/Setting/User.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const userRef = ref(new UserInfo([UserRole.User]))
const users = ref([])
const createColumns = (): DataTableColumns => {
function createColumns(): DataTableColumns {
return [
{
title: 'Email',
Expand Down Expand Up @@ -279,7 +279,6 @@ onMounted(async () => {
</NButton>
</NSpace>
<NDataTable
ref="table"
remote
:loading="loading"
:row-key="(rowData) => rowData._id"
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/Setting/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const apiModelOptions = ['ChatGPTAPI', 'ChatGPTUnofficialProxyAPI'].map((
}
})

export const userRoleOptions = Object.values(UserRole).filter(d => isNaN(Number(d))).map((role) => {
export const userRoleOptions = Object.values(UserRole).filter(d => Number.isNaN(Number(d))).map((role) => {
return {
label: role as string,
key: role as string,
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useIconRender.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { h } from 'vue'
import { SvgIcon } from '@/components/common'

export const useIconRender = () => {
export function useIconRender() {
interface IconConfig {
icon?: string
color?: string
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/scrollbarStyle.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { darkTheme, lightTheme } from 'naive-ui'

const setupScrollbarStyle = () => {
function setupScrollbarStyle() {
const style = document.createElement('style')
const styleContent = `
::-webkit-scrollbar {
Expand Down
2 changes: 1 addition & 1 deletion src/typings/chat.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ declare namespace Chat {

interface ChatState {
active: number | null
usingContext: boolean;
usingContext: boolean
history: History[]
chat: { uuid: number; data: Chat[] }[]
}
Expand Down
8 changes: 4 additions & 4 deletions src/typings/env.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/// <reference types="vite/client" />

interface ImportMetaEnv {
readonly VITE_GLOB_API_URL: string;
readonly VITE_APP_API_BASE_URL: string;
readonly VITE_GLOB_OPEN_LONG_REPLY: string;
readonly VITE_GLOB_APP_PWA: string;
readonly VITE_GLOB_API_URL: string
readonly VITE_APP_API_BASE_URL: string
readonly VITE_GLOB_OPEN_LONG_REPLY: string
readonly VITE_GLOB_APP_PWA: string
}
8 changes: 4 additions & 4 deletions src/typings/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
interface Window {
$loadingBar?: import('naive-ui').LoadingBarProviderInst;
$dialog?: import('naive-ui').DialogProviderInst;
$message?: import('naive-ui').MessageProviderInst;
$notification?: import('naive-ui').NotificationProviderInst;
$loadingBar?: import('naive-ui').LoadingBarProviderInst
$dialog?: import('naive-ui').DialogProviderInst
$message?: import('naive-ui').MessageProviderInst
$notification?: import('naive-ui').NotificationProviderInst
}
Loading

0 comments on commit 8bb765f

Please sign in to comment.