feat: add new interfaces, services, and utilities for API integration

refactor: reorganize type definitions and improve type safety

build: add lodash and @types/lodash as dependencies

chore: update tsconfig and vite config for path aliases

style: improve code organization and add documentation comments

fix: correct type usage in LanguageSwitcher component

perf: implement snackbar provider for global notifications

test: add new test interfaces and utility functions

ci: update pnpm-lock.yaml with new dependencies
This commit is contained in:
2025-10-10 15:09:04 +08:00
parent 8cf7a4e5d5
commit a1282de74f
45 changed files with 5088 additions and 274 deletions

1
.env Normal file
View File

@@ -0,0 +1 @@
VITE_API_BASE_URL = http://150.158.121.95

View File

@@ -19,6 +19,7 @@
"dayjs": "^1.11.18",
"i18next": "^25.5.3",
"i18next-browser-languagedetector": "^8.2.0",
"lodash": "^4.17.21",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.64.0",
@@ -30,6 +31,7 @@
},
"devDependencies": {
"@eslint/js": "^9.36.0",
"@types/lodash": "^4.17.20",
"@types/node": "^24.6.0",
"@types/react": "^19.1.16",
"@types/react-dom": "^19.1.9",

11
pnpm-lock.yaml generated
View File

@@ -35,6 +35,9 @@ importers:
i18next-browser-languagedetector:
specifier: ^8.2.0
version: 8.2.0
lodash:
specifier: ^4.17.21
version: 4.17.21
react:
specifier: ^18.3.1
version: 18.3.1
@@ -63,6 +66,9 @@ importers:
'@eslint/js':
specifier: ^9.36.0
version: 9.37.0
'@types/lodash':
specifier: ^4.17.20
version: 4.17.20
'@types/node':
specifier: ^24.6.0
version: 24.7.1
@@ -717,6 +723,9 @@ packages:
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
'@types/lodash@4.17.20':
resolution: {integrity: sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==}
'@types/node@24.7.1':
resolution: {integrity: sha512-CmyhGZanP88uuC5GpWU9q+fI61j2SkhO3UGMUdfYRE6Bcy0ccyzn1Rqj9YAB/ZY4kOXmNf0ocah5GtphmLMP6Q==}
@@ -2204,6 +2213,8 @@ snapshots:
'@types/json-schema@7.0.15': {}
'@types/lodash@4.17.20': {}
'@types/node@24.7.1':
dependencies:
undici-types: 7.14.0

View File

@@ -2,17 +2,30 @@ import { BrowserRouter } from 'react-router-dom';
import { CssBaseline, ThemeProvider } from '@mui/material';
import { theme } from './theme';
import AppRoutes from './routes';
import SnackbarProvider from './components/Provider/SnackbarProvider';
import './locales';
function App() {
/**
* 封装MaterialUIApp将主题、基础样式和路由包裹起来
*/
function MaterialUIApp() {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<BrowserRouter>
<AppRoutes />
</BrowserRouter>
<SnackbarProvider>
<BrowserRouter>
<AppRoutes />
</BrowserRouter>
</SnackbarProvider>
</ThemeProvider>
);
}
function App() {
return (
<MaterialUIApp />
);
}
export default App;

View File

@@ -2,6 +2,7 @@ import React from 'react';
import { useTranslation } from 'react-i18next';
import { Button, Menu, MenuItem } from '@mui/material';
import { LanguageAbbreviation } from '../locales';
import type { LanguageAbbreviationType } from '../locales';
interface LanguageSwitcherProps {
textColor?: string;
@@ -20,7 +21,7 @@ const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({ textColor = '#fff'
setAnchorEl(null);
};
const handleLanguageChange = (language: "en" | "zh") => {
const handleLanguageChange = (language: LanguageAbbreviationType) => {
i18n.changeLanguage(language);
handleClose();
};

View File

@@ -0,0 +1,115 @@
import React, { createContext, useContext, useState, useCallback, useEffect, type PropsWithChildren } from 'react';
import { Snackbar, Alert, type AlertColor } from '@mui/material';
interface SnackbarItem {
id: string;
message: string;
severity: AlertColor;
duration?: number;
title?: string;
}
interface SnackbarContextType {
showSnackbar: (snackbar: Omit<SnackbarItem, 'id'>) => void;
showMessage: {
success: (message: string, duration?: number) => void;
error: (message: string, duration?: number) => void;
warning: (message: string, duration?: number) => void;
info: (message: string, duration?: number) => void;
};
showNotification: {
success: (title: string, message?: string, duration?: number) => void;
error: (title: string, message?: string, duration?: number) => void;
warning: (title: string, message?: string, duration?: number) => void;
info: (title: string, message?: string, duration?: number) => void;
};
}
const SnackbarContext = createContext<SnackbarContextType | null>(null);
export const useSnackbar = () => {
const context = useContext(SnackbarContext);
if (!context) {
throw new Error('useSnackbar must be used within SnackbarProvider');
}
return context;
};
export default function SnackbarProvider({ children }: PropsWithChildren) {
const [snackbars, setSnackbars] = useState<SnackbarItem[]>([]);
const showSnackbar = useCallback((snackbar: Omit<SnackbarItem, 'id'>) => {
const id = Date.now().toString();
const newSnackbar = { ...snackbar, id };
setSnackbars(prev => [...prev, newSnackbar]);
}, []);
const removeSnackbar = useCallback((id: string) => {
setSnackbars(prev => prev.filter(snackbar => snackbar.id !== id));
}, []);
const showMessage = {
success: (message: string, duration = 2000) =>
showSnackbar({ message, severity: 'success', duration }),
error: (message: string, duration = 4000) =>
showSnackbar({ message, severity: 'error', duration }),
warning: (message: string, duration = 3000) =>
showSnackbar({ message, severity: 'warning', duration }),
info: (message: string, duration = 2000) =>
showSnackbar({ message, severity: 'info', duration }),
};
const showNotification = {
success: (title: string, message?: string, duration = 5000) =>
showSnackbar({ title, message: message || title, severity: 'success', duration }),
error: (title: string, message?: string, duration = 6000) =>
showSnackbar({ title, message: message || title, severity: 'error', duration }),
warning: (title: string, message?: string, duration = 5000) =>
showSnackbar({ title, message: message || title, severity: 'warning', duration }),
info: (title: string, message?: string, duration = 4000) =>
showSnackbar({ title, message: message || title, severity: 'info', duration }),
};
// 为非组件文件提供全局实例
useEffect(() => {
if (typeof window !== 'undefined') {
(window as any).__snackbarInstance = { showSnackbar, showMessage, showNotification };
}
}, [showSnackbar, showMessage, showNotification]);
return (
<SnackbarContext.Provider value={{ showSnackbar, showMessage, showNotification }}>
{children}
{snackbars.map((snackbar, index) => (
<Snackbar
key={snackbar.id}
open={true}
autoHideDuration={snackbar.duration}
onClose={() => removeSnackbar(snackbar.id)}
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
sx={{
top: `${80 + index * 70}px !important`,
zIndex: 9999 - index
}}
>
<Alert
onClose={() => removeSnackbar(snackbar.id)}
severity={snackbar.severity}
variant="filled"
sx={{
minWidth: 300,
alignItems: snackbar.title ? 'flex-start' : 'center'
}}
>
{snackbar.title && (
<div style={{ fontWeight: 600, marginBottom: 4 }}>
{snackbar.title}
</div>
)}
{snackbar.message}
</Alert>
</Snackbar>
))}
</SnackbarContext.Provider>
);
}

View File

@@ -0,0 +1,3 @@
export const Authorization = 'Authorization';
export const Token = 'token';
export const UserInfo = 'userInfo';

107
src/constants/knowledge.ts Normal file
View File

@@ -0,0 +1,107 @@
// object freeze
export const KNOWLEDGE_ROUTE_KEYS = Object.freeze({
Dataset: 'dataset',
Testing: 'testing',
Configuration: 'configuration',
KnowledgeGraph: 'knowledgeGraph',
} as const)
export type KnowledgeRouteKey = (typeof KNOWLEDGE_ROUTE_KEYS)[keyof typeof KNOWLEDGE_ROUTE_KEYS]
export const RUNNING_STATUS_KEYS = Object.freeze({
UNSTART: '0', // need to run
RUNNING: '1', // need to cancel
CANCEL: '2', // need to refresh
DONE: '3', // need to refresh
FAIL: '4', // need to refresh
} as const)
export type RunningStatus = (typeof RUNNING_STATUS_KEYS)[keyof typeof RUNNING_STATUS_KEYS]
export const RunningStatusMap = {
[RUNNING_STATUS_KEYS.UNSTART]: 'Pending',
[RUNNING_STATUS_KEYS.RUNNING]: 'Running',
[RUNNING_STATUS_KEYS.CANCEL]: 'Cancel',
[RUNNING_STATUS_KEYS.DONE]: 'Success',
[RUNNING_STATUS_KEYS.FAIL]: 'Failed',
} as const;
export const MODEL_VARIABLE_TYPES = Object.freeze({
Improvise: 'Improvise',
Precise: 'Precise',
Balance: 'Balance',
} as const)
export type ModelVariableType = (typeof MODEL_VARIABLE_TYPES)[keyof typeof MODEL_VARIABLE_TYPES]
export const settledModelVariableMap = {
[MODEL_VARIABLE_TYPES.Improvise]: {
temperature: 0.8,
top_p: 0.9,
frequency_penalty: 0.1,
presence_penalty: 0.1,
max_tokens: 4096,
},
[MODEL_VARIABLE_TYPES.Precise]: {
temperature: 0.2,
top_p: 0.75,
frequency_penalty: 0.5,
presence_penalty: 0.5,
max_tokens: 4096,
},
[MODEL_VARIABLE_TYPES.Balance]: {
temperature: 0.5,
top_p: 0.85,
frequency_penalty: 0.3,
presence_penalty: 0.2,
max_tokens: 4096,
},
} as const;
export const LLM_MODEL_TYPES = Object.freeze({
Embedding: 'embedding',
Chat: 'chat',
Image2text: 'image2text',
Speech2text: 'speech2text',
Rerank: 'rerank',
TTS: 'tts',
} as const)
export type LlmModelType = (typeof LLM_MODEL_TYPES)[keyof typeof LLM_MODEL_TYPES]
export const DOCUMENT_TYPES = Object.freeze({
Virtual: 'virtual',
Visual: 'visual',
} as const)
export type DocumentType = (typeof DOCUMENT_TYPES)[keyof typeof DOCUMENT_TYPES]
export const DOCUMENT_PARSER_TYPES = Object.freeze({
Naive: 'naive',
Qa: 'qa',
Resume: 'resume',
Manual: 'manual',
Table: 'table',
Paper: 'paper',
Book: 'book',
Laws: 'laws',
Presentation: 'presentation',
Picture: 'picture',
One: 'one',
Audio: 'audio',
Email: 'email',
Tag: 'tag',
KnowledgeGraph: 'knowledge_graph',
} as const)
export type DocumentParserType = (typeof DOCUMENT_PARSER_TYPES)[keyof typeof DOCUMENT_PARSER_TYPES]
export const KNOWLEDGE_SEARCH_PARAMS_KEYS = Object.freeze({
DocumentId: 'doc_id',
KnowledgeId: 'id',
Type: 'type',
} as const)
export type KnowledgeSearchParams = (typeof KNOWLEDGE_SEARCH_PARAMS_KEYS)[keyof typeof KNOWLEDGE_SEARCH_PARAMS_KEYS]
export const DATABASE_BASE_KEY = 'dataset';

12
src/hooks/useSnackbar.ts Normal file
View File

@@ -0,0 +1,12 @@
import { useSnackbar } from '@/components/Provider/SnackbarProvider';
// 简化的 hooks
export const useMessage = () => {
const { showMessage } = useSnackbar();
return showMessage;
};
export const useNotification = () => {
const { showNotification } = useSnackbar();
return showNotification;
};

25
src/interfaces/common.ts Normal file
View File

@@ -0,0 +1,25 @@
export interface Pagination {
current: number;
pageSize: number;
total: number;
}
export interface BaseState {
pagination: Pagination;
searchString: string;
}
export interface IModalProps<T> {
showModal?(): void;
hideModal?(): void;
switchVisible?(visible: boolean): void;
visible?: boolean;
loading?: boolean;
onOk?(payload?: T): Promise<any> | void;
}
export interface ResponseType {
code: number;
message?: string;
data?: any;
}

View File

@@ -0,0 +1,278 @@
export interface ICategorizeItem {
name: string;
description?: string;
examples?: { value: string }[];
index: number;
to: string[];
uuid: string;
}
export type ICategorizeItemResult = Record<
string,
Omit<ICategorizeItem, 'name' | 'examples' | 'uuid'> & { examples: string[] }
>;
export interface ISwitchCondition {
items: ISwitchItem[];
logical_operator: string;
to: string[];
}
export interface ISwitchItem {
cpn_id: string;
operator: string;
value: string;
}
export interface ISwitchForm {
conditions: ISwitchCondition[];
end_cpn_ids: string[];
no: string;
}
import { AgentCategory } from '@/constants/agent';
import { Edge, Node } from '@xyflow/react';
import { IReference, Message } from './chat';
export type DSLComponents = Record<string, IOperator>;
export interface DSL {
components: DSLComponents;
history: any[];
path?: string[];
answer?: any[];
graph?: IGraph;
messages?: Message[];
reference?: IReference[];
globals: Record<string, any>;
retrieval: IReference[];
}
export interface IOperator {
obj: IOperatorNode;
downstream: string[];
upstream: string[];
parent_id?: string;
}
export interface IOperatorNode {
component_name: string;
params: Record<string, unknown>;
}
export declare interface IFlow {
avatar?: string;
canvas_type: null;
create_date: string;
create_time: number;
description: null;
dsl: DSL;
id: string;
title: string;
update_date: string;
update_time: number;
user_id: string;
permission: string;
nickname: string;
operator_permission: number;
canvas_category: string;
}
export interface IFlowTemplate {
avatar: string;
canvas_type: string;
create_date: string;
create_time: number;
description: string;
dsl: DSL;
id: string;
title: string;
update_date: string;
update_time: number;
}
export interface IGenerateForm {
max_tokens?: number;
temperature?: number;
top_p?: number;
presence_penalty?: number;
frequency_penalty?: number;
cite?: boolean;
prompt: number;
llm_id: string;
parameters: { key: string; component_id: string };
}
export interface ICategorizeForm extends IGenerateForm {
category_description: ICategorizeItemResult;
items: ICategorizeItem[];
}
export interface IRelevantForm extends IGenerateForm {
yes: string;
no: string;
}
export interface ISwitchItem {
cpn_id: string;
operator: string;
value: string;
}
export interface ISwitchForm {
conditions: ISwitchCondition[];
end_cpn_id: string;
no: string;
}
export interface IBeginForm {
prologue?: string;
}
export interface IRetrievalForm {
similarity_threshold?: number;
keywords_similarity_weight?: number;
top_n?: number;
top_k?: number;
rerank_id?: string;
empty_response?: string;
kb_ids: string[];
}
export interface ICodeForm {
arguments: Record<string, string>;
lang: string;
script?: string;
outputs: Record<string, { value: string; type: string }>;
}
export interface IAgentForm {
sys_prompt: string;
prompts: Array<{
role: string;
content: string;
}>;
max_retries: number;
delay_after_error: number;
visual_files_var: string;
max_rounds: number;
exception_method: Nullable<'comment' | 'go'>;
exception_comment: any;
exception_goto: any;
tools: Array<{
name: string;
component_name: string;
params: Record<string, any>;
}>;
mcp: Array<{
mcp_id: string;
tools: Record<string, Record<string, any>>;
}>;
outputs: {
structured_output: Record<string, Record<string, any>>;
content: Record<string, any>;
};
}
export type BaseNodeData<TForm extends any> = {
label: string; // operator type
name: string; // operator name
color?: string;
form?: TForm;
};
export type BaseNode<T = any> = Node<BaseNodeData<T>>;
export type IBeginNode = BaseNode<IBeginForm>;
export type IRetrievalNode = BaseNode<IRetrievalForm>;
export type IGenerateNode = BaseNode<IGenerateForm>;
export type ICategorizeNode = BaseNode<ICategorizeForm>;
export type ISwitchNode = BaseNode<ISwitchForm>;
export type IRagNode = BaseNode;
export type IRelevantNode = BaseNode;
export type ILogicNode = BaseNode;
export type INoteNode = BaseNode;
export type IMessageNode = BaseNode;
export type IRewriteNode = BaseNode;
export type IInvokeNode = BaseNode;
export type ITemplateNode = BaseNode;
export type IEmailNode = BaseNode;
export type IIterationNode = BaseNode;
export type IIterationStartNode = BaseNode;
export type IKeywordNode = BaseNode;
export type ICodeNode = BaseNode<ICodeForm>;
export type IAgentNode = BaseNode;
export type IToolNode = BaseNode<IAgentForm>;
export type RAGFlowNodeType =
| IBeginNode
| IRetrievalNode
| IGenerateNode
| ICategorizeNode
| ISwitchNode
| IRagNode
| IRelevantNode
| ILogicNode
| INoteNode
| IMessageNode
| IRewriteNode
| IInvokeNode
| ITemplateNode
| IEmailNode
| IIterationNode
| IIterationStartNode
| IKeywordNode;
export interface IGraph {
nodes: RAGFlowNodeType[];
edges: Edge[];
}
export interface ITraceData {
component_id: string;
trace: Array<Record<string, any>>;
}
export interface IAgentLogResponse {
id: string;
message: IAgentLogMessage[];
update_date: string;
create_date: string;
update_time: number;
create_time: number;
round: number;
thumb_up: number;
errors: string;
source: string;
user_id: string;
dsl: string;
reference: IReference;
}
export interface IAgentLogsResponse {
total: number;
sessions: IAgentLogResponse[];
}
export interface IAgentLogsRequest {
keywords?: string;
to_date?: string | Date;
from_date?: string | Date;
orderby?: string;
desc?: boolean;
page?: number;
page_size?: number;
}
export interface IAgentLogMessage {
content: string;
role: 'user' | 'assistant';
id: string;
}
export interface IPipeLineListRequest {
page?: number;
page_size?: number;
keywords?: string;
orderby?: string;
desc?: boolean;
canvas_category?: AgentCategory;
}

View File

@@ -0,0 +1,17 @@
export interface ResponseType<T = any> {
code: number;
data: T;
message: string;
status: number;
}
export interface ResponseGetType<T = any> {
data: T;
loading?: boolean;
}
export interface ResponsePostType<T = any> {
data: T;
loading?: boolean;
[key: string]: unknown;
}

View File

@@ -0,0 +1,182 @@
import { MessageType } from '@/constants/chat';
export interface PromptConfig {
empty_response: string;
parameters: Parameter[];
prologue: string;
system: string;
tts?: boolean;
quote: boolean;
keyword: boolean;
refine_multiturn: boolean;
use_kg: boolean;
reasoning?: boolean;
cross_languages?: Array<string>;
}
export interface Parameter {
key: string;
optional: boolean;
}
export interface LlmSetting {
Creative: Variable;
Custom: Variable;
Evenly: Variable;
Precise: Variable;
}
export interface Variable {
frequency_penalty?: number;
max_tokens?: number;
presence_penalty?: number;
temperature?: number;
top_p?: number;
llm_id?: string;
}
export interface IDialog {
create_date: string;
create_time: number;
description: string;
icon: string;
id: string;
dialog_id: string;
kb_ids: string[];
kb_names: string[];
language: string;
llm_id: string;
llm_setting: Variable;
llm_setting_type: string;
name: string;
prompt_config: PromptConfig;
prompt_type: string;
status: string;
tenant_id: string;
update_date: string;
update_time: number;
vector_similarity_weight: number;
similarity_threshold: number;
top_k: number;
top_n: number;
meta_data_filter: MetaDataFilter;
}
interface MetaDataFilter {
manual: Manual[];
method: string;
}
interface Manual {
key: string;
op: string;
value: string;
}
export interface IConversation {
create_date: string;
create_time: number;
dialog_id: string;
id: string;
avatar: string;
message: Message[];
reference: IReference[];
name: string;
update_date: string;
update_time: number;
is_new: true;
}
export interface Message {
content: string;
role: MessageType;
doc_ids?: string[];
prompt?: string;
id?: string;
audio_binary?: string;
data?: any;
files?: File[];
chatBoxId?: string;
}
export interface IReferenceChunk {
id: string;
content: null;
document_id: string;
document_name: string;
dataset_id: string;
image_id: string;
similarity: number;
vector_similarity: number;
term_similarity: number;
positions: number[];
doc_type?: string;
}
export interface IReference {
chunks: IReferenceChunk[];
doc_aggs: Docagg[];
total: number;
}
export interface IReferenceObject {
chunks: Record<string, IReferenceChunk>;
doc_aggs: Record<string, Docagg>;
}
export interface IAnswer {
answer: string;
reference?: IReference;
conversationId?: string;
prompt?: string;
id?: string;
audio_binary?: string;
data?: any;
chatBoxId?: string;
}
export interface Docagg {
count: number;
doc_id: string;
doc_name: string;
url?: string;
}
// interface Chunk {
// chunk_id: string;
// content_ltks: string;
// content_with_weight: string;
// doc_id: string;
// docnm_kwd: string;
// img_id: string;
// important_kwd: any[];
// kb_id: string;
// similarity: number;
// term_similarity: number;
// vector_similarity: number;
// }
export interface IToken {
create_date: string;
create_time: number;
tenant_id: string;
token: string;
update_date?: any;
update_time?: any;
beta: string;
}
export interface IStats {
pv: [string, number][];
uv: [string, number][];
speed: [string, number][];
tokens: [string, number][];
round: [string, number][];
thumb_up: [string, number][];
}
export interface IExternalChatInfo {
avatar?: string;
title: string;
prologue?: string;
}

View File

@@ -0,0 +1,58 @@
import { RunningStatus } from '@/constants/knowledge';
export interface IDocumentInfo {
chunk_num: number;
create_date: string;
create_time: number;
created_by: string;
nickname: string;
id: string;
kb_id: string;
location: string;
name: string;
parser_config: IParserConfig;
parser_id: string;
pipeline_id: string;
pipeline_name: string;
process_begin_at?: string;
process_duration: number;
progress: number;
progress_msg: string;
run: RunningStatus;
size: number;
source_type: string;
status: string;
suffix: string;
thumbnail: string;
token_num: number;
type: string;
update_date: string;
update_time: number;
meta_fields?: Record<string, any>;
}
export interface IParserConfig {
delimiter?: string;
html4excel?: boolean;
layout_recognize?: boolean;
pages: any[];
raptor?: Raptor;
graphrag?: GraphRag;
}
interface Raptor {
use_raptor: boolean;
}
interface GraphRag {
community?: boolean;
entity_types?: string[];
method?: string;
resolution?: boolean;
use_graphrag?: boolean;
}
export type IDocumentInfoFilter = {
run_status: Record<number, number>;
suffix: Record<string, number>;
};

View File

@@ -0,0 +1,39 @@
export interface IFile {
create_date: string;
create_time: number;
created_by: string;
id: string;
kbs_info: { kb_id: string; kb_name: string }[];
location: string;
name: string;
parent_id: string;
size: number;
tenant_id: string;
type: string;
update_date: string;
update_time: number;
source_type: string;
has_child_folder?: boolean;
}
export interface IFolder {
create_date: string;
create_time: number;
created_by: string;
id: string;
location: string;
name: string;
parent_id: string;
size: number;
tenant_id: string;
type: string;
update_date: string;
update_time: number;
source_type: string;
}
export type IFetchFileListResult = {
files: IFile[];
parent_folder: IFolder;
total: number;
};

View File

@@ -0,0 +1,187 @@
import { Edge, Node } from '@xyflow/react';
import { IReference, Message } from './chat';
export type DSLComponents = Record<string, IOperator>;
export interface DSL {
components: DSLComponents;
history: any[];
path?: string[][];
answer?: any[];
graph?: IGraph;
messages: Message[];
reference: IReference[];
globals: Record<string, any>;
retrieval: IReference[];
}
export interface IOperator {
obj: IOperatorNode;
downstream: string[];
upstream: string[];
parent_id?: string;
}
export interface IOperatorNode {
component_name: string;
params: Record<string, unknown>;
}
export declare interface IFlow {
avatar?: string;
canvas_type: null;
create_date: string;
create_time: number;
description: string;
dsl: DSL;
id: string;
title: string;
update_date: string;
update_time: number;
user_id: string;
permission: string;
nickname: string;
}
export interface IFlowTemplate {
avatar: string;
canvas_type: string;
create_date: string;
create_time: number;
description: {
en: string;
zh: string;
};
dsl: DSL;
id: string;
title: {
en: string;
zh: string;
};
update_date: string;
update_time: number;
}
export type ICategorizeItemResult = Record<
string,
Omit<ICategorizeItem, 'name'>
>;
export interface IGenerateForm {
max_tokens?: number;
temperature?: number;
top_p?: number;
presence_penalty?: number;
frequency_penalty?: number;
cite?: boolean;
prompt: number;
llm_id: string;
parameters: { key: string; component_id: string };
}
export interface ICategorizeItem {
name: string;
description?: string;
examples?: string;
to?: string;
index: number;
}
export interface ICategorizeForm extends IGenerateForm {
category_description: ICategorizeItemResult;
}
export interface IRelevantForm extends IGenerateForm {
yes: string;
no: string;
}
export interface ISwitchCondition {
items: ISwitchItem[];
logical_operator: string;
to: string[] | string;
}
export interface ISwitchItem {
cpn_id: string;
operator: string;
value: string;
}
export interface ISwitchForm {
conditions: ISwitchCondition[];
end_cpn_id: string;
no: string;
}
export interface IBeginForm {
prologue?: string;
}
export interface IRetrievalForm {
similarity_threshold?: number;
keywords_similarity_weight?: number;
top_n?: number;
top_k?: number;
rerank_id?: string;
empty_response?: string;
kb_ids: string[];
}
export interface ICodeForm {
inputs?: Array<{ name?: string; component_id?: string }>;
lang: string;
script?: string;
}
export type BaseNodeData<TForm extends any> = {
label: string; // operator type
name: string; // operator name
color?: string;
form?: TForm;
};
export type BaseNode<T = any> = Node<BaseNodeData<T>>;
export type IBeginNode = BaseNode<IBeginForm>;
export type IRetrievalNode = BaseNode<IRetrievalForm>;
export type IGenerateNode = BaseNode<IGenerateForm>;
export type ICategorizeNode = BaseNode<ICategorizeForm>;
export type ISwitchNode = BaseNode<ISwitchForm>;
export type IRagNode = BaseNode;
export type IRelevantNode = BaseNode;
export type ILogicNode = BaseNode;
export type INoteNode = BaseNode;
export type IMessageNode = BaseNode;
export type IRewriteNode = BaseNode;
export type IInvokeNode = BaseNode;
export type ITemplateNode = BaseNode;
export type IEmailNode = BaseNode;
export type IIterationNode = BaseNode;
export type IIterationStartNode = BaseNode;
export type IKeywordNode = BaseNode;
export type ICodeNode = BaseNode<ICodeForm>;
export type IAgentNode = BaseNode;
export type RAGFlowNodeType =
| IBeginNode
| IRetrievalNode
| IGenerateNode
| ICategorizeNode
| ISwitchNode
| IRagNode
| IRelevantNode
| ILogicNode
| INoteNode
| IMessageNode
| IRewriteNode
| IInvokeNode
| ITemplateNode
| IEmailNode
| IIterationNode
| IIterationStartNode
| IKeywordNode;
export interface IGraph {
nodes: RAGFlowNodeType[];
edges: Edge[];
}

View File

@@ -0,0 +1,168 @@
import { RunningStatus } from '@/constants/knowledge';
import { TreeData } from '@antv/g6/lib/types';
// knowledge base
export interface IKnowledge {
avatar?: any;
chunk_num: number;
create_date: string;
create_time: number;
created_by: string;
description: string;
doc_num: number;
id: string;
name: string;
parser_config: ParserConfig;
parser_id: string;
pipeline_id: string;
pipeline_name: string;
pipeline_avatar: string;
permission: string;
similarity_threshold: number;
status: string;
tenant_id: string;
token_num: number;
update_date: string;
update_time: number;
vector_similarity_weight: number;
embd_id: string;
nickname: string;
operator_permission: number;
size: number;
raptor_task_finish_at?: string;
raptor_task_id?: string;
mindmap_task_finish_at?: string;
mindmap_task_id?: string;
}
export interface IKnowledgeResult {
kbs: IKnowledge[];
total: number;
}
export interface Raptor {
use_raptor: boolean;
}
export interface ParserConfig {
from_page?: number;
to_page?: number;
auto_keywords?: number;
auto_questions?: number;
chunk_token_num?: number;
delimiter?: string;
html4excel?: boolean;
layout_recognize?: boolean;
raptor?: Raptor;
tag_kb_ids?: string[];
topn_tags?: number;
graphrag?: { use_graphrag?: boolean };
}
export interface IKnowledgeFileParserConfig {
chunk_token_num: number;
layout_recognize: boolean;
pages: number[][];
task_page_size: number;
}
export interface IKnowledgeFile {
chunk_num: number;
create_date: string;
create_time: number;
created_by: string;
id: string;
kb_id: string;
location: string;
name: string;
parser_id: string;
process_begin_at?: any;
process_duration: number;
progress: number; // parsing process
progress_msg: string; // parsing log
run: RunningStatus; // parsing status
size: number;
source_type: string;
status: string; // enabled
thumbnail?: any; // base64
token_num: number;
type: string;
update_date: string;
update_time: number;
parser_config: IKnowledgeFileParserConfig;
}
export interface ITenantInfo {
asr_id: string;
embd_id: string;
img2txt_id: string;
llm_id: string;
name: string;
parser_ids: string;
role: string;
tenant_id: string;
chat_id: string;
speech2text_id: string;
tts_id: string;
}
export interface IChunk {
available_int: number; // Whether to enable, 0: not enabled, 1: enabled
chunk_id: string;
content_with_weight: string;
doc_id: string;
doc_name: string;
image_id: string;
important_kwd?: string[];
question_kwd?: string[]; // keywords
tag_kwd?: string[];
positions: number[][];
tag_feas?: Record<string, number>;
}
export interface ITestingChunk {
chunk_id: string;
content_ltks: string;
content_with_weight: string;
doc_id: string;
doc_name: string;
img_id: string;
image_id: string;
important_kwd: any[];
kb_id: string;
similarity: number;
term_similarity: number;
vector: number[];
vector_similarity: number;
highlight: string;
positions: number[][];
docnm_kwd: string;
doc_type_kwd: string;
}
export interface ITestingDocument {
count: number;
doc_id: string;
doc_name: string;
}
export interface ITestingResult {
chunks: ITestingChunk[];
documents: ITestingDocument[];
total: number;
labels?: Record<string, number>;
}
export interface INextTestingResult {
chunks: ITestingChunk[];
doc_aggs: ITestingDocument[];
total: number;
labels?: Record<string, number>;
isRuned?: boolean;
}
export type IRenameTag = { fromTag: string; toTag: string };
export interface IKnowledgeGraph {
graph: Record<string, any>;
mind_map: TreeData;
}

View File

@@ -0,0 +1,41 @@
export interface IThirdOAIModel {
available: boolean;
create_date: string;
create_time: number;
fid: string;
id: number;
llm_name: string;
max_tokens: number;
model_type: string;
status: string;
tags: string;
update_date: string;
update_time: number;
tenant_id?: string;
tenant_name?: string;
is_tools: boolean;
}
export type IThirdOAIModelCollection = Record<string, IThirdOAIModel[]>;
export interface IFactory {
create_date: string;
create_time: number;
logo: string;
name: string;
status: string;
tags: string;
update_date: string;
update_time: number;
}
export interface IMyLlmValue {
llm: Llm[];
tags: string;
}
export interface Llm {
name: string;
type: string;
used_token: number;
}

View File

@@ -0,0 +1,19 @@
export enum McpServerType {
Sse = 'sse',
StreamableHttp = 'streamable-http',
}
export interface IMcpServerVariable {
key: string;
name: string;
}
export interface IMcpServerInfo {
id: string;
name: string;
url: string;
server_type: McpServerType;
description?: string;
variables?: IMcpServerVariable[];
headers: Map<string, string>;
}

View File

@@ -0,0 +1,60 @@
export interface IMcpServer {
create_date: string;
description: null;
id: string;
name: string;
server_type: string;
update_date: string;
url: string;
variables: Record<string, any> & { tools?: IMCPToolObject };
}
export type IMCPToolObject = Record<string, Omit<IMCPTool, 'name'>>;
export type IMCPToolRecord = Record<string, IMCPTool>;
export interface IMcpServerListResponse {
mcp_servers: IMcpServer[];
total: number;
}
export interface IMCPTool {
annotations: null;
description: string;
enabled: boolean;
inputSchema: InputSchema;
name: string;
}
interface InputSchema {
properties: Properties;
required: string[];
title: string;
type: string;
}
interface Properties {
symbol: ISymbol;
}
interface ISymbol {
title: string;
type: string;
}
export interface IExportedMcpServers {
mcpServers: McpServers;
}
interface McpServers {
fetch_2: IExportedMcpServer;
github_1: IExportedMcpServer;
}
export interface IExportedMcpServer {
authorization_token: string;
name: string;
tool_configuration: Record<string, any>;
type: string;
url: string;
}

View File

@@ -0,0 +1,13 @@
export type ILLMTools = ILLMToolMetadata[];
export interface ILLMToolMetadata {
name: string;
displayName: string;
displayDescription: string;
parameters: Map<string, ILLMToolParameter>;
}
export interface ILLMToolParameter {
type: string;
displayDescription: string;
}

View File

@@ -0,0 +1,7 @@
export interface ILangfuseConfig {
secret_key: string;
public_key: string;
host: string;
project_id: string;
project_name: string;
}

View File

@@ -0,0 +1,96 @@
export interface IUserInfo {
access_token: string;
avatar?: any;
color_schema: string;
create_date: string;
create_time: number;
email: string;
id: string;
is_active: string;
is_anonymous: string;
is_authenticated: string;
is_superuser: boolean;
language: string;
last_login_time: string;
login_channel: string;
nickname: string;
password: string;
status: string;
timezone: string;
update_date: string;
update_time: number;
}
export type TaskExecutorElapsed = Record<string, number[]>;
export interface TaskExecutorHeartbeatItem {
boot_at: string;
current: null;
done: number;
failed: number;
lag: number;
name: string;
now: string;
pending: number;
}
export interface ISystemStatus {
es: Es;
storage: Storage;
database: Database;
redis: Redis;
task_executor_heartbeat: Record<string, TaskExecutorHeartbeatItem[]>;
}
interface Redis {
status: string;
elapsed: number;
error: string;
pending: number;
}
export interface Storage {
status: string;
elapsed: number;
error: string;
}
export interface Database {
status: string;
elapsed: number;
error: string;
}
interface Es {
status: string;
elapsed: number;
error: string;
number_of_nodes: number;
active_shards: number;
}
export interface ITenantUser {
id: string;
avatar: string;
delta_seconds: number;
email: string;
is_active: string;
is_anonymous: string;
is_authenticated: string;
is_superuser: boolean;
nickname: string;
role: string;
status: string;
update_date: string;
user_id: string;
}
export interface ITenant {
avatar: string;
delta_seconds: number;
email: string;
nickname: string;
role: string;
tenant_id: string;
update_date: string;
}

View File

@@ -0,0 +1,4 @@
export interface IDebugSingleRequestBody {
component_id: string;
params: Record<string, any>;
}

View File

@@ -0,0 +1,7 @@
export interface IPaginationRequestBody {
keywords?: string;
page?: number;
page_size?: number; // name|create|doc_num|create_time|update_time, defaultcreate_time
orderby?: string;
desc?: string;
}

View File

@@ -0,0 +1,11 @@
export interface IFeedbackRequestBody {
messageId?: string;
thumbup?: boolean;
feedback?: string;
}
export interface IAskRequestBody {
question: string;
kb_ids: string[];
search_id?: string;
}

View File

@@ -0,0 +1,18 @@
export interface IChangeParserConfigRequestBody {
pages: number[][];
chunk_token_num: number;
layout_recognize: boolean;
task_page_size: number;
}
export interface IChangeParserRequestBody {
parser_id: string;
pipeline_id: string;
doc_id: string;
parser_config: IChangeParserConfigRequestBody;
}
export interface IDocumentMetaRequestBody {
documentId: string;
meta: string; // json format string
}

View File

@@ -0,0 +1,14 @@
import { IPaginationRequestBody } from './base';
export interface IFileListRequestBody extends IPaginationRequestBody {
parent_id?: string; // folder id
}
interface BaseRequestBody {
parentId: string;
}
export interface IConnectRequestBody {
fileIds: string[];
kbIds: string[];
}

View File

@@ -0,0 +1,4 @@
export interface IDebugSingleRequestBody {
component_id: string;
params: any[];
}

View File

@@ -0,0 +1,26 @@
export interface ITestRetrievalRequestBody {
question: string;
similarity_threshold: number;
vector_similarity_weight: number;
rerank_id?: string;
top_k?: number;
use_kg?: boolean;
highlight?: boolean;
kb_id?: string[];
}
export interface IFetchKnowledgeListRequestBody {
owner_ids?: string[];
}
export interface IFetchKnowledgeListRequestParams {
kb_id?: string;
keywords?: string;
page?: number;
page_size?: number;
}
export interface IFetchDocumentListRequestBody {
suffix?: string[];
run_status?: string[];
}

View File

@@ -0,0 +1,13 @@
export interface IAddLlmRequestBody {
llm_factory: string; // Ollama
llm_name: string;
model_type: string;
api_base?: string; // chat|embedding|speech2text|image2text
api_key: string;
max_tokens: number;
}
export interface IDeleteLlmRequestBody {
llm_factory: string; // Ollama
llm_name?: string;
}

View File

@@ -0,0 +1,16 @@
import { IExportedMcpServer } from '@/interfaces/database/mcp';
export interface ITestMcpRequestBody {
server_type: string;
url: string;
headers?: Record<string, any>;
variables?: Record<string, any>;
timeout?: number;
}
export interface IImportMcpServersRequestBody {
mcpServers: Record<
string,
Pick<IExportedMcpServer, 'type' | 'url' | 'authorization_token'>
>;
}

View File

@@ -0,0 +1,5 @@
export interface ISetLangfuseConfigRequestBody {
secret_key: string;
public_key: string;
host: string;
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,9 @@ import zh from './zh';
export const LanguageAbbreviation = Object.freeze({
En: 'en',
Zh: 'zh',
})
} as const)
export type LanguageAbbreviationType = (typeof LanguageAbbreviation)[keyof typeof LanguageAbbreviation]
const resources = {
[LanguageAbbreviation.En]: en,

File diff suppressed because it is too large Load Diff

View File

@@ -13,9 +13,11 @@ import {
AppBar,
Toolbar,
Card,
CardContent
CardContent,
Alert
} from '@mui/material';
import LanguageSwitcher from '../components/LanguageSwitcher';
import userService from '../services/user_service';
const Login = () => {
const { t } = useTranslation();
@@ -25,24 +27,40 @@ const Login = () => {
const [isSubmitting, setIsSubmitting] = useState(false);
const [emailError, setEmailError] = useState(false);
const [passwordError, setPasswordError] = useState(false);
const [loginError, setLoginError] = useState('');
const navigate = useNavigate();
console.log(t, t('en'), t('login'));
const handleSubmit = (e: React.FormEvent) => {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const hasEmail = !!email.trim();
const hasPassword = !!password.trim();
setEmailError(!hasEmail);
setPasswordError(!hasPassword);
setLoginError('');
if (!hasEmail || !hasPassword) return;
setIsSubmitting(true);
// 模拟登录过程
setTimeout(() => {
navigate('/');
}, 800);
try {
const response = await userService.login({ email, password });
// if (response.code === 0) {
// // 登录成功,跳转到主页
// navigate('/');
// } else {
// // 登录失败,显示错误信息
// setLoginError(response.message || t('login.loginFailed'));
// }
} catch (error: any) {
// 处理网络错误或其他异常
setLoginError(error.message || t('login.networkError'));
} finally {
setIsSubmitting(false);
}
};
return (
@@ -84,6 +102,12 @@ const Login = () => {
</Typography>
<Box component="form" onSubmit={handleSubmit} noValidate>
{loginError && (
<Alert severity="error" sx={{ mb: 2 }}>
{loginError}
</Alert>
)}
<TextField
fullWidth
id="email"

213
src/services/api.ts Normal file
View File

@@ -0,0 +1,213 @@
let api_host = `/v1`;
const ExternalApi = `/api`;
export { api_host };
export default {
// user
login: `${api_host}/user/login`,
logout: `${api_host}/user/logout`,
register: `${api_host}/user/register`,
setting: `${api_host}/user/setting`,
user_info: `${api_host}/user/info`,
tenant_info: `${api_host}/user/tenant_info`,
set_tenant_info: `${api_host}/user/set_tenant_info`,
login_channels: `${api_host}/user/login/channels`,
login_channel: (channel: string) => `${api_host}/user/login/${channel}`,
// team
addTenantUser: (tenantId: string) => `${api_host}/tenant/${tenantId}/user`,
listTenantUser: (tenantId: string) =>
`${api_host}/tenant/${tenantId}/user/list`,
deleteTenantUser: (tenantId: string, userId: string) =>
`${api_host}/tenant/${tenantId}/user/${userId}`,
listTenant: `${api_host}/tenant/list`,
agreeTenant: (tenantId: string) => `${api_host}/tenant/agree/${tenantId}`,
// llm model
factories_list: `${api_host}/llm/factories`,
llm_list: `${api_host}/llm/list`,
my_llm: `${api_host}/llm/my_llms`,
set_api_key: `${api_host}/llm/set_api_key`,
add_llm: `${api_host}/llm/add_llm`,
delete_llm: `${api_host}/llm/delete_llm`,
deleteFactory: `${api_host}/llm/delete_factory`,
// plugin
llm_tools: `${api_host}/plugin/llm_tools`,
// knowledge base
kb_list: `${api_host}/kb/list`,
create_kb: `${api_host}/kb/create`,
update_kb: `${api_host}/kb/update`,
rm_kb: `${api_host}/kb/rm`,
get_kb_detail: `${api_host}/kb/detail`,
getKnowledgeGraph: (knowledgeId: string) =>
`${api_host}/kb/${knowledgeId}/knowledge_graph`,
getMeta: `${api_host}/kb/get_meta`,
getKnowledgeBasicInfo: `${api_host}/kb/basic_info`,
// data pipeline log
fetchDataPipelineLog: `${api_host}/kb/list_pipeline_logs`,
get_pipeline_detail: `${api_host}/kb/pipeline_log_detail`,
fetchPipelineDatasetLogs: `${api_host}/kb/list_pipeline_dataset_logs`,
runGraphRag: `${api_host}/kb/run_graphrag`,
traceGraphRag: `${api_host}/kb/trace_graphrag`,
runRaptor: `${api_host}/kb/run_raptor`,
traceRaptor: `${api_host}/kb/trace_raptor`,
unbindPipelineTask: ({ kb_id, type }: { kb_id: string; type: string }) =>
`${api_host}/kb/unbind_task?kb_id=${kb_id}&pipeline_task_type=${type}`,
pipelineRerun: `${api_host}/canvas/rerun`,
// tags
listTag: (knowledgeId: string) => `${api_host}/kb/${knowledgeId}/tags`,
listTagByKnowledgeIds: `${api_host}/kb/tags`,
removeTag: (knowledgeId: string) => `${api_host}/kb/${knowledgeId}/rm_tags`,
renameTag: (knowledgeId: string) =>
`${api_host}/kb/${knowledgeId}/rename_tag`,
// chunk
chunk_list: `${api_host}/chunk/list`,
create_chunk: `${api_host}/chunk/create`,
set_chunk: `${api_host}/chunk/set`,
get_chunk: `${api_host}/chunk/get`,
switch_chunk: `${api_host}/chunk/switch`,
rm_chunk: `${api_host}/chunk/rm`,
retrieval_test: `${api_host}/chunk/retrieval_test`,
knowledge_graph: `${api_host}/chunk/knowledge_graph`,
// document
get_document_list: `${api_host}/document/list`,
document_change_status: `${api_host}/document/change_status`,
document_rm: `${api_host}/document/rm`,
document_delete: `${api_host}/api/document`,
document_rename: `${api_host}/document/rename`,
document_create: `${api_host}/document/create`,
document_run: `${api_host}/document/run`,
document_change_parser: `${api_host}/document/change_parser`,
document_thumbnails: `${api_host}/document/thumbnails`,
get_document_file: `${api_host}/document/get`,
document_upload: `${api_host}/document/upload`,
web_crawl: `${api_host}/document/web_crawl`,
document_infos: `${api_host}/document/infos`,
upload_and_parse: `${api_host}/document/upload_and_parse`,
parse: `${api_host}/document/parse`,
setMeta: `${api_host}/document/set_meta`,
get_dataset_filter: `${api_host}/document/filter`,
// chat
setDialog: `${api_host}/dialog/set`,
getDialog: `${api_host}/dialog/get`,
removeDialog: `${api_host}/dialog/rm`,
listDialog: `${api_host}/dialog/list`,
setConversation: `${api_host}/conversation/set`,
getConversation: `${api_host}/conversation/get`,
getConversationSSE: `${api_host}/conversation/getsse`,
listConversation: `${api_host}/conversation/list`,
removeConversation: `${api_host}/conversation/rm`,
completeConversation: `${api_host}/conversation/completion`,
deleteMessage: `${api_host}/conversation/delete_msg`,
thumbup: `${api_host}/conversation/thumbup`,
tts: `${api_host}/conversation/tts`,
ask: `${api_host}/conversation/ask`,
mindmap: `${api_host}/conversation/mindmap`,
getRelatedQuestions: `${api_host}/conversation/related_questions`,
// chat for external
createToken: `${api_host}/api/new_token`,
listToken: `${api_host}/api/token_list`,
removeToken: `${api_host}/api/rm`,
getStats: `${api_host}/api/stats`,
createExternalConversation: `${api_host}/api/new_conversation`,
getExternalConversation: `${api_host}/api/conversation`,
completeExternalConversation: `${api_host}/api/completion`,
uploadAndParseExternal: `${api_host}/api/document/upload_and_parse`,
// next chat
listNextDialog: `${api_host}/dialog/next`,
fetchExternalChatInfo: (id: string) =>
`${ExternalApi}${api_host}/chatbots/${id}/info`,
// file manager
listFile: `${api_host}/file/list`,
uploadFile: `${api_host}/file/upload`,
removeFile: `${api_host}/file/rm`,
renameFile: `${api_host}/file/rename`,
getAllParentFolder: `${api_host}/file/all_parent_folder`,
createFolder: `${api_host}/file/create`,
connectFileToKnowledge: `${api_host}/file2document/convert`,
getFile: `${api_host}/file/get`,
moveFile: `${api_host}/file/mv`,
// system
getSystemVersion: `${api_host}/system/version`,
getSystemStatus: `${api_host}/system/status`,
getSystemTokenList: `${api_host}/system/token_list`,
createSystemToken: `${api_host}/system/new_token`,
listSystemToken: `${api_host}/system/token_list`,
removeSystemToken: `${api_host}/system/token`,
getSystemConfig: `${api_host}/system/config`,
setLangfuseConfig: `${api_host}/langfuse/api_key`,
// flow
listTemplates: `${api_host}/canvas/templates`,
listCanvas: `${api_host}/canvas/list`,
getCanvas: `${api_host}/canvas/get`,
getCanvasSSE: `${api_host}/canvas/getsse`,
removeCanvas: `${api_host}/canvas/rm`,
setCanvas: `${api_host}/canvas/set`,
settingCanvas: `${api_host}/canvas/setting`,
getListVersion: `${api_host}/canvas/getlistversion`,
getVersion: `${api_host}/canvas/getversion`,
resetCanvas: `${api_host}/canvas/reset`,
runCanvas: `${api_host}/canvas/completion`,
testDbConnect: `${api_host}/canvas/test_db_connect`,
getInputElements: `${api_host}/canvas/input_elements`,
debug: `${api_host}/canvas/debug`,
uploadCanvasFile: `${api_host}/canvas/upload`,
trace: `${api_host}/canvas/trace`,
// agent
inputForm: `${api_host}/canvas/input_form`,
fetchVersionList: (id: string) => `${api_host}/canvas/getlistversion/${id}`,
fetchVersion: (id: string) => `${api_host}/canvas/getversion/${id}`,
fetchCanvas: (id: string) => `${api_host}/canvas/get/${id}`,
fetchAgentAvatar: (id: string) => `${api_host}/canvas/getsse/${id}`,
uploadAgentFile: (id?: string) => `${api_host}/canvas/upload/${id}`,
fetchAgentLogs: (canvasId: string) =>
`${api_host}/canvas/${canvasId}/sessions`,
fetchExternalAgentInputs: (canvasId: string) =>
`${ExternalApi}${api_host}/agentbots/${canvasId}/inputs`,
prompt: `${api_host}/canvas/prompts`,
cancelDataflow: (id: string) => `${api_host}/canvas/cancel/${id}`,
downloadFile: `${api_host}/canvas/download`,
// mcp server
listMcpServer: `${api_host}/mcp_server/list`,
getMcpServer: `${api_host}/mcp_server/detail`,
createMcpServer: `${api_host}/mcp_server/create`,
updateMcpServer: `${api_host}/mcp_server/update`,
deleteMcpServer: `${api_host}/mcp_server/rm`,
importMcpServer: `${api_host}/mcp_server/import`,
exportMcpServer: `${api_host}/mcp_server/export`,
listMcpServerTools: `${api_host}/mcp_server/list_tools`,
testMcpServerTool: `${api_host}/mcp_server/test_tool`,
cacheMcpServerTool: `${api_host}/mcp_server/cache_tools`,
testMcpServer: `${api_host}/mcp_server/test_mcp`,
// next-search
createSearch: `${api_host}/search/create`,
getSearchList: `${api_host}/search/list`,
deleteSearch: `${api_host}/search/rm`,
getSearchDetail: `${api_host}/search/detail`,
getSearchDetailShare: `${ExternalApi}${api_host}/searchbots/detail`,
updateSearchSetting: `${api_host}/search/update`,
askShare: `${ExternalApi}${api_host}/searchbots/ask`,
mindmapShare: `${ExternalApi}${api_host}/searchbots/mindmap`,
getRelatedQuestionsShare: `${ExternalApi}${api_host}/searchbots/related_questions`,
retrievalTestShare: `${ExternalApi}${api_host}/searchbots/retrieval_test`,
// data pipeline
fetchDataflow: (id: string) => `${api_host}/dataflow/get/${id}`,
setDataflow: `${api_host}/dataflow/set`,
removeDataflow: `${api_host}/dataflow/rm`,
listDataflow: `${api_host}/dataflow/list`,
runDataflow: `${api_host}/dataflow/run`,
};

View File

@@ -0,0 +1,74 @@
import api from './api';
import request, { post } from '@/utils/request';
// 用户相关API服务
const userService = {
// 用户登录
login: (data: { email: string; password: string }) => {
return post(api.login, data);
},
// 用户登出
logout: () => {
return request.get(api.logout);
},
// 用户注册
register: (data: { email: string; password: string; username?: string }) => {
return post(api.register, data);
},
// 获取用户信息
getUserInfo: () => {
return request.get(api.user_info);
},
// 更新用户设置
updateSetting: (data: any) => {
return post(api.setting, data);
},
// 获取租户信息
getTenantInfo: () => {
return request.get(api.tenant_info);
},
// 设置租户信息
setTenantInfo: (data: any) => {
return post(api.set_tenant_info, data);
},
// 获取登录渠道
getLoginChannels: () => {
return request.get(api.login_channels);
},
// 通过渠道登录
loginWithChannel: (channel: string) => {
window.location.href = api.login_channel(channel);
},
// 租户用户管理
listTenantUser: (tenantId: string) => {
return request.get(api.listTenantUser(tenantId));
},
addTenantUser: (tenantId: string, email: string) => {
return post(api.addTenantUser(tenantId), { email });
},
deleteTenantUser: ({ tenantId, userId }: { tenantId: string; userId: string }) => {
return request.delete(api.deleteTenantUser(tenantId, userId));
},
// 租户管理
listTenant: () => {
return request.get(api.listTenant);
},
agreeTenant: (tenantId: string) => {
return request.put(api.agreeTenant(tenantId));
},
};
export default userService;

24
src/utils/common.ts Normal file
View File

@@ -0,0 +1,24 @@
import isObject from 'lodash/isObject';
import snakeCase from 'lodash/snakeCase';
export const isFormData = (data: unknown): data is FormData => {
return data instanceof FormData;
};
const excludedFields = ['img2txt_id', 'mcpServers'];
const isExcludedField = (key: string) => {
return excludedFields.includes(key);
};
export const convertTheKeysOfTheObjectToSnake = (data: unknown) => {
if (isObject(data) && !isFormData(data)) {
return Object.keys(data).reduce<Record<string, any>>((pre, cur) => {
const value = (data as Record<string, any>)[cur];
pre[isFormData(value) || isExcludedField(cur) ? cur : snakeCase(cur)] =
value;
return pre;
}, {});
}
return data;
};

188
src/utils/request.ts Normal file
View File

@@ -0,0 +1,188 @@
import { Authorization } from '@/constants/authorization';
import type { ResponseType } from '@/interfaces/database/base';
import i18n from '@/locales';
import axios from 'axios';
import type { AxiosRequestConfig, AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import { snackbar, notification } from '@/utils/snackbarInstance';
const FAILED_TO_FETCH = 'Failed to fetch';
export const RetcodeMessage = {
200: i18n.t('message.200'),
201: i18n.t('message.201'),
202: i18n.t('message.202'),
204: i18n.t('message.204'),
400: i18n.t('message.400'),
401: i18n.t('message.401'),
403: i18n.t('message.403'),
404: i18n.t('message.404'),
406: i18n.t('message.406'),
410: i18n.t('message.410'),
413: i18n.t('message.413'),
422: i18n.t('message.422'),
500: i18n.t('message.500'),
502: i18n.t('message.502'),
503: i18n.t('message.503'),
504: i18n.t('message.504'),
};
export type ResultCode =
| 200
| 201
| 202
| 204
| 400
| 401
| 403
| 404
| 406
| 410
| 413
| 422
| 500
| 502
| 503
| 504;
// 获取授权token
const getAuthorization = (): string => {
return localStorage.getItem('token') || '';
};
// 重定向到登录页
const redirectToLogin = (): void => {
localStorage.removeItem('token');
window.location.href = '/login';
};
// 转换对象键为snake_case
const convertTheKeysOfTheObjectToSnake = (obj: any): any => {
if (!obj || typeof obj !== 'object') return obj;
if (Array.isArray(obj)) {
return obj.map(convertTheKeysOfTheObjectToSnake);
}
const result: any = {};
Object.keys(obj).forEach(key => {
const snakeKey = key.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
result[snakeKey] = convertTheKeysOfTheObjectToSnake(obj[key]);
});
return result;
};
// 创建axios实例
const request: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 300000,
headers: {
'Content-Type': 'application/json',
},
});
// 请求拦截器
request.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
// 转换数据格式
if (config.data) {
config.data = convertTheKeysOfTheObjectToSnake(config.data);
}
if (config.params) {
config.params = convertTheKeysOfTheObjectToSnake(config.params);
}
// 添加授权头
const token = getAuthorization();
if (token && !config.headers?.skipToken) {
config.headers[Authorization] = token;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
request.interceptors.response.use(
(response: AxiosResponse) => {
const { status } = response;
// 处理特定状态码
if (status === 413 || status === 504) {
snackbar.error(RetcodeMessage[status as ResultCode]);
}
// 处理blob类型响应
if (response.config.responseType === 'blob') {
return response;
}
const data: ResponseType = response.data;
// 处理业务错误码
if (data?.code === 100) {
snackbar.error(data?.message);
} else if (data?.code === 401) {
// notification.error({
// message: data?.message,
// description: data?.message,
// duration: 3,
// });
notification.error(data?.message);
redirectToLogin();
} else if (data?.code !== 0) {
// notification.error({
// message: `${i18n.t('message.hint')} : ${data?.code}`,
// description: data?.message,
// duration: 3,
// });
notification.error(`${i18n.t('message.hint')} : ${data?.code}`, data?.message);
}
return response;
},
(error) => {
// 处理网络错误
if (error.message === FAILED_TO_FETCH || !error.response) {
// notification.error({
// description: i18n.t('message.networkAnomalyDescription'),
// message: i18n.t('message.networkAnomaly'),
// });
notification.error(i18n.t('message.networkAnomaly'), i18n.t('message.networkAnomalyDescription'));
} else if (error.response) {
const { status, statusText } = error.response;
const errorText = RetcodeMessage[status as ResultCode] || statusText;
// notification.error({
// message: `${i18n.t('message.requestError')} ${status}`,
// description: errorText,
// });
notification.error(`${i18n.t('message.requestError')} ${status}`, errorText);
}
return Promise.reject(error);
}
);
export default request;
// 便捷方法
export const get = (url: string, config?: AxiosRequestConfig) => {
return request.get(url, config);
};
export const post = (url: string, data?: any, config?: AxiosRequestConfig) => {
return request.post(url, data, config);
};
export const put = (url: string, data?: any, config?: AxiosRequestConfig) => {
return request.put(url, data, config);
};
export const del = (url: string, config?: AxiosRequestConfig) => {
return request.delete(url, config);
};

View File

@@ -0,0 +1,29 @@
// 为非组件文件提供全局 snackbar 实例
const getSnackbarInstance = () => {
if (typeof window !== 'undefined') {
return (window as any).__snackbarInstance;
}
return null;
};
export const snackbar = {
success: (msg: string, duration?: number) =>
getSnackbarInstance()?.showMessage.success(msg, duration),
error: (msg: string, duration?: number) =>
getSnackbarInstance()?.showMessage.error(msg, duration),
warning: (msg: string, duration?: number) =>
getSnackbarInstance()?.showMessage.warning(msg, duration),
info: (msg: string, duration?: number) =>
getSnackbarInstance()?.showMessage.info(msg, duration),
};
export const notification = {
success: (title: string, message?: string, duration?: number) =>
getSnackbarInstance()?.showNotification.success(title, message, duration),
error: (title: string, message?: string, duration?: number) =>
getSnackbarInstance()?.showNotification.error(title, message, duration),
warning: (title: string, message?: string, duration?: number) =>
getSnackbarInstance()?.showNotification.warning(title, message, duration),
info: (title: string, message?: string, duration?: number) =>
getSnackbarInstance()?.showNotification.info(title, message, duration),
};

View File

@@ -22,7 +22,13 @@
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
"noUncheckedSideEffectImports": true,
/* Path Aliases */
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src"]
}

View File

@@ -4,5 +4,8 @@
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
],
"exclude": ["rag_web_core"]
// exclude rag_web_core/**/*
"exclude": [
"rag_web_core/**"
]
}

View File

@@ -1,7 +1,13 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
})