Files
service-qgdzs/internal/grpc_server/server_question.go

248 lines
8.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package grpc_server
import (
"context"
"encoding/json"
"errors"
"fmt"
"git.hlsq.asia/mmorpg/service-common/db/redis"
"git.hlsq.asia/mmorpg/service-common/log"
"git.hlsq.asia/mmorpg/service-common/net/http/http_resp"
"git.hlsq.asia/mmorpg/service-common/proto/rs/grpc_pb"
"git.hlsq.asia/mmorpg/service-common/utils"
"git.hlsq.asia/mmorpg/service-qgdzs/internal/ai"
"git.hlsq.asia/mmorpg/service-qgdzs/internal/dao/model"
"git.hlsq.asia/mmorpg/service-qgdzs/internal/dao/repository"
"gorm.io/gorm"
"time"
)
var prompt = []string{`
你是一个微信小游戏的内容策划,我需要生成“每日趣味题”,要求:
- 避免敏感、争议或超纲内容
- 确保选项有迷惑性,解析有趣
- 绝对要避免重复,现在的时间是:%v
- 这些是我目前的分类:%v
- 输出格式为 JSON 数组不要任何解释、不要Markdown、不要任何其他字符
[{
"question": "题目文本", // 简洁30字以内
"options": ["A. 选项1", "B. 选项2", "C. 选项3", "D. 选项4"], // 提供4个选项A/B/C/D其中仅1个正确
"answer": "C", // 答案
"explanation": "解析文本", // 200字以内尽量幽默有趣
"category": "分类", // 尽量从上述分类中选择,你也可以增加,但是命名风格要类似
"difficulty": 100, // 难度分 0 - 100
}]
如果你准备好了,请回答”好的“,不要有其他任何字符
`, `
请帮我生成 %v 道,只允许回答 JSON 数组:
`, `
请继续生成 %v 道,只允许回答 JSON 数组:
`, `
请继续生成 %v 道,只允许回答 JSON 数组:
`, `
请继续生成 %v 道,只允许回答 JSON 数组:
`, `
请继续生成 %v 道,只允许回答 JSON 数组:
`}
type Question struct {
Question string `json:"question"` // 题干
Options []string `json:"options"` // 选项
Answer string `json:"answer"` // 答案
Explanation string `json:"explanation"` // 解析
Category string `json:"category"` // 分类
Difficulty int32 `json:"difficulty"` // 难度分
}
func (s *Server) GenerateQuestion(ctx context.Context, req *grpc_pb.GenerateQuestionReq) (*grpc_pb.GenerateQuestionResp, error) {
categoryDao := repository.NewCategoryDao(ctx, redis.GetCacheClient())
category, err := categoryDao.FindAll()
if err != nil {
log.Errorf("GenerateQuestion FindCategory error: %v", err)
return nil, err
}
question := make([]*Question, 0)
err = ai.NewAIClient(false, "", 0.9).
RequestAI(
[]string{
fmt.Sprintf(prompt[0], time.Now().Format("2006-01-02 15:04:05"), category),
fmt.Sprintf(prompt[1], req.Num, req.Category),
fmt.Sprintf(prompt[2], req.Num),
fmt.Sprintf(prompt[3], req.Num),
fmt.Sprintf(prompt[4], req.Num),
fmt.Sprintf(prompt[5], req.Num),
},
func(content string, i int) error {
if i == 0 {
return nil
}
step := make([]*Question, 0)
if err := json.Unmarshal([]byte(content), &step); err != nil {
log.Errorf("RequestAI json.Unmarshal error: %v, data: %v", err, content)
return err
}
question = append(question, step...)
return nil
},
)
if err != nil {
log.Errorf("RequestAI error: %v", err)
return nil, err
}
questionDao := repository.NewQuestionDao(ctx, redis.GetCacheClient())
for _, q := range question {
marshal, _ := json.Marshal(q.Options)
categorySn, err := categoryDao.FindSnByName(q.Category)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
cat, err := categoryDao.Create(&model.Category{
Category: q.Category,
})
if err != nil {
log.Errorf("GenerateQuestion CreateCategory error: %v", err)
continue
}
categorySn = cat.Sn
} else {
log.Errorf("GenerateQuestion FindSnByName error: %v", err)
continue
}
}
if _, err = questionDao.Create(&model.Question{
Question: q.Question,
Options: string(marshal),
Answer: q.Answer,
Explanation: q.Explanation,
CategorySn: categorySn,
Difficulty: q.Difficulty,
}); err != nil {
log.Errorf("GenerateQuestion Create error: %v", err)
return nil, err
}
}
return nil, nil
}
// GetQuestion 获取题目
func (s *Server) GetQuestion(ctx context.Context, req *grpc_pb.GetQuestionReq) (*grpc_pb.GetQuestionResp, error) {
question, err := repository.NewQuestionDao(ctx).FindByRandom(req.CategorySn)
if err != nil {
log.Errorf("GetQuestion error: %v", err)
return nil, err
}
options := make([]string, 0)
if err = json.Unmarshal([]byte(question.Options), &options); err != nil {
log.Errorf("GetQuestion json.Unmarshal error: %v, data: %v", err, question.Options)
return nil, err
}
category, _ := repository.NewCategoryDao(ctx).FindNameBySn(question.CategorySn)
return &grpc_pb.GetQuestionResp{
Sn: question.Sn,
Question: question.Question,
Options: options,
Category: category,
Difficulty: question.Difficulty,
}, nil
}
// GetQuestionInfo 获取具体的题目
func (s *Server) GetQuestionInfo(ctx context.Context, req *grpc_pb.GetQuestionInfoReq) (*grpc_pb.GetQuestionInfoResp, error) {
question, err := repository.NewQuestionDao(ctx).FindBySn(req.QuestionSn)
if err != nil {
log.Errorf("GetQuestionInfo error: %v", err)
return nil, err
}
options := make([]string, 0)
if err = json.Unmarshal([]byte(question.Options), &options); err != nil {
log.Errorf("GetQuestionInfo json.Unmarshal error: %v, data: %v", err, question.Options)
return nil, err
}
category, _ := repository.NewCategoryDao(ctx).FindNameBySn(question.CategorySn)
return &grpc_pb.GetQuestionInfoResp{
Question: question.Question,
Options: options,
Category: category,
Difficulty: question.Difficulty,
Explanation: question.Explanation,
}, nil
}
// AnswerQuestion 回答题目
func (s *Server) AnswerQuestion(ctx context.Context, req *grpc_pb.AnswerQuestionReq) (*grpc_pb.AnswerQuestionResp, error) {
question, err := repository.NewQuestionDao(ctx).FindBySn(req.Sn)
if err != nil {
log.Errorf("AnswerQuestion error: %v", err)
return nil, err
}
options := make([]string, 0)
if err = json.Unmarshal([]byte(question.Options), &options); err != nil {
log.Errorf("AnswerQuestion json.Unmarshal error: %v, data: %v", err, question.Options)
return nil, err
}
// 保存答题记录
if utils.ShouldBindUsn(ctx, &req.USN) {
isCorrect := int32(0)
if req.Answer == question.Answer {
isCorrect = 1
}
_, _ = repository.NewRecordDao(ctx).Create(&model.Record{
UserSn: req.USN,
QuestionSn: question.Sn,
Answer: req.Answer,
IsCorrect: isCorrect,
})
}
return &grpc_pb.AnswerQuestionResp{
Answer: question.Answer,
Explanation: question.Explanation,
}, nil
}
// GetAllCategory 获取所有类目
func (s *Server) GetAllCategory(ctx context.Context, req *grpc_pb.GetAllCategoryReq) (*grpc_pb.GetAllCategoryResp, error) {
categoryList, err := repository.NewCategoryDao(ctx).FindAll()
if err != nil {
log.Errorf("GetAllCategory error: %v", err)
return nil, err
}
categories := make([]*grpc_pb.GetAllCategoryItem, 0)
for _, category := range categoryList {
categories = append(categories, &grpc_pb.GetAllCategoryItem{
Sn: category.Sn,
Category: category.Category,
})
}
return &grpc_pb.GetAllCategoryResp{
Categories: categories,
}, nil
}
// GetRecord 获取答题记录
func (s *Server) GetRecord(ctx context.Context, req *grpc_pb.GetRecordReq) (*grpc_pb.GetRecordResp, error) {
if !utils.ShouldBindUsn(ctx, &req.USN) {
return nil, http_resp.ParamError
}
records, count, err := repository.NewRecordDao(ctx).FindByUSN(req.USN, int(req.Page), int(req.PageSize))
if err != nil {
log.Errorf("GetRecord error: %v", err)
return nil, err
}
resp := make([]*grpc_pb.GetRecordItem, 0)
for _, record := range records {
resp = append(resp, &grpc_pb.GetRecordItem{
QuestionSn: record.QuestionSn,
Question: record.Question,
Difficulty: record.Difficulty,
Category: record.Category,
QuestionAnswer: record.QuestionAnswer,
Answer: record.Answer,
CreateTime: record.CreatedAt.Unix(),
})
}
return &grpc_pb.GetRecordResp{
Count: int32(count),
Records: resp,
}, nil
}