mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-30 20:49:21 +08:00
fix: support provider-specific verify payload for per-model verify (#17522)
This commit is contained in:
@@ -46,6 +46,7 @@ export function DraftModeCard({
|
||||
modelInfoRef,
|
||||
draftName,
|
||||
setDraftName,
|
||||
verifyTransform,
|
||||
}: DraftModeCardProps) {
|
||||
// On success, fold the OAuth-issued key into the current form values so it
|
||||
// lands in the (editable) api_key field without clobbering other inputs.
|
||||
@@ -94,6 +95,7 @@ export function DraftModeCard({
|
||||
hideActions={false}
|
||||
hideIfEmpty={false}
|
||||
getFormValues={() => formRef.current?.getValues?.() ?? {}}
|
||||
verifyTransform={verifyTransform}
|
||||
onInstanceModelsChange={(info) => {
|
||||
modelInfoRef.current = info;
|
||||
}}
|
||||
|
||||
@@ -65,6 +65,7 @@ export function SavedModeCard({
|
||||
draftName,
|
||||
open,
|
||||
setOpen,
|
||||
verifyTransform,
|
||||
}: SavedModeCardProps) {
|
||||
const { t } = useTranslation();
|
||||
const { t: tSetting } = useTranslate('setting');
|
||||
@@ -215,6 +216,7 @@ export function SavedModeCard({
|
||||
hideIfEmpty={false}
|
||||
instanceDetailsLoaded={instanceDetailsLoaded}
|
||||
getFormValues={() => formRef.current?.getValues?.() ?? {}}
|
||||
verifyTransform={verifyTransform}
|
||||
onInstanceModelsChange={(info) => {
|
||||
modelInfoRef.current = info;
|
||||
}}
|
||||
|
||||
@@ -542,7 +542,6 @@ export function useInstanceSaveState({
|
||||
}, [
|
||||
isDraft,
|
||||
providerName,
|
||||
instanceName,
|
||||
instanceId,
|
||||
instanceDetails?.id,
|
||||
formRef,
|
||||
|
||||
@@ -19,6 +19,19 @@ import { IProviderInstance } from '@/interfaces/database/llm';
|
||||
import { IModelInfo } from '@/interfaces/request/llm';
|
||||
import { RefObject } from 'react';
|
||||
|
||||
/**
|
||||
* Provider-specific transform that maps form values onto the verify
|
||||
* payload's `api_key` / `base_url` / `region`. Shared by the saved and
|
||||
* draft mode cards so per-model verify can forward structured
|
||||
* credentials (e.g. PaddleOCR's nested config) the backend expects.
|
||||
*/
|
||||
export type VerifyTransform = (values: Record<string, any>) => {
|
||||
apiKey: string | object | Record<string, any>;
|
||||
baseUrl?: string;
|
||||
region?: string;
|
||||
modelInfo?: IModelInfo[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Imperative save API exposed by each instance card (generic, Bedrock,
|
||||
* SoMark) so the parent page can drive a single batch save from the
|
||||
@@ -152,6 +165,8 @@ export interface SavedModeCardProps {
|
||||
draftName: string;
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
/** Provider-specific transform forwarded to ModelsSection for per-model verify. */
|
||||
verifyTransform?: VerifyTransform;
|
||||
}
|
||||
|
||||
/** Props for the draft-mode card (instance name + form fields). */
|
||||
@@ -168,4 +183,6 @@ export interface DraftModeCardProps {
|
||||
modelInfoRef: React.MutableRefObject<IModelInfo[]>;
|
||||
draftName: string;
|
||||
setDraftName: (name: string) => void;
|
||||
/** Provider-specific transform forwarded to ModelsSection for per-model verify. */
|
||||
verifyTransform?: VerifyTransform;
|
||||
}
|
||||
|
||||
@@ -391,6 +391,26 @@ interface UseModelVerifyArgs {
|
||||
resolveCreds: () => ResolvedCreds;
|
||||
instanceModels: IInstanceModel[] | undefined;
|
||||
instance?: IProviderInstance;
|
||||
/**
|
||||
* Host card's current form values. Required when `verifyTransform` is
|
||||
* supplied so the transform can map provider-specific field names
|
||||
* (e.g. PaddleOCR's `paddleocr_api_url`) onto the structured `api_key`
|
||||
* object the verify endpoint expects.
|
||||
*/
|
||||
getFormValues?: () => Record<string, any>;
|
||||
/**
|
||||
* Provider-specific transform that maps form values onto the verify
|
||||
* payload's `api_key` / `base_url` / `region`. When present it takes
|
||||
* precedence over the generic `resolveCreds()` mapping. The
|
||||
* `modelInfo` it returns is ignored - per-model verify always sends
|
||||
* only the single model being verified.
|
||||
*/
|
||||
verifyTransform?: (values: Record<string, any>) => {
|
||||
apiKey: string | object | Record<string, any>;
|
||||
baseUrl?: string;
|
||||
region?: string;
|
||||
modelInfo?: IModelInfo[];
|
||||
};
|
||||
}
|
||||
|
||||
export function useModelVerify({
|
||||
@@ -398,6 +418,8 @@ export function useModelVerify({
|
||||
resolveCreds,
|
||||
instanceModels,
|
||||
instance,
|
||||
getFormValues,
|
||||
verifyTransform,
|
||||
}: UseModelVerifyArgs) {
|
||||
const { verifyProviderConnection } = useVerifyProviderConnection();
|
||||
const [verify, setVerify] = useState<Record<string, VerifyStatus>>({});
|
||||
@@ -426,18 +448,49 @@ export function useModelVerify({
|
||||
const handleVerify = async (model: IProviderModelItem) => {
|
||||
setVerify((prev) => ({ ...prev, [model.name]: 'loading' }));
|
||||
try {
|
||||
const { apiKey, baseUrl } = resolveCreds();
|
||||
// Per-model verify always sends only the model being verified -
|
||||
// even when `verifyTransform` returns a `modelInfo` array, it is
|
||||
// intentionally overridden here.
|
||||
const modelInfo: IModelInfo[] = [
|
||||
{
|
||||
model_name: model.name,
|
||||
model_type: model.model_types ?? [],
|
||||
max_tokens: model.max_tokens ?? 0,
|
||||
},
|
||||
];
|
||||
|
||||
let apiKey: string | object;
|
||||
let baseUrl: string | undefined;
|
||||
let region: string | undefined;
|
||||
|
||||
if (verifyTransform) {
|
||||
// Provider-specific field mapping (e.g. PaddleOCR's nested
|
||||
// `paddleocr_api_url` / `paddleocr_access_token` /
|
||||
// `paddleocr_algorithm` -> structured `api_key` object). Run the
|
||||
// host card's current form values through the transform so the
|
||||
// user can verify with values they are still editing.
|
||||
const formValues = getFormValues?.() ?? {};
|
||||
const transformed = verifyTransform(formValues);
|
||||
apiKey = transformed.apiKey;
|
||||
baseUrl = transformed.baseUrl;
|
||||
region = transformed.region;
|
||||
} else {
|
||||
const creds = resolveCreds();
|
||||
apiKey = creds.apiKey;
|
||||
baseUrl = creds.baseUrl;
|
||||
}
|
||||
|
||||
// `api_key` is typed `string` on the service signature, but
|
||||
// providers with a `verifyTransform` may legitimately produce an
|
||||
// object (e.g. PaddleOCR's nested config). The backend accepts
|
||||
// both shapes, so cast to `any` to match the existing card-level
|
||||
// verify path in `useVerifyProvider`.
|
||||
const ret = await verifyProviderConnection({
|
||||
provider_name: providerName,
|
||||
api_key: apiKey,
|
||||
api_key: apiKey as any,
|
||||
base_url: baseUrl,
|
||||
model_info: [
|
||||
{
|
||||
model_name: model.name,
|
||||
model_type: model.model_types ?? [],
|
||||
max_tokens: model.max_tokens ?? 0,
|
||||
},
|
||||
],
|
||||
model_info: modelInfo,
|
||||
...(region ? { region } : {}),
|
||||
...(instance?.id ? { instance_id: instance.id } : {}),
|
||||
});
|
||||
setVerify((prev) => ({
|
||||
|
||||
@@ -50,6 +50,7 @@ export function ModelsSection(props: ModelsSectionProps) {
|
||||
hideActions = false,
|
||||
hideIfEmpty = false,
|
||||
getFormValues,
|
||||
verifyTransform,
|
||||
onBlurSuppressChange,
|
||||
onInstanceModelsChange,
|
||||
onInstanceModelsEdited,
|
||||
@@ -154,6 +155,8 @@ export function ModelsSection(props: ModelsSectionProps) {
|
||||
resolveCreds,
|
||||
instanceModels,
|
||||
instance,
|
||||
getFormValues,
|
||||
verifyTransform,
|
||||
});
|
||||
|
||||
// 7. Add / remove / batch toggle / custom add.
|
||||
|
||||
@@ -54,6 +54,25 @@ export interface ModelsSectionProps {
|
||||
* blur-save persists them to the backend).
|
||||
*/
|
||||
getFormValues?: () => Record<string, any>;
|
||||
/**
|
||||
* Optional provider-specific transform used to build the verify
|
||||
* payload's `api_key` / `base_url` / `region` from the host card's
|
||||
* current form values. Providers whose credential field names don't
|
||||
* map directly onto `api_key` / `base_url` (e.g. PaddleOCR's nested
|
||||
* `paddleocr_api_url` / `paddleocr_access_token` / `paddleocr_algorithm`)
|
||||
* supply this so the per-model verify can forward the structured
|
||||
* `api_key` object the backend expects. When absent the generic
|
||||
* `values.api_key` / `values.base_url` mapping is used.
|
||||
*
|
||||
* `modelInfo` returned by the transform is ignored for per-model
|
||||
* verify - the single model being verified always overrides it.
|
||||
*/
|
||||
verifyTransform?: (values: Record<string, any>) => {
|
||||
apiKey: string | object | Record<string, any>;
|
||||
baseUrl?: string;
|
||||
region?: string;
|
||||
modelInfo?: IModelInfo[];
|
||||
};
|
||||
/**
|
||||
* Notifies the host that ModelsSection has opened (or closed) a modal
|
||||
* dialog whose contents live in a React Portal outside the host's
|
||||
|
||||
@@ -229,6 +229,7 @@ const GenericProviderInstanceCard = forwardRef<
|
||||
modelInfoRef={modelInfoRef}
|
||||
draftName={draftName}
|
||||
setDraftName={setDraftName}
|
||||
verifyTransform={providerConfig.verifyTransform}
|
||||
/>
|
||||
) : (
|
||||
<SavedModeCard
|
||||
@@ -248,6 +249,7 @@ const GenericProviderInstanceCard = forwardRef<
|
||||
draftName={draftName}
|
||||
open={open}
|
||||
setOpen={setOpen}
|
||||
verifyTransform={providerConfig.verifyTransform}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user