第一次提交

This commit is contained in:
wangjiming
2026-07-27 09:12:47 +08:00
commit b4ff5db17b
579 changed files with 48768 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
import { get, put } from '../request'
export interface AclEntry {
subject_type: string
subject_id: string
permissions: string[]
}
/** 资源 ACL 查询 */
export const getAcl = (resourceType: string, resourceId: string) =>
get<AclEntry[]>(`/resources/${resourceType}/${resourceId}/acl`)
/** 资源 ACL 设置 */
export const setAcl = (resourceType: string, resourceId: string, entries: AclEntry[]) =>
put<AclEntry[]>(`/resources/${resourceType}/${resourceId}/acl`, { entries })

View File

@@ -0,0 +1,50 @@
import { get, post } from '../request'
export interface ApprovalStep {
approver_id?: string | null
status: string
}
export interface ApprovalTemplate {
id: string
name: string
steps: ApprovalStep[]
create_time?: string
}
export interface ApprovalInstance {
id: string
template_id?: string | null
resource_type: string
resource_id: string
applicant_id: string
status: string
current_step: number
create_time?: string
steps: Array<ApprovalStep & { step_index: number; comment?: string | null; time?: string | null }>
}
export const getApprovalTemplates = () =>
get<ApprovalTemplate[]>('/approvals/templates')
export const createApprovalTemplate = (payload: { name: string; steps: ApprovalStep[] }) =>
post<ApprovalTemplate>('/approvals/templates', payload)
export const getApprovalInstances = (status?: string) =>
get<ApprovalInstance[]>('/approvals', { status })
export const createApprovalInstance = (payload: {
template_id?: string
resource_type: string
resource_id: string
applicant_id: string
}) => post<ApprovalInstance>('/approvals', payload)
export const getApprovalInstance = (id: string) =>
get<ApprovalInstance>(`/approvals/${id}`)
export const decideApproval = (
id: string,
step_index: number,
payload: { approver_id: string; approved: boolean; comment?: string },
) => post<ApprovalInstance>(`/approvals/${id}/steps/${step_index}/decision`, payload)

View File

@@ -0,0 +1,40 @@
import { get } from '../request'
import request from '../request'
export interface AuditLog {
id: string
tenant_id?: string
project_id?: string
actor_id?: string
action?: string
target_type?: string
target_id?: string
detail?: string
client_ip?: string
time?: string
}
export interface AuditQuery {
tenant_id?: string
project_id?: string
actor_id?: string
action?: string
target_type?: string
start_time?: string
end_time?: string
limit?: number
offset?: number
}
/** 审计日志查询:使用 get 辅助函数,拦截器已解包,直接返回 { items, total } */
export const getAuditLogs = (query: AuditQuery = {}) =>
get<{ items: AuditLog[]; total: number }>('/system/audit-logs', query)
/** 审计日志导出 CSVblob 响应走完整 axios response需手动取 data */
export const exportAuditLogs = (query: AuditQuery = {}) =>
request<Blob>({
url: '/system/audit-logs/export',
method: 'get',
params: query,
responseType: 'blob',
}).then((res) => res.data)

View File

