Spaces:
Sleeping
Sleeping
import React, { useState, useRef } from "react"; | |
import "./App.css"; | |
import { RQicon } from './mysvg' | |
import { Button, Divider, Form, Input, Layout, Space, Table, notification } from "antd"; | |
import { Content, Footer, Header } from "antd/es/layout/layout"; | |
import { SearchOutlined } from '@ant-design/icons'; | |
import TextArea from "antd/es/input/TextArea"; | |
import FullPageLoader from "./FullPageLoader"; | |
import { answers, columns, filterColumns, paperColumns } from "./columns"; | |
function App() { | |
const [loading, setLoading] = useState(false) | |
const contentRef = useRef(); | |
const scrollToBottom = () => { | |
let elem = document.getElementById("mainContainer") | |
setTimeout(()=>{ | |
elem.scroll(0,elem.scrollHeight) | |
}, 300) | |
}; | |
const [name, setName] = useState("'My work aims to systematically identify and analyze, the literature on Large language models in software development'"); | |
const [noOfQuestion, setNoOfQuestions] = useState(2) | |
const [researchQuestions, setResearchQuestions] = useState([]) | |
const [researchQuestionApiResponse, setResearchQuestionApiResponse] = useState() | |
const [searchString, setSearchString] = useState('') | |
const [start_year, setstartYear] = useState(2023) | |
const [end_year, setEndYear] = useState(2020) | |
const generateSearchString = async (e) => { | |
e.preventDefault(); | |
try { | |
setLoading(true) | |
const response = await fetch("/api/generate_search_string", { | |
method: "post", | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify({ | |
objective: name, | |
research_questions: researchQuestions | |
}) | |
}); | |
const message = await response.json(); | |
setSearchString( | |
message.search_string | |
.replace(/^\d+\.\s*/, '') // Remove any leading digits and dots | |
.replace(/\bAND\b/g, 'OR') // Replace "AND" with "OR" | |
.replace(/[()]/g, '') // Remove parentheses | |
); | |
setLoading(false) | |
scrollToBottom() | |
notification.success({ | |
message:"Search String Generated" | |
}) | |
} catch (e) { | |
notification.error({ | |
message: `internal Server Error` | |
}) | |
setLoading(false) | |
} | |
} | |
const [papersData, setPapersData] = useState() | |
const [limitPaper, setLimitPaper] = useState(10) | |
const fetchAndSavePapers = async (e) => { | |
e.preventDefault(); | |
try { | |
setLoading(true) | |
const response = await fetch("/api/search_papers", { | |
method: "post", | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify({ | |
search_string: searchString, | |
start_year: start_year, | |
limit: limitPaper | |
}) | |
}); | |
const message = await response.json(); | |
if (message) { | |
setPapersData(message) | |
} | |
scrollToBottom() | |
setLoading(false) | |
notification.success({ | |
message:"Papers Found" | |
}) | |
} catch (e) { | |
console.log("error:", e) | |
setLoading(false) | |
notification.error({ | |
message:"Internal Server Error" | |
}) | |
} | |
} | |
const handleSubmit = async (e) => { | |
e.preventDefault(); | |
try { | |
setLoading(true) | |
const response = await fetch("/api/generate_research_questions_and_purpose", { | |
method: "post", | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify({ | |
objective: name, | |
num_questions: noOfQuestion | |
}), | |
}); | |
const message = await response.json(); | |
let dataResponse = message.research_questions.research_questions.map((i, index) => ({ ...i, key: index })) | |
console.log("response:", dataResponse); | |
setResearchQuestionApiResponse(dataResponse) | |
let questions = message.research_questions.research_questions.map(i => i.question) | |
setResearchQuestions(questions) | |
setLoading(false) | |
scrollToBottom() | |
notification.success({ | |
message:"Research Questions Generated" | |
}) | |
} catch (error) { | |
console.error("Error submitting data:", error); | |
setLoading(false) | |
notification.error({ | |
message:"Internal Server Error" | |
}) | |
} | |
}; | |
const [papersFilterData, setPapersFilterData] = useState([]) | |
const handleCheckboxChange = (key) => { | |
const newpapersFilterData = [...papersFilterData]; | |
if (newpapersFilterData.includes(key)) { | |
newpapersFilterData.splice(newpapersFilterData.indexOf(key), 1); | |
} else { | |
newpapersFilterData.push(key); | |
} | |
setPapersFilterData(newpapersFilterData); | |
}; | |
const fetchAndFilterPapers = async (e) => { | |
e.preventDefault(); | |
try { | |
setLoading(true) | |
const response = await fetch("/api/filter_papers", { | |
method: "post", | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify({ | |
search_string: searchString, | |
papers: papersData | |
}) | |
}); | |
const message = await response.json(); | |
if (message) { | |
const newFilteredPapers = message.filtered_papers; | |
const combinedArray = [...new Set([...papersFilterData, ...newFilteredPapers])]; | |
setPapersFilterData(combinedArray); | |
} | |
scrollToBottom() | |
setLoading(false) | |
notification.success({ | |
message:"Papers Filtered" | |
}) | |
} catch (e) { | |
console.log("error:", e) | |
setLoading(false) | |
notification.error({ | |
message:"internal server error" | |
}) | |
} | |
} | |
const [ansWithQuestions, setAnsWithQuestionsData] = useState() | |
const ansWithQuestionsData = async (e) => { | |
e.preventDefault(); | |
try { | |
setLoading(true) | |
const response = await fetch("/api/answer_question", { | |
method: "post", | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify({ | |
questions: researchQuestions, | |
papers_info: [...new Set([...papersFilterData, ...papersFilterData])] | |
}) | |
}); | |
const message = await response.json(); | |
console.log("message:", message) | |
if (message) { | |
setAnsWithQuestionsData(message.answers) | |
} | |
setLoading(false) | |
notification.success({ | |
message:"Answers Generated" | |
}) | |
scrollToBottom() | |
} catch (e) { | |
console.log("error:", e) | |
setLoading(false) | |
notification.error({ | |
message:"Internal Server Error" | |
}) | |
} | |
} | |
const [summary, setSummary] = useState() | |
const [introSummary, setIntroSummary] = useState() | |
const generateSummaryAbstract = async (e) =>{ | |
e.preventDefault() | |
setLoading(true) | |
try{ | |
let response = await fetch ("api/generate-summary-abstract", { | |
method: "post", | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify({ | |
questions: researchQuestions, | |
objective: name, | |
search_string: searchString | |
}) | |
}); | |
let message = await response.json() | |
setSummary(message.summary_abstract) | |
setLoading(false) | |
notification.success({ | |
message:"Summary Abstract Generated" | |
}) | |
scrollToBottom() | |
}catch(error) { | |
setLoading(false) | |
console.log("error:", error) | |
} | |
} | |
const introductionSummary = async (e) =>{ | |
e.preventDefault() | |
setLoading(true) | |
try{ | |
let response = await fetch ("api/generate-introduction-summary", { | |
method: "post", | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify({ | |
questions: researchQuestions, | |
objective: name, | |
search_string: searchString, | |
total_papers: papersData, | |
filtered_papers: papersFilterData, | |
answers: ansWithQuestions | |
}) | |
}); | |
let message = await response.json() | |
setIntroSummary(message.introduction_summary) | |
setLoading(false) | |
notification.success({ | |
message:"Introduction Summary Generated" | |
}) | |
scrollToBottom() | |
}catch(error) { | |
setLoading(false) | |
console.log("error:", error) | |
} | |
} | |
const [downloadlink, setDownloadLink] = useState() | |
const generateAllSummary = async (e) =>{ | |
e.preventDefault() | |
setLoading(true) | |
try{ | |
let response = await fetch ("api/generate-summary-all", { | |
method: "post", | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify({ | |
abstract_summary: summary, | |
intro_summary: introSummary, | |
conclusion_summary: summary | |
}) | |
});if (!response.ok) { | |
throw new Error(`Error: ${response.status} - ${response.statusText}`); | |
} | |
const blob = await response.blob(); | |
const contentDisposition = response.headers.get('Content-Disposition'); | |
const filename = contentDisposition ? contentDisposition.split('filename=')[1] : 'paper_summary.tex'; | |
const url = window.URL.createObjectURL(new Blob([blob])); | |
const link = document.createElement('a'); | |
link.href = url; | |
link.setAttribute('download', filename); | |
document.body.appendChild(link); | |
link.click(); | |
window.URL.revokeObjectURL(url); | |
document.body.removeChild(link); | |
setLoading(false) | |
}catch(error) { | |
setLoading(false) | |
console.log("error:", error) | |
} | |
} | |
const handleTextareaChange = (event) => { | |
const newText = event.target.value; | |
const modifiedString = newText.replace(/^Question \d+: /gm, ''); | |
console.log("modified value",modifiedString.trim()); | |
// console.log("question value:", event.target.value) | |
const newQuestions = modifiedString.split('\n').map((question) => question); | |
setResearchQuestions(newQuestions); | |
}; | |
const handleSearchStringChange = (event) => { | |
if(event.target.value == ""){ | |
setSearchString(" ") | |
}else{ | |
setSearchString(event.target.value); | |
} | |
}; | |
return ( | |
<Layout> | |
<Header style={{ backgroundColor: "#f3fff3", }} > | |
<div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between", marginLeft: "0px" }}> | |
<div> | |
<RQicon width={"60px"} height={"60px"} /> | |
</div> | |
<div style={{ fontSize: "20px", color: "black" }}> | |
<strong >SLR Automation Tool</strong> | |
</div> | |
<div> | |
</div> | |
</div> | |
</Header> | |
<Layout> | |
<Content> | |
{loading && <FullPageLoader/>} | |
<div | |
id="mainContainer" | |
style={{ | |
// paddingTop:"150px", | |
lineHeight: "0px", | |
display: "flex", | |
flexDirection: "column", | |
// justifyContent: "center", | |
// alignContent: "center", | |
alignItems: "center", | |
overflowY: "auto", | |
height: "85vh", | |
paddingBottom:"30px" | |
}} | |
ref={contentRef} | |
> | |
<div> | |
<div> | |
{/* <div style={{textAlign:"center"}}><RQicon width={"100px"} height={"100px"} /></div> */} | |
<h5>Hello, I am your Agent, Enter Your Research Objective.</h5> | |
</div> | |
<div style={{ display: 'flex', alignItems: 'center', width: "80vw", border: '1px solid #ccc', padding: 15, marginBottom: 5, borderRadius: "10px" }}> | |
<Form layout="vertical" style={{ width: "100%", display: "flex", alignItems: "center" }}> | |
<Form.Item label="Objective" style={{ flex: "1 1 70%", marginRight: '5px' }}> | |
<Input | |
placeholder="Ask me anything..." | |
value={name} | |
onChange={(e) => setName(e.target.value)} | |
/> | |
</Form.Item> | |
<Form.Item label="No of Questions" style={{ flex: 1, marginRight: '5px' }}> | |
<Input | |
placeholder="Number of Questions" | |
min={1} | |
max={5} | |
value={noOfQuestion} | |
onChange={(e) => setNoOfQuestions(e.target.value)} | |
type="number" | |
/> | |
</Form.Item> | |
<Form.Item style={{marginBottom:"-4px"}}> | |
<Button | |
type="primary" | |
icon={<SearchOutlined />} | |
onClick={handleSubmit} | |
> | |
Search | |
</Button> | |
</Form.Item> | |
</Form> | |
</div> | |
</div> | |
{researchQuestionApiResponse && | |
<div style={{ display: 'flex', alignItems: 'center', width: "80vw", border: '1px solid #ccc', padding: 10, borderRadius: "10px", marginBottom:5 }}> | |
<Space direction="vertical" style={{ width: "100%", padding: "10px 0px" }} > | |
<Table scroll={{ | |
x: 1200, | |
y: 500, | |
}} style={{width:'100%'}} dataSource={researchQuestionApiResponse} columns={columns} pagination={false} /> | |
</Space> | |
</div>} | |
{researchQuestions && researchQuestions.length > 0 && | |
<div style={{ display: 'flex', flexDirection: "column", alignItems: 'center', width: "80vw", border: '1px solid #ccc', padding: 10, borderRadius: "10px" }}> | |
<div> | |
<Space align="center" direction="vertical" style={{ display: 'flex', justifyContent: 'center' }}> | |
<Form layout="vertical"> | |
<Form.Item label="List Of Questions"> | |
<TextArea style={{ width: "70vw" }} onChange={handleTextareaChange} value={researchQuestions.map((question, index) => question.length == 0 ?"":`Question ${index + 1}: ${question}`).join('\n')} rows={researchQuestions.length} /> | |
</Form.Item> | |
<Button type="primary" style={{ width: "auto", float: 'right' }} onClick={generateSearchString}>Create Search String</Button> | |
</Form> | |
</Space> | |
</div> | |
{searchString && searchString.length > 0 && <div> | |
<div> | |
<Divider /> | |
<Space align="center" direction="vertical" style={{ display: 'flex', justifyContent: 'center' }}> | |
<Form layout="vertical"> | |
<Form.Item label="Search String"> | |
<TextArea onChange={handleSearchStringChange} value={searchString} rows={3} style={{ width: "70vw" }} /> | |
</Form.Item> | |
{/* <Space.Compact> */} | |
<Form.Item label="Year" style={{width:"70vw"}}> | |
<Input type="number" max={2024} min={2014} value={start_year} onChange={(e) => setstartYear(e.target.value)} /> | |
</Form.Item> | |
<Form.Item label="No of Papers" style={{width:"70vw"}}> | |
<Input type="number" max={15} min={5} value={limitPaper} onChange={(e)=> setLimitPaper(e.target.value)} placeholder="No Of Papers"/> | |
</Form.Item> | |
{/* </Space.Compact> */} | |
<Button type="primary" style={{ width: "auto", float: 'right' }} onClick={fetchAndSavePapers}>Fetch Papers</Button> | |
</Form> | |
</Space> | |
</div> | |
</div>} | |
{papersData && | |
<><Divider /> | |
<Space direction="vertical" style={{ width: "100%", padding: "10px 0px" }} > | |
<Table scroll={{ | |
x: 1500, | |
y: 450, | |
}} style={{ width: "100%" }} dataSource={papersData} columns={paperColumns(papersFilterData, handleCheckboxChange)} pagination={false} /> | |
<Button type="primary" style={{ float: "right", marginTop: "10px" }} onClick={fetchAndFilterPapers}>Filter with title</Button> | |
</Space></> | |
} | |
{(papersFilterData.length >0 || papersFilterData.length >0) && <Space direction="vertical" style={{ width: "100%", padding: "10px 0px" }} > | |
<Table scroll={{ | |
x: 1500, | |
y: 450, | |
}} dataSource={[...new Set([...papersFilterData, ...papersFilterData])]} columns={filterColumns} pagination={false} /> | |
{(papersFilterData.length > 0 || papersFilterData.length > 0) && <Button type="primary" style={{ float: "right", marginTop: "10px" }} onClick={ansWithQuestionsData}>Find Answers of Each Question </Button>} | |
</Space>} | |
{ansWithQuestions && | |
<Space direction="vertical" style={{ width: "100%", padding: "10px 0px" }}> | |
<Table dataSource={ansWithQuestions} columns={answers} pagination={false} /> | |
<Button type="primary" style={{float:"right", marginTop:"10px"}} onClick={generateSummaryAbstract}>Generate Summary Abstract </Button> | |
</Space> | |
} | |
{summary && summary.length >0 && <><Divider /> | |
<Space align="center" direction="vertical" style={{ display: 'flex', justifyContent: 'center' }}> | |
<Form layout="vertical"> | |
<Form.Item label="Summary Abstract"> | |
<TextArea onChange={(e)=> setSummary(e.target.value)} value={summary} rows={7} style={{ width: "70vw" }} /> | |
</Form.Item> | |
<Button type="primary" style={{ width: "auto", float: 'right' }} onClick={introductionSummary}>Introduction Summary</Button> | |
</Form> | |
</Space> | |
</>} | |
{introSummary && introSummary.length >0 && <><Divider /> | |
<Space align="center" direction="vertical" style={{ display: 'flex', justifyContent: 'center' }}> | |
<Form layout="vertical"> | |
<Form.Item label="Introduction Summary"> | |
<TextArea onChange={(e)=> setIntroSummary(e.target.value)} value={introSummary} rows={7} style={{ width: "70vw" }} /> | |
</Form.Item> | |
<Button type="primary" style={{ width: "auto", float: 'right' }} onClick={generateAllSummary}>Create Paper Summary</Button> | |
{downloadlink && downloadlink.length>0 && <a href={downloadlink} >download file</a> } | |
</Form> | |
</Space> | |
</>} | |
</div>} | |
</div> | |
</Content> | |
</Layout> | |
<Footer className="footerFixed"> | |
<div style={{float:"right", lineHeight:0}}> | |
<p>© {new Date().getFullYear()} SLR Automation Tool. All rights reserved. </p> | |
</div> | |
</Footer> | |
</Layout> | |
); | |
} | |
export default App; |