Spaces:
Paused
Paused
| const GPTResearcher = (() => { | |
| const init = () => { | |
| // Not sure, but I think it would be better to add event handlers here instead of in the HTML | |
| //document.getElementById("startResearch").addEventListener("click", startResearch); | |
| document | |
| .getElementById('copyToClipboard') | |
| .addEventListener('click', copyToClipboard) | |
| updateState('initial') | |
| } | |
| const changeSource = () => { | |
| const report_source = document.querySelector('select[name="report_source"]').value | |
| if (report_source === 'sources') { | |
| document.getElementById('sources').style.display = 'block' | |
| } else { | |
| document.getElementById('sources').style.display = 'none' | |
| } | |
| } | |
| const startResearch = () => { | |
| document.getElementById('output').innerHTML = '' | |
| document.getElementById('reportContainer').innerHTML = '' | |
| const imageContainer = document.getElementById('selectedImagesContainer') | |
| imageContainer.innerHTML = '' | |
| imageContainer.style.display = 'none' | |
| updateState('in_progress') | |
| addAgentResponse({ | |
| output: '🤔 Thinking about research questions for the task...', | |
| }) | |
| listenToSockEvents() | |
| } | |
| const listenToSockEvents = () => { | |
| const { protocol, host, pathname } = window.location | |
| const ws_uri = `${ | |
| protocol === 'https:' ? 'wss:' : 'ws:' | |
| }//${host}${pathname}ws` | |
| const converter = new showdown.Converter() | |
| const socket = new WebSocket(ws_uri) | |
| socket.onmessage = (event) => { | |
| const data = JSON.parse(event.data) | |
| console.log("Received message:", data); // Debug log | |
| if (data.type === 'logs') { | |
| addAgentResponse(data) | |
| } else if (data.type === 'images') { | |
| console.log("Received images:", data); // Debug log | |
| displaySelectedImages(data) | |
| } else if (data.type === 'report') { | |
| writeReport(data, converter) | |
| } else if (data.type === 'path') { | |
| updateState('finished') | |
| updateDownloadLink(data) | |
| } | |
| } | |
| socket.onopen = (event) => { | |
| const task = document.querySelector('input[name="task"]').value | |
| const report_type = document.querySelector( | |
| 'select[name="report_type"]' | |
| ).value | |
| const report_source = document.querySelector( | |
| 'select[name="report_source"]' | |
| ).value | |
| const tone = document.querySelector('select[name="tone"]').value | |
| const agent = document.querySelector('input[name="agent"]:checked').value | |
| let source_urls = tags | |
| if (report_source !== 'sources' && source_urls.length > 0) { | |
| source_urls = source_urls.slice(0, source_urls.length - 1) | |
| } | |
| const requestData = { | |
| task: task, | |
| report_type: report_type, | |
| report_source: report_source, | |
| source_urls: source_urls, | |
| tone: tone, | |
| agent: agent, | |
| } | |
| socket.send(`start ${JSON.stringify(requestData)}`) | |
| } | |
| } | |
| const addAgentResponse = (data) => { | |
| const output = document.getElementById('output') | |
| output.innerHTML += '<div class="agent_response">' + data.output + '</div>' | |
| output.scrollTop = output.scrollHeight | |
| output.style.display = 'block' | |
| updateScroll() | |
| } | |
| const writeReport = (data, converter) => { | |
| const reportContainer = document.getElementById('reportContainer') | |
| const markdownOutput = converter.makeHtml(data.output) | |
| reportContainer.innerHTML += markdownOutput | |
| updateScroll() | |
| } | |
| const updateDownloadLink = (data) => { | |
| if (!data.output) { | |
| console.error('No output data received'); | |
| return; | |
| } | |
| const { pdf, docx, md, json } = data.output; | |
| console.log('Received paths:', { pdf, docx, md, json }); | |
| // Helper function to safely update link | |
| const updateLink = (id, path) => { | |
| const element = document.getElementById(id); | |
| if (element && path) { | |
| console.log(`Setting ${id} href to:`, path); | |
| element.setAttribute('href', path); | |
| element.classList.remove('disabled'); | |
| } else { | |
| console.warn(`Either element ${id} not found or path not provided`); | |
| } | |
| }; | |
| updateLink('downloadLink', pdf); | |
| updateLink('downloadLinkWord', docx); | |
| updateLink('downloadLinkMd', md); | |
| updateLink('downloadLinkJson', json); | |
| } | |
| const updateScroll = () => { | |
| window.scrollTo(0, document.body.scrollHeight) | |
| } | |
| const copyToClipboard = () => { | |
| const textarea = document.createElement('textarea') | |
| textarea.id = 'temp_element' | |
| textarea.style.height = 0 | |
| document.body.appendChild(textarea) | |
| textarea.value = document.getElementById('reportContainer').innerText | |
| const selector = document.querySelector('#temp_element') | |
| selector.select() | |
| document.execCommand('copy') | |
| document.body.removeChild(textarea) | |
| } | |
| const updateState = (state) => { | |
| var status = '' | |
| switch (state) { | |
| case 'in_progress': | |
| status = 'Research in progress...' | |
| setReportActionsStatus('disabled') | |
| break | |
| case 'finished': | |
| status = 'Research finished!' | |
| setReportActionsStatus('enabled') | |
| break | |
| case 'error': | |
| status = 'Research failed!' | |
| setReportActionsStatus('disabled') | |
| break | |
| case 'initial': | |
| status = '' | |
| setReportActionsStatus('hidden') | |
| break | |
| default: | |
| setReportActionsStatus('disabled') | |
| } | |
| document.getElementById('status').innerHTML = status | |
| if (document.getElementById('status').innerHTML == '') { | |
| document.getElementById('status').style.display = 'none' | |
| } else { | |
| document.getElementById('status').style.display = 'block' | |
| } | |
| } | |
| /** | |
| * Shows or hides the download and copy buttons | |
| * @param {str} status Kind of hacky. Takes "enabled", "disabled", or "hidden". "Hidden is same as disabled but also hides the div" | |
| */ | |
| const setReportActionsStatus = (status) => { | |
| const reportActions = document.getElementById('reportActions') | |
| // Disable everything in reportActions until research is finished | |
| if (status == 'enabled') { | |
| reportActions.querySelectorAll('a').forEach((link) => { | |
| link.classList.remove('disabled') | |
| link.removeAttribute('onclick') | |
| reportActions.style.display = 'block' | |
| }) | |
| } else { | |
| reportActions.querySelectorAll('a').forEach((link) => { | |
| link.classList.add('disabled') | |
| link.setAttribute('onclick', 'return false;') | |
| }) | |
| if (status == 'hidden') { | |
| reportActions.style.display = 'none' | |
| } | |
| } | |
| } | |
| const tagsInput = document.getElementById('tags-input'); | |
| const input = document.getElementById('custom_source'); | |
| const tags = []; | |
| const addTag = (url) => { | |
| if (tags.includes(url)) return; | |
| tags.push(url); | |
| const tagElement = document.createElement('span'); | |
| tagElement.className = 'tag'; | |
| tagElement.textContent = url; | |
| const removeButton = document.createElement('span'); | |
| removeButton.className = 'remove-tag'; | |
| removeButton.textContent = 'x'; | |
| removeButton.onclick = function () { | |
| tagsInput.removeChild(tagElement); | |
| tags.splice(tags.indexOf(url), 1); | |
| }; | |
| tagElement.appendChild(removeButton); | |
| tagsInput.insertBefore(tagElement, input); | |
| } | |
| const displaySelectedImages = (data) => { | |
| const imageContainer = document.getElementById('selectedImagesContainer') | |
| //imageContainer.innerHTML = '<h3>Selected Images</h3>' | |
| const images = JSON.parse(data.output) | |
| console.log("Received images:", images); // Debug log | |
| if (images && images.length > 0) { | |
| images.forEach(imageUrl => { | |
| const imgElement = document.createElement('img') | |
| imgElement.src = imageUrl | |
| imgElement.alt = 'Research Image' | |
| imgElement.style.maxWidth = '200px' | |
| imgElement.style.margin = '5px' | |
| imgElement.style.cursor = 'pointer' | |
| imgElement.onclick = () => showImageDialog(imageUrl) | |
| imageContainer.appendChild(imgElement) | |
| }) | |
| imageContainer.style.display = 'block' | |
| } else { | |
| imageContainer.innerHTML += '<p>No images found for this research.</p>' | |
| } | |
| } | |
| const showImageDialog = (imageUrl) => { | |
| const dialog = document.createElement('div'); | |
| dialog.className = 'image-dialog'; | |
| const img = document.createElement('img'); | |
| img.src = imageUrl; | |
| img.alt = 'Full-size Research Image'; | |
| const closeBtn = document.createElement('button'); | |
| closeBtn.textContent = 'Close'; | |
| closeBtn.onclick = () => document.body.removeChild(dialog); | |
| dialog.appendChild(img); | |
| dialog.appendChild(closeBtn); | |
| document.body.appendChild(dialog); | |
| } | |
| document.addEventListener('DOMContentLoaded', init) | |
| return { | |
| startResearch, | |
| copyToClipboard, | |
| changeSource, | |
| addTag, | |
| displaySelectedImages, | |
| showImageDialog, | |
| } | |
| })() | |