Skip to content

Commit b1045e4

Browse files
authored
Add evaluation backend foundation (#17)
Co-authored-by: fengting124 <fengting124@users.noreply.github.com>
1 parent f1bd9f7 commit b1045e4

21 files changed

Lines changed: 1272 additions & 0 deletions
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.fengting.aigcforensics.evaluation.controller;
2+
3+
import java.util.List;
4+
5+
import org.springframework.http.HttpStatus;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.PathVariable;
8+
import org.springframework.web.bind.annotation.PostMapping;
9+
import org.springframework.web.bind.annotation.RequestBody;
10+
import org.springframework.web.bind.annotation.RequestMapping;
11+
import org.springframework.web.bind.annotation.RequestParam;
12+
import org.springframework.web.bind.annotation.ResponseStatus;
13+
import org.springframework.web.bind.annotation.RestController;
14+
15+
import com.fengting.aigcforensics.evaluation.dto.CreateEvaluationRequest;
16+
import com.fengting.aigcforensics.evaluation.dto.EvaluationDetailResponse;
17+
import com.fengting.aigcforensics.evaluation.dto.EvaluationRunResponse;
18+
import com.fengting.aigcforensics.evaluation.dto.EvaluationSampleResponse;
19+
import com.fengting.aigcforensics.evaluation.service.EvaluationService;
20+
21+
import jakarta.validation.Valid;
22+
23+
@RestController
24+
@RequestMapping("/api/evaluations")
25+
public class EvaluationController {
26+
27+
private final EvaluationService evaluationService;
28+
29+
public EvaluationController(EvaluationService evaluationService) {
30+
this.evaluationService = evaluationService;
31+
}
32+
33+
@PostMapping
34+
@ResponseStatus(HttpStatus.CREATED)
35+
public EvaluationRunResponse createEvaluation(@Valid @RequestBody CreateEvaluationRequest request) {
36+
return evaluationService.createEvaluation(request);
37+
}
38+
39+
@GetMapping
40+
public List<EvaluationRunResponse> listEvaluations() {
41+
return evaluationService.listEvaluations();
42+
}
43+
44+
@GetMapping("/{evaluationId}")
45+
public EvaluationDetailResponse getEvaluation(@PathVariable String evaluationId) {
46+
return evaluationService.getEvaluation(evaluationId);
47+
}
48+
49+
@GetMapping("/{evaluationId}/samples")
50+
public List<EvaluationSampleResponse> listSamples(
51+
@PathVariable String evaluationId,
52+
@RequestParam(required = false) Boolean correct) {
53+
return evaluationService.listSamples(evaluationId, correct);
54+
}
55+
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package com.fengting.aigcforensics.evaluation.domain;
2+
3+
import java.time.Instant;
4+
5+
import jakarta.persistence.Column;
6+
import jakarta.persistence.Entity;
7+
import jakarta.persistence.EnumType;
8+
import jakarta.persistence.Enumerated;
9+
import jakarta.persistence.GeneratedValue;
10+
import jakarta.persistence.GenerationType;
11+
import jakarta.persistence.Id;
12+
import jakarta.persistence.Table;
13+
14+
@Entity
15+
@Table(name = "evaluation_run")
16+
public class EvaluationRun {
17+
18+
@Id
19+
@GeneratedValue(strategy = GenerationType.IDENTITY)
20+
private Long id;
21+
22+
@Column(name = "evaluation_id", nullable = false, unique = true, length = 64)
23+
private String evaluationId;
24+
25+
@Column(name = "name", nullable = false)
26+
private String name;
27+
28+
@Column(name = "dataset_name", nullable = false)
29+
private String datasetName;
30+
31+
@Column(name = "model_id", nullable = false, length = 64)
32+
private String modelId;
33+
34+
@Enumerated(EnumType.STRING)
35+
@Column(name = "status", nullable = false, length = 32)
36+
private EvaluationStatus status;
37+
38+
@Column(name = "total_samples", nullable = false)
39+
private int totalSamples;
40+
41+
@Column(name = "completed_samples", nullable = false)
42+
private int completedSamples;
43+
44+
@Column(name = "accuracy")
45+
private Double accuracy;
46+
47+
@Column(name = "precision_score")
48+
private Double precision;
49+
50+
@Column(name = "recall_score")
51+
private Double recall;
52+
53+
@Column(name = "f1_score")
54+
private Double f1;
55+
56+
@Column(name = "created_at", nullable = false)
57+
private Instant createdAt;
58+
59+
@Column(name = "started_at")
60+
private Instant startedAt;
61+
62+
@Column(name = "completed_at")
63+
private Instant completedAt;
64+
65+
@Column(name = "failure_reason", length = 2048)
66+
private String failureReason;
67+
68+
protected EvaluationRun() {
69+
}
70+
71+
public EvaluationRun(
72+
String evaluationId,
73+
String name,
74+
String datasetName,
75+
String modelId,
76+
EvaluationStatus status,
77+
int totalSamples,
78+
int completedSamples,
79+
Double accuracy,
80+
Double precision,
81+
Double recall,
82+
Double f1,
83+
Instant createdAt,
84+
Instant startedAt,
85+
Instant completedAt,
86+
String failureReason) {
87+
this.evaluationId = evaluationId;
88+
this.name = name;
89+
this.datasetName = datasetName;
90+
this.modelId = modelId;
91+
this.status = status;
92+
this.totalSamples = totalSamples;
93+
this.completedSamples = completedSamples;
94+
this.accuracy = accuracy;
95+
this.precision = precision;
96+
this.recall = recall;
97+
this.f1 = f1;
98+
this.createdAt = createdAt;
99+
this.startedAt = startedAt;
100+
this.completedAt = completedAt;
101+
this.failureReason = failureReason;
102+
}
103+
104+
public Long getId() {
105+
return id;
106+
}
107+
108+
public String getEvaluationId() {
109+
return evaluationId;
110+
}
111+
112+
public String getName() {
113+
return name;
114+
}
115+
116+
public String getDatasetName() {
117+
return datasetName;
118+
}
119+
120+
public String getModelId() {
121+
return modelId;
122+
}
123+
124+
public EvaluationStatus getStatus() {
125+
return status;
126+
}
127+
128+
public int getTotalSamples() {
129+
return totalSamples;
130+
}
131+
132+
public int getCompletedSamples() {
133+
return completedSamples;
134+
}
135+
136+
public Double getAccuracy() {
137+
return accuracy;
138+
}
139+
140+
public Double getPrecision() {
141+
return precision;
142+
}
143+
144+
public Double getRecall() {
145+
return recall;
146+
}
147+
148+
public Double getF1() {
149+
return f1;
150+
}
151+
152+
public Instant getCreatedAt() {
153+
return createdAt;
154+
}
155+
156+
public Instant getStartedAt() {
157+
return startedAt;
158+
}
159+
160+
public Instant getCompletedAt() {
161+
return completedAt;
162+
}
163+
164+
public String getFailureReason() {
165+
return failureReason;
166+
}
167+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package com.fengting.aigcforensics.evaluation.domain;
2+
3+
import java.time.Instant;
4+
5+
import com.fengting.aigcforensics.domain.ModelLabel;
6+
7+
import jakarta.persistence.Column;
8+
import jakarta.persistence.Entity;
9+
import jakarta.persistence.EnumType;
10+
import jakarta.persistence.Enumerated;
11+
import jakarta.persistence.GeneratedValue;
12+
import jakarta.persistence.GenerationType;
13+
import jakarta.persistence.Id;
14+
import jakarta.persistence.Table;
15+
16+
@Entity
17+
@Table(name = "evaluation_sample")
18+
public class EvaluationSample {
19+
20+
@Id
21+
@GeneratedValue(strategy = GenerationType.IDENTITY)
22+
private Long id;
23+
24+
@Column(name = "sample_id", nullable = false, unique = true, length = 64)
25+
private String sampleId;
26+
27+
@Column(name = "evaluation_id", nullable = false, length = 64)
28+
private String evaluationId;
29+
30+
@Column(name = "filename", nullable = false)
31+
private String filename;
32+
33+
@Enumerated(EnumType.STRING)
34+
@Column(name = "ground_truth_label", nullable = false, length = 32)
35+
private ModelLabel groundTruthLabel;
36+
37+
@Enumerated(EnumType.STRING)
38+
@Column(name = "predicted_label", length = 32)
39+
private ModelLabel predictedLabel;
40+
41+
@Column(name = "score")
42+
private Double score;
43+
44+
@Column(name = "latency_ms")
45+
private Integer latencyMs;
46+
47+
@Column(name = "correct")
48+
private Boolean correct;
49+
50+
@Column(name = "failure_reason", length = 2048)
51+
private String failureReason;
52+
53+
@Column(name = "created_at", nullable = false)
54+
private Instant createdAt;
55+
56+
protected EvaluationSample() {
57+
}
58+
59+
public EvaluationSample(
60+
String sampleId,
61+
String evaluationId,
62+
String filename,
63+
ModelLabel groundTruthLabel,
64+
ModelLabel predictedLabel,
65+
Double score,
66+
Integer latencyMs,
67+
Boolean correct,
68+
String failureReason,
69+
Instant createdAt) {
70+
this.sampleId = sampleId;
71+
this.evaluationId = evaluationId;
72+
this.filename = filename;
73+
this.groundTruthLabel = groundTruthLabel;
74+
this.predictedLabel = predictedLabel;
75+
this.score = score;
76+
this.latencyMs = latencyMs;
77+
this.correct = correct;
78+
this.failureReason = failureReason;
79+
this.createdAt = createdAt;
80+
}
81+
82+
public Long getId() {
83+
return id;
84+
}
85+
86+
public String getSampleId() {
87+
return sampleId;
88+
}
89+
90+
public String getEvaluationId() {
91+
return evaluationId;
92+
}
93+
94+
public String getFilename() {
95+
return filename;
96+
}
97+
98+
public ModelLabel getGroundTruthLabel() {
99+
return groundTruthLabel;
100+
}
101+
102+
public ModelLabel getPredictedLabel() {
103+
return predictedLabel;
104+
}
105+
106+
public Double getScore() {
107+
return score;
108+
}
109+
110+
public Integer getLatencyMs() {
111+
return latencyMs;
112+
}
113+
114+
public Boolean getCorrect() {
115+
return correct;
116+
}
117+
118+
public String getFailureReason() {
119+
return failureReason;
120+
}
121+
122+
public Instant getCreatedAt() {
123+
return createdAt;
124+
}
125+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.fengting.aigcforensics.evaluation.domain;
2+
3+
public enum EvaluationStatus {
4+
QUEUED,
5+
RUNNING,
6+
COMPLETED,
7+
FAILED
8+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.fengting.aigcforensics.evaluation.dto;
2+
3+
import jakarta.validation.constraints.NotBlank;
4+
5+
public record CreateEvaluationRequest(
6+
@NotBlank String name,
7+
@NotBlank String datasetName,
8+
@NotBlank String modelId,
9+
@NotBlank String manifest) {
10+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.fengting.aigcforensics.evaluation.dto;
2+
3+
import java.time.Instant;
4+
import java.util.List;
5+
6+
import com.fengting.aigcforensics.evaluation.domain.EvaluationStatus;
7+
8+
public record EvaluationDetailResponse(
9+
String evaluationId,
10+
String name,
11+
String datasetName,
12+
String modelId,
13+
EvaluationStatus status,
14+
int totalSamples,
15+
int completedSamples,
16+
Double accuracy,
17+
Double precision,
18+
Double recall,
19+
Double f1,
20+
Instant createdAt,
21+
Instant startedAt,
22+
Instant completedAt,
23+
String failureReason,
24+
List<EvaluationSampleResponse> samples) {
25+
}

0 commit comments

Comments
 (0)