Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 42 additions & 2 deletions dashboard/app/ai.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ type uiAIJobsPage struct {
}

type uiAIJobPage struct {
Header *uiHeader
Header *uiHeader
Job *uiAIJob
// The slice contains the same single Job, just for HTML templates convenience.
Jobs []*uiAIJob
Results []*uiAIResult
Trajectory []*uiAITrajectorySpan
Expand All @@ -49,6 +51,7 @@ type uiAIJob struct {
CodeRevision string
CodeRevisionLink string
Error string
Correct string
}

type uiAIResult struct {
Expand Down Expand Up @@ -103,6 +106,22 @@ func handleAIJobPage(ctx context.Context, w http.ResponseWriter, r *http.Request
if err != nil {
return err
}
if correct := r.FormValue("correct"); correct != "" {
if !job.Finished.Valid || job.Error != "" {
return fmt.Errorf("job is in wrong state to set correct status")
}
switch correct {
case aiCorrectnessCorrect:
job.Correct = spanner.NullBool{Bool: true, Valid: true}
case aiCorrectnessIncorrect:
job.Correct = spanner.NullBool{Bool: false, Valid: true}
default:
job.Correct = spanner.NullBool{}
}
if err := aidb.UpdateJob(ctx, job); err != nil {
return err
}
}
trajectory, err := aidb.LoadTrajectory(ctx, job.ID)
if err != nil {
return err
Expand All @@ -111,9 +130,11 @@ func handleAIJobPage(ctx context.Context, w http.ResponseWriter, r *http.Request
if err != nil {
return err
}
uiJob := makeUIAIJob(job)
page := &uiAIJobPage{
Header: hdr,
Jobs: []*uiAIJob{makeUIAIJob(job)},
Job: uiJob,
Jobs: []*uiAIJob{uiJob},
Trajectory: makeUIAITrajectory(trajectory),
}
if m, ok := job.Results.Value.(map[string]any); ok && job.Results.Valid {
Expand All @@ -131,6 +152,16 @@ func handleAIJobPage(ctx context.Context, w http.ResponseWriter, r *http.Request
}

func makeUIAIJob(job *aidb.Job) *uiAIJob {
correct := aiCorrectnessIncorrect
if !job.Finished.Valid {
correct = aiCorrectnessPending
} else if job.Error != "" {
correct = aiCorrectnessErrored
} else if !job.Correct.Valid {
correct = aiCorrectnessUnset
} else if job.Correct.Bool {
correct = aiCorrectnessCorrect
}
return &uiAIJob{
ID: job.ID,
Link: fmt.Sprintf("/ai_job?id=%v", job.ID),
Expand All @@ -144,6 +175,7 @@ func makeUIAIJob(job *aidb.Job) *uiAIJob {
CodeRevision: job.CodeRevision,
CodeRevisionLink: vcs.LogLink(vcs.SyzkallerRepo, job.CodeRevision),
Error: job.Error,
Correct: correct,
}
}

Expand Down Expand Up @@ -447,6 +479,14 @@ func workflowsForBug(bug *Bug, manual bool) map[ai.WorkflowType]bool {
return workflows
}

const (
aiCorrectnessCorrect = "✅"
aiCorrectnessIncorrect = "❌"
aiCorrectnessUnset = "❓"
aiCorrectnessPending = "⏳"
aiCorrectnessErrored = "💥"
)

func nullTime(v spanner.NullTime) time.Time {
if !v.Valid {
return time.Time{}
Expand Down
15 changes: 15 additions & 0 deletions dashboard/app/templates/ai_job.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@
{{template "header" .Header}}
{{template "ai_job_list" .Jobs}}

{{if and (ne .Job.Correct "⏳") (ne .Job.Correct "💥")}}
<form method="POST">
<fieldset>
<legend>Result correct:</legend>
<input type="radio" name="correct" id="✅" value="✅" {{if eq .Job.Correct "✅"}}checked{{end}}>
<label for="✅">✅</label>
<input type="radio" name="correct" id="❌" value="❌" {{if eq .Job.Correct "❌"}}checked{{end}}>
<label for="❌">❌</label>
<input type="radio" name="correct" id="❓" value="❓" {{if eq .Job.Correct "❓"}}checked{{end}}>
<label for="❓">❓</label>
<button type="submit">Set</button>
</fieldset>
</form>
{{end}}

{{range $res := .Results}}
<br><b>{{$res.Name}}:</b><br>
<div id="ai_result_div"><pre>{{$res.Value}}</pre></div><br>
Expand Down
2 changes: 2 additions & 0 deletions dashboard/app/templates/templates.html
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,7 @@ <h1>{{.Caption}}:</h1>
<thead><tr>
<th><a onclick="return sortTable(this, 'ID', textSort)" href="#">ID</a></th>
<th><a onclick="return sortTable(this, 'Workflow', textSort)" href="#">Workflow</a></th>
<th><a onclick="return sortTable(this, 'Correct', textSort)" href="#">Correct</a></th>
<th><a onclick="return sortTable(this, 'Description', textSort)" href="#">Description</a></th>
<th><a onclick="return sortTable(this, 'Created', textSort)" href="#">Created</a></th>
<th><a onclick="return sortTable(this, 'Started', textSort)" href="#">Started</a></th>
Expand All @@ -706,6 +707,7 @@ <h1>{{.Caption}}:</h1>
<tr>
<td>{{link $job.Link $job.ID}}</td>
<td>{{$job.Workflow}}</td>
<td>{{$job.Correct}}</td>
<td>{{link $job.DescriptionLink $job.Description}}</td>
<td>{{formatTime $job.Created}}</td>
<td>{{formatTime $job.Started}}</td>
Expand Down
Loading