@@ -0,0 +1,80 @@
import { get, post, del } from '../request'
import type { CompareTask, CompareModelRef } from '@/types'
/** 推理/对比任务列表 */
export const getCompareList = () => get<CompareTask[]>('/model-compare')
/** 任务详情 */
export const getCompare = (id: string | number) => get<CompareTask>(`/model-compare/${id}`)
/** 创建任务 */
export const createCompare = (data: Partial<CompareTask>) =>
post<{ id: string | number }>('/model-compare', data)
/** 删除任务 */
export const deleteCompare = (id: string | number) => del(`/model-compare/${id}`)
/** 更新任务加载状态 */
export const updateLoadStatus = (id: string | number, load_status: any) =>
post(`/model-compare/${id}/load-status`, { load_status })
/** 查询任务加载状态 */
export const getLoadStatus = (id: string | number) =>
get<{ all_ready: boolean; loaded_models: any[] }>(`/model-compare/${id}/load-status`)
/** 停止所有旧模型服务 */
export const stopAllModels = () => post('/model-compare/all/stop-all')
/** 启动单个模型服务 */
export const startModel = (id: string | number, data: Partial<CompareModelRef>) =>
post<{ pid: number; port: number }>(`/model-compare/${id}/start-model`, data)
/** 按 PID 停止模型进程 */
export const stopModelByPid = (pid: number) =>
post('/model-compare/stop-by-pid', { pid })
/** 加载任务 */
export const loadCompare = (id: string | number) => post(`/model-compare/${id}/load`)
/** 卸载任务 */
export const unloadCompare = (id: string | number) => post(`/model-compare/${id}/unload`)
/** 流式对话mock 模式下返回非流式响应,调用方需兼容) */
export const streamChat = async (data: any): Promise<any> => {
// Mock 环境:返回非流式响应对象,调用方检测 content-type 决定如何处理
const resp = await post<{ response: string }>('/model-compare/stream-chat', data)
return {
ok: true,
body: {
getReader: () => {
// 模拟流式读取:把整个响应切成小块逐个返回
const text = resp?.response || ''
const encoder = new TextEncoder()
const chunks = [text.slice(0, text.length / 3), text.slice(text.length / 3, 2 * text.length / 3), text.slice(2 * text.length / 3)]
let i = 0
return {
read: async () => {
if (i >= chunks.length) return { done: true, value: undefined }
const value = encoder.encode(chunks[i++])
return { done: false, value }
},
}
},
},
}
}
/** 非流式对话(按端口代理) */
export const chatWithPort = (data: any) => post('/model-compare/chat-with-port', data)
/** 批量对话API 类型模型) */
export const batchChat = (data: any) => post('/model-chat/batch', data)
/** 本地 transformers 模型对话 */
export const localChat = (data: any) => post('/model-chat/local/chat', data)
/** 预加载本地模型 */
export const preloadLocalModel = (data: any) => post('/model-chat/local/preload', data)
/** 预加载已训练模型 */
export const preloadTrainedModel = (data: any) => post('/model-chat/trained/preload', data)

View File

@@ -0,0 +1,85 @@
import { get, post, put } from '../request'
export interface ComputeNode {
id: string
code: string
name: string
api_base_url: string
file_gateway_url: string
enabled: boolean
scheduler_status: string
scheduler_weight: number
tags: string[]
gpu_count: number
current_running_jobs: number
max_parallel_jobs: number
data_root: string
model_root: string
log_root: string
last_health_check_at?: string
}
export interface ComputeGpu {
id: number
node_id: string
node_code: string
node_name: string
name: string
uuid: string
status: string
gpu_percent: number
memory_used_gb: number
memory_total_gb: number
memory_percent: number
temperature: number
power_w: number
power_limit_w: number
processes?: Array<{
pid: number
name: string
memory_used_gb: number
task_name?: string
user?: string
}>
}
export interface ComputeQueueItem {
id: string
name: string
status: string
progress: number
compute_node_id?: string
gpus: number[]
create_time?: string
}
export interface ResourceReplica {
id: string
node_id: string
resource_type: string
resource_id: string
local_path: string
status: string
sync_status: string
create_time: string
}
export const getComputeNodes = () => get<ComputeNode[]>('/compute/nodes')
export const updateComputeNode = (id: string, data: Partial<ComputeNode>) =>
put<ComputeNode>(`/compute/nodes/${id}`, data)
export const testComputeNode = (id: string) =>
post<{ node_id: string; success: boolean; latency_ms: number }>(`/compute/nodes/${id}/test-connection`)
export const enableComputeNode = (id: string) => post<ComputeNode>(`/compute/nodes/${id}/enable`)
export const disableComputeNode = (id: string) => post<ComputeNode>(`/compute/nodes/${id}/disable`)
export const drainComputeNode = (id: string) => post<ComputeNode>(`/compute/nodes/${id}/drain`)
export const getComputeGpus = () => get<ComputeGpu[]>('/compute/gpus')
export const getComputeQueue = () => get<ComputeQueueItem[]>('/compute/queue')
export const getNodeReplicas = (id: string) => get<ResourceReplica[]>(`/compute/nodes/${id}/replicas`)

View File

@@ -0,0 +1,35 @@
import { get } from '../request'
export interface ServiceStatusStat {
type: string
status: 'normal' | 'busy' | 'error'
count: number
}
export interface TrainingTaskStat {
id: string
name: string
status: string
train_type: string
train_method: string
base_model: string
progress: number
accuracy: number | null
started_at: string
}
export interface DashboardStats {
online_services: number
running_tasks: number
pending_alerts: number
training_7d: { date: string; train: number; gpu: number; accuracy: number | null }[]
service_status: ServiceStatusStat[]
training_tasks: TrainingTaskStat[]
operation_distribution: { name: string; value: number }[]
login_duration_rank: { user: string; role: string; duration: string }[]
recent_login_users: { user: string; role: string; last_login: string }[]
}
export function getDashboardStats() {
return get<DashboardStats>('/dashboard/stats')
}

View File

@@ -0,0 +1,98 @@
import { get, post, put, del } from '../request'
import type { DatasetItem, DatasetVersion, DatasetVersionList } from '@/types'
/** 数据集列表 */
export const getDatasetList = () => get<DatasetItem[]>('/dataset-manage')
/** 数据集详情 */
export const getDataset = (id: string | number) => get<DatasetItem>(`/dataset-manage/${id}`)
/** 创建数据集 */
export const createDataset = (data: Partial<DatasetItem>) =>
post<{ id: string | number }>('/dataset-manage', data)
/** 更新数据集 */
export const updateDataset = (id: string | number, data: Partial<DatasetItem>) =>
put(`/dataset-manage/${id}`, data)
/** 删除数据集 */
export const deleteDataset = (id: string | number) => del(`/dataset-manage/${id}`)
/** 上传数据集文件multipart字段名 files */
export const uploadDatasetFiles = (datasetId: string | number, files: File[]) => {
const formData = new FormData()
files.forEach((f) => formData.append('files', f))
return post(`/dataset-manage/upload/${datasetId}`, formData, {
headers: { 'Content-Type': 'multipart/form-data' },
})
}
/** 预览数据集文件内容 */
export const previewDatasetFile = (fileId: string | number) =>
get<{ content: string }>(`/dataset-manage/preview/${encodeURIComponent(fileId)}`)
/** 数据集文件版本列表 */
export const getDatasetFileVersions = (fileId: string | number) =>
get<DatasetVersionList>(`/dataset-manage/versions/${encodeURIComponent(fileId)}`)
/** 读取指定历史版本内容(不改变当前版本) */
export const getDatasetFileVersionContent = (fileId: string | number, versionId: string) =>
get<{ version: DatasetVersion; content: string }>(
`/dataset-manage/versions/${encodeURIComponent(fileId)}/${encodeURIComponent(versionId)}`,
)
/** 保存为新版本,并自动设为当前版本 */
export const createDatasetFileVersion = (
fileId: string | number,
content: string,
options: {
description?: string
baseVersionId: string
expectedCurrentVersionId: string
},
) =>
post<{ version: DatasetVersion; content: string }>(
`/dataset-manage/versions/${encodeURIComponent(fileId)}`,
{
content,
description: options.description || '在线编辑',
base_version_id: options.baseVersionId,
expected_current_version_id: options.expectedCurrentVersionId,
},
)
/** 切换当前使用的数据集版本 */
export const activateDatasetFileVersion = (
fileId: string | number,
versionId: string,
expectedCurrentVersionId: string,
) =>
put<{ version: DatasetVersion; content: string }>(
`/dataset-manage/versions/${encodeURIComponent(fileId)}/active`,
{ version_id: versionId, expected_current_version_id: expectedCurrentVersionId },
)
/** 删除非当前、非初始的历史版本 */
export const deleteDatasetFileVersion = (
fileId: string | number,
versionId: string,
expectedCurrentVersionId: string,
) =>
del<DatasetVersionList>(
`/dataset-manage/versions/${encodeURIComponent(fileId)}/${encodeURIComponent(versionId)}`,
{ expected_current_version_id: expectedCurrentVersionId },
)
/** 下载文件 URL */
export const downloadFileUrl = (
datasetId: string | number,
fileId: string | number,
versionId?: string,
) => {
const baseUrl = `/modelTF/dataset-manage/download/${datasetId}/${fileId}`
return versionId ? `${baseUrl}?version_id=${encodeURIComponent(versionId)}` : baseUrl
}
/** 打包下载数据集 URL */
export const downloadDatasetUrl = (datasetId: string | number) =>
`/modelTF/dataset-manage/download/${datasetId}`

