推理接口更新

This commit is contained in:
somunslotus 2026-01-26 14:32:32 +08:00
parent 00a4798150
commit e98bc40203
6 changed files with 286 additions and 0 deletions

View File

@ -164,6 +164,41 @@ func (h *Handler) QueryStatus(c *gin.Context) {
c.JSON(http.StatusOK, SuccessResponse(status))
}
// SubmitInferenceTask 处理推理任务提交请求
func (h *Handler) SubmitInferenceTask(c *gin.Context) {
var request models.InferenceSubmitTaskRequest
if err := c.ShouldBindJSON(&request); err != nil {
c.JSON(http.StatusOK, BadRequestResponse("请求参数错误: "+err.Error()))
return
}
// 获取认证信息
authData, err := h.authService.GetToken(c.Request.Context())
if err != nil {
c.JSON(http.StatusOK, InternalServerErrorResponse("获取认证信息失败: "+err.Error()))
return
}
// 获取集群ID从 resource 中获取,如果没有则使用默认值)
clusterID := request.Resource.ClusterID
if clusterID == "" {
clusterID, err = h.authService.GetClusterID(c.Request.Context(), "default")
if err != nil {
c.JSON(http.StatusOK, InternalServerErrorResponse("获取集群ID失败: "+err.Error()))
return
}
}
// 提交推理任务(包含准备步骤)
response, err := h.inferenceService.SubmitInferenceTask(c.Request.Context(), authData, &request, clusterID)
if err != nil {
c.JSON(http.StatusOK, InternalServerErrorResponse("提交推理任务失败: "+err.Error()))
return
}
c.JSON(http.StatusOK, response)
}
// HealthCheck 处理健康检查请求
func (h *Handler) HealthCheck(c *gin.Context) {
c.JSON(http.StatusOK, SuccessResponse(gin.H{

View File

@ -12,3 +12,40 @@ type SubmitTaskRequest struct {
type UploadCodeRequest struct {
RunConfig RunConfig `json:"run_config"` // 运行配置
}
// InferenceSubmitTaskRequest 推理任务提交请求结构体
type InferenceSubmitTaskRequest struct {
Version string `json:"version"` // 版本
Description string `json:"description"` // 描述
Model DataResourceConfig `json:"model"` // 模型信息
SubModel *DataResourceConfig `json:"sub_model"` // 增量模型信息(可选)
Image ImageInfo `json:"image"` // 镜像信息
CodeConfig CodeConfig `json:"code_config"` // 代码配置
ResourceType string `json:"resource_type"` // 资源类型
Resource ResourceConfig `json:"resource"` // 资源配置
Command string `json:"command"` // 启动命令
}
// ImageInfo 镜像信息
type ImageInfo struct {
ImageID int `json:"imageID"`
Name string `json:"name"`
CreateTime string `json:"createTime"`
ClusterImages []ClusterImage `json:"clusterImages"`
}
// ClusterImage 集群镜像信息
type ClusterImage struct {
ImageID int `json:"imageID"`
ClusterID string `json:"clusterID"`
OriginImageType string `json:"originImageType"`
OriginImageID string `json:"originImageID"`
OriginImageName string `json:"originImageName"`
Cards []Card `json:"cards"`
}
// Card 卡片信息
type Card struct {
OriginImageID string `json:"originImageID"`
Card string `json:"card"`
}

View File

@ -275,3 +275,64 @@ type InferenceTaskDetailData struct {
Status string `json:"status"`
CreatedTime string `json:"createdTime"`
}
// InferenceSubmitTaskResponse 推理任务提交响应
type InferenceSubmitTaskResponse struct {
Code int `json:"code"` // 状态码
Msg string `json:"msg"` // 消息
Data InferenceSubmitTaskResponseData `json:"data"` // 响应数据
}
// InferenceSubmitTaskResponseData 推理任务提交响应数据
type InferenceSubmitTaskResponseData struct {
TaskInfo InferenceTaskInfo `json:"taskInfo"` // 任务信息
ResultInfo InferenceResultInfo `json:"resultInfo"` // 结果信息
}
// InferenceTaskInfo 推理任务信息
type InferenceTaskInfo struct {
UserID int `json:"userID"` // 用户ID
JobSetInfo InferenceJobSetInfo `json:"jobSetInfo"` // 任务集信息
}
// InferenceJobSetInfo 推理任务集信息
type InferenceJobSetInfo struct {
Jobs []InferenceJob `json:"jobs"` // 任务列表
}
// InferenceJob 推理任务
type InferenceJob struct {
LocalJobID string `json:"localJobID"` // 本地任务ID
Name string `json:"name"` // 任务名称
Description string `json:"description"` // 任务描述
Type string `json:"type"` // 任务类型
Files *InferenceJobFiles `json:"files"` // 文件信息
JobResources *InferenceJobResources `json:"jobResources"` // 资源信息
}
// InferenceJobFiles 推理任务文件
type InferenceJobFiles struct {
Model FileBinding `json:"model"` // 模型绑定
SubModel *FileBinding `json:"sub_model,omitempty"` // 增量模型绑定(可选)
Image ImageBinding `json:"image"` // 镜像绑定
}
// InferenceJobResources 推理任务资源
type InferenceJobResources struct {
ScheduleStrategy string `json:"scheduleStrategy"` // 调度策略
Clusters []InferenceCluster `json:"clusters"` // 集群列表
}
// InferenceCluster 推理集群信息
type InferenceCluster struct {
ClusterID string `json:"clusterID"` // 集群ID
Runtime Runtime `json:"runtime"` // 运行时配置
Code CodeInfo `json:"code"` // 代码信息
Resources []ResourcesItem `json:"resources"` // 资源列表
}
// InferenceResultInfo 推理结果信息
type InferenceResultInfo struct {
LocalJobID string `json:"localJobID"` // 本地任务ID
JobSetID string `json:"jobSetID"` // 任务集ID
}

View File

@ -86,3 +86,68 @@ func BuildSubmitTaskRequest(ctx context.Context, authData *models.AuthData, conf
},
}
}
// BuildInferenceSubmitTaskRequest 构建推理任务提交请求
func BuildInferenceSubmitTaskRequest(ctx context.Context, authData *models.AuthData,
codeBindingID, modelBindingID, subModelBindingID int, imageID int, clusterID string,
resourceType string, resources []models.ResourcesItem, command string, description string) models.InferenceSubmitTaskResponseData {
// 构建文件信息
files := models.InferenceJobFiles{
Model: models.FileBinding{
Type: "Binding",
BindingID: modelBindingID,
},
Image: models.ImageBinding{
Type: "Image",
ImageID: imageID,
},
}
// 如果有增量模型,添加到文件信息中
if subModelBindingID > 0 {
files.SubModel = &models.FileBinding{
Type: "Binding",
BindingID: subModelBindingID,
}
}
// 构建任务
job := models.InferenceJob{
LocalJobID: models.MainTaskID,
Name: "inference-task" + preparation.GenerateUniqueID(),
Description: description,
Type: "PCM_Inference",
Files: &files,
JobResources: &models.InferenceJobResources{
ScheduleStrategy: "dataLocality",
Clusters: []models.InferenceCluster{
{
ClusterID: clusterID,
Runtime: models.Runtime{
Envs: make(map[string]string),
Params: make(map[string]string),
},
Code: models.CodeInfo{
Type: "Binding",
BindingID: codeBindingID,
},
Resources: resources,
},
},
},
}
return models.InferenceSubmitTaskResponseData{
TaskInfo: models.InferenceTaskInfo{
UserID: authData.JsmUserInfo.Data.UserID,
JobSetInfo: models.InferenceJobSetInfo{
Jobs: []models.InferenceJob{job},
},
},
ResultInfo: models.InferenceResultInfo{
LocalJobID: models.MainTaskID,
JobSetID: "", // 这个会在提交后由服务器返回
},
}
}

View File

@ -52,3 +52,89 @@ func (s *inferenceService) StopTask(ctx context.Context, authData *models.AuthDa
// 这里需要实现停止任务的逻辑
return fmt.Errorf("StopTask not implemented")
}
// SubmitInferenceTask 提交推理任务(包含准备步骤)
func (s *inferenceService) SubmitInferenceTask(ctx context.Context, authData *models.AuthData,
request *models.InferenceSubmitTaskRequest, clusterID string) (*models.InferenceSubmitTaskResponse, error) {
// 1. 准备代码
fmt.Println("开始准备代码")
codeConfig := models.CodeConfig{
GitUrl: request.CodeConfig.GitUrl,
GitBranch: request.CodeConfig.GitBranch,
MountPath: request.CodeConfig.MountPath,
}
runConfig := &models.RunConfig{
CodeConfig: codeConfig,
Image: request.Image.ImageID,
Command: request.Command,
Resource: request.Resource,
}
codeID, err := s.preparationService.PrepareCode(ctx, authData, runConfig, clusterID)
if err != nil {
return nil, fmt.Errorf("准备代码失败: %w", err)
}
fmt.Println("代码准备成功ID:", codeID)
// 2. 准备模型
fmt.Println("开始准备模型")
// 如果 MountPath 为空,使用 Path 作为 MountPath
modelConfig := request.Model
if modelConfig.MountPath == "" {
modelConfig.MountPath = modelConfig.Path
}
modelID, err := s.preparationService.PrepareModel(ctx, authData, modelConfig, clusterID)
if err != nil {
return nil, fmt.Errorf("准备模型失败: %w", err)
}
fmt.Println("模型准备成功ID:", modelID)
// 3. 准备增量模型(如果有)
var subModelID int
if request.SubModel != nil {
fmt.Println("开始准备增量模型")
// 如果 MountPath 为空,使用 Path 作为 MountPath
subModelConfig := *request.SubModel
if subModelConfig.MountPath == "" {
subModelConfig.MountPath = subModelConfig.Path
}
subModelID, err = s.preparationService.PrepareModel(ctx, authData, subModelConfig, clusterID)
if err != nil {
return nil, fmt.Errorf("准备增量模型失败: %w", err)
}
fmt.Println("增量模型准备成功ID:", subModelID)
}
// 4. 构建推理任务响应数据(用于返回)
taskData := common.BuildInferenceSubmitTaskRequest(
ctx, authData,
codeID, modelID, subModelID,
request.Image.ImageID,
clusterID,
request.ResourceType,
request.Resource.Resources,
request.Command,
request.Description,
)
// 5. 使用 taskSubmitter 提交任务
// 注意taskSubmitter 会使用 BuildSubmitTaskRequest它构建的是训练任务格式
// 对于推理任务,我们需要传入 BindDatasetID=0这样 Files 中的 Dataset 会是空的
jobSetID, err := s.taskSubmitter.SubmitTask(ctx, authData, runConfig, clusterID, &models.BindResultSet{
BindCodeID: codeID,
BindModelID: modelID,
BindDatasetID: 0, // 推理任务不需要数据集
})
if err != nil {
return nil, fmt.Errorf("提交任务失败: %w", err)
}
// 更新结果信息
taskData.ResultInfo.JobSetID = jobSetID
return &models.InferenceSubmitTaskResponse{
Code: 200,
Msg: "",
Data: taskData,
}, nil
}

View File

@ -30,6 +30,8 @@ type TaskService interface {
type InferenceService interface {
SubmitTask(ctx context.Context, authData *models.AuthData, config *models.RunConfig,
clusterID string, bindResultSet *models.BindResultSet) (string, error)
SubmitInferenceTask(ctx context.Context, authData *models.AuthData,
request *models.InferenceSubmitTaskRequest, clusterID string) (*models.InferenceSubmitTaskResponse, error)
GetTaskStatus(ctx context.Context, authData *models.AuthData, jobSetID string) (*models.InferenceTaskDetailResponse, error)
StopTask(ctx context.Context, authData *models.AuthData, jobSetID string) error
}