struct&&assiQues
This commit is contained in:
@@ -1,67 +1,173 @@
|
||||
using Entities.DTO;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
using Entities.Contracts;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace TechHelper.Client.Exam
|
||||
{
|
||||
public class ParentStructInfo
|
||||
{
|
||||
public string Number { get; set; }
|
||||
public SubjectAreaEnum SubjectArea { get; set; }
|
||||
public byte Index { get; set; }
|
||||
}
|
||||
|
||||
public static class ExamPaperExtensions
|
||||
{
|
||||
public static ExamDto ConvertToExamDTO(this ExamPaper examPaper)
|
||||
public static AssignmentDto ConvertToExamDTO(this ExamPaper examPaper)
|
||||
{
|
||||
ExamDto dto = new ExamDto();
|
||||
AssignmentDto dto = new AssignmentDto();
|
||||
|
||||
dto.AssignmentTitle = examPaper.AssignmentTitle;
|
||||
dto.Title = examPaper.AssignmentTitle;
|
||||
dto.Description = examPaper.Description;
|
||||
dto.SubjectArea = examPaper.SubjectArea;
|
||||
dto.QuestionGroups.Title = examPaper.AssignmentTitle;
|
||||
dto.QuestionGroups.Descript = examPaper.Description;
|
||||
|
||||
var SubjectArea = SubjectAreaEnum.Literature;
|
||||
Enum.TryParse<SubjectAreaEnum>(examPaper.SubjectArea, out SubjectArea);
|
||||
dto.SubjectArea = SubjectArea;
|
||||
|
||||
AssignmentStructDto examStruct = new AssignmentStructDto();
|
||||
|
||||
foreach (var qg in examPaper.QuestionGroups)
|
||||
{
|
||||
var qgd = new QuestionGroupDto();
|
||||
ParseMajorQuestionGroup(qg, qgd, false);
|
||||
dto.QuestionGroups.SubQuestionGroups.Add(qgd);
|
||||
examStruct.ChildrenGroups.Add(ParseMajorQuestionGroup(qg));
|
||||
examStruct.ChildrenGroups.Last().Index = (byte)(examStruct.ChildrenGroups.Count());
|
||||
}
|
||||
|
||||
|
||||
foreach (var question in examPaper.TopLevelQuestions)
|
||||
{
|
||||
if (question.SubQuestions != null && question.SubQuestions.Any())
|
||||
{
|
||||
var qgDto = new QuestionGroupDto
|
||||
{
|
||||
Title = question.Stem,
|
||||
Score = (int)question.Score,
|
||||
Descript = "",
|
||||
};
|
||||
|
||||
qgDto.ValidQuestionGroup = !string.IsNullOrEmpty(qgDto.Descript);
|
||||
|
||||
|
||||
ParseQuestionWithSubQuestions(question, qgDto, qgDto.ValidQuestionGroup);
|
||||
dto.QuestionGroups.SubQuestionGroups.Add(qgDto);
|
||||
}
|
||||
else
|
||||
{
|
||||
var qgDto = new QuestionGroupDto
|
||||
{
|
||||
Title = question.Stem,
|
||||
Score = (int)question.Score,
|
||||
Descript = "",
|
||||
};
|
||||
|
||||
qgDto.ValidQuestionGroup = !string.IsNullOrEmpty(qgDto.Descript);
|
||||
|
||||
var subQuestionDto = new SubQuestionDto();
|
||||
ParseSingleQuestion(question, subQuestionDto, !qgDto.ValidQuestionGroup);
|
||||
qgDto.SubQuestions.Add(subQuestionDto);
|
||||
dto.QuestionGroups.SubQuestionGroups.Add(qgDto);
|
||||
}
|
||||
}
|
||||
dto.ExamStruct = examStruct;
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
private static AssignmentStructDto ParseMajorQuestionGroup(MajorQuestionGroup sqg)
|
||||
{
|
||||
var examStruct = new AssignmentStructDto();
|
||||
|
||||
if (sqg.SubQuestionGroups != null)
|
||||
{
|
||||
|
||||
examStruct.Title = sqg.Title;
|
||||
examStruct.Score = sqg.Score;
|
||||
examStruct.ChildrenGroups = new List<AssignmentStructDto>();
|
||||
sqg.SubQuestionGroups?.ForEach(ssqg =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(ssqg.Descript))
|
||||
{
|
||||
examStruct.ChildrenGroups.Add(ParseMajorQuestionGroup(ssqg));
|
||||
examStruct.ChildrenGroups.Last().Index = (byte)(examStruct.ChildrenGroups.Count());
|
||||
}
|
||||
else
|
||||
{
|
||||
examStruct.AssignmentQuestions.Add(ParseGroupToAssignmentQuestion(ssqg, false));
|
||||
examStruct.AssignmentQuestions.Last().Index = (byte)(examStruct.AssignmentQuestions.Count());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (sqg.SubQuestions != null)
|
||||
{
|
||||
|
||||
sqg.SubQuestions?.ForEach(sq =>
|
||||
{
|
||||
if(sq.SubQuestions.Any())
|
||||
{
|
||||
|
||||
}
|
||||
examStruct.AssignmentQuestions.Add(ParseAssignmentQuestion(sq));
|
||||
examStruct.AssignmentQuestions.Last().Index = (byte)(examStruct.AssignmentQuestions.Count());
|
||||
});
|
||||
}
|
||||
|
||||
return examStruct;
|
||||
}
|
||||
|
||||
|
||||
public static List<string> ParseOptionsFromText(this string optionsText)
|
||||
{
|
||||
return optionsText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)
|
||||
.Where(line => !string.IsNullOrWhiteSpace(line)).ToList();
|
||||
}
|
||||
|
||||
private static QuestionDto ParseGroupToQuestion(MajorQuestionGroup qg, bool subQ = true)
|
||||
{
|
||||
var dq = new QuestionDto();
|
||||
dq.Title = qg.Title + Environment.NewLine + qg.Descript;
|
||||
|
||||
if (subQ) dq.GroupState = QuestionGroupState.Subquestion;
|
||||
else dq.GroupState = QuestionGroupState.Group;
|
||||
|
||||
qg.SubQuestions?.ForEach(ssq =>
|
||||
{
|
||||
dq.ChildrenQuestion.Add(ParseQuestion(ssq));
|
||||
});
|
||||
|
||||
qg.SubQuestionGroups?.ForEach(sqg =>
|
||||
{
|
||||
dq.ChildrenQuestion.Add(ParseGroupToQuestion(sqg));
|
||||
});
|
||||
|
||||
return dq;
|
||||
}
|
||||
|
||||
private static AssignmentQuestionDto ParseGroupToAssignmentQuestion(MajorQuestionGroup qg, bool subQ = true)
|
||||
{
|
||||
var aq = new AssignmentQuestionDto();
|
||||
aq.Score = qg.Score;
|
||||
|
||||
qg.SubQuestions?.ForEach(ssq =>
|
||||
{
|
||||
aq.Question.ChildrenQuestion.Add(ParseQuestion(ssq));
|
||||
aq.Question.ChildrenQuestion.Last().Index = (byte)aq.Question.ChildrenQuestion.Count;
|
||||
});
|
||||
|
||||
qg.SubQuestionGroups?.ForEach(sqg =>
|
||||
{
|
||||
aq.Question.ChildrenQuestion.Add(ParseGroupToQuestion(sqg));
|
||||
aq.Question.ChildrenQuestion.Last().Index = (byte)aq.Question.ChildrenQuestion.Count;
|
||||
});
|
||||
|
||||
return aq;
|
||||
}
|
||||
|
||||
|
||||
private static AssignmentQuestionDto ParseAssignmentQuestion(PaperQuestion sq)
|
||||
{
|
||||
var aq = new AssignmentQuestionDto();
|
||||
aq.Score = sq.Score;
|
||||
|
||||
aq.Question = ParseQuestion(sq);
|
||||
|
||||
sq.SubQuestions?.ForEach(ssq =>
|
||||
{
|
||||
|
||||
aq.Question.ChildrenQuestion.Add(ParseQuestion(ssq));
|
||||
aq.Question.ChildrenQuestion.Last().Index = (byte)aq.Question.ChildrenQuestion.Count;
|
||||
|
||||
});
|
||||
|
||||
return aq;
|
||||
}
|
||||
|
||||
private static QuestionDto ParseQuestion(PaperQuestion sq)
|
||||
{
|
||||
var dq = new QuestionDto();
|
||||
dq.Title = sq.Stem;
|
||||
dq.Options = string.Join(Environment.NewLine, sq.Options.Select(opt => $"{opt.Label} {opt.Text}"));
|
||||
dq.Score = sq.Score;
|
||||
|
||||
|
||||
sq.SubQuestions?.ForEach(ssq =>
|
||||
{
|
||||
dq.ChildrenQuestion.Add(ParseQuestion(ssq));
|
||||
dq.ChildrenQuestion.Last().Index = (byte)dq.ChildrenQuestion.Count;
|
||||
});
|
||||
|
||||
return dq;
|
||||
}
|
||||
|
||||
private static void ParseMajorQuestionGroup(MajorQuestionGroup qg, QuestionGroupDto qgd, bool isParentGroupValidChain)
|
||||
{
|
||||
qgd.Title = qg.Title;
|
||||
@@ -86,12 +192,10 @@ namespace TechHelper.Client.Exam
|
||||
});
|
||||
}
|
||||
|
||||
// 处理 MajorQuestionGroup 下的 SubQuestions
|
||||
if (qg.SubQuestions != null)
|
||||
{
|
||||
qg.SubQuestions.ForEach(sq =>
|
||||
{
|
||||
// 如果 MajorQuestionGroup 下的 Question 包含子问题,则转为 QuestionGroupDto
|
||||
if (sq.SubQuestions != null && sq.SubQuestions.Any())
|
||||
{
|
||||
var subQgd = new QuestionGroupDto
|
||||
@@ -101,7 +205,6 @@ namespace TechHelper.Client.Exam
|
||||
Score = (int)sq.Score,
|
||||
Descript = "" // 默认为空
|
||||
};
|
||||
// 判断当前组是否有效:如果有描述,并且其父级链中没有任何一个组是有效组,则当前组有效
|
||||
subQgd.ValidQuestionGroup = !string.IsNullOrEmpty(subQgd.Descript) && !nextIsParentGroupValidChain;
|
||||
|
||||
ParseQuestionWithSubQuestions(sq, subQgd, subQgd.ValidQuestionGroup || nextIsParentGroupValidChain);
|
||||
@@ -121,7 +224,7 @@ namespace TechHelper.Client.Exam
|
||||
|
||||
// 解析包含子问题的 Question,将其转换为 QuestionGroupDto
|
||||
// isParentGroupValidChain 参数表示从顶层到当前组的任一父组是否已经是“有效组”
|
||||
private static void ParseQuestionWithSubQuestions(Question question, QuestionGroupDto qgd, bool isParentGroupValidChain)
|
||||
private static void ParseQuestionWithSubQuestions(PaperQuestion question, QuestionGroupDto qgd, bool isParentGroupValidChain)
|
||||
{
|
||||
qgd.Title = question.Stem;
|
||||
qgd.Score = (int)question.Score;
|
||||
@@ -165,7 +268,7 @@ namespace TechHelper.Client.Exam
|
||||
}
|
||||
|
||||
// 解析单个 Question (没有子问题) 为 SubQuestionDto
|
||||
private static void ParseSingleQuestion(Question question, SubQuestionDto subQd, bool validQ)
|
||||
private static void ParseSingleQuestion(PaperQuestion question, SubQuestionDto subQd, bool validQ)
|
||||
{
|
||||
subQd.Stem = question.Stem;
|
||||
subQd.Score = (int)question.Score;
|
||||
@@ -187,7 +290,7 @@ namespace TechHelper.Client.Exam
|
||||
|
||||
public static void SeqIndex(this ExamDto dto)
|
||||
{
|
||||
dto.QuestionGroups.SeqQGroupIndex();
|
||||
dto.ExamStruct.SeqQGroupIndex();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -51,7 +51,7 @@ namespace TechHelper.Client.Exam
|
||||
public string Description { get; set; } = "未识别试卷描述";
|
||||
public string SubjectArea { get; set; } = "试卷类别";
|
||||
public List<MajorQuestionGroup> QuestionGroups { get; set; } = new List<MajorQuestionGroup>();
|
||||
public List<Question> TopLevelQuestions { get; set; } = new List<Question>();
|
||||
public List<PaperQuestion> TopLevelQuestions { get; set; } = new List<PaperQuestion>();
|
||||
public List<ParseError> Errors { get; set; } = new List<ParseError>();
|
||||
}
|
||||
|
||||
@@ -61,17 +61,18 @@ namespace TechHelper.Client.Exam
|
||||
public string Descript { get; set; } = string.Empty;
|
||||
public float Score { get; set; }
|
||||
public List<MajorQuestionGroup> SubQuestionGroups { get; set; } = new List<MajorQuestionGroup>();
|
||||
public List<Question> SubQuestions { get; set; } = new List<Question>();
|
||||
public List<PaperQuestion> SubQuestions { get; set; } = new List<PaperQuestion>();
|
||||
public int Priority { get; set; }
|
||||
public bool bGroup { get; set; } = true;
|
||||
}
|
||||
|
||||
public class Question
|
||||
public class PaperQuestion
|
||||
{
|
||||
public string Number { get; set; } = string.Empty;
|
||||
public string Stem { get; set; } = string.Empty;
|
||||
public float Score { get; set; }
|
||||
public List<Option> Options { get; set; } = new List<Option>();
|
||||
public List<Question> SubQuestions { get; set; } = new List<Question>();
|
||||
public List<PaperQuestion> SubQuestions { get; set; } = new List<PaperQuestion>();
|
||||
public string SampleAnswer { get; set; } = string.Empty;
|
||||
public string QuestionType { get; set; } = string.Empty;
|
||||
public int Priority { get; set; }
|
||||
@@ -120,17 +121,17 @@ namespace TechHelper.Client.Exam
|
||||
public ExamParserConfig()
|
||||
{
|
||||
MajorQuestionGroupPatterns.Add(new RegexPatternConfig(@"^([一二三四五六七八九十]+)[、\.]\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 1));
|
||||
MajorQuestionGroupPatterns.Add(new RegexPatternConfig(@"^\(([一二三四五六七八九十]{1,2}|十[一二三四五六七八九])\)\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 2));
|
||||
QuestionPatterns.Add(new RegexPatternConfig(@"^\(([一二三四五六七八九十]{1,2}|十[一二三四五六七八九])\)\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 1));
|
||||
|
||||
|
||||
// 模式 1: "1. 这是一个题目 (5分)" 或 "1. 这是一个题目"
|
||||
QuestionPatterns.Add(new RegexPatternConfig(@"^(\d+)\.\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 1));
|
||||
QuestionPatterns.Add(new RegexPatternConfig(@"^(\d+)\.\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 2));
|
||||
|
||||
// 模式 2: "(1) 这是一个子题目 (3分)" 或 "(1) 这是一个子题目"
|
||||
QuestionPatterns.Add(new RegexPatternConfig(@"^\((\d+)\)\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 2));
|
||||
QuestionPatterns.Add(new RegexPatternConfig(@"^\((\d+)\)\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 3));
|
||||
|
||||
// 模式 3: "① 这是一个更深层次的子题目 (2分)" 或 "① 这是一个更深层次的子题目"
|
||||
QuestionPatterns.Add(new RegexPatternConfig(@"^[①②③④⑤⑥⑦⑧⑨⑩]+\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 3));
|
||||
QuestionPatterns.Add(new RegexPatternConfig(@"^[①②③④⑤⑥⑦⑧⑨⑩]+\s*(.+?)(?:\s*\(((\d+(?:\.\d+)?))\s*分\))?\s*$", 4));
|
||||
|
||||
|
||||
OptionPatterns.Add(new RegexPatternConfig(@"([A-Z]\.)\s*(.*?)(?=[A-Z]\.|$)", 1)); // 大写字母选项
|
||||
@@ -251,6 +252,23 @@ namespace TechHelper.Client.Exam
|
||||
_config = config ?? throw new ArgumentNullException(nameof(config), "ExamParserConfig cannot be null.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// 一.基础
|
||||
/// 1.听写
|
||||
/// 2.阅读
|
||||
/// 二.提升
|
||||
/// 1.阅读
|
||||
/// (1).选择
|
||||
/// (2).填空
|
||||
/// 三.写
|
||||
/// (一)课文
|
||||
///
|
||||
///
|
||||
///
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Builds the ExamPaper structure from raw text and potential matches.
|
||||
/// Collects and returns parsing errors encountered during the process.
|
||||
@@ -260,7 +278,7 @@ namespace TechHelper.Client.Exam
|
||||
/// <returns>An ExamPaper object containing the parsed structure and a list of errors.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown if fullExamText is null or empty.</exception>
|
||||
/// <exception cref="ArgumentNullException">Thrown if allPotentialMatches is null.</exception>
|
||||
public ExamPaper BuildExamPaper(string fullExamText, List<PotentialMatch> allPotentialMatches)
|
||||
public ExamPaper BuildExam(string fullExamText, List<PotentialMatch> allPotentialMatches)
|
||||
{
|
||||
// 核心输入验证仍然是必要的,因为这些错误是无法恢复的
|
||||
if (string.IsNullOrWhiteSpace(fullExamText))
|
||||
@@ -289,8 +307,8 @@ namespace TechHelper.Client.Exam
|
||||
var majorQGStack = new Stack<MajorQuestionGroup>();
|
||||
MajorQuestionGroup currentMajorQG = null;
|
||||
|
||||
var questionStack = new Stack<Question>();
|
||||
Question currentQuestion = null;
|
||||
var questionStack = new Stack<PaperQuestion>();
|
||||
PaperQuestion currentQuestion = null;
|
||||
|
||||
int currentContentStart = 0;
|
||||
|
||||
@@ -388,6 +406,7 @@ namespace TechHelper.Client.Exam
|
||||
Title = pm.RegexMatch.Groups[2].Value.Trim(), // 标题是 Group 2
|
||||
Score = score,
|
||||
Priority = pm.PatternConfig.Priority,
|
||||
bGroup = true
|
||||
};
|
||||
|
||||
if (majorQGStack.Any())
|
||||
@@ -446,7 +465,7 @@ namespace TechHelper.Client.Exam
|
||||
}
|
||||
}
|
||||
|
||||
Question newQuestion = new Question
|
||||
PaperQuestion newQuestion = new PaperQuestion
|
||||
{
|
||||
Number = pm.RegexMatch.Groups[1].Value.Trim(),
|
||||
Stem = pm.RegexMatch.Groups[2].Value.Trim(),
|
||||
@@ -618,7 +637,7 @@ namespace TechHelper.Client.Exam
|
||||
/// Processes the content of a Question, mainly for parsing Options and identifying unstructured text.
|
||||
/// Logs errors to the provided error list instead of throwing.
|
||||
/// </summary>
|
||||
private void ProcessQuestionContent(Question question, string contentText, List<PotentialMatch> potentialMatchesInScope, List<ParseError> errors)
|
||||
private void ProcessQuestionContent(PaperQuestion question, string contentText, List<PotentialMatch> potentialMatchesInScope, List<ParseError> errors)
|
||||
{
|
||||
// 参数验证,这些是内部方法的契约,如果违反则直接抛出,因为这意味着调用者有错
|
||||
if (question == null) throw new ArgumentNullException(nameof(question), "Question cannot be null in ProcessQuestionContent.");
|
||||
@@ -674,8 +693,10 @@ namespace TechHelper.Client.Exam
|
||||
question.Options.Add(newOption);
|
||||
lastOptionEndIndex = pm.EndIndex;
|
||||
}
|
||||
// TODO: If there are SubQuestion types, they can be processed similarly here.
|
||||
// 你可以在此处添加对子问题的处理逻辑,同样需要小心处理其内容和嵌套。
|
||||
else
|
||||
{
|
||||
question.Stem += contentText;
|
||||
}
|
||||
}
|
||||
catch (Exception innerEx)
|
||||
{
|
||||
@@ -734,7 +755,7 @@ namespace TechHelper.Client.Exam
|
||||
// 2. 构建:根据扫描结果和原始文本,线性遍历并构建层级结构
|
||||
// BuildExamPaper 现在会返回一个包含错误列表的 ExamPaper 对象
|
||||
// 外部不再需要捕获内部解析异常,只需检查 ExamPaper.Errors 列表
|
||||
return _builder.BuildExamPaper(examPaperText, allPotentialMatches);
|
||||
return _builder.BuildExam(examPaperText, allPotentialMatches);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,163 +0,0 @@
|
||||
using System.Xml.Serialization; // 用于 XML 序列化/反序列化
|
||||
using TechHelper.Client.AI;
|
||||
using TechHelper.Services;
|
||||
using Entities.DTO;
|
||||
using System.Net.Http.Json; // 用于 PostAsJsonAsync
|
||||
using Newtonsoft.Json; // 用于 JSON 反序列化
|
||||
|
||||
namespace TechHelper.Client.Exam
|
||||
{
|
||||
public class ExamService : IExamService
|
||||
{
|
||||
private readonly IAIService _aIService; // 遵循命名规范,字段前加下划线
|
||||
private readonly HttpClient _client; // 直接注入 HttpClient
|
||||
|
||||
public ExamService(IAIService aIService, HttpClient client) // 修正点:直接注入 HttpClient
|
||||
{
|
||||
_aIService = aIService;
|
||||
_client = client; // 赋值注入的 HttpClient 实例
|
||||
}
|
||||
|
||||
public ApiResponse ConvertToXML<T>(string xmlContent)
|
||||
{
|
||||
string cleanedXml = xmlContent.Trim();
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(T));
|
||||
|
||||
using (StringReader reader = new StringReader(cleanedXml))
|
||||
{
|
||||
try
|
||||
{
|
||||
T deserializedObject = (T)serializer.Deserialize(reader);
|
||||
return ApiResponse.Success(result: deserializedObject, message: "XML 反序列化成功。");
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return ApiResponse.Error(
|
||||
message: $"XML 反序列化操作错误: {ex.Message}. 内部异常: {ex.InnerException?.Message ?? "无"}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ApiResponse.Error(message: $"处理 XML 反序列化时发生未知错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> DividExam(string examContent)
|
||||
{
|
||||
try
|
||||
{
|
||||
string? response = await _aIService.CallGLM(examContent, AIConfiguration.BreakQuestions);
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
return ApiResponse.Success(result: response, message: "试题分割成功。");
|
||||
}
|
||||
else
|
||||
{
|
||||
return ApiResponse.Error(message: "AI 服务未能返回有效内容,或返回内容为空。");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 实际应用中,这里应该加入日志记录
|
||||
return ApiResponse.Error(message: $"处理试题分割时发生内部错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> FormatExam(string examContent)
|
||||
{
|
||||
try
|
||||
{
|
||||
string? response = await _aIService.CallGLM(examContent, AIConfiguration.Format);
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
return ApiResponse.Success(result: response, message: "试题格式化成功。");
|
||||
}
|
||||
else
|
||||
{
|
||||
return ApiResponse.Error(message: "AI 服务未能返回有效内容,或返回内容为空。");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 实际应用中,这里应该加入日志记录
|
||||
return ApiResponse.Error(message: $"处理试题格式化时发生内部错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetAllExam(string user)
|
||||
{
|
||||
// 直接使用注入的 _client 实例
|
||||
var response = await _client.GetAsync($"exam/getAllPreview?user={user}");
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonConvert.DeserializeObject<List<ExamDto>>(content);
|
||||
return ApiResponse.Success(result: result);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 读取错误信息,并返回 ApiResponse
|
||||
var errorContent = await response.Content.ReadAsStringAsync();
|
||||
return ApiResponse.Error(message: $"获取所有试题失败: {response.StatusCode} - {errorContent}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> GetExam(Guid guid)
|
||||
{
|
||||
|
||||
var response = await _client.GetAsync($"exam/get?id={guid}");
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
var exam = JsonConvert.DeserializeObject<ExamDto>(content);
|
||||
return ApiResponse.Success(result: exam);
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorContent = await response.Content.ReadAsStringAsync();
|
||||
return ApiResponse.Error(message: $"获取试题失败: {response.StatusCode} - {errorContent}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> ParseSingleQuestionGroup(string examContent)
|
||||
{
|
||||
try
|
||||
{
|
||||
string? response = await _aIService.CallGLM(examContent, AIConfiguration.ParseSignelQuestion2);
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
return ApiResponse.Success(result: response, message: "试题解析成功。");
|
||||
}
|
||||
else
|
||||
{
|
||||
return ApiResponse.Error(message: "AI 服务未能返回有效内容,或返回内容为空。");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 实际应用中,这里应该加入日志记录
|
||||
return ApiResponse.Error(message: $"处理试题解析时发生内部错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ApiResponse> SaveParsedExam(ExamDto examDto)
|
||||
{
|
||||
// 直接使用注入的 _client 实例
|
||||
var response = await _client.PostAsJsonAsync("exam/add", examDto);
|
||||
|
||||
if (response.IsSuccessStatusCode) // 检查是否是成功的状态码,例如 200 OK, 201 Created 等
|
||||
{
|
||||
return ApiResponse.Success(message: "试题保存成功。");
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorContent = await response.Content.ReadAsStringAsync();
|
||||
return ApiResponse.Error(message: $"保存试题失败: {response.StatusCode} - {errorContent}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -52,7 +52,7 @@ namespace TechHelper.Client.Exam
|
||||
Title = dto.AssignmentTitle
|
||||
};
|
||||
|
||||
GetSeqRecursive(dto.QuestionGroups, null, examStruct.Questions);
|
||||
GetSeqRecursive(dto.ExamStruct, null, examStruct.Questions);
|
||||
|
||||
return examStruct;
|
||||
}
|
||||
|
@@ -1,17 +0,0 @@
|
||||
using Entities.DTO;
|
||||
using TechHelper.Services;
|
||||
|
||||
namespace TechHelper.Client.Exam
|
||||
{
|
||||
public interface IExamService
|
||||
{
|
||||
public Task<ApiResponse> FormatExam(string examContent);
|
||||
public Task<ApiResponse> DividExam(string examContent);
|
||||
public Task<ApiResponse> SaveParsedExam(ExamDto examDto);
|
||||
public Task<ApiResponse> ParseSingleQuestionGroup(string examContent);
|
||||
public ApiResponse ConvertToXML<T>(string xmlContent);
|
||||
|
||||
public Task<ApiResponse> GetAllExam(string user);
|
||||
public Task<ApiResponse> GetExam(Guid guid);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user