feat: 添加请求验证错误详细日志
All checks were successful
continuous-integration/drone/push Build is passing

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yuliang_guo
2026-01-31 10:03:54 +08:00
parent fadeaadd65
commit 0b7c07eb7f
11 changed files with 2282 additions and 2267 deletions

View File

@@ -1,218 +1,218 @@
"""
分数分配工具
解决题目分数无法整除的问题,确保:
1. 所有题目分数之和精确等于总分
2. 题目分数差异最小化最多相差1分
3. 支持整数分配和小数分配两种模式
"""
from typing import List, Tuple
from decimal import Decimal, ROUND_HALF_UP
import math
class ScoreDistributor:
"""
智能分数分配器
使用示例:
distributor = ScoreDistributor(total_score=100, question_count=6)
scores = distributor.distribute()
# 结果: [17, 17, 17, 17, 16, 16] 总和=100
"""
def __init__(self, total_score: float, question_count: int):
"""
初始化分配器
Args:
total_score: 总分(如 100
question_count: 题目数量(如 6
"""
if question_count <= 0:
raise ValueError("题目数量必须大于0")
if total_score <= 0:
raise ValueError("总分必须大于0")
self.total_score = total_score
self.question_count = question_count
def distribute_integer(self) -> List[int]:
"""
整数分配模式
将总分分配为整数前面的题目分数可能比后面的多1分
Returns:
分数列表,如 [17, 17, 17, 17, 16, 16]
示例:
100分 / 6题 = [17, 17, 17, 17, 16, 16]
100分 / 7题 = [15, 15, 14, 14, 14, 14, 14]
"""
total = int(self.total_score)
count = self.question_count
# 基础分数(向下取整)
base_score = total // count
# 需要额外加1分的题目数量
extra_count = total % count
# 生成分数列表
scores = []
for i in range(count):
if i < extra_count:
scores.append(base_score + 1)
else:
scores.append(base_score)
return scores
def distribute_decimal(self, decimal_places: int = 1) -> List[float]:
"""
小数分配模式
将总分分配为小数,最后一题用于补齐差额
Args:
decimal_places: 小数位数默认1位
Returns:
分数列表,如 [16.7, 16.7, 16.7, 16.7, 16.7, 16.5]
"""
count = self.question_count
# 计算每题分数并四舍五入
per_score = self.total_score / count
rounded_score = round(per_score, decimal_places)
# 前 n-1 题使用四舍五入的分数
scores = [rounded_score] * (count - 1)
# 最后一题用总分减去前面的和,确保总分精确
last_score = round(self.total_score - sum(scores), decimal_places)
scores.append(last_score)
return scores
def distribute(self, mode: str = "integer") -> List[float]:
"""
分配分数
Args:
mode: 分配模式
- "integer": 整数分配(推荐)
- "decimal": 小数分配
- "decimal_1": 保留1位小数
- "decimal_2": 保留2位小数
Returns:
分数列表
"""
if mode == "integer":
return [float(s) for s in self.distribute_integer()]
elif mode == "decimal" or mode == "decimal_1":
return self.distribute_decimal(1)
elif mode == "decimal_2":
return self.distribute_decimal(2)
else:
return [float(s) for s in self.distribute_integer()]
def get_score_for_question(self, question_index: int, mode: str = "integer") -> float:
"""
获取指定题目的分数
Args:
question_index: 题目索引从0开始
mode: 分配模式
Returns:
该题目的分数
"""
scores = self.distribute(mode)
if 0 <= question_index < len(scores):
return scores[question_index]
raise IndexError(f"题目索引 {question_index} 超出范围 [0, {self.question_count})")
def validate(self) -> Tuple[bool, str]:
"""
验证分配结果
Returns:
(是否有效, 信息)
"""
scores = self.distribute()
total = sum(scores)
if abs(total - self.total_score) < 0.01:
return True, f"分配有效:{scores},总分={total}"
else:
return False, f"分配无效:{scores},总分={total},期望={self.total_score}"
@staticmethod
def format_score(score: float, decimal_places: int = 1) -> str:
"""
格式化分数显示
Args:
score: 分数
decimal_places: 小数位数
Returns:
格式化的分数字符串
"""
if score == int(score):
return str(int(score))
return f"{score:.{decimal_places}f}"
@staticmethod
def calculate_pass_score(total_score: float, pass_rate: float = 0.6) -> float:
"""
计算及格分数
Args:
total_score: 总分
pass_rate: 及格率默认60%
Returns:
及格分数(整数)
"""
return math.ceil(total_score * pass_rate)
def distribute_scores(total_score: float, question_count: int, mode: str = "integer") -> List[float]:
"""
便捷函数:分配分数
Args:
total_score: 总分
question_count: 题目数量
mode: 分配模式integer/decimal
Returns:
分数列表
"""
distributor = ScoreDistributor(total_score, question_count)
return distributor.distribute(mode)
def get_question_score(
total_score: float,
question_count: int,
question_index: int,
mode: str = "integer"
) -> float:
"""
便捷函数:获取指定题目的分数
Args:
total_score: 总分
question_count: 题目数量
question_index: 题目索引从0开始
mode: 分配模式
Returns:
该题目的分数
"""
distributor = ScoreDistributor(total_score, question_count)
return distributor.get_score_for_question(question_index, mode)
"""
分数分配工具
解决题目分数无法整除的问题,确保:
1. 所有题目分数之和精确等于总分
2. 题目分数差异最小化最多相差1分
3. 支持整数分配和小数分配两种模式
"""
from typing import List, Tuple
from decimal import Decimal, ROUND_HALF_UP
import math
class ScoreDistributor:
"""
智能分数分配器
使用示例:
distributor = ScoreDistributor(total_score=100, question_count=6)
scores = distributor.distribute()
# 结果: [17, 17, 17, 17, 16, 16] 总和=100
"""
def __init__(self, total_score: float, question_count: int):
"""
初始化分配器
Args:
total_score: 总分(如 100
question_count: 题目数量(如 6
"""
if question_count <= 0:
raise ValueError("题目数量必须大于0")
if total_score <= 0:
raise ValueError("总分必须大于0")
self.total_score = total_score
self.question_count = question_count
def distribute_integer(self) -> List[int]:
"""
整数分配模式
将总分分配为整数前面的题目分数可能比后面的多1分
Returns:
分数列表,如 [17, 17, 17, 17, 16, 16]
示例:
100分 / 6题 = [17, 17, 17, 17, 16, 16]
100分 / 7题 = [15, 15, 14, 14, 14, 14, 14]
"""
total = int(self.total_score)
count = self.question_count
# 基础分数(向下取整)
base_score = total // count
# 需要额外加1分的题目数量
extra_count = total % count
# 生成分数列表
scores = []
for i in range(count):
if i < extra_count:
scores.append(base_score + 1)
else:
scores.append(base_score)
return scores
def distribute_decimal(self, decimal_places: int = 1) -> List[float]:
"""
小数分配模式
将总分分配为小数,最后一题用于补齐差额
Args:
decimal_places: 小数位数默认1位
Returns:
分数列表,如 [16.7, 16.7, 16.7, 16.7, 16.7, 16.5]
"""
count = self.question_count
# 计算每题分数并四舍五入
per_score = self.total_score / count
rounded_score = round(per_score, decimal_places)
# 前 n-1 题使用四舍五入的分数
scores = [rounded_score] * (count - 1)
# 最后一题用总分减去前面的和,确保总分精确
last_score = round(self.total_score - sum(scores), decimal_places)
scores.append(last_score)
return scores
def distribute(self, mode: str = "integer") -> List[float]:
"""
分配分数
Args:
mode: 分配模式
- "integer": 整数分配(推荐)
- "decimal": 小数分配
- "decimal_1": 保留1位小数
- "decimal_2": 保留2位小数
Returns:
分数列表
"""
if mode == "integer":
return [float(s) for s in self.distribute_integer()]
elif mode == "decimal" or mode == "decimal_1":
return self.distribute_decimal(1)
elif mode == "decimal_2":
return self.distribute_decimal(2)
else:
return [float(s) for s in self.distribute_integer()]
def get_score_for_question(self, question_index: int, mode: str = "integer") -> float:
"""
获取指定题目的分数
Args:
question_index: 题目索引从0开始
mode: 分配模式
Returns:
该题目的分数
"""
scores = self.distribute(mode)
if 0 <= question_index < len(scores):
return scores[question_index]
raise IndexError(f"题目索引 {question_index} 超出范围 [0, {self.question_count})")
def validate(self) -> Tuple[bool, str]:
"""
验证分配结果
Returns:
(是否有效, 信息)
"""
scores = self.distribute()
total = sum(scores)
if abs(total - self.total_score) < 0.01:
return True, f"分配有效:{scores},总分={total}"
else:
return False, f"分配无效:{scores},总分={total},期望={self.total_score}"
@staticmethod
def format_score(score: float, decimal_places: int = 1) -> str:
"""
格式化分数显示
Args:
score: 分数
decimal_places: 小数位数
Returns:
格式化的分数字符串
"""
if score == int(score):
return str(int(score))
return f"{score:.{decimal_places}f}"
@staticmethod
def calculate_pass_score(total_score: float, pass_rate: float = 0.6) -> float:
"""
计算及格分数
Args:
total_score: 总分
pass_rate: 及格率默认60%
Returns:
及格分数(整数)
"""
return math.ceil(total_score * pass_rate)
def distribute_scores(total_score: float, question_count: int, mode: str = "integer") -> List[float]:
"""
便捷函数:分配分数
Args:
total_score: 总分
question_count: 题目数量
mode: 分配模式integer/decimal
Returns:
分数列表
"""
distributor = ScoreDistributor(total_score, question_count)
return distributor.distribute(mode)
def get_question_score(
total_score: float,
question_count: int,
question_index: int,
mode: str = "integer"
) -> float:
"""
便捷函数:获取指定题目的分数
Args:
total_score: 总分
question_count: 题目数量
question_index: 题目索引从0开始
mode: 分配模式
Returns:
该题目的分数
"""
distributor = ScoreDistributor(total_score, question_count)
return distributor.get_score_for_question(question_index, mode)