using Microsoft.Extensions.Logging; using OrpaonVision.Core.Results; using OrpaonVision.Core.Training; using OrpaonVision.Core.Security; using OrpaonVision.Model.Training; using OrpaonVision.ConfigApp.Infrastructure.Services; namespace OrpaonVision.ConfigApp.Infrastructure.Services; /// /// 训练任务管理服务实现。 /// public sealed class TrainingTaskService : ITrainingTaskService { private readonly ILogger _logger; private readonly ITrainingTaskStore _taskStore; private readonly IUserRoleStore _userRoleStore; private readonly IPermissionStore _permissionStore; /// /// 构造函数。 /// public TrainingTaskService( ILogger logger, ITrainingTaskStore taskStore, IUserRoleStore userRoleStore, IPermissionStore permissionStore) { _logger = logger; _taskStore = taskStore; _userRoleStore = userRoleStore; _permissionStore = permissionStore; } /// public async Task> CreateTask(TrainingTaskModel task) { try { if (task == null) { return Result.Fail("TASK_NULL", "训练任务不能为空。"); } if (string.IsNullOrWhiteSpace(task.Name)) { return Result.Fail("TASK_NAME_REQUIRED", "训练任务名称不能为空。"); } _logger.LogInformation("正在创建训练任务: {TaskName}", task.Name); // 检查任务名称是否存在 var nameExistsResult = await _taskStore.NameExistsAsync(task.Name); if (!nameExistsResult.Succeeded) { return Result.Fail(nameExistsResult.Code, nameExistsResult.Message); } if (nameExistsResult.Data) { return Result.Fail("TASK_NAME_EXISTS", "训练任务名称已存在。"); } // 设置默认值 task.Id = Guid.NewGuid(); task.Status = TrainingTaskStatus.Draft; task.CreatedAtUtc = DateTime.UtcNow; task.UpdatedAtUtc = DateTime.UtcNow; task.CurrentEpoch = 0; task.TotalEpochs = task.TotalEpochs > 0 ? task.TotalEpochs : 100; task.CurrentLoss = 0; task.CurrentMap = 0; task.Progress = 0; task.Priority = (int)task.Priority >= 0 && (int)task.Priority <= 2 ? task.Priority : TrainingPriority.Medium; var result = await _taskStore.CreateAsync(task); if (!result.Succeeded) { return result; } _logger.LogInformation("训练任务创建成功: {TaskId} - {TaskName}", task.Id, task.Name); return Result.Success(task); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "创建训练任务失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_CREATE_FAILED", "创建训练任务失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> UpdateTask(TrainingTaskModel task) { try { if (task == null) { return Result.Fail("TASK_NULL", "训练任务不能为空。"); } if (task.Id == Guid.Empty) { return Result.Fail("TASK_ID_REQUIRED", "训练任务ID不能为空。"); } _logger.LogInformation("正在更新训练任务: {TaskId}", task.Id); // 检查任务名称是否存在(排除当前任务) var nameExistsResult = await _taskStore.NameExistsAsync(task.Name, task.Id); if (!nameExistsResult.Succeeded) { return Result.Fail(nameExistsResult.Code, nameExistsResult.Message); } if (nameExistsResult.Data) { return Result.Fail("TASK_NAME_EXISTS", "训练任务名称已存在。"); } task.UpdatedAtUtc = DateTime.UtcNow; var result = await _taskStore.UpdateAsync(task); if (!result.Succeeded) { return result; } _logger.LogInformation("训练任务更新成功: {TaskId}", task.Id); return Result.Success(task); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "更新训练任务失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_UPDATE_FAILED", "更新训练任务失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task DeleteTask(Guid taskId) { try { _logger.LogInformation("正在删除训练任务: {TaskId}", taskId); // 检查任务是否存在 var taskResult = await _taskStore.GetByIdAsync(taskId); if (!taskResult.Succeeded || taskResult.Data == null) { return Result.Fail("TASK_NOT_FOUND", "训练任务不存在"); } // 检查任务状态,只有草稿状态的任务可以删除 if (taskResult.Data.Status != TrainingTaskStatus.Draft) { return Result.Fail("TASK_STATUS_NOT_ALLOW_DELETE", "只有草稿状态的任务可以删除"); } var result = await _taskStore.DeleteAsync(taskId); if (!result.Succeeded) { return result; } _logger.LogInformation("训练任务删除成功: {TaskId}", taskId); return Result.Success("训练任务删除成功"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "删除训练任务失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_DELETE_FAILED", "删除训练任务失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> GetTaskById(Guid taskId) { try { _logger.LogDebug("正在获取训练任务: {TaskId}", taskId); var result = await _taskStore.GetByIdAsync(taskId); if (!result.Succeeded) { return Result.Fail(result.Code, result.Message, result.Errors.ToArray()); } if (result.Data == null) { return Result.Fail("TASK_NOT_FOUND", "训练任务不存在"); } _logger.LogDebug("训练任务获取成功: {TaskId}", taskId); return Result.Success(result.Data); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取训练任务失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_GET_FAILED", "获取训练任务失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task>> GetTaskPagedList(int pageIndex = 1, int pageSize = 20, TrainingTaskStatus? status = null, string? keyword = null) { try { _logger.LogDebug("正在获取训练任务分页列表: PageIndex={PageIndex}, PageSize={PageSize}, Status={Status}, Keyword={Keyword}", pageIndex, pageSize, status, keyword); var result = await _taskStore.GetPagedListAsync(pageIndex, pageSize, status, keyword); return Result>.Success(new PagedResult { Items = result.Data.tasks, TotalCount = result.Data.totalCount, PageIndex = pageIndex, PageSize = pageSize }); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取训练任务分页列表失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_GET_PAGED_LIST_FAILED", "获取训练任务列表失败", traceId); return Result>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task StartTask(Guid taskId, string startedBy) { try { _logger.LogInformation("正在启动训练任务: {TaskId} - {StartedBy}", taskId, startedBy); var result = await _taskStore.UpdateStatusAsync(taskId, TrainingTaskStatus.Running, startedBy); if (!result.Succeeded) { return result; } _logger.LogInformation("训练任务启动成功: {TaskId}", taskId); return Result.Success("训练任务启动成功"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "启动训练任务失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_START_FAILED", "启动训练任务失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task PauseTask(Guid taskId, string pausedBy) { try { _logger.LogInformation("正在暂停训练任务: {TaskId} - {PausedBy}", taskId, pausedBy); var result = await _taskStore.UpdateStatusAsync(taskId, TrainingTaskStatus.Paused, pausedBy); if (!result.Succeeded) { return result; } _logger.LogInformation("训练任务暂停成功: {TaskId}", taskId); return Result.Success("训练任务暂停成功"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "暂停训练任务失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_PAUSE_FAILED", "暂停训练任务失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task StopTask(Guid taskId, string stoppedBy) { try { _logger.LogInformation("正在停止训练任务: {TaskId} - {StoppedBy}", taskId, stoppedBy); var result = await _taskStore.UpdateStatusAsync(taskId, TrainingTaskStatus.Pending, stoppedBy); if (!result.Succeeded) { return result; } _logger.LogInformation("训练任务停止成功: {TaskId}", taskId); return Result.Success("训练任务停止成功"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "停止训练任务失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_STOP_FAILED", "停止训练任务失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task CancelTask(Guid taskId, string cancelledBy) { try { _logger.LogInformation("正在取消训练任务: {TaskId} - {CancelledBy}", taskId, cancelledBy); var result = await _taskStore.UpdateStatusAsync(taskId, TrainingTaskStatus.Cancelled, cancelledBy); if (!result.Succeeded) { return result; } _logger.LogInformation("训练任务取消成功: {TaskId}", taskId); return Result.Success("训练任务取消成功"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "取消训练任务失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_CANCEL_FAILED", "取消训练任务失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task RestartTask(Guid taskId, string restartedBy) { try { _logger.LogInformation("正在重新启动训练任务: {TaskId} - {RestartedBy}", taskId, restartedBy); var result = await _taskStore.UpdateStatusAsync(taskId, TrainingTaskStatus.Pending, restartedBy); if (!result.Succeeded) { return result; } _logger.LogInformation("训练任务重新启动成功: {TaskId}", taskId); return Result.Success("训练任务重新启动成功"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "重新启动训练任务失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_RESTART_FAILED", "重新启动训练任务失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> GetTaskStatus(Guid taskId) { try { _logger.LogDebug("正在获取训练任务状态: {TaskId}", taskId); var taskResult = await _taskStore.GetByIdAsync(taskId); if (!taskResult.Succeeded) { return Result.Fail(taskResult.Code, taskResult.Message, taskResult.Errors.ToArray()); } if (taskResult.Data == null) { return Result.Fail("TASK_NOT_FOUND", "训练任务不存在"); } _logger.LogDebug("训练任务状态获取成功: {TaskId} - {Status}", taskId, taskResult.Data.Status); return Result.Success(taskResult.Data.Status); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取训练任务状态失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_GET_STATUS_FAILED", "获取训练任务状态失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> GetTaskProgress(Guid taskId) { try { _logger.LogDebug("正在获取训练任务进度: {TaskId}", taskId); var taskResult = await _taskStore.GetByIdAsync(taskId); if (!taskResult.Succeeded) { return Result.Fail(taskResult.Code, taskResult.Message, taskResult.Errors.ToArray()); } if (taskResult.Data == null) { return Result.Fail("TASK_NOT_FOUND", "训练任务不存在"); } _logger.LogDebug("训练任务进度获取成功: {TaskId} - {Progress}%", taskId, taskResult.Data.Progress); return Result.Success(taskResult.Data.Progress); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取训练任务进度失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_GET_PROGRESS_FAILED", "获取训练任务进度失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task> GetTaskStatistics() { try { _logger.LogDebug("正在获取训练任务统计信息"); var result = await _taskStore.GetStatisticsAsync(); if (!result.Succeeded) { return Result.Fail(result.Code, result.Message, result.Errors.ToArray()); } _logger.LogDebug("训练任务统计信息获取成功"); // 转换Core类型到ConfigApp类型 var configStats = new TrainingTaskStatistics { TotalTasks = result.Data.TotalTasks, DraftTasks = result.Data.DraftTasks, PendingTasks = result.Data.PendingTasks, RunningTasks = result.Data.RunningTasks, PausedTasks = result.Data.PausedTasks, CompletedTasks = result.Data.CompletedTasks, FailedTasks = result.Data.FailedTasks, CancelledTasks = result.Data.CancelledTasks }; return Result.Success(configStats); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取训练任务统计信息失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_GET_STATISTICS_FAILED", "获取统计信息失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task AssignTask(Guid taskId, Guid assignedToId, string assignedToName, string assignedBy) { try { _logger.LogInformation("正在分配训练任务: {TaskId} -> {AssignedToId} - {AssignedBy}", taskId, assignedToId, assignedBy); var result = await _taskStore.AssignTaskAsync(taskId, assignedToId, assignedToName, assignedBy); if (!result.Succeeded) { return result; } _logger.LogInformation("训练任务分配成功: {TaskId} -> {AssignedToId}", taskId, assignedToId); return Result.Success("训练任务分配成功"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "分配训练任务失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_ASSIGN_FAILED", "分配训练任务失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task UpdateTaskProgress(Guid taskId, int currentEpoch, double currentLoss, double currentMap, double progress) { try { _logger.LogInformation("正在更新训练任务进度: {TaskId} - Epoch {CurrentEpoch} - Progress {Progress}%", taskId, currentEpoch, progress); var result = await _taskStore.UpdateProgressAsync(taskId, currentEpoch, currentLoss, currentMap, progress); if (!result.Succeeded) { return result; } _logger.LogInformation("训练任务进度更新成功: {TaskId} - Progress {Progress}%", taskId, progress); return Result.Success("训练任务进度更新成功"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "更新训练任务进度失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_UPDATE_PROGRESS_FAILED", "更新训练任务进度失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task CompleteTask(Guid taskId, string outputModelPath, double finalLoss, double finalMap, string completedBy) { try { _logger.LogInformation("正在完成训练任务: {TaskId} - {CompletedBy}", taskId, completedBy); var result = await _taskStore.CompleteTaskAsync(taskId, outputModelPath, finalLoss, finalMap, completedBy); if (!result.Succeeded) { return result; } _logger.LogInformation("训练任务完成成功: {TaskId}", taskId); return Result.Success("训练任务完成成功"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "完成训练任务失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_COMPLETE_FAILED", "完成训练任务失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public async Task FailTask(Guid taskId, string errorMessage, string failedBy) { try { _logger.LogInformation("正在标记训练任务失败: {TaskId} - {FailedBy}", taskId, failedBy); var result = await _taskStore.FailTaskAsync(taskId, errorMessage, failedBy); if (!result.Succeeded) { return result; } _logger.LogInformation("训练任务失败标记成功: {TaskId}", taskId); return Result.Success("训练任务失败标记成功"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "标记训练任务失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "TRAINING_TASK_FAIL_FAILED", "标记训练任务失败", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } }