245 lines
7.5 KiB
JavaScript
245 lines
7.5 KiB
JavaScript
/**
|
||
* Annotations UI
|
||
*
|
||
* UI компонент для работы с аннотациями ответов.
|
||
*/
|
||
|
||
import appState from '../state/appState.js'
|
||
import { getInputValue, setInputValue } from '../utils/dom.utils.js'
|
||
|
||
/**
|
||
* Инициализировать аннотацию для ответа
|
||
* @param {number} index - Индекс ответа
|
||
*/
|
||
export function initForAnswer(index) {
|
||
const env = appState.getCurrentEnv()
|
||
|
||
if (!env.annotations[index]) {
|
||
env.annotations[index] = {
|
||
overall: { rating: '', comment: '' },
|
||
body_research: { issues: [], comment: '' },
|
||
body_analytical_hub: { issues: [], comment: '' },
|
||
docs_from_vectorstore: { research: {}, analytical_hub: {} },
|
||
docs_to_llm: { research: {}, analytical_hub: {} }
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Загрузить аннотации для ответа
|
||
* @param {number} index - Индекс ответа
|
||
*/
|
||
export function loadForAnswer(index) {
|
||
initForAnswer(index)
|
||
|
||
const env = appState.getCurrentEnv()
|
||
const annotation = env.annotations[index]
|
||
|
||
// Load overall rating
|
||
const ratingSelect = document.getElementById('overall-rating')
|
||
const overallComment = document.getElementById('overall-comment')
|
||
|
||
if (ratingSelect) {
|
||
ratingSelect.value = annotation.overall.rating || ''
|
||
}
|
||
|
||
if (overallComment) {
|
||
setInputValue(overallComment, annotation.overall.comment || '')
|
||
}
|
||
|
||
// Load body annotations
|
||
loadSection('body_research', annotation.body_research)
|
||
loadSection('body_analytical_hub', annotation.body_analytical_hub)
|
||
|
||
// Load document annotations
|
||
loadDocuments('docs_from_vectorstore', 'research', annotation.docs_from_vectorstore?.research)
|
||
loadDocuments('docs_from_vectorstore', 'analytical_hub', annotation.docs_from_vectorstore?.analytical_hub)
|
||
loadDocuments('docs_to_llm', 'research', annotation.docs_to_llm?.research)
|
||
loadDocuments('docs_to_llm', 'analytical_hub', annotation.docs_to_llm?.analytical_hub)
|
||
|
||
// Setup event listeners for current answer
|
||
setupListeners()
|
||
}
|
||
|
||
/**
|
||
* Загрузить аннотацию секции (body)
|
||
* @param {string} section - Название секции
|
||
* @param {object} data - Данные аннотации
|
||
*/
|
||
export function loadSection(section, data) {
|
||
// Load checkboxes
|
||
document.querySelectorAll(`input[data-section="${section}"]`).forEach(checkbox => {
|
||
if (checkbox.type === 'checkbox') {
|
||
const issue = checkbox.dataset.issue
|
||
checkbox.checked = data.issues.includes(issue)
|
||
updateCheckboxStyle(checkbox)
|
||
}
|
||
})
|
||
|
||
// Load comment
|
||
const textarea = document.querySelector(`textarea[data-section="${section}"]:not([data-doc-index])`)
|
||
if (textarea) {
|
||
setInputValue(textarea, data.comment || '')
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Загрузить аннотации документов
|
||
* @param {string} section - Секция (docs_from_vectorstore, docs_to_llm)
|
||
* @param {string} subsection - Подсекция (research, analytical_hub)
|
||
* @param {object} docs - Объект с аннотациями документов
|
||
*/
|
||
export function loadDocuments(section, subsection, docs) {
|
||
if (!docs) return
|
||
|
||
Object.keys(docs).forEach(docIndex => {
|
||
const data = docs[docIndex]
|
||
|
||
// Load checkboxes
|
||
document.querySelectorAll(
|
||
`input[data-section="${section}"][data-subsection="${subsection}"][data-doc-index="${docIndex}"]`
|
||
).forEach(checkbox => {
|
||
if (checkbox.type === 'checkbox') {
|
||
const issue = checkbox.dataset.issue
|
||
checkbox.checked = data.issues?.includes(issue) || false
|
||
updateCheckboxStyle(checkbox)
|
||
}
|
||
})
|
||
|
||
// Load comment
|
||
const textarea = document.querySelector(
|
||
`textarea[data-section="${section}"][data-subsection="${subsection}"][data-doc-index="${docIndex}"]`
|
||
)
|
||
if (textarea) {
|
||
setInputValue(textarea, data.comment || '')
|
||
}
|
||
})
|
||
}
|
||
|
||
/**
|
||
* Настроить обработчики событий для аннотаций
|
||
*/
|
||
export function setupListeners() {
|
||
const env = appState.getCurrentEnv()
|
||
const index = env.currentAnswerIndex
|
||
|
||
// Overall rating
|
||
const ratingSelect = document.getElementById('overall-rating')
|
||
const overallComment = document.getElementById('overall-comment')
|
||
|
||
if (ratingSelect) {
|
||
ratingSelect.onchange = (e) => {
|
||
env.annotations[index].overall.rating = e.target.value
|
||
saveDraft()
|
||
}
|
||
}
|
||
|
||
if (overallComment) {
|
||
overallComment.oninput = (e) => {
|
||
env.annotations[index].overall.comment = getInputValue(e.target)
|
||
saveDraft()
|
||
}
|
||
}
|
||
|
||
// Section checkboxes and textareas
|
||
document.querySelectorAll('input.checkbox, textarea').forEach(element => {
|
||
const section = element.dataset.section
|
||
const subsection = element.dataset.subsection
|
||
const docIndex = element.dataset.docIndex
|
||
|
||
if (!section) return
|
||
|
||
if (element.type === 'checkbox') {
|
||
element.onchange = (e) => {
|
||
const issue = e.target.dataset.issue
|
||
|
||
if (docIndex !== undefined) {
|
||
// Document annotation
|
||
if (!env.annotations[index][section]) {
|
||
env.annotations[index][section] = { research: {}, analytical_hub: {} }
|
||
}
|
||
if (!env.annotations[index][section][subsection]) {
|
||
env.annotations[index][section][subsection] = {}
|
||
}
|
||
if (!env.annotations[index][section][subsection][docIndex]) {
|
||
env.annotations[index][section][subsection][docIndex] = { issues: [], comment: '' }
|
||
}
|
||
|
||
const issues = env.annotations[index][section][subsection][docIndex].issues
|
||
|
||
if (e.target.checked) {
|
||
if (!issues.includes(issue)) issues.push(issue)
|
||
} else {
|
||
const idx = issues.indexOf(issue)
|
||
if (idx > -1) issues.splice(idx, 1)
|
||
}
|
||
} else {
|
||
// Body annotation
|
||
const issues = env.annotations[index][section].issues
|
||
|
||
if (e.target.checked) {
|
||
if (!issues.includes(issue)) issues.push(issue)
|
||
} else {
|
||
const idx = issues.indexOf(issue)
|
||
if (idx > -1) issues.splice(idx, 1)
|
||
}
|
||
}
|
||
|
||
updateCheckboxStyle(e.target)
|
||
saveDraft()
|
||
}
|
||
} else if (element.tagName === 'TEXTAREA') {
|
||
element.oninput = (e) => {
|
||
const value = getInputValue(e.target)
|
||
|
||
if (docIndex !== undefined) {
|
||
// Document annotation
|
||
if (!env.annotations[index][section][subsection][docIndex]) {
|
||
env.annotations[index][section][subsection][docIndex] = { issues: [], comment: '' }
|
||
}
|
||
env.annotations[index][section][subsection][docIndex].comment = value
|
||
} else if (section !== 'overall') {
|
||
// Body annotation
|
||
env.annotations[index][section].comment = value
|
||
}
|
||
|
||
saveDraft()
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
/**
|
||
* Обновить стиль чекбокса (добавить checked класс к label)
|
||
* @param {HTMLElement} checkbox - Чекбокс элемент
|
||
*/
|
||
export function updateCheckboxStyle(checkbox) {
|
||
const label = checkbox.closest('.issue-checkbox')
|
||
if (label) {
|
||
if (checkbox.checked) {
|
||
label.classList.add('checked')
|
||
} else {
|
||
label.classList.remove('checked')
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Сохранить черновик аннотаций в localStorage
|
||
*/
|
||
export function saveDraft() {
|
||
const currentEnv = appState.getCurrentEnvironment()
|
||
appState.saveEnvironmentToStorage(currentEnv)
|
||
}
|
||
|
||
// Export as default object
|
||
export default {
|
||
initForAnswer,
|
||
loadForAnswer,
|
||
loadSection,
|
||
loadDocuments,
|
||
setupListeners,
|
||
updateCheckboxStyle,
|
||
saveDraft
|
||
}
|