Fixes
This commit is contained in:
+4
-3
@@ -3,6 +3,7 @@ use strict;
|
|||||||
use Dancer2;
|
use Dancer2;
|
||||||
use Dancer2::Plugin::Database;
|
use Dancer2::Plugin::Database;
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
use JSON ();
|
||||||
use SQL::SplitStatement;
|
use SQL::SplitStatement;
|
||||||
use HTTP::Lite;
|
use HTTP::Lite;
|
||||||
|
|
||||||
@@ -164,8 +165,8 @@ post '/api/v1/task/:task/complete' => sub {
|
|||||||
# Accept both JSON body and form-encoded data for assign_key/results.
|
# Accept both JSON body and form-encoded data for assign_key/results.
|
||||||
my ($assign_key, $results);
|
my ($assign_key, $results);
|
||||||
my $ct = request_header('Content-Type') || '';
|
my $ct = request_header('Content-Type') || '';
|
||||||
if ($ct eq 'application/json') {
|
if ($ct =~ m{application/json}i) {
|
||||||
my $body = decode_json(request->body());
|
my $body = JSON::decode_json(request->body());
|
||||||
$assign_key = $body->{assign_key};
|
$assign_key = $body->{assign_key};
|
||||||
$results = $body->{results};
|
$results = $body->{results};
|
||||||
} else {
|
} else {
|
||||||
@@ -195,7 +196,7 @@ post '/api/v1/task/:task/complete' => sub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Update the task as completed (store results as JSON text for MariaDB)
|
# Update the task as completed (store results as JSON text for MariaDB)
|
||||||
my $results_json = defined $results ? encode_json($results) : 'null';
|
my $results_json = defined $results ? JSON::encode_json($results) : 'null';
|
||||||
my $update_sth = database->prepare("UPDATE tasks SET status='COMPLETED', results=?, updated_at=NOW() WHERE id=?");
|
my $update_sth = database->prepare("UPDATE tasks SET status='COMPLETED', results=?, updated_at=NOW() WHERE id=?");
|
||||||
$update_sth->execute($results_json, $task_id);
|
$update_sth->execute($results_json, $task_id);
|
||||||
if($update_sth->rows == 0) {
|
if($update_sth->rows == 0) {
|
||||||
|
|||||||
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
curl http://10.0.1.7:11434/api/generate -d '{
|
||||||
|
"model": "qwen3.6:35b-a3b",
|
||||||
|
"keep_alive": "60m"
|
||||||
|
}'
|
||||||
@@ -310,10 +310,17 @@ def api_submit_review(task_id):
|
|||||||
return jsonify({"error": "verdict is required"}), 400
|
return jsonify({"error": "verdict is required"}), 400
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = api_post(f"task/{task_id}/complete", {
|
api_response = api_post(f"task/{task_id}/complete", {
|
||||||
"results": {"reviewer_verdict": verdict},
|
"results": {
|
||||||
|
"review_verdict": verdict,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return jsonify({
|
||||||
|
"status": "completed",
|
||||||
|
"task_id": task_id,
|
||||||
|
"verdict": verdict,
|
||||||
|
"api_response": api_response,
|
||||||
})
|
})
|
||||||
return jsonify({"status": "completed", "task_id": task_id, "verdict": verdict})
|
|
||||||
except requests.RequestException as exc:
|
except requests.RequestException as exc:
|
||||||
return jsonify({"error": f"API error: {exc}"}), 503
|
return jsonify({"error": f"API error: {exc}"}), 503
|
||||||
|
|
||||||
@@ -445,6 +452,7 @@ _REVIEW_TEMPLATE = """
|
|||||||
.actions{display:flex;gap:12px;margin-top:14px}
|
.actions{display:flex;gap:12px;margin-top:14px}
|
||||||
.action-btn{flex:1;padding:14px;border:2px solid #dee2e6;border-radius:8px;background:#fff;cursor:pointer;font-size:15px;font-weight:600;transition:all .15s;text-align:center}
|
.action-btn{flex:1;padding:14px;border:2px solid #dee2e6;border-radius:8px;background:#fff;cursor:pointer;font-size:15px;font-weight:600;transition:all .15s;text-align:center}
|
||||||
.action-btn:hover{border-color:#007bff;transform:translateY(-1px);box-shadow:0 2px 8px rgba(0,0,0,.1)}
|
.action-btn:hover{border-color:#007bff;transform:translateY(-1px);box-shadow:0 2px 8px rgba(0,0,0,.1)}
|
||||||
|
.action-btn:disabled{opacity:.6;cursor:not-allowed;transform:none}
|
||||||
.action-btn.false-positive:hover{border-color:#dc3545;color:#dc3545;background:#fff5f5}
|
.action-btn.false-positive:hover{border-color:#dc3545;color:#dc3545;background:#fff5f5}
|
||||||
.action-btn.correct:hover{border-color:#28a745;color:#28a745;background:#f0fff4}
|
.action-btn.correct:hover{border-color:#28a745;color:#28a745;background:#f0fff4}
|
||||||
.skip-btn:hover{border-color:#6c757d;color:#6c757d;background:#f8f9fa}
|
.skip-btn:hover{border-color:#6c757d;color:#6c757d;background:#f8f9fa}
|
||||||
@@ -453,6 +461,7 @@ _REVIEW_TEMPLATE = """
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div id="flash"></div>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h1>VideoDetect</h1>
|
<h1>VideoDetect</h1>
|
||||||
<a href="/">« Back to queue</a>
|
<a href="/">« Back to queue</a>
|
||||||
@@ -497,33 +506,58 @@ _REVIEW_TEMPLATE = """
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
async function submitVerdict(verdict) {
|
async function submitVerdict(verdict) {
|
||||||
|
setActionButtonsDisabled(true);
|
||||||
|
showFlash('Submitting verdict...', '#007bff');
|
||||||
|
|
||||||
|
try {
|
||||||
const resp = await fetch(`/api/review/submit/{{ video.id }}`, {
|
const resp = await fetch(`/api/review/submit/{{ video.id }}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({verdict})
|
body: JSON.stringify({verdict})
|
||||||
});
|
});
|
||||||
|
const body = await resp.json().catch(() => ({}));
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
showFlash('Verdict submitted ✓', '#28a745');
|
showFlash('Verdict submitted', '#28a745');
|
||||||
setTimeout(() => location.href = '/', 1000);
|
setTimeout(() => location.href = '/', 1000);
|
||||||
} else {
|
} else {
|
||||||
const err = await resp.json();
|
alert(body.error || 'Submission failed');
|
||||||
alert(err.error || 'Submission failed');
|
setActionButtonsDisabled(false);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
alert(`Submission failed: ${err.message}`);
|
||||||
|
setActionButtonsDisabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function skipTask() {
|
async function skipTask() {
|
||||||
if (!confirm('Skip this task? It will be returned to the PENDING queue.')) return;
|
if (!confirm('Skip this task? It will be returned to the PENDING queue.')) return;
|
||||||
|
setActionButtonsDisabled(true);
|
||||||
|
showFlash('Skipping task...', '#6c757d');
|
||||||
|
|
||||||
|
try {
|
||||||
const resp = await fetch(`/api/review/skip/{{ video.id }}`, {method: 'POST'});
|
const resp = await fetch(`/api/review/skip/{{ video.id }}`, {method: 'POST'});
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
showFlash('Task skipped, returned to queue', '#6c757d');
|
showFlash('Task skipped, returned to queue', '#6c757d');
|
||||||
setTimeout(() => location.href = '/', 1000);
|
setTimeout(() => location.href = '/', 1000);
|
||||||
} else {
|
} else {
|
||||||
alert('Skip failed');
|
alert('Skip failed');
|
||||||
|
setActionButtonsDisabled(false);
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
alert(`Skip failed: ${err.message}`);
|
||||||
|
setActionButtonsDisabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActionButtonsDisabled(disabled) {
|
||||||
|
document.querySelectorAll('.action-btn').forEach((button) => {
|
||||||
|
button.disabled = disabled;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showFlash(msg, color) {
|
function showFlash(msg, color) {
|
||||||
const el = document.getElementById('flash');
|
const el = document.getElementById('flash');
|
||||||
|
if (!el) return;
|
||||||
el.textContent = msg; el.style.background = color; el.style.display = 'block';
|
el.textContent = msg; el.style.background = color; el.style.display = 'block';
|
||||||
setTimeout(() => el.style.display = 'none', 2500);
|
setTimeout(() => el.style.display = 'none', 2500);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user