mirror of
https://github.com/labring/FastGPT.git
synced 2026-05-07 01:02:55 +08:00
V4.14.10 dev (#6674)
* feat: model config with brand-new price calculate machanism (#6616) * fix: image read and json error (Agent) (#6502) * fix: 1.image read 2.JSON parsing error * dataset cite and pause * perf: plancall second parse * add test --------- Co-authored-by: archer <545436317@qq.com> * master message * remove invalid code * wip: model config * feat: model config with brand-new price calculate machanism * merge main branch * ajust calculate way * ajust priceTiers resolve procession * perf: price config code * fix: default price * fix: test * fix: comment * fix test --------- Co-authored-by: YeYuheng <57035043+YYH211@users.noreply.github.com> Co-authored-by: archer <545436317@qq.com> * wip: fix modal UI (#6634) * wip: fix modal UI * fix: maxInputToken set * chore: add price unit for non llm models * chore: replace question mark icon with beta tag (#6672) * feat:rerank too long; fix:rerank ui(agent),embedding returns 0 (#6663) * feat:rerank too long; fix:rerank ui(agent),embedding returns 0 * rerank * fix:rerank function * perf: rerank code * fix rerank * perf: model price ui --------- Co-authored-by: archer <545436317@qq.com> * remove llmtype field * revert model init * fix: filed * fix: model select filter * perf: multiple selector render * remove invalid checker * remove invalid i18n * perf: model selector tip * perf: model selector tip * fix cr * limit pnpm version * fix: i18n * fix action * set default mintoken * update i18n * perf: usage push * fix:rerank model ui (#6677) * fix: tier match error * fix: testr --------- Co-authored-by: Ryo <whoeverimf5@gmail.com> Co-authored-by: YeYuheng <57035043+YYH211@users.noreply.github.com>
This commit is contained in:
@@ -21,6 +21,28 @@ type Props = Omit<NumberInputProps, 'onChange' | 'onBlur'> & {
|
||||
hideStepper?: boolean;
|
||||
};
|
||||
|
||||
const getSafeNumberValue = (value: unknown) => {
|
||||
if (value === '' || value === null || value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
return Number.isFinite(value) ? value : undefined;
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
const trimmedValue = value.trim();
|
||||
if (!trimmedValue) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const parsedValue = Number(trimmedValue);
|
||||
return Number.isFinite(parsedValue) ? parsedValue : undefined;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const MyNumberInput = (props: Props) => {
|
||||
const {
|
||||
register,
|
||||
@@ -30,60 +52,62 @@ const MyNumberInput = (props: Props) => {
|
||||
placeholder,
|
||||
inputFieldProps,
|
||||
hideStepper = false,
|
||||
value,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
const registeredField =
|
||||
register && name
|
||||
? register(name, {
|
||||
required: props.isRequired,
|
||||
min: props.min,
|
||||
max: props.max,
|
||||
setValueAs: (value) => getSafeNumberValue(value)
|
||||
})
|
||||
: undefined;
|
||||
const inputFieldRegisterProps = registeredField
|
||||
? {
|
||||
name: registeredField.name,
|
||||
ref: registeredField.ref
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const safeControlledValue =
|
||||
value === '' ? '' : typeof value === 'undefined' ? undefined : getSafeNumberValue(value) ?? '';
|
||||
|
||||
const getRegisteredValue = (value: unknown) => {
|
||||
const safeValue = getSafeNumberValue(value);
|
||||
|
||||
if (typeof safeValue === 'number') {
|
||||
return safeValue;
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
return (
|
||||
<NumberInput
|
||||
{...restProps}
|
||||
{...(typeof value !== 'undefined' ? { value: safeControlledValue } : {})}
|
||||
onBlur={(e) => {
|
||||
const numE = e.target.value === '' ? '' : Number(e.target.value);
|
||||
if (onBlur) {
|
||||
if (numE === '') {
|
||||
// @ts-ignore
|
||||
onBlur('');
|
||||
} else {
|
||||
onBlur(numE);
|
||||
}
|
||||
}
|
||||
if (onChange) {
|
||||
if (numE === '') {
|
||||
// @ts-ignore
|
||||
onChange('');
|
||||
} else {
|
||||
onChange(numE);
|
||||
}
|
||||
}
|
||||
if (register && name) {
|
||||
const event = {
|
||||
target: {
|
||||
name,
|
||||
value: numE
|
||||
}
|
||||
};
|
||||
register(name).onBlur(event);
|
||||
}
|
||||
}}
|
||||
onChange={(e) => {
|
||||
const numE = e === '' ? '' : e.endsWith('.') || /^\d+\.0+$/.test(e) ? e : Number(e);
|
||||
if (onChange) {
|
||||
if (numE === '') {
|
||||
// @ts-ignore
|
||||
onChange('');
|
||||
} else {
|
||||
// @ts-ignore
|
||||
onChange(numE);
|
||||
}
|
||||
}
|
||||
if (register && name) {
|
||||
const event = {
|
||||
target: {
|
||||
name,
|
||||
value: numE
|
||||
}
|
||||
};
|
||||
const numE = getSafeNumberValue(e.target.value);
|
||||
onBlur?.(numE);
|
||||
onChange?.(numE);
|
||||
|
||||
register(name).onChange(event);
|
||||
if (registeredField && name) {
|
||||
const registeredValue = getRegisteredValue(e.target.value);
|
||||
const target = {
|
||||
name,
|
||||
value: registeredValue
|
||||
};
|
||||
registeredField.onChange({
|
||||
target,
|
||||
type: 'change'
|
||||
});
|
||||
registeredField.onBlur({
|
||||
target,
|
||||
type: 'blur'
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -91,14 +115,7 @@ const MyNumberInput = (props: Props) => {
|
||||
placeholder={placeholder}
|
||||
h={restProps.h}
|
||||
defaultValue={restProps.defaultValue}
|
||||
{...(register && name
|
||||
? register(name, {
|
||||
required: props.isRequired,
|
||||
min: props.min,
|
||||
max: props.max,
|
||||
valueAsNumber: true
|
||||
})
|
||||
: {})}
|
||||
{...(inputFieldRegisterProps || {})}
|
||||
{...inputFieldProps}
|
||||
/>
|
||||
{!hideStepper && (
|
||||
|
||||
@@ -16,6 +16,141 @@ import EmptyTip from '../EmptyTip';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '../../common/Icon';
|
||||
|
||||
type RenderListProps = {
|
||||
index: number;
|
||||
list: MultipleSelectProps['list'];
|
||||
cloneValue: (string | undefined)[];
|
||||
setCloneValue: React.Dispatch<React.SetStateAction<(string | undefined)[]>>;
|
||||
onSelect: (val: (string | undefined)[]) => void;
|
||||
onClose: () => void;
|
||||
changeOnEverySelect: boolean;
|
||||
emptyTip?: string;
|
||||
maxH: number;
|
||||
minWidth: string;
|
||||
rowMinWidth: string;
|
||||
MenuRef: React.MutableRefObject<(HTMLDivElement | null)[]>;
|
||||
SelectedItemRef: React.MutableRefObject<(HTMLDivElement | null)[]>;
|
||||
};
|
||||
|
||||
const RenderList = React.memo(function RenderList({
|
||||
index,
|
||||
list,
|
||||
cloneValue,
|
||||
setCloneValue,
|
||||
onSelect,
|
||||
onClose,
|
||||
changeOnEverySelect,
|
||||
emptyTip,
|
||||
maxH,
|
||||
minWidth,
|
||||
rowMinWidth,
|
||||
MenuRef,
|
||||
SelectedItemRef
|
||||
}: RenderListProps) {
|
||||
const { t } = useTranslation();
|
||||
const selectedValue = cloneValue[index];
|
||||
const selectedIndex = list.findIndex((item) => item.value === selectedValue);
|
||||
const children = list[selectedIndex]?.children || [];
|
||||
|
||||
const currentScrollTop = MenuRef.current[index]?.scrollTop;
|
||||
useEffect(() => {
|
||||
if (currentScrollTop !== undefined && MenuRef.current[index]) {
|
||||
MenuRef.current[index]!.scrollTop = currentScrollTop;
|
||||
}
|
||||
}, [currentScrollTop, index, MenuRef]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
ref={(ref) => {
|
||||
MenuRef.current[index] = ref;
|
||||
}}
|
||||
className="nowheel"
|
||||
flex={'1 0 auto'}
|
||||
px={2}
|
||||
borderLeft={index !== 0 ? 'base' : 'none'}
|
||||
minW={index !== 0 ? minWidth : rowMinWidth}
|
||||
maxH={`${maxH}px`}
|
||||
overflowY={'auto'}
|
||||
whiteSpace={'nowrap'}
|
||||
>
|
||||
{list.map((item) => {
|
||||
const hasChildren = item.children && item.children.length > 0;
|
||||
|
||||
return (
|
||||
<Flex
|
||||
key={item.value}
|
||||
ref={(ref) => {
|
||||
if (item.value === selectedValue) {
|
||||
SelectedItemRef.current[index] = ref;
|
||||
}
|
||||
}}
|
||||
py={1.5}
|
||||
_notLast={{ mb: 1 }}
|
||||
cursor={'pointer'}
|
||||
px={1.5}
|
||||
borderRadius={'sm'}
|
||||
_hover={{
|
||||
bg: 'primary.50'
|
||||
}}
|
||||
onClick={() => {
|
||||
const newValue = [...cloneValue];
|
||||
|
||||
if (item.value === selectedValue) {
|
||||
for (let i = index; i < newValue.length; i++) {
|
||||
newValue[i] = undefined;
|
||||
}
|
||||
setCloneValue(newValue);
|
||||
onSelect(newValue);
|
||||
} else {
|
||||
newValue[index] = item.value;
|
||||
setCloneValue(newValue);
|
||||
|
||||
if (changeOnEverySelect || !hasChildren) {
|
||||
onSelect(newValue);
|
||||
}
|
||||
|
||||
if (!hasChildren) {
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
}}
|
||||
{...(item.value === selectedValue
|
||||
? {
|
||||
bg: 'primary.50',
|
||||
color: 'primary.600'
|
||||
}
|
||||
: {})}
|
||||
>
|
||||
{item.label}
|
||||
</Flex>
|
||||
);
|
||||
})}
|
||||
{list.length === 0 && (
|
||||
<EmptyTip text={emptyTip ?? t('common:no_select_data')} pt={1} pb={3} />
|
||||
)}
|
||||
</Box>
|
||||
{children.length > 0 && (
|
||||
<RenderList
|
||||
list={children}
|
||||
index={index + 1}
|
||||
cloneValue={cloneValue}
|
||||
setCloneValue={setCloneValue}
|
||||
onSelect={onSelect}
|
||||
onClose={onClose}
|
||||
changeOnEverySelect={changeOnEverySelect}
|
||||
emptyTip={emptyTip}
|
||||
maxH={maxH}
|
||||
minWidth={minWidth}
|
||||
rowMinWidth={rowMinWidth}
|
||||
MenuRef={MenuRef}
|
||||
SelectedItemRef={SelectedItemRef}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export const MultipleRowSelect = ({
|
||||
placeholder,
|
||||
label,
|
||||
@@ -30,7 +165,6 @@ export const MultipleRowSelect = ({
|
||||
}: MultipleSelectProps & {
|
||||
rowMinWidth?: string;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const ButtonRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
@@ -53,99 +187,6 @@ export const MultipleRowSelect = ({
|
||||
|
||||
const minWidth = `${MenuRef.current?.[0]?.offsetWidth || 0}px`;
|
||||
|
||||
const RenderList = useCallback(
|
||||
({ index, list }: { index: number; list: MultipleSelectProps['list'] }) => {
|
||||
const selectedValue = cloneValue[index];
|
||||
const selectedIndex = list.findIndex((item) => item.value === selectedValue);
|
||||
const children = list[selectedIndex]?.children || [];
|
||||
|
||||
// Store current scroll position before update
|
||||
const currentScrollTop = MenuRef.current[index]?.scrollTop;
|
||||
// Use useEffect to restore scroll position after render
|
||||
useEffect(() => {
|
||||
if (currentScrollTop !== undefined && MenuRef.current[index]) {
|
||||
MenuRef.current[index]!.scrollTop = currentScrollTop;
|
||||
}
|
||||
}, [currentScrollTop, index]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
ref={(ref) => {
|
||||
MenuRef.current[index] = ref;
|
||||
}}
|
||||
className="nowheel"
|
||||
flex={'1 0 auto'}
|
||||
px={2}
|
||||
borderLeft={index !== 0 ? 'base' : 'none'}
|
||||
minW={index !== 0 ? minWidth : rowMinWidth}
|
||||
maxH={`${maxH}px`}
|
||||
overflowY={'auto'}
|
||||
whiteSpace={'nowrap'}
|
||||
>
|
||||
{list.map((item) => {
|
||||
const hasChildren = item.children && item.children.length > 0;
|
||||
|
||||
return (
|
||||
<Flex
|
||||
key={item.value}
|
||||
ref={(ref) => {
|
||||
if (item.value === selectedValue) {
|
||||
SelectedItemRef.current[index] = ref;
|
||||
}
|
||||
}}
|
||||
py={1.5}
|
||||
_notLast={{ mb: 1 }}
|
||||
cursor={'pointer'}
|
||||
px={1.5}
|
||||
borderRadius={'sm'}
|
||||
_hover={{
|
||||
bg: 'primary.50'
|
||||
}}
|
||||
onClick={() => {
|
||||
const newValue = [...cloneValue];
|
||||
|
||||
if (item.value === selectedValue) {
|
||||
for (let i = index; i < newValue.length; i++) {
|
||||
newValue[i] = undefined;
|
||||
}
|
||||
setCloneValue(newValue);
|
||||
onSelect(newValue);
|
||||
} else {
|
||||
newValue[index] = item.value;
|
||||
setCloneValue(newValue);
|
||||
|
||||
if (changeOnEverySelect || !hasChildren) {
|
||||
onSelect(newValue);
|
||||
}
|
||||
|
||||
if (!hasChildren) {
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
}}
|
||||
{...(item.value === selectedValue
|
||||
? {
|
||||
bg: 'primary.50',
|
||||
color: 'primary.600'
|
||||
}
|
||||
: {})}
|
||||
>
|
||||
{item.label}
|
||||
</Flex>
|
||||
);
|
||||
})}
|
||||
{list.length === 0 && (
|
||||
<EmptyTip text={emptyTip ?? t('common:no_select_data')} pt={1} pb={3} />
|
||||
)}
|
||||
</Box>
|
||||
{children.length > 0 && <RenderList list={children} index={index + 1} />}
|
||||
</>
|
||||
);
|
||||
},
|
||||
[changeOnEverySelect, cloneValue, emptyTip, maxH, minWidth, onClose, onSelect, rowMinWidth, t]
|
||||
);
|
||||
|
||||
const onOpenSelect = useCallback(() => {
|
||||
setCloneValue(Array.isArray(value) ? value : []);
|
||||
onOpen();
|
||||
@@ -221,7 +262,21 @@ export const MultipleRowSelect = ({
|
||||
display={'flex'}
|
||||
userSelect={'none'}
|
||||
>
|
||||
<RenderList list={list} index={0} />
|
||||
<RenderList
|
||||
list={list}
|
||||
index={0}
|
||||
cloneValue={cloneValue}
|
||||
setCloneValue={setCloneValue}
|
||||
onSelect={onSelect}
|
||||
onClose={onClose}
|
||||
changeOnEverySelect={changeOnEverySelect}
|
||||
emptyTip={emptyTip}
|
||||
maxH={maxH}
|
||||
minWidth={minWidth}
|
||||
rowMinWidth={rowMinWidth}
|
||||
MenuRef={MenuRef}
|
||||
SelectedItemRef={SelectedItemRef}
|
||||
/>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</Box>
|
||||
|
||||
@@ -62,6 +62,7 @@ export type SelectProps<T = any> = {
|
||||
onOpenFunc?: () => void;
|
||||
|
||||
tagStyle?: FlexProps;
|
||||
menuBottomSlot?: React.ReactNode;
|
||||
} & Omit<ButtonProps, 'onSelect'>;
|
||||
|
||||
type SelectedItemType<T> = {
|
||||
@@ -91,6 +92,7 @@ const MultipleSelect = <T = any,>({
|
||||
onOpenFunc,
|
||||
|
||||
tagStyle,
|
||||
menuBottomSlot,
|
||||
isLoading,
|
||||
...props
|
||||
}: SelectProps<T>) => {
|
||||
@@ -135,7 +137,7 @@ const MultipleSelect = <T = any,>({
|
||||
if (!isOpen) {
|
||||
setInputValue?.('');
|
||||
}
|
||||
}, [isOpen]);
|
||||
}, [isOpen, setInputValue]);
|
||||
|
||||
const onclickItem = useCallback(
|
||||
(val: T) => {
|
||||
@@ -480,6 +482,15 @@ const MultipleSelect = <T = any,>({
|
||||
|
||||
{ScrollData ? <ScrollData minH={20}>{ListRender}</ScrollData> : ListRender}
|
||||
|
||||
{menuBottomSlot && (
|
||||
<>
|
||||
<MyDivider my={1} />
|
||||
<Box px={1} py={1}>
|
||||
{menuBottomSlot}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
|
||||
{isLoading && <MyLoading fixed={false} />}
|
||||
</MenuList>
|
||||
</Menu>
|
||||
|
||||
@@ -15,19 +15,23 @@ type Props<T = string> = Omit<BoxProps, 'onChange'> & {
|
||||
iconGap?: number;
|
||||
};
|
||||
|
||||
const FillRowTabs = ({
|
||||
list,
|
||||
value,
|
||||
onChange,
|
||||
py = '2.5',
|
||||
px = '4',
|
||||
iconSize = '18px',
|
||||
labelSize = 'sm',
|
||||
iconGap = 2,
|
||||
...props
|
||||
}: Props) => {
|
||||
const FillRowTabs = (
|
||||
{
|
||||
list,
|
||||
value,
|
||||
onChange,
|
||||
py = '2.5',
|
||||
px = '4',
|
||||
iconSize = '18px',
|
||||
labelSize = 'sm',
|
||||
iconGap = 2,
|
||||
...props
|
||||
}: Props,
|
||||
ref: React.Ref<HTMLDivElement>
|
||||
) => {
|
||||
return (
|
||||
<Box
|
||||
ref={ref}
|
||||
display={'inline-flex'}
|
||||
px={'3px'}
|
||||
py={'3px'}
|
||||
@@ -76,5 +80,5 @@ const FillRowTabs = ({
|
||||
};
|
||||
|
||||
export default forwardRef(FillRowTabs) as <T>(
|
||||
props: Props<T> & { ref?: React.Ref<HTMLSelectElement> }
|
||||
props: Props<T> & { ref?: React.Ref<HTMLDivElement> }
|
||||
) => JSX.Element;
|
||||
|
||||
@@ -17,6 +17,9 @@ export interface MyModalProps extends ModalContentProps {
|
||||
iconSrc?: string;
|
||||
iconColor?: ImageProps['color'];
|
||||
title?: any;
|
||||
contentPx?: ModalContentProps['px'];
|
||||
contentPy?: ModalContentProps['py'];
|
||||
headerPx?: ModalContentProps['px'];
|
||||
isCentered?: boolean;
|
||||
isLoading?: boolean;
|
||||
isOpen?: boolean;
|
||||
@@ -38,6 +41,9 @@ const MyModal = ({
|
||||
iconColor,
|
||||
size = 'sm',
|
||||
showCloseButton = true,
|
||||
contentPx = '8',
|
||||
contentPy = '8',
|
||||
headerPx,
|
||||
...props
|
||||
}: MyModalProps) => {
|
||||
const { isPc } = useSystem();
|
||||
@@ -77,7 +83,8 @@ const MyModal = ({
|
||||
position={'relative'}
|
||||
maxH={'80vh'}
|
||||
boxShadow={'3.5'}
|
||||
padding={'8'}
|
||||
px={contentPx}
|
||||
py={contentPy}
|
||||
containerProps={{
|
||||
zIndex: props.zIndex
|
||||
}}
|
||||
@@ -92,7 +99,7 @@ const MyModal = ({
|
||||
fontWeight={'500'}
|
||||
mb={6}
|
||||
py={0}
|
||||
px={0}
|
||||
px={headerPx ?? contentPx}
|
||||
gap={3}
|
||||
>
|
||||
{iconSrc && (
|
||||
|
||||
@@ -38,9 +38,11 @@
|
||||
"max_dataset_amount": "Max dataset amount",
|
||||
"max_dataset_size": "Max dataset size",
|
||||
"max_team_member": "Max team members",
|
||||
"model.action": "Action",
|
||||
"model.active": "Active",
|
||||
"model.alias": "Alias",
|
||||
"model.alias_tip": "The name of the model displayed in the system is convenient for users to understand.",
|
||||
"model.basic_config_section": "Basic config",
|
||||
"model.censor": "Censor check",
|
||||
"model.censor_tip": "If sensitive verification is required, turn on this switch",
|
||||
"model.charsPointsPrice": "Chars Price",
|
||||
@@ -57,7 +59,9 @@
|
||||
"model.default_token_tip": "The length of the default text block of the index model must be less than the maximum length above",
|
||||
"model.delete_model_confirm": "Confirm to delete this model?",
|
||||
"model.edit_model": "Model parameter editing",
|
||||
"model.input_price": "Input price",
|
||||
"model.feature_config_section": "Feature config",
|
||||
"model.function_call": "Function Call",
|
||||
"model.function_call_tip": "If the model supports function calling, turn on this switch. \nTool calls have higher priority.",
|
||||
"model.input_price_tip": "Language model input price. If this item is configured, the model comprehensive price will be invalid.",
|
||||
"model.json_config": "File config",
|
||||
"model.json_config_confirm": "Confirm to use this configuration for override?",
|
||||
@@ -68,9 +72,18 @@
|
||||
"model.model_id_tip": "The unique identifier of the model, that is, the value of the actual request to the service provider model, needs to correspond to the model in the OneAPI channel.",
|
||||
"model.normalization": "Normalization processing",
|
||||
"model.normalization_tip": "If the Embedding API does not normalize vector values, the switch can be enabled and the system will normalize.\n\nUnnormalized APIs, which are represented by the vector search score greater than 1.",
|
||||
"model.output_price": "Output price",
|
||||
"model.output_price_tip": "The language model output price. If this item is configured, the model comprehensive price will be invalid.",
|
||||
"model.param_name": "Parameter name",
|
||||
"model.params_config_section": "Parameter config",
|
||||
"model.price_config_section": "Price config",
|
||||
"model.price_tier": "Tier",
|
||||
"model.price_tier_max_required": "All tiers except the last one need an upper bound",
|
||||
"model.price_tier_open_ended": "Default is positive infinity",
|
||||
"model.price_tier_prev_range_required": "Complete the previous tier upper bound first",
|
||||
"model.price_tier_price_required": "Each price tier needs at least an input or output price",
|
||||
"model.price_tier_range_invalid": "Invalid price tier range. Please make sure upper bounds keep increasing",
|
||||
"model.price_tiers": "Price tiers",
|
||||
"model.price_tiers_tip": "Match a tier by input token range, then bill input and output tokens with that tier's prices. Each next range starts after the previous upper bound. Leave the last upper bound empty to mean and above.",
|
||||
"model.reasoning": "Support output thinking",
|
||||
"model.reasoning_tip": "For example, Deepseek-reasoner can output the thinking process.",
|
||||
"model.request_auth": "Custom key",
|
||||
@@ -78,8 +91,11 @@
|
||||
"model.request_url": "Custom url",
|
||||
"model.request_url_tip": "If this value is filled in, a request will be made directly to this address without going through the configuration of the model channel.\n\nThe interface needs to follow OpenAI’s API format and fill in the complete request address, for example:\n\nLLM: {{host}}/v1/chat/completions\nEmbedding: {{host}}/v1/embeddings\nSTT: {{host}}/v1/audio/transcriptions\nTTS: {{host}}/v1/audio/speech\nRerank: {{host}}/v1/rerank",
|
||||
"model.response_format": "Response format",
|
||||
"model.response_format_placeholder": "Custom parameters",
|
||||
"model.show_stop_sign": "Display stop sequence parameters",
|
||||
"model.show_top_p": "Show Top-p parameters",
|
||||
"model.test_mode": "Mark as test model",
|
||||
"model.test_mode_tip": "After being turned on, the model is only used for AI dialogue and is not used for other model processing scenarios such as knowledge base file processing, text extraction, application evaluation, problem classification, tool calling nodes, etc.",
|
||||
"model.test_model": "Model testing",
|
||||
"model.tool_choice": "Tool choice",
|
||||
"model.tool_choice_tag": "ToolCall",
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"channel_status_enabled": "Enable",
|
||||
"channel_status_unknown": "unknown",
|
||||
"channel_type": "Protocol Type",
|
||||
"clear": "Clear",
|
||||
"clear_model": "Clear the model",
|
||||
"confirm_delete_channel": "Confirm the deletion of the [{{name}}] channel?",
|
||||
"copy_model_id_success": "Copyed model id",
|
||||
@@ -42,6 +43,8 @@
|
||||
"mapping": "Model Mapping",
|
||||
"mapping_tip": "A valid Json is required. \nThe model can be mapped when sending a request to the actual address. \nFor example:\n{\n \n \"gpt-4o\": \"gpt-4o-test\"\n\n}\n\nWhen FastGPT requests the gpt-4o model, the gpt-4o-test model is sent to the actual address, instead of gpt-4o.",
|
||||
"maxToken_tip": "Model max_tokens parameter",
|
||||
"rerank_max_token": "Max Token Limit",
|
||||
"rerank_max_token_tip": "Token limit per rerank request (query + single document). Documents exceeding the limit will be automatically split.",
|
||||
"max_rpm": "Max RPM (Requests Per Minute)",
|
||||
"max_temperature_tip": "If the model temperature parameter is not filled in, it means that the model does not support the temperature parameter.",
|
||||
"max_tpm": "Max TPM (Tokens Per Minute)",
|
||||
@@ -56,6 +59,7 @@
|
||||
"model_ttfb_time": "Response time of first word",
|
||||
"monitoring": "Monitoring",
|
||||
"output": "Output",
|
||||
"price_tier_open_ended": "endless",
|
||||
"request_at": "Request time",
|
||||
"request_duration": "Request duration: {{duration}}s",
|
||||
"retry_times": "Number of retry times",
|
||||
|
||||
@@ -797,8 +797,11 @@
|
||||
"minute": "Minute",
|
||||
"minute_unit": "m",
|
||||
"model.billing": "Billing",
|
||||
"model.input_price": "Input price",
|
||||
"model.model_type": "Model type",
|
||||
"model.name": "Model name",
|
||||
"model.output_price": "output price",
|
||||
"model.price_tier_range": "Input interval: k/tokens",
|
||||
"model.provider": "Provider",
|
||||
"model.search_name_placeholder": "Search by model name",
|
||||
"model.type.chat": "LLM",
|
||||
@@ -1064,6 +1067,7 @@
|
||||
"sync_success": "Synced Successfully",
|
||||
"system.Concat us": "Contact Us",
|
||||
"system_intro": "{{title}} is a comprehensive model application orchestration system that offers out-of-the-box data processing and model invocation capabilities. It allows for rapid Dataset construction and workflow orchestration through Flow visualization, enabling complex Dataset scenarios!",
|
||||
"system_tools": "system tools",
|
||||
"tag_list": "Tag List",
|
||||
"team_tag": "Team Tag",
|
||||
"templateTags.Image_generation": "Image generation",
|
||||
@@ -1072,6 +1076,7 @@
|
||||
"templateTags.Web_search": "Search online",
|
||||
"templateTags.Writing": "Writing",
|
||||
"template_market": "Template Market",
|
||||
"test_model_tip": "This model is a test model and does not support high concurrency use.",
|
||||
"textarea_variable_picker_tip": "Enter \"/\" to select a variable",
|
||||
"to_dataset": "To dataset",
|
||||
"tool_invalid": "Tool has expired",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"Start_end_time": "Start time / End time",
|
||||
"Task_name": "Task name",
|
||||
"Task_name_placeholder": "Please enter a task name",
|
||||
"app_deleted": "App deleted",
|
||||
"app_required": "Please select the evaluation application",
|
||||
"app_response": "Application output",
|
||||
"back": "back",
|
||||
|
||||
@@ -38,9 +38,11 @@
|
||||
"max_dataset_amount": "知识库上限",
|
||||
"max_dataset_size": "知识库索引上限",
|
||||
"max_team_member": "团队成员上限",
|
||||
"model.action": "操作",
|
||||
"model.active": "启用",
|
||||
"model.alias": "别名",
|
||||
"model.alias_tip": "模型在系统中展示的名字,方便用户理解",
|
||||
"model.basic_config_section": "基本配置",
|
||||
"model.censor": "启用敏感校验",
|
||||
"model.censor_tip": "如果需要进行敏感校验,则开启该开关",
|
||||
"model.charsPointsPrice": "模型综合价格",
|
||||
@@ -57,7 +59,9 @@
|
||||
"model.default_token_tip": "索引模型默认文本分块的长度,必须小于最大上文",
|
||||
"model.delete_model_confirm": "确认删除该模型?",
|
||||
"model.edit_model": "模型参数编辑",
|
||||
"model.input_price": "模型输入价格",
|
||||
"model.feature_config_section": "功能配置",
|
||||
"model.function_call": "支持函数调用",
|
||||
"model.function_call_tip": "如果模型支持函数调用,则开启该开关。工具调用优先级更高。",
|
||||
"model.input_price_tip": "语言模型输入价格,如果配置了该项,则模型综合价格会失效",
|
||||
"model.json_config": "配置文件",
|
||||
"model.json_config_confirm": "确认使用该配置进行覆盖?",
|
||||
@@ -68,9 +72,18 @@
|
||||
"model.model_id_tip": "模型的唯一标识,也就是实际请求到服务商model 的值,需要与 OneAPI 渠道中的模型对应。",
|
||||
"model.normalization": "归一化处理",
|
||||
"model.normalization_tip": "如果Embedding API 未对向量值进行归一化,可以启用该开关,系统会进行归一化处理。\n未归一化的 API,表现为向量检索得分会大于 1。",
|
||||
"model.output_price": "模型输出价格",
|
||||
"model.output_price_tip": "语言模型输出价格,如果配置了该项,则模型综合价格会失效",
|
||||
"model.param_name": "参数名",
|
||||
"model.params_config_section": "参数配置",
|
||||
"model.price_config_section": "价格配置",
|
||||
"model.price_tier": "梯度",
|
||||
"model.price_tier_max_required": "除最后一个梯度外,都需要填写区间上限",
|
||||
"model.price_tier_open_ended": "默认正无穷",
|
||||
"model.price_tier_prev_range_required": "请先补全上一梯度的区间上限",
|
||||
"model.price_tier_price_required": "每个价格梯度都需要至少配置一个输入价或输出价",
|
||||
"model.price_tier_range_invalid": "价格梯度区间设置有误,请检查区间上限是否递增",
|
||||
"model.price_tiers": "模型价格梯度",
|
||||
"model.price_tiers_tip": "按输入 Token 所在区间匹配一个梯度,再使用该梯度的输入价格和输出价格分别计费。区间起点自动按上一梯度递增,最后一个梯度上限留空表示及以上。",
|
||||
"model.reasoning": "支持输出思考",
|
||||
"model.reasoning_tip": "例如 Deepseek-reasoner,可以输出思考过程。",
|
||||
"model.request_auth": "自定义请求 Key",
|
||||
@@ -78,8 +91,11 @@
|
||||
"model.request_url": "自定义请求地址",
|
||||
"model.request_url_tip": "如果填写该值,则会直接向该地址发起请求,不经过模型渠道的配置。\n接口需要遵循 OpenAI 的 API格式,并填写完整请求地址,例如:\nLLM: {{host}}/v1/chat/completions\nEmbedding: {{host}}/v1/embeddings\nSTT: {{host}}/v1/audio/transcriptions\nTTS: {{host}}/v1/audio/speech\nRerank: {{host}}/v1/rerank",
|
||||
"model.response_format": "响应格式",
|
||||
"model.response_format_placeholder": "自定义参数",
|
||||
"model.show_stop_sign": "展示停止序列参数",
|
||||
"model.show_top_p": "展示 Top-p 参数",
|
||||
"model.test_mode": "标记为测试模型",
|
||||
"model.test_mode_tip": "开启后,该模型仅用于 AI 对话,不用于知识库文件处理、文本提取、应用评测、问题分类、工具调用节点等其他模型处理场景。",
|
||||
"model.test_model": "模型测试",
|
||||
"model.tool_choice": "支持工具调用",
|
||||
"model.tool_choice_tag": "工具调用",
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"channel_status_enabled": "启用",
|
||||
"channel_status_unknown": "未知",
|
||||
"channel_type": "协议类型",
|
||||
"clear": "清空",
|
||||
"clear_model": "清空模型",
|
||||
"confirm_delete_channel": "确认删除 【{{name}}】渠道?",
|
||||
"copy_model_id_success": "已复制模型id",
|
||||
@@ -42,6 +43,8 @@
|
||||
"mapping": "模型映射",
|
||||
"mapping_tip": "需填写一个有效 Json。可在向实际地址发送请求时,对模型进行映射。例如:\n{\n \"gpt-4o\": \"gpt-4o-test\"\n}\n当 FastGPT 请求 gpt-4o 模型时,会向实际地址发送 gpt-4o-test 的模型,而不是 gpt-4o。",
|
||||
"maxToken_tip": "模型 max_tokens 参数",
|
||||
"rerank_max_token": "最大 Token 限制",
|
||||
"rerank_max_token_tip": "Rerank 阶段单次请求的 token 上限(query + 单个文档),超出限制的文档会被自动切分",
|
||||
"max_rpm": "最大RPM (每分钟请求数)",
|
||||
"max_temperature_tip": "模型 temperature 参数,不填则代表模型不支持 temperature 参数。",
|
||||
"max_tpm": "最大TPM (每分钟Token数)",
|
||||
@@ -56,6 +59,7 @@
|
||||
"model_ttfb_time": "首字响应时长",
|
||||
"monitoring": "监控",
|
||||
"output": "输出",
|
||||
"price_tier_open_ended": "无穷",
|
||||
"request_at": "请求时间",
|
||||
"request_duration": "请求时长: {{duration}}s",
|
||||
"retry_times": "重试次数",
|
||||
|
||||
@@ -797,8 +797,11 @@
|
||||
"minute": "分钟",
|
||||
"minute_unit": "分",
|
||||
"model.billing": "模型计费",
|
||||
"model.input_price": "输入价格",
|
||||
"model.model_type": "模型类型",
|
||||
"model.name": "模型名",
|
||||
"model.output_price": "输出价格",
|
||||
"model.price_tier_range": "输入区间:k/tokens",
|
||||
"model.provider": "模型提供商",
|
||||
"model.search_name_placeholder": "根据模型名搜索",
|
||||
"model.type.chat": "语言模型",
|
||||
@@ -1058,12 +1061,13 @@
|
||||
"support.wallet.usage.Audio Speech": "语音播放",
|
||||
"support.wallet.usage.Code Copilot": "代码助手",
|
||||
"support.wallet.usage.Optimize Prompt": "提示词优化",
|
||||
"support.wallet.usage.Total points": "AI 积分总消耗",
|
||||
"support.wallet.usage.Total points": "积分总消耗",
|
||||
"support.wallet.usage.Whisper": "语音输入",
|
||||
"sync_link": "同步链接",
|
||||
"sync_success": "同步成功",
|
||||
"system.Concat us": "联系我们",
|
||||
"system_intro": "{{title}} 是一个大模型应用编排系统,提供开箱即用的数据处理、模型调用等能力,可以快速的构建知识库并通过 Flow 可视化进行工作流编排,实现复杂的知识库场景!\n",
|
||||
"system_tools": "系统工具",
|
||||
"tag_list": "标签列表",
|
||||
"team_tag": "团队标签",
|
||||
"templateTags.Image_generation": "图片生成",
|
||||
@@ -1072,6 +1076,7 @@
|
||||
"templateTags.Web_search": "联网搜索",
|
||||
"templateTags.Writing": "文本创作",
|
||||
"template_market": "模板市场",
|
||||
"test_model_tip": "该模型为测试模型,不支持高并发使用。",
|
||||
"textarea_variable_picker_tip": "输入\"/\"可选择变量",
|
||||
"to_dataset": "前往知识库",
|
||||
"tool_invalid": "工具已失效",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"Start_end_time": "开始时间 / 结束时间",
|
||||
"Task_name": "任务名",
|
||||
"Task_name_placeholder": "请输入任务名",
|
||||
"app_deleted": "应用已被删除",
|
||||
"app_required": "请选择评测应用",
|
||||
"app_response": "应用输出",
|
||||
"back": "退出",
|
||||
|
||||
@@ -38,9 +38,11 @@
|
||||
"max_dataset_amount": "知識庫上限",
|
||||
"max_dataset_size": "知識庫索引上限",
|
||||
"max_team_member": "團隊成員上限",
|
||||
"model.action": "操作",
|
||||
"model.active": "啟用",
|
||||
"model.alias": "別名",
|
||||
"model.alias_tip": "模型在系統中展示的名字,方便使用者理解",
|
||||
"model.basic_config_section": "基本配置",
|
||||
"model.censor": "啟用敏感校驗",
|
||||
"model.censor_tip": "如果需要進行敏感校驗,則開啟該開關",
|
||||
"model.charsPointsPrice": "模型綜合價格",
|
||||
@@ -57,7 +59,9 @@
|
||||
"model.default_token_tip": "索引模型預設文字分塊的長度,必須小於最大上文",
|
||||
"model.delete_model_confirm": "確認刪除該模型?",
|
||||
"model.edit_model": "模型參數編輯",
|
||||
"model.input_price": "模型輸入價格",
|
||||
"model.feature_config_section": "功能配置",
|
||||
"model.function_call": "支援函式呼叫",
|
||||
"model.function_call_tip": "如果模型支援函式呼叫,則開啟該開關。\n工具呼叫優先權更高。",
|
||||
"model.input_price_tip": "語言模型輸入價格,如果設定了該項,則模型綜合價格會失效",
|
||||
"model.json_config": "設定檔",
|
||||
"model.json_config_confirm": "確認使用該設定進行覆蓋?",
|
||||
@@ -68,9 +72,18 @@
|
||||
"model.model_id_tip": "模型的唯一標識,也就是實際請求到服務商 model 的值,需要與 OneAPI 管道中的模型對應。",
|
||||
"model.normalization": "歸一化處理",
|
||||
"model.normalization_tip": "如果 Embedding API 未對向量值進行歸一化,可以啟用該開關,系統會進行歸一化處理。\n未歸一化的 API,表現為向量檢索得分會大於 1。",
|
||||
"model.output_price": "模型輸出價格",
|
||||
"model.output_price_tip": "語言模型輸出價格,如果設定了該項,則模型綜合價格會失效",
|
||||
"model.param_name": "參數名稱",
|
||||
"model.params_config_section": "參數配置",
|
||||
"model.price_config_section": "價格配置",
|
||||
"model.price_tier": "梯度",
|
||||
"model.price_tier_max_required": "除了最後一個梯度,其餘都需要填寫區間上限",
|
||||
"model.price_tier_open_ended": "預設無窮",
|
||||
"model.price_tier_prev_range_required": "請先補齊上一梯度的區間上限",
|
||||
"model.price_tier_price_required": "每個價格梯度都需要至少設定一個輸入價或輸出價",
|
||||
"model.price_tier_range_invalid": "價格梯度區間設定有誤,請確認區間上限有持續遞增",
|
||||
"model.price_tiers": "模型價格梯度",
|
||||
"model.price_tiers_tip": "依輸入 Token 所在區間匹配一個梯度,再使用該梯度的輸入價格和輸出價格分別計費。區間起點會依上一梯度自動遞增,最後一個梯度上限留空表示及以上。",
|
||||
"model.reasoning": "支援輸出思考",
|
||||
"model.reasoning_tip": "例如 Deepseek-reasoner,可以輸出思考過程。",
|
||||
"model.request_auth": "自訂請求 Key",
|
||||
@@ -78,8 +91,11 @@
|
||||
"model.request_url": "自訂請求地址",
|
||||
"model.request_url_tip": "如果填寫該值,則會直接向該地址發起請求,不經過模型渠道的配置。\n\n接口需要遵循 OpenAI 的 API格式,並填寫完整請求地址,例如:\nLLM: {{host}}/v1/chat/completions\nEmbedding: {{host}}/v1/embeddings\nSTT: {{host}}/v1/audio/transcriptions\nTTS: {{host}}/v1/audio/speech\nRerank: {{host}}/v1/rerank",
|
||||
"model.response_format": "響應格式",
|
||||
"model.response_format_placeholder": "自訂參數",
|
||||
"model.show_stop_sign": "展示停止序列參數",
|
||||
"model.show_top_p": "展示 Top-p 參數",
|
||||
"model.test_mode": "標記為測試模型",
|
||||
"model.test_mode_tip": "開啟後,此模型僅用於 AI 對話,不用於知識庫文件處理、文字擷取、應用評測、問題分類、工具呼叫節點等其他模型處理場景。",
|
||||
"model.test_model": "模型測試",
|
||||
"model.tool_choice": "支援工具呼叫",
|
||||
"model.tool_choice_tag": "工具呼叫",
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"channel_status_enabled": "啟用",
|
||||
"channel_status_unknown": "未知",
|
||||
"channel_type": "協議類型",
|
||||
"clear": "清空",
|
||||
"clear_model": "清空模型",
|
||||
"confirm_delete_channel": "確認刪除【{{name}}】管道?",
|
||||
"copy_model_id_success": "已復制模型 id",
|
||||
@@ -42,6 +43,8 @@
|
||||
"mapping": "模型對映",
|
||||
"mapping_tip": "需填寫一個有效 Json。\n可在向實際地址傳送請求時,對模型進行對映。\n例如:\n{\n \n \"gpt-4o\": \"gpt-4o-test\"\n\n}\n\n當 FastGPT 請求 gpt-4o 模型時,會向實際地址傳送 gpt-4o-test 的模型,而不是 gpt-4o。",
|
||||
"maxToken_tip": "模型 max_tokens 參數",
|
||||
"rerank_max_token": "最大 Token 限制",
|
||||
"rerank_max_token_tip": "Rerank 階段單次請求的 token 上限(query + 單個文件),超出限制的文件會被自動切分",
|
||||
"max_rpm": "最大RPM (每分鐘請求數)",
|
||||
"max_temperature_tip": "模型 temperature 參數,不填則代表模型不支援 temperature 參數。",
|
||||
"max_tpm": "最大TPM (每分鐘Token數)",
|
||||
@@ -56,6 +59,7 @@
|
||||
"model_ttfb_time": "首字響應時長",
|
||||
"monitoring": "監控",
|
||||
"output": "輸出",
|
||||
"price_tier_open_ended": "無窮",
|
||||
"request_at": "請求時間",
|
||||
"request_duration": "請求時長:{{duration}}s",
|
||||
"retry_times": "重試次數",
|
||||
|
||||
@@ -791,8 +791,11 @@
|
||||
"minute": "分鐘",
|
||||
"minute_unit": "分",
|
||||
"model.billing": "模型計費",
|
||||
"model.input_price": "輸入價格",
|
||||
"model.model_type": "模型類型",
|
||||
"model.name": "模型名",
|
||||
"model.output_price": "輸出價格",
|
||||
"model.price_tier_range": "輸入區間:k/tokens",
|
||||
"model.provider": "模型提供者",
|
||||
"model.search_name_placeholder": "根據模型名搜尋",
|
||||
"model.type.chat": "語言模型",
|
||||
@@ -1047,12 +1050,13 @@
|
||||
"support.wallet.usage.Audio Speech": "語音播放",
|
||||
"support.wallet.usage.Code Copilot": "代碼助手",
|
||||
"support.wallet.usage.Optimize Prompt": "提示詞優化",
|
||||
"support.wallet.usage.Total points": "AI 積分總消耗",
|
||||
"support.wallet.usage.Total points": "積分總消耗",
|
||||
"support.wallet.usage.Whisper": "語音輸入",
|
||||
"sync_link": "同步連結",
|
||||
"sync_success": "同步成功",
|
||||
"system.Concat us": "聯絡我們",
|
||||
"system_intro": "{{title}} 是一個大模型應用編排系統,提供開箱即用的數據處理、模型調用等能力,可以快速的構建知識庫並通過 Flow 可視化進行工作流編排,實現複雜的知識庫場景!",
|
||||
"system_tools": "系統工具",
|
||||
"tag_list": "標籤列表",
|
||||
"team_tag": "團隊標籤",
|
||||
"templateTags.Image_generation": "圖片生成",
|
||||
@@ -1061,6 +1065,7 @@
|
||||
"templateTags.Web_search": "聯網搜索",
|
||||
"templateTags.Writing": "文字創作",
|
||||
"template_market": "模板市場",
|
||||
"test_model_tip": "此模型為測試模型,不支援高並發使用。",
|
||||
"textarea_variable_picker_tip": "輸入「/」以選擇變數",
|
||||
"to_dataset": "前往知識庫",
|
||||
"tool_invalid": "工具已失效",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"Progress": "進度",
|
||||
"Start_end_time": "開始時間 / 結束時間",
|
||||
"Task_name_placeholder": "請輸入任務名",
|
||||
"app_deleted": "應用程式已刪除",
|
||||
"app_required": "請選擇評測應用",
|
||||
"app_response": "應用輸出",
|
||||
"back": "退出",
|
||||
|
||||
Reference in New Issue
Block a user