package services import ( "ankao/pkg/config" "context" "encoding/json" "fmt" "strings" "github.com/sashabaranov/go-openai" ) // AIGradingService AI评分服务 type AIGradingService struct { client *openai.Client config *config.AIConfig } // NewAIGradingService 创建AI评分服务实例 func NewAIGradingService() *AIGradingService { cfg := config.GetAIConfig() // 创建OpenAI客户端配置 clientConfig := openai.DefaultConfig(cfg.APIKey) clientConfig.BaseURL = cfg.BaseURL + "/v1" // 标准OpenAI API格式需要/v1后缀 client := openai.NewClientWithConfig(clientConfig) return &AIGradingService{ client: client, config: cfg, } } // AIGradingResult AI评分结果 type AIGradingResult struct { Score float64 `json:"score"` // 得分 (0-100) IsCorrect bool `json:"is_correct"` // 是否正确 (Score >= 60 视为正确) Feedback string `json:"feedback"` // 评语 Suggestion string `json:"suggestion"` // 改进建议 } // GradeShortAnswer 对简答题进行AI评分 // question: 题目内容 // standardAnswer: 标准答案 // userAnswer: 用户答案 func (s *AIGradingService) GradeShortAnswer(question, standardAnswer, userAnswer string) (*AIGradingResult, error) { // 构建评分提示词 prompt := fmt.Sprintf(`你是一位专业的阅卷老师,请对以下简答题进行评分。 题目:%s 标准答案:%s 学生答案:%s 请按照以下要求进行评分: 1. 给出一个0-100的分数 2. 判断答案是否正确(60分及以上为正确) 3. 给出简短的评语(不超过50字) 4. 如果答案不完善,给出改进建议(不超过50字,如果答案很好可以为空) 请按照以下JSON格式返回结果: { "score": 85, "is_correct": true, "feedback": "答案基本正确,要点全面", "suggestion": "可以补充一些具体的例子" } 注意:只返回JSON格式的结果,不要有其他内容。`, question, standardAnswer, userAnswer) // 调用AI API resp, err := s.client.CreateChatCompletion( context.Background(), openai.ChatCompletionRequest{ Model: s.config.Model, Messages: []openai.ChatCompletionMessage{ { Role: openai.ChatMessageRoleSystem, Content: "你是一位专业的阅卷老师,擅长对简答题进行公正、客观的评分。", }, { Role: openai.ChatMessageRoleUser, Content: prompt, }, }, Temperature: 0.3, // 较低的温度以获得更稳定的评分结果 }, ) if err != nil { return nil, fmt.Errorf("AI评分失败: %w", err) } if len(resp.Choices) == 0 { return nil, fmt.Errorf("AI未返回评分结果") } // 解析AI返回的JSON结果 content := resp.Choices[0].Message.Content var result AIGradingResult if err := parseAIResponse(content, &result); err != nil { return nil, fmt.Errorf("解析AI响应失败: %w", err) } return &result, nil } // parseAIResponse 解析AI返回的JSON响应 func parseAIResponse(content string, result *AIGradingResult) error { // 移除可能的markdown代码块标记 jsonStr := removeMarkdownCodeBlock(content) // 使用json包解析 if err := json.Unmarshal([]byte(jsonStr), result); err != nil { return fmt.Errorf("JSON解析失败: %w, 原始内容: %s", err, content) } return nil } // removeMarkdownCodeBlock 移除markdown代码块标记 func removeMarkdownCodeBlock(s string) string { // 去除可能的```json和```标记 s = strings.TrimSpace(s) // 移除开头的```json或``` if strings.HasPrefix(s, "```json") { s = s[7:] } else if strings.HasPrefix(s, "```") { s = s[3:] } // 移除结尾的``` if strings.HasSuffix(s, "```") { s = s[:len(s)-3] } s = strings.TrimSpace(s) // 查找第一个{的位置 startIdx := strings.Index(s, "{") if startIdx == -1 { return s } // 查找最后一个}的位置 endIdx := strings.LastIndex(s, "}") if endIdx == -1 || endIdx <= startIdx { return s } return s[startIdx : endIdx+1] }