1
0
mirror of https://github.com/fumiama/paper-manager.git synced 2026-06-04 23:40:24 +08:00

implement GenerateFile

This commit is contained in:
源文雨
2023-04-23 00:53:18 +08:00
parent 2e44127672
commit ff831f2f7a
3 changed files with 80 additions and 4 deletions

View File

@@ -236,6 +236,7 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
que := &Question{
ID: int64(binary.LittleEndian.Uint64(m[:8])),
FileID: file.ID,
Major: majorq.Name,
Plain: base14.BytesToString(sb.Bytes()),
Images: func() []byte {
m := make(map[string]string)

View File

@@ -1,9 +1,18 @@
package global
import "errors"
import (
"errors"
"strconv"
sql "github.com/FloatTech/sqlite"
"github.com/fumiama/go-docx"
)
var (
ErrInvalidGenerateConfig = errors.New("invalid generate config")
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 试卷生成配置
@@ -16,9 +25,59 @@ type GenerateConfig struct {
}
// GenerateFile 用一些限定条件生成新试卷, 云端不保存
func (f *FileDatabase) GenerateFile(config *GenerateConfig) ([]byte, error) {
if config == nil || config.Distribution == nil {
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
}
// TODO: 写入question到docf
}
return nil, nil
}

View File

@@ -81,6 +81,7 @@ func (f *FileDatabase) DelQuestion(id int64, istemp bool) error {
type Question struct {
ID int64 // ID is the first 8 bytes of the Plain's md5
FileID int64 // FileID is fk to File(ID)
Major string // Major is sub's major name
Path string // Path is the question's docx position
Plain string // Plain is the plain text of the question (like markdown format)
Images []byte // Images is json of the image dhash in XML, ex. ['rId1': '1234567890abcdef', ...]
@@ -110,6 +111,21 @@ func (f *FileDatabase) GetQuestionHex(hexid string, istemp bool) (q Question, er
return f.GetQuestion(int64(binary.LittleEndian.Uint64(idb)), istemp)
}
// GetMajors ...
func (f *FileDatabase) GetMajors() (majors []string) {
type majorq struct {
Major string
}
var maj majorq
f.mu.RLock()
defer f.mu.RUnlock()
f.db.QueryFor("SELECT DISTINCT Major FROM question;", &maj, func() error {
majors = append(majors, maj.Major)
return nil
})
return
}
// MaxDuplicateRate parse q.Dup and get the max rate
func (q *Question) MaxDuplicateRate() float64 {
dupmap := make(map[string]float64, 64)