mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-07-16 02:21:47 +08:00
### What problem does this PR solve? Feat: Add LangfuseCard component. #6155 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
5e0a77df2b
commit
3c57a9986c
10
web/src/assets/svg/langfuse.svg
Normal file
10
web/src/assets/svg/langfuse.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 14 KiB |
@ -2,12 +2,14 @@ import { LanguageTranslationMap } from '@/constants/common';
|
|||||||
import { ResponseGetType } from '@/interfaces/database/base';
|
import { ResponseGetType } from '@/interfaces/database/base';
|
||||||
import { IToken } from '@/interfaces/database/chat';
|
import { IToken } from '@/interfaces/database/chat';
|
||||||
import { ITenantInfo } from '@/interfaces/database/knowledge';
|
import { ITenantInfo } from '@/interfaces/database/knowledge';
|
||||||
|
import { ILangfuseConfig } from '@/interfaces/database/system';
|
||||||
import {
|
import {
|
||||||
ISystemStatus,
|
ISystemStatus,
|
||||||
ITenant,
|
ITenant,
|
||||||
ITenantUser,
|
ITenantUser,
|
||||||
IUserInfo,
|
IUserInfo,
|
||||||
} from '@/interfaces/database/user-setting';
|
} from '@/interfaces/database/user-setting';
|
||||||
|
import { ISetLangfuseConfigRequestBody } from '@/interfaces/request/system';
|
||||||
import userService, {
|
import userService, {
|
||||||
addTenantUser,
|
addTenantUser,
|
||||||
agreeTenant,
|
agreeTenant,
|
||||||
@ -375,3 +377,57 @@ export const useAgreeTenant = () => {
|
|||||||
|
|
||||||
return { data, loading, agreeTenant: mutateAsync };
|
return { data, loading, agreeTenant: mutateAsync };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useSetLangfuseConfig = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isPending: loading,
|
||||||
|
mutateAsync,
|
||||||
|
} = useMutation({
|
||||||
|
mutationKey: ['setLangfuseConfig'],
|
||||||
|
mutationFn: async (params: ISetLangfuseConfigRequestBody) => {
|
||||||
|
const { data } = await userService.setLangfuseConfig(params);
|
||||||
|
if (data.code === 0) {
|
||||||
|
message.success(t('message.operated'));
|
||||||
|
}
|
||||||
|
return data?.code;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading, setLangfuseConfig: mutateAsync };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeleteLangfuseConfig = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
isPending: loading,
|
||||||
|
mutateAsync,
|
||||||
|
} = useMutation({
|
||||||
|
mutationKey: ['deleteLangfuseConfig'],
|
||||||
|
mutationFn: async () => {
|
||||||
|
const { data } = await userService.deleteLangfuseConfig();
|
||||||
|
if (data.code === 0) {
|
||||||
|
message.success(t('message.deleted'));
|
||||||
|
}
|
||||||
|
return data?.code;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading, deleteLangfuseConfig: mutateAsync };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useFetchLangfuseConfig = () => {
|
||||||
|
const { data, isFetching: loading } = useQuery<ILangfuseConfig>({
|
||||||
|
queryKey: ['fetchLangfuseConfig'],
|
||||||
|
gcTime: 0,
|
||||||
|
queryFn: async () => {
|
||||||
|
const { data } = await userService.getLangfuseConfig();
|
||||||
|
|
||||||
|
return data?.data;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, loading };
|
||||||
|
};
|
||||||
|
7
web/src/interfaces/database/system.ts
Normal file
7
web/src/interfaces/database/system.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export interface ILangfuseConfig {
|
||||||
|
secret_key: string;
|
||||||
|
public_key: string;
|
||||||
|
host: string;
|
||||||
|
project_id: string;
|
||||||
|
project_name: string;
|
||||||
|
}
|
5
web/src/interfaces/request/system.ts
Normal file
5
web/src/interfaces/request/system.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export interface ISetLangfuseConfigRequestBody {
|
||||||
|
secret_key: string;
|
||||||
|
public_key: string;
|
||||||
|
host: string;
|
||||||
|
}
|
@ -699,6 +699,16 @@ This auto-tag feature enhances retrieval by adding another layer of domain-speci
|
|||||||
sureDelete: 'Are you sure to remove this member?',
|
sureDelete: 'Are you sure to remove this member?',
|
||||||
quit: 'Quit',
|
quit: 'Quit',
|
||||||
sureQuit: 'Are you sure you want to quit the team you joined?',
|
sureQuit: 'Are you sure you want to quit the team you joined?',
|
||||||
|
secretKey: 'Secret key',
|
||||||
|
publicKey: 'Public key',
|
||||||
|
secretKeyMessage: 'Please enter the secret key',
|
||||||
|
publicKeyMessage: 'Please enter the public key',
|
||||||
|
hostMessage: 'Please enter the host',
|
||||||
|
configuration: 'Configuration',
|
||||||
|
langfuseDescription:
|
||||||
|
'Traces, evals, prompt management and metrics to debug and improve your LLM application.',
|
||||||
|
viewLangfuseSDocumentation: "View Langfuse's documentation",
|
||||||
|
view: 'View',
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
registered: 'Registered!',
|
registered: 'Registered!',
|
||||||
|
@ -211,7 +211,8 @@ export default {
|
|||||||
embeddingModelTip:
|
embeddingModelTip:
|
||||||
'用於嵌入塊的嵌入模型。一旦知識庫有了塊,它就無法更改。如果你想改變它,你需要刪除所有的塊。',
|
'用於嵌入塊的嵌入模型。一旦知識庫有了塊,它就無法更改。如果你想改變它,你需要刪除所有的塊。',
|
||||||
permissionsTip: '如果權限是“團隊”,則所有團隊成員都可以操作知識庫。',
|
permissionsTip: '如果權限是“團隊”,則所有團隊成員都可以操作知識庫。',
|
||||||
chunkTokenNumberTip: '建議的生成文本塊的 token 數閾值。如果切分得到的小文本段 token 數達不到這一閾值,系統就會不斷與之後的文本段合併,直至再合併下一個文本段會超過這一閾值為止,此時產生一個最終文本塊。如果系統在切分文本段時始終沒有遇到文本分段標識符,即便文本段 token 數已經超過這一閾值,系統也不會生成新文本塊。',
|
chunkTokenNumberTip:
|
||||||
|
'建議的生成文本塊的 token 數閾值。如果切分得到的小文本段 token 數達不到這一閾值,系統就會不斷與之後的文本段合併,直至再合併下一個文本段會超過這一閾值為止,此時產生一個最終文本塊。如果系統在切分文本段時始終沒有遇到文本分段標識符,即便文本段 token 數已經超過這一閾值,系統也不會生成新文本塊。',
|
||||||
chunkMethod: '切片方法',
|
chunkMethod: '切片方法',
|
||||||
chunkMethodTip: '說明位於右側。',
|
chunkMethodTip: '說明位於右側。',
|
||||||
upload: '上傳',
|
upload: '上傳',
|
||||||
@ -668,6 +669,16 @@ export default {
|
|||||||
sureDelete: '您確定刪除該成員嗎?',
|
sureDelete: '您確定刪除該成員嗎?',
|
||||||
quit: '退出',
|
quit: '退出',
|
||||||
sureQuit: '確定退出加入的團隊嗎?',
|
sureQuit: '確定退出加入的團隊嗎?',
|
||||||
|
secretKey: '密鑰',
|
||||||
|
publicKey: '公鑰',
|
||||||
|
secretKeyMessage: '請輸入私钥',
|
||||||
|
publicKeyMessage: '請輸入公钥',
|
||||||
|
hostMessage: '請輸入 host',
|
||||||
|
configuration: '配置',
|
||||||
|
langfuseDescription:
|
||||||
|
'追蹤、評估、提示管理和指標以調試和改進您的 LLM 應用程式。',
|
||||||
|
viewLangfuseSDocumentation: '查看 Langfuse 的文檔',
|
||||||
|
view: '查看',
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
registered: '註冊成功',
|
registered: '註冊成功',
|
||||||
|
@ -210,8 +210,10 @@ export default {
|
|||||||
chunkTokenNumberMessage: '块Token数是必填项',
|
chunkTokenNumberMessage: '块Token数是必填项',
|
||||||
embeddingModelTip:
|
embeddingModelTip:
|
||||||
'用于嵌入块的嵌入模型。 一旦知识库有了块,它就无法更改。 如果你想改变它,你需要删除所有的块。',
|
'用于嵌入块的嵌入模型。 一旦知识库有了块,它就无法更改。 如果你想改变它,你需要删除所有的块。',
|
||||||
permissionsTip: '如果把知识库权限设为“团队”,则所有团队成员都可以操作该知识库。',
|
permissionsTip:
|
||||||
chunkTokenNumberTip: '建议的生成文本块的 token 数阈值。如果切分得到的小文本段 token 数达不到这一阈值就会不断与之后的文本段合并,直至再合并下一个文本段会超过这一阈值为止,此时产生一个最终文本块。如果系统在切分文本段时始终没有遇到文本分段标识符,即便文本段 token 数已经超过这一阈值,系统也不会生成新文本块。',
|
'如果把知识库权限设为“团队”,则所有团队成员都可以操作该知识库。',
|
||||||
|
chunkTokenNumberTip:
|
||||||
|
'建议的生成文本块的 token 数阈值。如果切分得到的小文本段 token 数达不到这一阈值就会不断与之后的文本段合并,直至再合并下一个文本段会超过这一阈值为止,此时产生一个最终文本块。如果系统在切分文本段时始终没有遇到文本分段标识符,即便文本段 token 数已经超过这一阈值,系统也不会生成新文本块。',
|
||||||
chunkMethod: '切片方法',
|
chunkMethod: '切片方法',
|
||||||
chunkMethodTip: '说明位于右侧。',
|
chunkMethodTip: '说明位于右侧。',
|
||||||
upload: '上传',
|
upload: '上传',
|
||||||
@ -687,6 +689,16 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
|
|||||||
sureDelete: '您确定要删除该成员吗?',
|
sureDelete: '您确定要删除该成员吗?',
|
||||||
quit: '退出',
|
quit: '退出',
|
||||||
sureQuit: '确定退出加入的团队吗?',
|
sureQuit: '确定退出加入的团队吗?',
|
||||||
|
secretKey: '密钥',
|
||||||
|
publicKey: '公钥',
|
||||||
|
secretKeyMessage: '请输入私钥',
|
||||||
|
publicKeyMessage: '请输入公钥',
|
||||||
|
hostMessage: '请输入 host',
|
||||||
|
configuration: '配置',
|
||||||
|
langfuseDescription:
|
||||||
|
'跟踪、评估、提示管理和指标,以调试和改进您的 LLM 应用程序。',
|
||||||
|
viewLangfuseSDocumentation: '查看 Langfuse 的文档',
|
||||||
|
view: '查看',
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
registered: '注册成功',
|
registered: '注册成功',
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
.modelWrapper {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modelContainer {
|
.modelContainer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
.factoryOperationWrapper {
|
.factoryOperationWrapper {
|
||||||
|
@ -49,6 +49,7 @@ import {
|
|||||||
} from './hooks';
|
} from './hooks';
|
||||||
import HunyuanModal from './hunyuan-modal';
|
import HunyuanModal from './hunyuan-modal';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
import { LangfuseCard } from './langfuse';
|
||||||
import OllamaModal from './ollama-modal';
|
import OllamaModal from './ollama-modal';
|
||||||
import SparkModal from './spark-modal';
|
import SparkModal from './spark-modal';
|
||||||
import SystemModelSettingModal from './system-model-setting-modal';
|
import SystemModelSettingModal from './system-model-setting-modal';
|
||||||
@ -358,7 +359,8 @@ const UserSettingModel = () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section id="xx" className={styles.modelWrapper}>
|
<section id="xx" className="w-full space-y-6">
|
||||||
|
<LangfuseCard></LangfuseCard>
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
<section className={styles.modelContainer}>
|
<section className={styles.modelContainer}>
|
||||||
<SettingTitle
|
<SettingTitle
|
||||||
|
69
web/src/pages/user-setting/setting-model/langfuse/index.tsx
Normal file
69
web/src/pages/user-setting/setting-model/langfuse/index.tsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import SvgIcon from '@/components/svg-icon';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardDescription,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from '@/components/ui/card';
|
||||||
|
import { useFetchLangfuseConfig } from '@/hooks/user-setting-hooks';
|
||||||
|
import { Eye, Settings2 } from 'lucide-react';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { LangfuseConfigurationDialog } from './langfuse-configuration-dialog';
|
||||||
|
import { useSaveLangfuseConfiguration } from './use-save-langfuse-configuration';
|
||||||
|
|
||||||
|
export function LangfuseCard() {
|
||||||
|
const {
|
||||||
|
saveLangfuseConfigurationOk,
|
||||||
|
showSaveLangfuseConfigurationModal,
|
||||||
|
hideSaveLangfuseConfigurationModal,
|
||||||
|
saveLangfuseConfigurationVisible,
|
||||||
|
loading,
|
||||||
|
} = useSaveLangfuseConfiguration();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { data } = useFetchLangfuseConfig();
|
||||||
|
|
||||||
|
const handleView = useCallback(() => {
|
||||||
|
window.open(
|
||||||
|
`https://cloud.langfuse.com/project/${data?.project_id}`,
|
||||||
|
'_blank',
|
||||||
|
);
|
||||||
|
}, [data?.project_id]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="flex justify-between">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<SvgIcon name={'langfuse'} width={24} height={24}></SvgIcon>
|
||||||
|
Langfuse
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-4 items-center">
|
||||||
|
{data && (
|
||||||
|
<Button variant={'outline'} size={'sm'} onClick={handleView}>
|
||||||
|
<Eye /> {t('setting.view')}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
size={'sm'}
|
||||||
|
onClick={showSaveLangfuseConfigurationModal}
|
||||||
|
className="bg-blue-500 hover:bg-blue-400"
|
||||||
|
>
|
||||||
|
<Settings2 />
|
||||||
|
{t('setting.configuration')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription>{t('setting.langfuseDescription')}</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
{saveLangfuseConfigurationVisible && (
|
||||||
|
<LangfuseConfigurationDialog
|
||||||
|
hideModal={hideSaveLangfuseConfigurationModal}
|
||||||
|
onOk={saveLangfuseConfigurationOk}
|
||||||
|
loading={loading}
|
||||||
|
></LangfuseConfigurationDialog>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from '@/components/ui/dialog';
|
||||||
|
import { LoadingButton } from '@/components/ui/loading-button';
|
||||||
|
import { useDeleteLangfuseConfig } from '@/hooks/user-setting-hooks';
|
||||||
|
import { IModalProps } from '@/interfaces/common';
|
||||||
|
import { ExternalLink, Trash2 } from 'lucide-react';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import {
|
||||||
|
FormId,
|
||||||
|
LangfuseConfigurationForm,
|
||||||
|
} from './langfuse-configuration-form';
|
||||||
|
|
||||||
|
export function LangfuseConfigurationDialog({
|
||||||
|
hideModal,
|
||||||
|
loading,
|
||||||
|
onOk,
|
||||||
|
}: IModalProps<any>) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { deleteLangfuseConfig } = useDeleteLangfuseConfig();
|
||||||
|
|
||||||
|
const handleDelete = useCallback(async () => {
|
||||||
|
const ret = await deleteLangfuseConfig();
|
||||||
|
if (ret === 0) {
|
||||||
|
hideModal?.();
|
||||||
|
}
|
||||||
|
}, [deleteLangfuseConfig, hideModal]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open onOpenChange={hideModal}>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Button variant="outline"></Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>{t('setting.configuration')} Langfuse</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<LangfuseConfigurationForm onOk={onOk}></LangfuseConfigurationForm>
|
||||||
|
<DialogFooter className="!justify-between">
|
||||||
|
<a
|
||||||
|
href="https://langfuse.com/docs"
|
||||||
|
className="flex items-center gap-2 underline text-blue-600 hover:text-blue-800 visited:text-purple-600"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
{t('setting.viewLangfuseSDocumentation')}
|
||||||
|
<ExternalLink className="size-4" />
|
||||||
|
</a>
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<ConfirmDeleteDialog onOk={handleDelete}>
|
||||||
|
<Button variant={'outline'}>
|
||||||
|
<Trash2 className="text-red-500" /> {t('common.delete')}
|
||||||
|
</Button>
|
||||||
|
</ConfirmDeleteDialog>
|
||||||
|
|
||||||
|
<LoadingButton type="submit" form={FormId} loading={loading}>
|
||||||
|
{t('common.save')}
|
||||||
|
</LoadingButton>
|
||||||
|
</div>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Form,
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from '@/components/ui/form';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { useFetchLangfuseConfig } from '@/hooks/user-setting-hooks';
|
||||||
|
import { IModalProps } from '@/interfaces/common';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
export const FormId = 'LangfuseConfigurationForm';
|
||||||
|
|
||||||
|
export function LangfuseConfigurationForm({ onOk }: IModalProps<any>) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { data } = useFetchLangfuseConfig();
|
||||||
|
|
||||||
|
const FormSchema = z.object({
|
||||||
|
secret_key: z
|
||||||
|
.string()
|
||||||
|
.min(1, {
|
||||||
|
message: t('setting.secretKeyMessage'),
|
||||||
|
})
|
||||||
|
.trim(),
|
||||||
|
public_key: z
|
||||||
|
.string()
|
||||||
|
.min(1, {
|
||||||
|
message: t('setting.publicKeyMessage'),
|
||||||
|
})
|
||||||
|
.trim(),
|
||||||
|
host: z
|
||||||
|
.string()
|
||||||
|
.min(0, {
|
||||||
|
message: t('setting.hostMessage'),
|
||||||
|
})
|
||||||
|
.trim(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const form = useForm<z.infer<typeof FormSchema>>({
|
||||||
|
resolver: zodResolver(FormSchema),
|
||||||
|
defaultValues: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
async function onSubmit(data: z.infer<typeof FormSchema>) {
|
||||||
|
onOk?.(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data) {
|
||||||
|
form.reset(data);
|
||||||
|
}
|
||||||
|
}, [data, form]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form {...form}>
|
||||||
|
<form
|
||||||
|
onSubmit={form.handleSubmit(onSubmit)}
|
||||||
|
className="space-y-6"
|
||||||
|
id={FormId}
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="secret_key"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>{t('setting.secretKey')}</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
type={'password'}
|
||||||
|
placeholder={t('setting.secretKeyMessage')}
|
||||||
|
{...field}
|
||||||
|
autoComplete="off"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="public_key"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>{t('setting.publicKey')}</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
type={'password'}
|
||||||
|
placeholder={t('setting.publicKeyMessage')}
|
||||||
|
{...field}
|
||||||
|
autoComplete="off"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="host"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Host</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
placeholder={'https://cloud.langfuse.com'}
|
||||||
|
{...field}
|
||||||
|
autoComplete="off"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
import { useSetModalState } from '@/hooks/common-hooks';
|
||||||
|
import { useSetLangfuseConfig } from '@/hooks/user-setting-hooks';
|
||||||
|
import { ISetLangfuseConfigRequestBody } from '@/interfaces/request/system';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
export const useSaveLangfuseConfiguration = () => {
|
||||||
|
const {
|
||||||
|
visible: saveLangfuseConfigurationVisible,
|
||||||
|
hideModal: hideSaveLangfuseConfigurationModal,
|
||||||
|
showModal: showSaveLangfuseConfigurationModal,
|
||||||
|
} = useSetModalState();
|
||||||
|
const { setLangfuseConfig, loading } = useSetLangfuseConfig();
|
||||||
|
|
||||||
|
const onSaveLangfuseConfigurationOk = useCallback(
|
||||||
|
async (params: ISetLangfuseConfigRequestBody) => {
|
||||||
|
const ret = await setLangfuseConfig(params);
|
||||||
|
|
||||||
|
if (ret === 0) {
|
||||||
|
hideSaveLangfuseConfigurationModal();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
[hideSaveLangfuseConfigurationModal],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
loading,
|
||||||
|
saveLangfuseConfigurationOk: onSaveLangfuseConfigurationOk,
|
||||||
|
saveLangfuseConfigurationVisible,
|
||||||
|
hideSaveLangfuseConfigurationModal,
|
||||||
|
showSaveLangfuseConfigurationModal,
|
||||||
|
};
|
||||||
|
};
|
@ -23,6 +23,7 @@ const {
|
|||||||
removeSystemToken,
|
removeSystemToken,
|
||||||
createSystemToken,
|
createSystemToken,
|
||||||
getSystemConfig,
|
getSystemConfig,
|
||||||
|
setLangfuseConfig,
|
||||||
} = api;
|
} = api;
|
||||||
|
|
||||||
const methods = {
|
const methods = {
|
||||||
@ -106,6 +107,18 @@ const methods = {
|
|||||||
url: getSystemConfig,
|
url: getSystemConfig,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
},
|
},
|
||||||
|
setLangfuseConfig: {
|
||||||
|
url: setLangfuseConfig,
|
||||||
|
method: 'put',
|
||||||
|
},
|
||||||
|
getLangfuseConfig: {
|
||||||
|
url: setLangfuseConfig,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
deleteLangfuseConfig: {
|
||||||
|
url: setLangfuseConfig,
|
||||||
|
method: 'delete',
|
||||||
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const userService = registerServer<keyof typeof methods>(methods, request);
|
const userService = registerServer<keyof typeof methods>(methods, request);
|
||||||
|
@ -120,6 +120,7 @@ export default {
|
|||||||
listSystemToken: `${api_host}/system/token_list`,
|
listSystemToken: `${api_host}/system/token_list`,
|
||||||
removeSystemToken: `${api_host}/system/token`,
|
removeSystemToken: `${api_host}/system/token`,
|
||||||
getSystemConfig: `${api_host}/system/config`,
|
getSystemConfig: `${api_host}/system/config`,
|
||||||
|
setLangfuseConfig: `${api_host}/langfuse/api_key`,
|
||||||
|
|
||||||
// flow
|
// flow
|
||||||
listTemplates: `${api_host}/canvas/templates`,
|
listTemplates: `${api_host}/canvas/templates`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user