View File

@@ -0,0 +1,31 @@
import { get, post, put, del } from '../request'
import type { EvalTask, EvalTaskDetail, Dimension, StartEvalPayload } from '@/types'
/** 评测任务列表 */
export const getEvalList = () => get<EvalTask[]>('/model-eval')
/** 评测任务详情 */
export const getEvalDetail = (id: string | number) => get<EvalTaskDetail>(`/model-eval/${id}`)
/** 删除评测任务 */
export const deleteEval = (id: string | number) => del(`/model-eval/${id}`)
/** 启动评测 */
export const startEval = (data: StartEvalPayload) => post('/model-eval/start', data)
/** 评测维度列表 */
export const getDimensionList = () => get<Dimension[]>('/dimension')
/** 评测维度详情 */
export const getDimension = (id: string | number) => get<Dimension>(`/dimension/${id}`)
/** 创建维度 */
export const createDimension = (data: Partial<Dimension>) =>
post<{ id: string | number }>('/dimension', data)
/** 编辑维度 */
export const updateDimension = (id: string | number, data: Partial<Dimension>) =>
put(`/dimension/${id}`, data)
/** 删除维度 */
export const deleteDimension = (id: string | number) => del(`/dimension/${id}`)

View File

@@ -0,0 +1,40 @@
import { get, post, put, del } from '../request'
import type { FineTuneStartPayload, FineTuneTask, TrainingProgress } from '@/types'
/** 训练任务列表 */
export const getFineTuneList = () => get<FineTuneTask[]>('/fine-tune')
/** 训练任务详情 */
export const getFineTune = (id: string | number) => get<FineTuneTask>(`/fine-tune/${id}`)
/** 任务名查重 */
export const checkFineTuneName = (name: string) =>
get<{ exists: boolean }>('/fine-tune/check-name', { name })
/** 创建训练任务记录(第一步) */
export const createFineTune = (data: Partial<FineTuneTask>) =>
post<{ id: string | number }>('/fine-tune', data)
/** 启动训练(第二步) */
export const startFineTune = (data: FineTuneStartPayload) => post('/fine-tune/start', data)
/** 更新训练任务 */
export const updateFineTune = (id: string | number, data: Partial<FineTuneTask>) =>
put(`/fine-tune/${id}`, data)
/** 停止训练任务 */
export const stopFineTune = (id: string | number) => post(`/fine-tune/stop/${id}`)
/** 删除训练任务 */
export const deleteFineTune = (id: string | number) => del(`/fine-tune/${id}`)
/** 获取训练进度 */
export const getFineTuneProgress = (id: string | number) =>
get<TrainingProgress>(`/fine-tune/progress/${id}`)
/** 启动 TensorBoard */
export const startTensorboard = () => post('/fine-tune/tensorboard/start')
/** 提交 Web 日志 */
export const sendWebLog = (level: string, message: string, page: string) =>
post('/web-log', { level, message, page, timestamp: new Date().toISOString() })

View File

@@ -0,0 +1,18 @@
import { get } from '../request'
import type { LogFile, LogContent, TrainingLogFile } from '@/types'
/** 按日期获取系统日志文件列表 */
export const getLogFiles = (date: string) =>
get<LogFile[]>('/log-files', { date })
/** 获取系统日志内容 */
export const getLogContent = (file: string) =>
get<LogContent>('/log-content', { file })
/** 训练日志文件列表 */
export const getTrainingLogFiles = () =>
get<TrainingLogFile[]>('/training-log-files')
/** 训练日志内容 */
export const getTrainingLogContent = (file: string) =>
get<LogContent>('/training-log-content', { file })

View File

