优化题目代码
This commit is contained in:
+104
-12
@@ -3,6 +3,8 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"regexp"
|
||||
|
||||
"server/models"
|
||||
"server/services"
|
||||
@@ -14,6 +16,65 @@ type ExamQuestionController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
// normalizeText removes HTML tags, converts to space, and collapses whitespace
|
||||
func normalizeText(s string) string {
|
||||
str := strings.TrimSpace(s)
|
||||
if str == "" {
|
||||
return ""
|
||||
}
|
||||
// remove HTML tags
|
||||
re := regexp.MustCompile("<[^>]*>")
|
||||
str = re.ReplaceAllString(str, "")
|
||||
// decode common entities
|
||||
str = strings.ReplaceAll(str, " ", " ")
|
||||
str = strings.ReplaceAll(str, " ", " ")
|
||||
// collapse whitespace
|
||||
reSpace := regexp.MustCompile(`\s+`)
|
||||
str = reSpace.ReplaceAllString(str, " ")
|
||||
return strings.TrimSpace(str)
|
||||
}
|
||||
|
||||
// computeMatchRate returns a simple similarity percentage between two strings based on
|
||||
// position-wise identical characters over the max length, rounded to integer 0-100.
|
||||
func computeMatchRate(a, b string) int {
|
||||
s1 := normalizeText(a)
|
||||
s2 := normalizeText(b)
|
||||
if s1 == "" && s2 == "" {
|
||||
return 100
|
||||
}
|
||||
maxLen := len([]rune(s1))
|
||||
if l := len([]rune(s2)); l > maxLen {
|
||||
maxLen = l
|
||||
}
|
||||
if maxLen == 0 {
|
||||
return 0
|
||||
}
|
||||
r1 := []rune(s1)
|
||||
r2 := []rune(s2)
|
||||
same := 0
|
||||
for i := 0; i < maxLen; i++ {
|
||||
var c1, c2 rune
|
||||
if i < len(r1) {
|
||||
c1 = r1[i]
|
||||
}
|
||||
if i < len(r2) {
|
||||
c2 = r2[i]
|
||||
}
|
||||
if c1 != 0 && c2 != 0 && c1 == c2 {
|
||||
same++
|
||||
}
|
||||
}
|
||||
// round to nearest int
|
||||
rate := int(float64(same)/float64(maxLen)*100.0 + 0.5)
|
||||
if rate < 0 {
|
||||
return 0
|
||||
}
|
||||
if rate > 100 {
|
||||
return 100
|
||||
}
|
||||
return rate
|
||||
}
|
||||
|
||||
type ExamQuestionBankController struct {
|
||||
beego.Controller
|
||||
}
|
||||
@@ -22,9 +83,10 @@ type ExamQuestionBankController struct {
|
||||
// @router /exam-questions [get]
|
||||
func (c *ExamQuestionController) GetList() {
|
||||
tenantId, _ := c.Ctx.Input.GetData("tenantId").(int)
|
||||
keyword := c.GetString("keyword")
|
||||
keyword := c.GetString("keyword")
|
||||
typeStr := c.GetString("type")
|
||||
bankId, _ := c.GetInt64("bank_id", 0)
|
||||
minRate, _ := c.GetInt("min_rate", 0)
|
||||
|
||||
var qtype *int8
|
||||
if typeStr != "" {
|
||||
@@ -37,32 +99,62 @@ func (c *ExamQuestionController) GetList() {
|
||||
page, _ := c.GetInt("page", 1)
|
||||
pageSize, _ := c.GetInt("pageSize", 10)
|
||||
|
||||
list, total, err := services.GetExamQuestions(services.QuestionListParams{
|
||||
TenantId: tenantId,
|
||||
Keyword: keyword,
|
||||
QuestionType: qtype,
|
||||
BankId: bankId,
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
})
|
||||
// use normalized keyword for DB searching to improve hit rate when editor HTML is posted
|
||||
normKeyword := normalizeText(keyword)
|
||||
list, total, err := services.GetExamQuestions(services.QuestionListParams{
|
||||
TenantId: tenantId,
|
||||
Keyword: normKeyword,
|
||||
QuestionType: qtype,
|
||||
BankId: bankId,
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
})
|
||||
if err != nil {
|
||||
c.Data["json"] = map[string]interface{}{"code": 1, "message": "获取试题列表失败: " + err.Error(), "data": nil}
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
// 当启用相似度筛选且按关键字无结果时,回退到不带关键字的最近记录中做相似度匹配
|
||||
if minRate > 0 && strings.TrimSpace(normKeyword) != "" && len(list) == 0 {
|
||||
fbPageSize := 50
|
||||
fbList, _, fbErr := services.GetExamQuestions(services.QuestionListParams{
|
||||
TenantId: tenantId,
|
||||
Keyword: "",
|
||||
BankId: bankId,
|
||||
Page: 1,
|
||||
PageSize: fbPageSize,
|
||||
})
|
||||
if fbErr == nil {
|
||||
list = fbList
|
||||
}
|
||||
}
|
||||
|
||||
items := make([]map[string]interface{}, 0, len(list))
|
||||
currentTitle := normalizeText(keyword)
|
||||
for _, q := range list {
|
||||
if q == nil {
|
||||
continue
|
||||
}
|
||||
items = append(items, map[string]interface{}{
|
||||
// 可选相似度计算与过滤
|
||||
var rate *int
|
||||
if currentTitle != "" {
|
||||
v := computeMatchRate(currentTitle, q.QuestionTitle)
|
||||
rate = &v
|
||||
if minRate > 0 && v < minRate {
|
||||
continue
|
||||
}
|
||||
}
|
||||
item := map[string]interface{}{
|
||||
"id": q.Id,
|
||||
"tenant_id": q.TenantId,
|
||||
"question_type": q.QuestionType,
|
||||
"question_title": q.QuestionTitle,
|
||||
"score": q.Score,
|
||||
})
|
||||
}
|
||||
if rate != nil {
|
||||
item["_match_rate"] = *rate
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
@@ -160,7 +252,7 @@ func (c *ExamQuestionController) BatchCreate() {
|
||||
tenantId, _ := c.Ctx.Input.GetData("tenantId").(int)
|
||||
var payload struct {
|
||||
BankId int64 `json:"bank_id"`
|
||||
Items []struct {
|
||||
Items []struct {
|
||||
QuestionTitle string `json:"question_title"`
|
||||
QuestionType int8 `json:"question_type"`
|
||||
Score float64 `json:"score"`
|
||||
|
||||
Reference in New Issue
Block a user