diff --git a/backend/ai_services/admin.py b/backend/ai_services/admin.py index 3da40ef..421a97b 100644 --- a/backend/ai_services/admin.py +++ b/backend/ai_services/admin.py @@ -22,8 +22,8 @@ class TranscriptionTaskAdmin(UnfoldModelAdmin): @admin.register(AIEvaluationTemplate) class AIEvaluationTemplateAdmin(UnfoldModelAdmin): - list_display = ['name', 'model_selection', 'score_dimension', 'is_active', 'created_at'] - list_filter = ['is_active', 'model_selection', 'created_at'] + list_display = ['name', 'model_selection', 'score_dimension', 'is_default', 'is_active', 'created_at'] + list_filter = ['is_active', 'is_default', 'model_selection', 'created_at'] search_fields = ['name', 'prompt'] @admin.register(AIEvaluation) diff --git a/backend/ai_services/migrations/0008_add_is_default_to_template.py b/backend/ai_services/migrations/0008_add_is_default_to_template.py new file mode 100644 index 0000000..9c0a799 --- /dev/null +++ b/backend/ai_services/migrations/0008_add_is_default_to_template.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0.1 on 2026-03-17 15:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ai_services', '0007_aievaluationtemplate_score_dimension'), + ] + + operations = [ + migrations.AddField( + model_name='aievaluationtemplate', + name='is_default', + field=models.BooleanField(default=False, help_text='默认模板会评价所有比赛,非默认模板且未关联评分维度时不会自动评价', verbose_name='是否为默认模板'), + ), + ] diff --git a/backend/ai_services/models.py b/backend/ai_services/models.py index 442d913..2e174f4 100644 --- a/backend/ai_services/models.py +++ b/backend/ai_services/models.py @@ -73,6 +73,11 @@ class AIEvaluationTemplate(models.Model): verbose_name=_('关联评分维度'), help_text=_('如果同步到比赛评分,优先使用此维度。未填写则默认使用"AI Rating"或包含"AI"的维度') ) + is_default = models.BooleanField( + verbose_name=_('是否为默认模板'), + default=False, + help_text=_('默认模板会评价所有比赛,非默认模板且未关联评分维度时不会自动评价') + ) is_active = models.BooleanField(verbose_name=_('是否启用'), default=True, help_text=_('启用后,新的转写任务完成后将自动使用此模板进行评估')) created_at = models.DateTimeField(verbose_name=_('创建时间'), auto_now_add=True) diff --git a/backend/ai_services/services.py b/backend/ai_services/services.py index 367360b..cd64249 100644 --- a/backend/ai_services/services.py +++ b/backend/ai_services/services.py @@ -331,17 +331,23 @@ class AliyunTingwuService: def trigger_ai_evaluations(self, task_id): """ 根据启用的模板自动触发 AI 评估 + + 逻辑: + 1. 如果模板关联了评分维度(s score_dimension),只对关联了相同维度的比赛进行评估 + 2. 如果模板未关联评分维度: + - 如果是默认模板(is_default=True),评价所有比赛 + - 否则不进行自动评价 """ try: # 在线程中重新获取 task 对象,并预加载 project,避免懒加载导致的线程数据库连接问题 from .models import TranscriptionTask - task = TranscriptionTask.objects.select_related('project').get(id=task_id) + task = TranscriptionTask.objects.select_related('project', 'project__competition').get(id=task_id) except Exception as e: # 兼容处理:如果 task_id 其实是 task 对象(虽然我们上面改了,但防止其他地方调用传错) if hasattr(task_id, 'id'): try: from .models import TranscriptionTask - task = TranscriptionTask.objects.select_related('project').get(id=task_id.id) + task = TranscriptionTask.objects.select_related('project', 'project__competition').get(id=task_id.id) except: task = task_id else: @@ -361,6 +367,41 @@ class AliyunTingwuService: if AIEvaluation.objects.filter(task=task, template=template).exists(): logger.info(f"Evaluation for task {task.id} and template {template.name} already exists.") continue + + # 获取任务关联的比赛 + task_competition = None + if task.project and task.project.competition: + task_competition = task.project.competition + + # 判断是否应该对此任务进行评估 + should_evaluate = False + + if template.score_dimension: + # 模板关联了评分维度,只对关联了相同维度的比赛进行评估 + if task_competition: + # 获取该比赛下所有关联了相同评分维度的比赛ID列表 + from competition.models import ScoreDimension + related_competition_ids = ScoreDimension.objects.filter( + id=template.score_dimension.id + ).values_list('competition_id', flat=True) + + if task_competition.id in related_competition_ids: + should_evaluate = True + logger.info(f"Template '{template.name}' is linked to score_dimension, task's competition matches.") + else: + logger.info(f"Template '{template.name}' is linked to score_dimension, but task's competition does not match. Skipping.") + else: + logger.info(f"Task {task.id} has no associated competition. Skipping template '{template.name}'.") + else: + # 模板未关联评分维度,只有默认模板才评价所有比赛 + if template.is_default: + should_evaluate = True + logger.info(f"Template '{template.name}' is default template, evaluating all competitions.") + else: + logger.info(f"Template '{template.name}' is not linked to score_dimension and is not default. Skipping.") + + if not should_evaluate: + continue # 创建评估记录 evaluation = AIEvaluation.objects.create(