146 lines
3.7 KiB
Go
146 lines
3.7 KiB
Go
package xuexitong
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"likedream-goframe/internal/application/quesbank"
|
|
"likedream-goframe/internal/application/xuexitong/entity"
|
|
"likedream-goframe/internal/framework/logger"
|
|
"strings"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// AIType 类型别名,引用 quesbank 包
|
|
type AIType = quesbank.AIType
|
|
|
|
// AI类型常量
|
|
const (
|
|
AITypeChatGLM = quesbank.AITypeChatGLM
|
|
AITypeXingHuo = quesbank.AITypeXingHuo
|
|
AITypeTongYi = quesbank.AITypeTongYi
|
|
AITypeDouBao = quesbank.AITypeDouBao
|
|
AITypeOpenAI = quesbank.AITypeOpenAI
|
|
AITypeOther = quesbank.AITypeOther
|
|
)
|
|
|
|
// AIConfig 类型别名
|
|
type AIConfig = quesbank.AIConfig
|
|
|
|
// convertToQuesbankQuestion 将学习通题目转换为通用题目格式
|
|
func convertToQuesbankQuestion(q entity.WorkQuestion) quesbank.Question {
|
|
return quesbank.Question{
|
|
Qid: q.Qid,
|
|
Type: quesbank.QuestionType(q.Type),
|
|
Text: q.Text,
|
|
Options: q.Options,
|
|
Answers: q.Answers,
|
|
BlankCount: q.BlankCount,
|
|
BlankAnswer: q.BlankAnswer,
|
|
}
|
|
}
|
|
|
|
// AIAnswerWork AI答题处理作业
|
|
func (c *XuexitongCourse) AIAnswerWork(ctx context.Context, workDto *entity.WorkDto, aiConfig AIConfig) error {
|
|
aiService := quesbank.NewAIAnswerService(aiConfig)
|
|
|
|
for i := range workDto.Questions {
|
|
q := &workDto.Questions[i]
|
|
|
|
// 转换为通用题目格式
|
|
question := convertToQuesbankQuestion(*q)
|
|
|
|
// 构建提示词
|
|
prompt := quesbank.BuildQuestionPrompt(question)
|
|
|
|
// 获取AI答案
|
|
aiResponse, err := aiService.GetAnswer(ctx, prompt)
|
|
if err != nil {
|
|
logger.Logger.Error("AI答题失败",
|
|
zap.String("qid", q.Qid),
|
|
zap.String("text", q.Text),
|
|
zap.Error(err))
|
|
continue
|
|
}
|
|
|
|
// 解析答案
|
|
answers, err := quesbank.ParseAIAnswer(aiResponse)
|
|
if err != nil {
|
|
logger.Logger.Error("解析AI答案失败",
|
|
zap.String("qid", q.Qid),
|
|
zap.String("aiResponse", aiResponse),
|
|
zap.Error(err))
|
|
continue
|
|
}
|
|
|
|
// 根据题型处理答案
|
|
switch q.Type {
|
|
case entity.QuestionTypeSingleChoice, entity.QuestionTypeMultipleChoice:
|
|
var matchedAnswers []string
|
|
for _, ans := range answers {
|
|
matched := quesbank.MatchAnswerToOption(ans, q.Options)
|
|
if matched != "" {
|
|
matchedAnswers = append(matchedAnswers, matched)
|
|
}
|
|
}
|
|
q.Answers = matchedAnswers
|
|
|
|
case entity.QuestionTypeTrueFalse:
|
|
if len(answers) > 0 {
|
|
q.Answers = answers
|
|
}
|
|
|
|
case entity.QuestionTypeFillBlank:
|
|
q.BlankAnswer = make(map[string]string)
|
|
for idx, ans := range answers {
|
|
key := fmt.Sprintf("第%d空", idx+1)
|
|
q.BlankAnswer[key] = ans
|
|
}
|
|
q.BlankCount = len(answers)
|
|
|
|
case entity.QuestionTypeShortAnswer:
|
|
if len(answers) > 0 {
|
|
q.Answers = []string{strings.Join(answers, "")}
|
|
}
|
|
}
|
|
|
|
logger.Logger.Debug("AI答题成功",
|
|
zap.String("qid", q.Qid),
|
|
zap.Int("type", int(q.Type)),
|
|
zap.Strings("answers", q.Answers))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// AutoCompleteWorkWithAI 使用AI自动完成作业
|
|
func (c *XuexitongCourse) AutoCompleteWorkWithAI(ctx context.Context, p *entity.PointWorkDto, aiConfig AIConfig, autoSubmit bool) (string, error) {
|
|
// 获取作业题目
|
|
workDto, err := c.FetchWorkQuestions(ctx, p)
|
|
if err != nil {
|
|
return "", fmt.Errorf("获取作业题目失败: %w", err)
|
|
}
|
|
|
|
if len(workDto.Questions) == 0 {
|
|
return "", errors.New("作业无题目")
|
|
}
|
|
|
|
logger.Logger.Info("开始AI答题",
|
|
zap.String("title", workDto.Title),
|
|
zap.Int("questionCount", len(workDto.Questions)))
|
|
|
|
// AI答题
|
|
if err := c.AIAnswerWork(ctx, workDto, aiConfig); err != nil {
|
|
return "", fmt.Errorf("AI答题失败: %w", err)
|
|
}
|
|
|
|
// 提交答案
|
|
result, err := c.SubmitWorkAnswers(ctx, workDto, !autoSubmit)
|
|
if err != nil {
|
|
return "", fmt.Errorf("提交答案失败: %w", err)
|
|
}
|
|
|
|
return result, nil
|
|
}
|