mirror of
https://github.com/fumiama/paper-manager.git
synced 2026-06-25 05:20:16 +08:00
implement GenerateFile
This commit is contained in:
@@ -236,6 +236,7 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
que := &Question{
|
que := &Question{
|
||||||
ID: int64(binary.LittleEndian.Uint64(m[:8])),
|
ID: int64(binary.LittleEndian.Uint64(m[:8])),
|
||||||
FileID: file.ID,
|
FileID: file.ID,
|
||||||
|
Major: majorq.Name,
|
||||||
Plain: base14.BytesToString(sb.Bytes()),
|
Plain: base14.BytesToString(sb.Bytes()),
|
||||||
Images: func() []byte {
|
Images: func() []byte {
|
||||||
m := make(map[string]string)
|
m := make(map[string]string)
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
package global
|
package global
|
||||||
|
|
||||||
import "errors"
|
import (
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
sql "github.com/FloatTech/sqlite"
|
||||||
|
"github.com/fumiama/go-docx"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
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 试卷生成配置
|
// GenerateConfig 试卷生成配置
|
||||||
@@ -16,9 +25,59 @@ type GenerateConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GenerateFile 用一些限定条件生成新试卷, 云端不保存
|
// GenerateFile 用一些限定条件生成新试卷, 云端不保存
|
||||||
func (f *FileDatabase) GenerateFile(config *GenerateConfig) ([]byte, error) {
|
func (f *FileDatabase) GenerateFile(config *GenerateConfig) (*docx.Docx, error) {
|
||||||
if config == nil || config.Distribution == nil {
|
if config == nil || config.Distribution == nil || len(config.Distribution) == 0 {
|
||||||
return nil, ErrInvalidGenerateConfig
|
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
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ func (f *FileDatabase) DelQuestion(id int64, istemp bool) error {
|
|||||||
type Question struct {
|
type Question struct {
|
||||||
ID int64 // ID is the first 8 bytes of the Plain's md5
|
ID int64 // ID is the first 8 bytes of the Plain's md5
|
||||||
FileID int64 // FileID is fk to File(ID)
|
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
|
Path string // Path is the question's docx position
|
||||||
Plain string // Plain is the plain text of the question (like markdown format)
|
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', ...]
|
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)
|
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
|
// MaxDuplicateRate parse q.Dup and get the max rate
|
||||||
func (q *Question) MaxDuplicateRate() float64 {
|
func (q *Question) MaxDuplicateRate() float64 {
|
||||||
dupmap := make(map[string]float64, 64)
|
dupmap := make(map[string]float64, 64)
|
||||||
|
|||||||
Reference in New Issue
Block a user