@@ -0,0 +1,48 @@
import { get, post, put, del } from '../request'
import type { ModelItem, ModelForm, TrainedModel } from '@/types'
/** 模型列表 */
export const getModelList = () => get<ModelItem[]>('/model-manage')
/** 模型详情 */
export const getModel = (id: string | number) => get<ModelItem>(`/model-manage/${id}`)
/** 按名称查模型 */
export const getModelByName = (name: string) => get<ModelItem>(`/model-manage/name/${name}`)
/** 本地模型路径列表 */
export const getLocalModels = () =>
get<{ models: { path: string; name: string }[] }>('/model-manage/local-models')
/** 已训练模型列表 */
export const getTrainedModels = () =>
get<{ models: TrainedModel[] }>('/model-manage/trained-models')
/** 创建模型 */
export const createModel = (data: ModelForm) => post('/model-manage', data)
/** 编辑模型 */
export const updateModel = (id: string | number, data: ModelForm) =>
put(`/model-manage/${id}`, data)
/** 删除模型 */
export const deleteModel = (id: string | number) => del(`/model-manage/${id}`)
/** 删除已训练模型(合并权重) */
export const deleteTrainedModel = (id: string | number, type: 'merged' | 'lora' = 'merged') =>
del(`/model-manage/trained-models/${id}`, { type })
/** 更新模型用途 */
export const updateModelPurpose = (id: string | number, purpose: string) =>
put(`/model-manage/${id}/purpose`, { purpose })
/** 合并 LoRA 权重 */
export const mergeModel = (data: {
model_name: string
train_method: string
base_model_path: string
}) => post('/model-manage/merge', data)
/** 导出已训练模型权重 */
export const exportModelUrl = (modelName: string) =>
`/modelTF/model-manage/trained-models/${encodeURIComponent(modelName)}/export`

View File

@@ -0,0 +1,55 @@
import { del, get, post, put } from '../request'
export interface Project {
id: string
tenant_id: string
name: string
code: string
description?: string
status: string
quota?: Record<string, unknown>
member_count?: number
task_count?: number
create_time?: string
}
export interface ProjectMember {
user_id: string
role: string
joined_at?: string
}
/** 项目列表(按租户过滤,默认 default */
export const getProjects = (tenantId = 'default') =>
get<Project[]>('/projects', { tenant_id: tenantId })
/** 项目详情 */
export const getProject = (id: string) => get<Project>(`/projects/${id}`)
/** 创建项目 */
export const createProject = (payload: Partial<Project>) =>
post<Project>('/projects', payload)
/** 更新项目 */
export const updateProject = (id: string, payload: Partial<Project>) =>
put<Project>(`/projects/${id}`, payload)
/** 归档项目 */
export const archiveProject = (id: string) =>
post<Project>(`/projects/${id}/archive`)
/** 项目成员列表 */
export const getProjectMembers = (id: string) =>
get<ProjectMember[]>(`/projects/${id}/members`)
/** 添加成员 */
export const addProjectMember = (id: string, payload: { user_id: string; role: string }) =>
post<ProjectMember>(`/projects/${id}/members`, payload)
/** 更新成员角色 */
export const updateProjectMember = (id: string, userId: string, role: string) =>
put<ProjectMember>(`/projects/${id}/members/${userId}`, { role })
/** 移除成员 */
export const removeProjectMember = (id: string, userId: string) =>
del(`/projects/${id}/members/${userId}`)

View File

@@ -0,0 +1,57 @@
import { del, get, post, put } from '../request'
import type {
CreateUserPayload,
HealthMetrics,
LoginResponse,
PermissionCode,
SystemInfo,
SystemUser,
UpdateUserAccessPayload,
} from '@/types'
/** 系统信息CPU/内存/磁盘/GPU/网络/系统) */
export const getSystemInfo = () => get<SystemInfo>('/system-info')
/** 健康指标(顶部栏轻量指标) */
export const getHealth = () => get<HealthMetrics>('/health')
/** 登录 */
export const login = (username: string, password: string) =>
post<LoginResponse>('/login', { username, password })
/** 用户列表 */
export const getUsers = () => get<SystemUser[]>('/users')
/** 创建用户 */
export const createUser = (payload: CreateUserPayload) =>
post<SystemUser>('/users', payload)
/** 删除用户currentUsername 用于防止删除当前登录账号 */
export const deleteUser = (id: string, currentUsername: string) =>
del<{ deleted: string }>(`/users/${encodeURIComponent(id)}`, {
current_username: currentUsername,
})
/** 更新用户角色、状态及页面权限 */
export const updateUserAccess = (id: string, payload: UpdateUserAccessPayload) =>
put<SystemUser>(`/users/${encodeURIComponent(id)}`, payload)
/** 重置用户密码password 留空则重置为默认密码 platform123 */
export const resetUserPassword = (id: string, password: string) =>
post<{ id: string }>(`/users/${encodeURIComponent(id)}/reset-password`, { password })
/** 角色定义 */
export interface RoleInfo {
id: string
name: string
display_name: string
permissions: PermissionCode[]
}
/** 权限码清单 */
export const getPermissionCodes = () =>
get<{ codes: PermissionCode[] }>('/system/permissions/codes')
/** 权限码清单 + 角色定义 */
export const getPermissions = () =>
get<{ codes: PermissionCode[]; roles: RoleInfo[] }>('/system/permissions')

