mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-12 18:11:34 +08:00
Merge remote-tracking branch 'origin/feature/1.5-cx' into feature/1.5-local-model
This commit is contained in:
@@ -136,6 +136,7 @@ type EoRequest = RequestInit & {
|
||||
eoBody?: { [k: string]: unknown } | Array<unknown> | string
|
||||
isStream?: boolean
|
||||
handleStream?: (line: any) => void
|
||||
callback?: (cancel: () => void) => void
|
||||
}
|
||||
|
||||
type EoHeaders = Headers | { [k: string]: string }
|
||||
@@ -145,6 +146,14 @@ export function useFetch() {
|
||||
const pluginEventHub = usePluginEventHub()
|
||||
|
||||
function fetchData<T>(url: string, options: EoRequest) {
|
||||
const controller = new AbortController()
|
||||
const signal = controller.signal
|
||||
|
||||
// 如果提供了callback,则传递取消请求的函数
|
||||
if (options.callback) {
|
||||
options.callback(() => controller.abort())
|
||||
}
|
||||
|
||||
// 合并传入的headers与默认headers
|
||||
const headers = { ...(options.body ? {} : DEFAULT_HEADERS), ...options.headers }
|
||||
|
||||
@@ -163,7 +172,8 @@ export function useFetch() {
|
||||
headers: {
|
||||
...headers
|
||||
// Authorization: 'Bearer your-token', // 示例:添加统一的Token认证
|
||||
}
|
||||
},
|
||||
signal // 将signal传递给fetch请求
|
||||
}
|
||||
|
||||
return fetch(`${options?.eoApiPrefix === undefined ? '/api/v1/' : options.eoApiPrefix}${url}`, finalOptions)
|
||||
|
||||
@@ -19,6 +19,7 @@ export type AiServiceConfigFieldType = {
|
||||
serviceType?:'public'|'inner';
|
||||
catalogue?:string | string[];
|
||||
approvalType?:string;
|
||||
providerType?:string
|
||||
};
|
||||
|
||||
export type AiServiceSubServiceTableListItem = {
|
||||
|
||||
@@ -31,7 +31,8 @@ const AiServiceInsidePage: FC = () => {
|
||||
const getAiServiceInfo = () => {
|
||||
fetchData<BasicResponse<{ service: AiServiceConfigFieldType }>>('service/info', {
|
||||
method: 'GET',
|
||||
eoParams: { team: teamId, service: serviceId }
|
||||
eoParams: { team: teamId, service: serviceId },
|
||||
eoTransformKeys: ['provider_type']
|
||||
}).then((response) => {
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
|
||||
@@ -15,12 +15,12 @@ import { AI_SERVICE_VARIABLES_TABLE_COLUMNS } from '@core/const/ai-service/const
|
||||
import { VariableItems } from '@core/const/ai-service/type.ts'
|
||||
import { API_PATH_MATCH_RULES } from '@core/const/system/const'
|
||||
import { useAiServiceContext } from '@core/contexts/AiServiceContext.tsx'
|
||||
import { AiProviderDefaultConfig, AiProviderLlmsItems } from '@core/pages/aiSetting/AiSettingList'
|
||||
import { Icon } from '@iconify/react/dist/iconify.js'
|
||||
import { App, Button, Form, Input, InputNumber, Row, Space, Spin, Switch, Tag } from 'antd'
|
||||
import { MutableRefObject, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
import AiServiceRouterModelConfig, { AiServiceRouterModelConfigHandle } from './AiServiceInsideRouterModelConfig'
|
||||
import { AiProviderDefaultConfig, AiProviderLlmsItems } from '@core/pages/aiSetting/types'
|
||||
|
||||
type AiServiceRouterField = {
|
||||
name: string
|
||||
@@ -151,7 +151,13 @@ const AiServiceInsideRouterCreate = () => {
|
||||
type: aiModel?.type
|
||||
}) as AiProviderDefaultConfig & { config: string }
|
||||
)
|
||||
aiModel?.type !== 'local' && getDefaultModelConfig(aiModel?.provider, false)
|
||||
getDefaultModelConfig({
|
||||
provider: aiModel?.provider,
|
||||
id: aiModel?.id,
|
||||
replaceDefaultLlm: false,
|
||||
setIcon: true,
|
||||
type: aiModel?.type
|
||||
})
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
@@ -160,36 +166,109 @@ const AiServiceInsideRouterCreate = () => {
|
||||
.finally(() => setLoading(false))
|
||||
}
|
||||
|
||||
const getDefaultModelConfig = (provider?: string, resetDefaultLlm = true) => {
|
||||
fetchData<BasicResponse<{ llms: AiProviderLlmsItems[]; provider: AiProviderDefaultConfig }>>('ai/provider/llms', {
|
||||
method: 'GET',
|
||||
eoParams: { provider: provider ?? aiServiceInfo?.provider?.id },
|
||||
eoTransformKeys: ['default_llm']
|
||||
})
|
||||
.then((response) => {
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
setLlmList(data.llms)
|
||||
if (resetDefaultLlm) {
|
||||
setDefaultLlm((prev) => {
|
||||
const llmSetting = data.llms?.find(
|
||||
(x: AiProviderLlmsItems) => x.id === (prev?.id ?? data.provider.defaultLlm)
|
||||
)
|
||||
return {
|
||||
...prev,
|
||||
defaultLlm: data.provider.defaultLlm,
|
||||
provider: data.provider.id,
|
||||
name: data.provider.name,
|
||||
config: llmSetting?.config || '',
|
||||
...(llmSetting ?? {})
|
||||
} as AiProviderDefaultConfig & { config: string }
|
||||
})
|
||||
}
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
const getDefaultModelConfig = ({
|
||||
provider,
|
||||
id,
|
||||
replaceDefaultLlm = true,
|
||||
setIcon = true,
|
||||
type
|
||||
}: {
|
||||
provider?: string
|
||||
id?: string
|
||||
replaceDefaultLlm?: boolean
|
||||
setIcon?: boolean
|
||||
type?: string
|
||||
} = {}) => {
|
||||
// 如果编辑状态下 是本地 或者,新增状态下是本地
|
||||
if (type === 'local' || (!type && aiServiceInfo?.providerType === 'local')) {
|
||||
fetchData<BasicResponse<{ llms: AiProviderLlmsItems[]; provider: AiProviderDefaultConfig }>>('simple/ai/models/local/configured', {
|
||||
method: 'GET',
|
||||
eoTransformKeys: ['default_config']
|
||||
})
|
||||
.catch((errorInfo) => console.error(errorInfo))
|
||||
.then((response) => {
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
setLlmList(data.models)
|
||||
const localId = id || aiServiceInfo?.id
|
||||
|
||||
if (replaceDefaultLlm) {
|
||||
setDefaultLlm((prev) => {
|
||||
const llmSetting = data.models?.find(
|
||||
(x: AiProviderLlmsItems) => x.id === (prev?.id ?? localId)
|
||||
)
|
||||
return {
|
||||
...prev,
|
||||
defaultLlm: localId,
|
||||
provider: localId,
|
||||
name: aiServiceInfo?.name,
|
||||
config: llmSetting?.defaultConfig || '',
|
||||
type: 'local',
|
||||
...(llmSetting ?? {})
|
||||
} as AiProviderDefaultConfig & { config: string }
|
||||
})
|
||||
}
|
||||
if (setIcon) {
|
||||
setDefaultLlm((prev) => {
|
||||
const llmSetting = data.models?.find(
|
||||
(x: AiProviderLlmsItems) => x.id === (prev?.id ?? localId)
|
||||
)
|
||||
return {
|
||||
...prev,
|
||||
logo: llmSetting?.logo,
|
||||
scopes: llmSetting?.scopes
|
||||
} as AiProviderDefaultConfig & { config: string }
|
||||
})
|
||||
}
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
})
|
||||
.catch((errorInfo) => console.error(errorInfo))
|
||||
} else {
|
||||
fetchData<BasicResponse<{ llms: AiProviderLlmsItems[]; provider: AiProviderDefaultConfig }>>('ai/provider/llms', {
|
||||
method: 'GET',
|
||||
eoParams: { provider: provider ?? aiServiceInfo?.provider?.id },
|
||||
eoTransformKeys: ['default_llm']
|
||||
})
|
||||
.then((response) => {
|
||||
const { code, data, msg } = response
|
||||
if (code === STATUS_CODE.SUCCESS) {
|
||||
setLlmList(data.llms)
|
||||
if (replaceDefaultLlm) {
|
||||
setDefaultLlm((prev) => {
|
||||
const llmSetting = data.llms?.find(
|
||||
(x: AiProviderLlmsItems) => x.id === (prev?.id ?? data.provider.defaultLlm)
|
||||
)
|
||||
return {
|
||||
...prev,
|
||||
defaultLlm: data.provider.defaultLlm,
|
||||
provider: data.provider.id,
|
||||
name: data.provider.name,
|
||||
config: llmSetting?.config || '',
|
||||
type: 'online',
|
||||
...(llmSetting ?? {})
|
||||
} as AiProviderDefaultConfig & { config: string }
|
||||
})
|
||||
}
|
||||
if (setIcon) {
|
||||
setDefaultLlm((prev) => {
|
||||
const llmSetting = data.llms?.find(
|
||||
(x: AiProviderLlmsItems) => x.id === (prev?.id ?? data.provider.defaultLlm)
|
||||
)
|
||||
return {
|
||||
...prev,
|
||||
logo: llmSetting?.logo,
|
||||
scopes: llmSetting?.scopes
|
||||
} as AiProviderDefaultConfig & { config: string }
|
||||
})
|
||||
}
|
||||
} else {
|
||||
message.error(msg || $t(RESPONSE_TIPS.error))
|
||||
}
|
||||
})
|
||||
.catch((errorInfo) => console.error(errorInfo))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@@ -241,6 +320,13 @@ const AiServiceInsideRouterCreate = () => {
|
||||
|
||||
const handlerSubmit: () => Promise<boolean> | undefined = () => {
|
||||
return drawerAddFormRef.current?.save()?.then((res: { id: string; config: string, type: string, provider: string }) => {
|
||||
getDefaultModelConfig({
|
||||
provider: res.provider,
|
||||
id: res.id,
|
||||
type: res.type,
|
||||
replaceDefaultLlm: false,
|
||||
setIcon: true
|
||||
})
|
||||
setDefaultLlm(
|
||||
(prev) =>
|
||||
({
|
||||
|
||||
@@ -273,12 +273,23 @@ const LocalModelList: React.FC = () => {
|
||||
reload && pageListRef.current?.reload()
|
||||
modalInstance.destroy()
|
||||
}
|
||||
const updateFooter = () => {
|
||||
record.state = 'error'
|
||||
modalInstance.update({})
|
||||
}
|
||||
let cancelCb: () => void = () => {}
|
||||
const cancel = (cancel: () => void) => {
|
||||
cancelCb = cancel
|
||||
}
|
||||
const modalInstance = modal.confirm({
|
||||
title: $t('部署过程'),
|
||||
content: <ServiceDeployment record={record} closeModal={closeModal} />,
|
||||
content: <ServiceDeployment record={record} closeModal={closeModal} updateFooter={updateFooter} cancelCb={cancel} />,
|
||||
footer: () => {
|
||||
return <LogsFooter record={record} closeModal={closeModal} />
|
||||
},
|
||||
afterClose: () => {
|
||||
cancelCb()
|
||||
},
|
||||
width: 600,
|
||||
okText: $t('确认'),
|
||||
cancelText: $t('取消'),
|
||||
|
||||
@@ -141,12 +141,23 @@ const SystemList: FC = () => {
|
||||
modalInstance.destroy()
|
||||
reload && manualReloadTable()
|
||||
}
|
||||
const updateFooter = () => {
|
||||
record.state = 'error'
|
||||
modalInstance.update({})
|
||||
}
|
||||
let cancelCb: () => void = () => {}
|
||||
const cancel = (cancel: () => void) => {
|
||||
cancelCb = cancel
|
||||
}
|
||||
const modalInstance = modal.confirm({
|
||||
title: $t('部署过程'),
|
||||
content: <ServiceDeployment record={record} closeModal={closeModal} />,
|
||||
content: <ServiceDeployment record={record} closeModal={closeModal} updateFooter={updateFooter} cancelCb={cancel} />,
|
||||
footer: () => {
|
||||
return <LogsFooter record={record} closeModal={closeModal} />
|
||||
},
|
||||
afterClose: () => {
|
||||
cancelCb()
|
||||
},
|
||||
width: 600,
|
||||
okText: $t('确认'),
|
||||
cancelText: $t('取消'),
|
||||
|
||||
@@ -8,8 +8,8 @@ import { $t } from '@common/locales/index.ts'
|
||||
import { useFetch } from '@common/hooks/http'
|
||||
import { BasicResponse, RESPONSE_TIPS, STATUS_CODE } from '@common/const/const'
|
||||
|
||||
export const ServiceDeployment = (props: { record: SystemTableListItem, closeModal?: () => void }) => {
|
||||
const { record, closeModal } = props
|
||||
export const ServiceDeployment = (props: { record: SystemTableListItem, closeModal?: () => void, updateFooter?: () => void, cancelCb?: (cancel: () => void) => void }) => {
|
||||
const { record, closeModal, updateFooter, cancelCb } = props
|
||||
const { message } = App.useApp()
|
||||
const getIcon = (status: string) => {
|
||||
switch (status) {
|
||||
@@ -126,6 +126,9 @@ export const ServiceDeployment = (props: { record: SystemTableListItem, closeMod
|
||||
method: 'POST',
|
||||
eoBody: { model: record.id, team: record.team?.id },
|
||||
isStream: true,
|
||||
callback: (cancel: () => void) => {
|
||||
cancelCb?.(cancel)
|
||||
},
|
||||
handleStream: (chunk) => {
|
||||
const parsedChunk = JSON.parse(chunk)
|
||||
// 下载中
|
||||
@@ -144,6 +147,7 @@ export const ServiceDeployment = (props: { record: SystemTableListItem, closeMod
|
||||
closeModal?.()
|
||||
}, 200)
|
||||
} else if (parsedChunk?.data?.state.includes('error')) {
|
||||
updateFooter?.()
|
||||
setStepItem((prevItems) =>
|
||||
prevItems.map((item, index) => {
|
||||
return { ...item, status: index === step.current ? 'error' : item.status }
|
||||
|
||||
Reference in New Issue
Block a user