feat: photo quality improvements
- webcam capture resolution/quality configurable in admin settings (defaults 640x480 / 0.92) - enhance photo modal in journal: original vs preview with sliders (brightness, contrast, saturation, sharpen) and auto-levels button - new endpoint PUT /api/entries/:id/photo/enhance replaces photo, cleans old file and thumb - sharper HEIC conversion (0.92) and webp thumbnails (85) - worker: fail explicitly on empty AI response
This commit is contained in:
+13
-3
@@ -1,4 +1,4 @@
|
||||
const DIRTY_FIELDS = ['spamInterval', 'footerLeft', 'footerRight', 'aiPrompt', 'aiAutoCheck', 'shareShowMessage', 'shareShowDate', 'shareShowNames', 'shareShowPhotos', 'cookieNoticeText'];
|
||||
const DIRTY_FIELDS = ['spamInterval', 'footerLeft', 'footerRight', 'aiPrompt', 'aiAutoCheck', 'shareShowMessage', 'shareShowDate', 'shareShowNames', 'shareShowPhotos', 'cookieNoticeText', 'photoResolution', 'photoQuality'];
|
||||
const SECTION_IDS = ['sec-system', 'sec-antispam', 'sec-share', 'sec-form', 'sec-ai', 'sec-backup', 'sec-bans'];
|
||||
const SPAM_MAX = 10080;
|
||||
const BAN_REASONS = {
|
||||
@@ -81,7 +81,9 @@ function updateDirty() {
|
||||
|
||||
function bindDirty() {
|
||||
DIRTY_FIELDS.forEach(id => {
|
||||
document.getElementById(id).addEventListener('input', updateDirty);
|
||||
const el = document.getElementById(id);
|
||||
el.addEventListener('input', updateDirty);
|
||||
el.addEventListener('change', updateDirty);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -151,6 +153,10 @@ async function loadSettings() {
|
||||
document.getElementById('shareShowNames').checked = s.share_show_student_names !== 'false';
|
||||
document.getElementById('shareShowPhotos').checked = s.share_show_group_photos !== 'false';
|
||||
document.getElementById('cookieNoticeText').value = s.cookie_notice_text || '';
|
||||
const pr = document.getElementById('photoResolution');
|
||||
if (s.photo_capture_resolution) pr.value = s.photo_capture_resolution;
|
||||
if (!pr.value) pr.value = '640x480';
|
||||
document.getElementById('photoQuality').value = s.photo_capture_quality !== undefined && s.photo_capture_quality !== '' ? s.photo_capture_quality : '0.92';
|
||||
snapshotDirty();
|
||||
updateSpamUi();
|
||||
loadAiQueue();
|
||||
@@ -274,7 +280,7 @@ async function loadAiProfiles() {
|
||||
<div class="ai-profile-item${data.active === p.id ? ' active' : ''}">
|
||||
<div class="pi-info">
|
||||
<div class="pi-name">${esc(p.name)}${data.active === p.id ? ' <span class="pi-badge">по умолчанию</span>' : ''}</div>
|
||||
<div class="pi-meta">${esc(p.model)} · ${esc(p.base_url)}</div>
|
||||
<div class="pi-meta">${esc(p.model)} · ${esc(p.base_url)}${p.max_tokens ? ` · max_tokens: ${esc(p.max_tokens)}` : ''}</div>
|
||||
</div>
|
||||
<div class="pi-actions">
|
||||
${p.native ? '' : `<button type="button" class="pi-btn" data-edit-profile="${esc(p.id)}">Изменить</button>`}
|
||||
@@ -295,6 +301,7 @@ function openAiProfileForm(profile) {
|
||||
document.getElementById('aiProfileModel').value = profile ? profile.model : '';
|
||||
document.getElementById('aiProfileBaseUrl').value = profile ? profile.base_url : '';
|
||||
document.getElementById('aiProfileApiKey').value = '';
|
||||
document.getElementById('aiProfileMaxTokens').value = profile && profile.max_tokens ? profile.max_tokens : '';
|
||||
document.getElementById('aiProfileTestStatus').textContent = '';
|
||||
document.getElementById('aiProfileName').focus();
|
||||
}
|
||||
@@ -310,6 +317,7 @@ function aiProfileFormData() {
|
||||
model: document.getElementById('aiProfileModel').value,
|
||||
base_url: document.getElementById('aiProfileBaseUrl').value,
|
||||
api_key: document.getElementById('aiProfileApiKey').value,
|
||||
max_tokens: document.getElementById('aiProfileMaxTokens').value.trim() === '' ? null : document.getElementById('aiProfileMaxTokens').value,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -486,6 +494,8 @@ async function saveSettings() {
|
||||
share_show_student_names: document.getElementById('shareShowNames').checked ? 'true' : 'false',
|
||||
share_show_group_photos: document.getElementById('shareShowPhotos').checked ? 'true' : 'false',
|
||||
cookie_notice_text: document.getElementById('cookieNoticeText').value.trim(),
|
||||
photo_capture_resolution: document.getElementById('photoResolution').value,
|
||||
photo_capture_quality: String(document.getElementById('photoQuality').value),
|
||||
} })
|
||||
});
|
||||
if (res.ok) {
|
||||
|
||||
Reference in New Issue
Block a user