mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-14 20:41:15 +08:00
feat: add key
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
import { memo, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react'
|
||||
import type { RefObject } from 'react'
|
||||
import { Box, useTheme } from '@mui/material'
|
||||
import { Editor, useMonaco } from '@monaco-editor/react'
|
||||
import { type editor as MonacoEditor } from 'monaco-editor'
|
||||
import { IconButton } from '../IconButton'
|
||||
import { message } from 'antd'
|
||||
import { $t } from '@common/locales'
|
||||
import { RESPONSE_TIPS } from '@common/const/const'
|
||||
import { $t } from '@common/locales'
|
||||
import { Editor, useMonaco } from '@monaco-editor/react'
|
||||
import { Box, useTheme } from '@mui/material'
|
||||
import { message } from 'antd'
|
||||
import { type editor as MonacoEditor } from 'monaco-editor'
|
||||
import type { RefObject } from 'react'
|
||||
import { memo, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react'
|
||||
import { IconButton } from '../IconButton'
|
||||
|
||||
export interface CodeboxApiRef {
|
||||
insertCode: (value: string) => void
|
||||
|
||||
@@ -20,124 +20,118 @@ type AiSettingModalContentField = {
|
||||
defaultLlm: string
|
||||
}
|
||||
|
||||
const AiSettingModalContent = forwardRef<AiSettingModalContentHandle, AiSettingModalContentProps>(
|
||||
(props, ref) => {
|
||||
const [form] = Form.useForm()
|
||||
const { message } = App.useApp()
|
||||
const { entity, readOnly } = props
|
||||
const { fetchData } = useFetch()
|
||||
const [llmList, setLlmList] = useState<AiProviderLlmsItems[]>()
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
const AiSettingModalContent = forwardRef<AiSettingModalContentHandle, AiSettingModalContentProps>((props, ref) => {
|
||||
const [form] = Form.useForm()
|
||||
const { message } = App.useApp()
|
||||
const { entity, readOnly } = props
|
||||
const { fetchData } = useFetch()
|
||||
const [llmList, setLlmList] = useState<AiProviderLlmsItems[]>()
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
|
||||
const getLlmList = () => {
|
||||
setLoading(true)
|
||||
fetchData<BasicResponse<{ llms: AiProviderLlmsItems[] }>>(`ai/provider/llms`, {
|
||||
method: 'GET',
|
||||
eoParams: { provider: entity.id }
|
||||
const getLlmList = () => {
|
||||
setLoading(true)
|
||||
fetchData<BasicResponse<{ llms: AiProviderLlmsItems[] }>>(`ai/provider/llms`, {
|
||||
method: 'GET',
|
||||
eoParams: { provider: entity.id }
|
||||
})
|
||||
.then((response) => {
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
setLlmList(data.llms)
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
setLlmList(data.llms)
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getLlmList()
|
||||
try {
|
||||
form.setFieldsValue({
|
||||
defaultLlm: entity.defaultLlm,
|
||||
config: entity!.config ? JSON.stringify(JSON.parse(entity!.config), null, 2) : ''
|
||||
})
|
||||
} catch (e) {
|
||||
form.setFieldsValue({
|
||||
defaultLlm: entity.defaultLlm,
|
||||
config: ''
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
const save: () => Promise<boolean | string> = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
form
|
||||
.validateFields()
|
||||
.then(value => {
|
||||
fetchData<BasicResponse<null>>('ai/provider/config', {
|
||||
method: 'PUT',
|
||||
eoParams: { provider: entity?.id },
|
||||
eoBody: value,
|
||||
eoTransformKeys: ['defaultLlm']
|
||||
})
|
||||
.then(response => {
|
||||
const { code, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
message.success(msg || $t(RESPONSE_TIPS.success))
|
||||
resolve(true)
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
reject(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
})
|
||||
.catch(errorInfo => reject(errorInfo))
|
||||
})
|
||||
.catch(errorInfo => reject(errorInfo))
|
||||
.finally(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
save
|
||||
}))
|
||||
|
||||
return (
|
||||
<Form
|
||||
layout="vertical"
|
||||
labelAlign="left"
|
||||
scrollToFirstError
|
||||
form={form}
|
||||
className="flex flex-col mx-auto h-full"
|
||||
name="aiServiceInsideRouterModalConfig"
|
||||
autoComplete="off"
|
||||
>
|
||||
<Form.Item<AiSettingModalContentField>
|
||||
label={$t('模型')}
|
||||
name="defaultLlm"
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Select
|
||||
className="w-INPUT_NORMAL"
|
||||
placeholder={$t(PLACEHOLDER.select)}
|
||||
loading={loading}
|
||||
options={llmList?.map(x => ({
|
||||
value: x.id,
|
||||
label: (
|
||||
<div className="flex items-center gap-[10px]">
|
||||
<span>{x.id}</span>
|
||||
{x?.scopes?.map(s => <Tag>{s?.toLocaleUpperCase()}</Tag>)}
|
||||
</div>
|
||||
)
|
||||
}))}
|
||||
></Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item<AiSettingModalContentField> label={$t('参数')} name="config">
|
||||
<Codebox
|
||||
editorTheme="vs-dark"
|
||||
readOnly={readOnly}
|
||||
width="100%"
|
||||
height="300px"
|
||||
language="json"
|
||||
enableToolbar={false}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
getLlmList()
|
||||
try {
|
||||
form.setFieldsValue({
|
||||
defaultLlm: entity.defaultLlm,
|
||||
config: entity!.config ? JSON.stringify(JSON.parse(entity!.config), null, 2) : ''
|
||||
})
|
||||
} catch (e) {
|
||||
form.setFieldsValue({
|
||||
defaultLlm: entity.defaultLlm,
|
||||
config: ''
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
const save: () => Promise<boolean | string> = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
form
|
||||
.validateFields()
|
||||
.then((value) => {
|
||||
fetchData<BasicResponse<null>>('ai/provider/config', {
|
||||
method: 'PUT',
|
||||
eoParams: { provider: entity?.id },
|
||||
eoBody: value,
|
||||
eoTransformKeys: ['defaultLlm']
|
||||
})
|
||||
.then((response) => {
|
||||
const { code, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
message.success(msg || $t(RESPONSE_TIPS.success))
|
||||
resolve(true)
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
reject(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
})
|
||||
.catch((errorInfo) => reject(errorInfo))
|
||||
})
|
||||
.catch((errorInfo) => reject(errorInfo))
|
||||
})
|
||||
}
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
save
|
||||
}))
|
||||
|
||||
return (
|
||||
<Form
|
||||
layout="vertical"
|
||||
labelAlign="left"
|
||||
scrollToFirstError
|
||||
form={form}
|
||||
className="flex flex-col mx-auto h-full"
|
||||
name="aiServiceInsideRouterModalConfig"
|
||||
autoComplete="off"
|
||||
>
|
||||
<Form.Item<AiSettingModalContentField> label={$t('模型')} name="defaultLlm" rules={[{ required: true }]}>
|
||||
<Select
|
||||
className="w-INPUT_NORMAL"
|
||||
placeholder={$t(PLACEHOLDER.select)}
|
||||
loading={loading}
|
||||
options={llmList?.map((x) => ({
|
||||
value: x.id,
|
||||
label: (
|
||||
<div className="flex items-center gap-[10px]">
|
||||
<span>{x.id}</span>
|
||||
{x?.scopes?.map((s) => <Tag>{s?.toLocaleUpperCase()}</Tag>)}
|
||||
</div>
|
||||
)
|
||||
}))}
|
||||
></Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item<AiSettingModalContentField> label={$t('参数')} name="config">
|
||||
<Codebox
|
||||
editorTheme="vs-dark"
|
||||
readOnly={readOnly}
|
||||
width="100%"
|
||||
height="300px"
|
||||
language="json"
|
||||
enableToolbar={false}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
)
|
||||
})
|
||||
|
||||
export default AiSettingModalContent
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Codebox } from '@common/components/postcat/api/Codebox'
|
||||
import { BasicResponse, RESPONSE_TIPS, STATUS_CODE } from '@common/const/const'
|
||||
import { useFetch } from '@common/hooks/http'
|
||||
import { $t } from '@common/locales'
|
||||
import { AIProvider } from '@core/components/AIProviderSelect'
|
||||
import { DatePicker, Form, Input, Switch } from 'antd'
|
||||
import { App, DatePicker, Form, Input, Switch } from 'antd'
|
||||
import dayjs from 'dayjs'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react'
|
||||
import { EditAPIKey } from '../types'
|
||||
|
||||
interface ApiKeyContentProps {
|
||||
@@ -11,15 +13,19 @@ interface ApiKeyContentProps {
|
||||
entity: EditAPIKey
|
||||
}
|
||||
|
||||
const ApiKeyContent: React.FC<ApiKeyContentProps> = ({ provider, entity }) => {
|
||||
const ApiKeyContent: React.FC<ApiKeyContentProps> = forwardRef(({ provider, entity }, ref) => {
|
||||
const [form] = Form.useForm()
|
||||
const [neverExpire, setNeverExpire] = useState(true)
|
||||
const { fetchData } = useFetch()
|
||||
const { message } = App.useApp()
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
const isNeverExpire = entity.expire_time === '0'
|
||||
setNeverExpire(isNeverExpire)
|
||||
form.setFieldsValue({
|
||||
name: entity.name,
|
||||
expire_time: entity.expire_time === '0' ? 0 : dayjs(entity.expire_time),
|
||||
expire_time: isNeverExpire ? undefined : dayjs(entity.expire_time),
|
||||
config: entity.config
|
||||
})
|
||||
} catch (e) {
|
||||
@@ -29,23 +35,43 @@ const ApiKeyContent: React.FC<ApiKeyContentProps> = ({ provider, entity }) => {
|
||||
config: ''
|
||||
})
|
||||
}
|
||||
// setNeverExpire(entity.expire_time === '0')
|
||||
}, [])
|
||||
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
const values = await form.validateFields()
|
||||
// onSave({
|
||||
// ...values,
|
||||
// expire_time: neverExpire ? null : values.expire_time.format('YYYY-MM-DD HH:mm:ss')
|
||||
// })
|
||||
const { expire_time, ...restValues } = values
|
||||
const expireTime = neverExpire ? '0' : expire_time?.format('YYYY-MM-DD HH:mm:ss')
|
||||
|
||||
const [response, error] = await fetchData<BasicResponse<null>>('ai/resource/key', {
|
||||
method: 'POST',
|
||||
eoParams: { provider: provider?.id },
|
||||
eoBody: { ...restValues, expire_time: expireTime },
|
||||
eoTransformKeys: ['config']
|
||||
})
|
||||
|
||||
if (error) {
|
||||
console.error('API request failed:', error)
|
||||
message.error($t(RESPONSE_TIPS.error))
|
||||
throw error
|
||||
}
|
||||
|
||||
const { code, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
message.success(msg || $t(RESPONSE_TIPS.success))
|
||||
return true
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
throw new Error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Validation failed:', error)
|
||||
}
|
||||
}
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
handleOk
|
||||
}))
|
||||
const handleNeverExpireChange = (checked: boolean) => {
|
||||
console.log(checked)
|
||||
setNeverExpire(checked)
|
||||
if (!checked) {
|
||||
form.setFieldsValue({
|
||||
@@ -64,18 +90,17 @@ const ApiKeyContent: React.FC<ApiKeyContentProps> = ({ provider, entity }) => {
|
||||
editorTheme="vs-dark"
|
||||
readOnly={false}
|
||||
width="100%"
|
||||
height="300px"
|
||||
height="150px"
|
||||
language="json"
|
||||
enableToolbar={false}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label={$t('过期时间')} name="neverExpire" valuePropName="checked">
|
||||
<div className="flex items-center">
|
||||
<Switch onChange={handleNeverExpireChange} />
|
||||
<Switch onChange={handleNeverExpireChange} checked={neverExpire} />
|
||||
<span className="ml-2">{neverExpire ? $t('永不过期') : $t('设置过期时间')}</span>
|
||||
</div>
|
||||
</Form.Item>
|
||||
neverExpire:{neverExpire}
|
||||
{!neverExpire && (
|
||||
<Form.Item
|
||||
name="expire_time"
|
||||
@@ -87,6 +112,6 @@ const ApiKeyContent: React.FC<ApiKeyContentProps> = ({ provider, entity }) => {
|
||||
)}
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
export default ApiKeyContent
|
||||
|
||||
@@ -4,8 +4,10 @@ import InsidePage from '@common/components/aoplatform/InsidePage'
|
||||
import PageList, { PageProColumns } from '@common/components/aoplatform/PageList'
|
||||
import TableBtnWithPermission from '@common/components/aoplatform/TableBtnWithPermission'
|
||||
import { BasicResponse, RESPONSE_TIPS, STATUS_CODE } from '@common/const/const'
|
||||
import { useGlobalContext } from '@common/contexts/GlobalStateContext'
|
||||
import { useFetch } from '@common/hooks/http'
|
||||
import { $t } from '@common/locales'
|
||||
import { checkAccess } from '@common/utils/permission'
|
||||
import AIProviderSelect, { AIProvider } from '@core/components/AIProviderSelect'
|
||||
import { App, Divider, Space, Typography } from 'antd'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
@@ -22,6 +24,8 @@ const KeySettings: React.FC = () => {
|
||||
const [searchWord, setSearchWord] = useState<string>('')
|
||||
const [total, setTotal] = useState<number>(0)
|
||||
const modalRef = useRef<any>()
|
||||
const { accessData } = useGlobalContext()
|
||||
|
||||
useEffect(() => {
|
||||
pageListRef.current?.reload()
|
||||
}, [selectedProvider])
|
||||
@@ -63,9 +67,10 @@ const KeySettings: React.FC = () => {
|
||||
title: mode === 'add' ? $t(`添加 ${provider?.name} APIKey`) : $t('编辑 APIKey'),
|
||||
content: <ApiKeyContent ref={modalRef} entity={newEntity} provider={provider} />,
|
||||
onOk: () => {
|
||||
return modalRef.current?.save().then((res) => {
|
||||
// if (res === true) setAiConfigFlushed(true)
|
||||
// getAiSettingList()
|
||||
return modalRef.current?.handleOk().then((res) => {
|
||||
if (res === true) {
|
||||
pageListRef.current?.reload()
|
||||
}
|
||||
})
|
||||
},
|
||||
width: 600,
|
||||
@@ -84,7 +89,7 @@ const KeySettings: React.FC = () => {
|
||||
</a>
|
||||
<div>
|
||||
<CancelBtn />
|
||||
{/* {checkAccess('system.devops.ai_provider.edit', accessData) ? <OkBtn /> : null} */}
|
||||
{checkAccess('system.settings.ai_key_resource.manager', accessData) ? <OkBtn /> : null}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user