feat: weighted criteria in AI ranking, z-score normalization, threshold advancement, CSV export
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m16s

- Add criteriaWeights to EvaluationConfig for per-criterion weight assignment (0-10)
- Rewrite ai-ranking service: fetch eval form criteria, compute per-criterion averages,
  z-score normalize juror scores to correct grading bias, send weighted criteria to AI
- Update AI prompts with criteria_definitions and per-project criteria_scores
- compositeScore uses weighted criteria when configured, falls back to globalScore
- Add collapsible ranking config section to dashboard (criteria text + weight sliders)
- Move rankingCriteria textarea from eval config tab to ranking dashboard
- Store criteriaWeights in ranking snapshot parsedRulesJson for audit
- Enhance projectScores CSV export with per-criterion averages, category, country
- Add Export CSV button to ranking dashboard header
- Add threshold-based advancement mode (decimal score threshold, e.g. 6.5)
  alongside existing top-N mode in advance dialog

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-02 11:24:14 +01:00
parent c6ebd169dd
commit 19b58e4434
6 changed files with 674 additions and 107 deletions

View File

@@ -4,7 +4,6 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Switch } from '@/components/ui/switch'
import { Textarea } from '@/components/ui/textarea'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
type EvaluationConfigProps = {
@@ -225,7 +224,7 @@ export function EvaluationConfig({ config, onChange }: EvaluationConfigProps) {
<div className="flex items-center justify-between">
<div>
<Label htmlFor="autoRankEnabled">AI Ranking</Label>
<p className="text-xs text-muted-foreground">Rank projects using AI when all evaluations are complete</p>
<p className="text-xs text-muted-foreground">Rank projects using AI when all evaluations are complete. Configure ranking criteria and weights in the Ranking tab.</p>
</div>
<Switch
id="autoRankEnabled"
@@ -233,21 +232,6 @@ export function EvaluationConfig({ config, onChange }: EvaluationConfigProps) {
onCheckedChange={(v) => update('autoRankEnabled', v)}
/>
</div>
<div className="space-y-2">
<Label htmlFor="rankingCriteria">Ranking Criteria</Label>
<p className="text-xs text-muted-foreground">
Natural-language criteria the AI uses to rank projects. E.g. &quot;Prioritize innovation and ocean impact. Weight jury scores 60%, feasibility 40%.&quot;
</p>
<Textarea
id="rankingCriteria"
rows={4}
placeholder="Describe how projects should be ranked..."
value={(config.rankingCriteria as string) ?? ''}
onChange={(e) => update('rankingCriteria', e.target.value)}
className="resize-y"
/>
</div>
</div>
</CardContent>
</Card>