1
0
mirror of https://github.com/fumiama/paper-manager.git synced 2026-06-05 07:50:23 +08:00
Files
paper-manager/backend/global/generate.go
2023-04-24 00:59:06 +08:00

104 lines
2.8 KiB
Go

package global
import (
"errors"
"os"
"strconv"
sql "github.com/FloatTech/sqlite"
"github.com/fumiama/go-docx"
)
var (
ErrInvalidGenerateConfig = errors.New("invalid generate config")
ErrMajorTooLarge = errors.New("major too large")
ErrNoEnoughQuestionToMatchRequire = errors.New("no enough question to match require")
ErrRateLimitExceeded = errors.New("rate limit exceeded")
)
// GenerateConfig 试卷生成配置
type GenerateConfig struct {
Distribution map[string]uint // Distribution is map[majorname]subcount
RateLimit float64 // RateLimit 重复率上限
YearStart StudyYear // YearStart 起始年份(空则直到最旧)
YearEnd StudyYear // YearEnd 截止年份(空则直到最新)
TypeMask PaperType // TypeMask & File.Type != 0 则匹配
}
// GenerateFile 用一些限定条件生成新试卷, 云端不保存
func (f *FileDatabase) GenerateFile(config *GenerateConfig) (*docx.Docx, error) {
if config == nil || config.Distribution == nil || len(config.Distribution) == 0 {
return nil, ErrInvalidGenerateConfig
}
if len(config.Distribution) > 10 {
return nil, ErrMajorTooLarge
}
docf := docx.NewA4()
f.mu.RLock()
defer f.mu.RUnlock()
for n, c := range config.Distribution {
if c == 0 {
continue
}
docf.AddParagraph().AddText(string([]rune("一二三四五六七八九十")[c]) + "、" + n).Size("44").Bold()
cond := " WHERE"
hasfront := false
if config.YearStart > 0 {
cond += " Year>=" + strconv.Itoa(int(config.YearStart))
hasfront = true
}
if config.YearEnd > 0 {
if hasfront {
cond += " AND"
}
cond += " Year<=" + strconv.Itoa(int(config.YearStart))
hasfront = true
}
if hasfront {
cond += " AND"
}
cond += " (Type&" + strconv.Itoa(int(config.TypeMask)) + ")!=0"
ques, err := sql.QueryAll[Question](&f.db,
"SELECT * FROM "+FileTableQuestion+
" WHERE FileID IN (SELECT FileID FROM "+
FileTableFile+cond+
") ORDER BY RANDOM() limit "+strconv.Itoa(int(c))+";",
)
if err != nil {
return nil, err
}
if len(ques) != int(c) {
return nil, ErrNoEnoughQuestionToMatchRequire
}
rate := 0.0
for _, q := range ques {
rate += q.MaxDuplicateRate()
}
rate /= float64(len(ques))
if rate > config.RateLimit {
return nil, ErrRateLimitExceeded
}
for i, q := range ques {
lst, err := sql.Find[List](&f.db, FileTableFile, "WHERE ID="+strconv.Itoa(q.ListID))
if err != nil {
return nil, err
}
quesfile, err := os.Open(q.Path)
if err != nil {
return nil, err
}
stat, err := quesfile.Stat()
if err != nil {
return nil, err
}
docq, err := docx.Parse(quesfile, stat.Size())
if err != nil {
return nil, err
}
docf.AddParagraph().AddText(strconv.Itoa(i+1) + ". (" + lst.Desc + ")")
docf.AppendFile(docq)
}
}
return docf, nil
}