View File

@@ -0,0 +1,34 @@
import { get, post, put } from '../request'
export interface Tenant {
id: string
name: string
code: string
status: string
owner_user_id?: string | null
quota: Record<string, unknown>
retention_policy_id?: string | null
create_time?: string
}
/** 租户列表 */
export const getTenants = () => get<Tenant[]>('/tenants')
/** 租户详情 */
export const getTenant = (id: string) => get<Tenant>(`/tenants/${id}`)
/** 创建租户 */
export const createTenant = (payload: Partial<Tenant>) =>
post<Tenant>('/tenants', payload)
/** 更新租户 */
export const updateTenant = (id: string, payload: Partial<Tenant>) =>
put<Tenant>(`/tenants/${id}`, payload)
/** 设置租户配额 */
export const setTenantQuota = (id: string, quota: Record<string, unknown>) =>
put<Tenant>(`/tenants/${id}/quota`, { quota })
/** 设置租户留存策略 */
export const setTenantRetention = (id: string, retention_policy_id: string) =>
put<Tenant>(`/tenants/${id}/retention-policy`, { retention_policy_id })

View File

@@ -0,0 +1,77 @@
import axios, { type AxiosInstance, type AxiosRequestConfig } from 'axios'
import { ElMessage } from 'element-plus'
/**
* 后端统一响应格式
* code === 0 表示成功data 为业务数据
*/
export interface ApiResult<T = any> {
code: number
message?: string
data: T
}
const service: AxiosInstance = axios.create({
// Use a relative path; Vite proxies /modelTF to http://localhost:17861 in local development.
baseURL: '/modelTF',
timeout: 30000,
})
// 请求拦截器:携带认证令牌
service.interceptors.request.use(
(config) => {
const token = localStorage.getItem('authToken')
if (token) {
config.headers = config.headers || {}
;(config.headers as Record<string, string>).Authorization = `Bearer ${token}`
}
return config
},
(error) => Promise.reject(error),
)
// 响应拦截器:统一解包 { code, data, message }
service.interceptors.response.use(
(response) => {
const res = response.data as ApiResult
// 二进制流等非 JSON 响应直接返回
if (response.config.responseType === 'blob' || response.config.responseType === 'arraybuffer') {
return response
}
if (res.code === 0) {
return res.data
}
// 业务错误
const message = res.message || '请求失败'
ElMessage.error(message)
return Promise.reject(new Error(message))
},
(error) => {
const detail = error.response?.data?.detail
const message = detail?.message || error.response?.data?.message || detail || error.message || '网络异常'
ElMessage.error(message)
return Promise.reject(error)
},
)
/** GET 请求,返回已解包的 data */
export function get<T = any>(url: string, params?: any, config?: AxiosRequestConfig): Promise<T> {
return service.get(url, { params, ...config }) as unknown as Promise<T>
}
/** POST 请求 */
export function post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
return service.post(url, data, config) as unknown as Promise<T>
}
/** PUT 请求 */
export function put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
return service.put(url, data, config) as unknown as Promise<T>
}
/** DELETE 请求 */
export function del<T = any>(url: string, params?: any, config?: AxiosRequestConfig): Promise<T> {
return service.delete(url, { params, ...config }) as unknown as Promise<T>
}
export default service