// Cloned by Daugirdas Stirbys on 2 Dec 2023 from World "Practical 2 - Simple Hello World" by Daugirdas Stirbys
// Please leave this clone trail here.
document.write (`
<head>
<style type="text/css">
html, body {
margin: 0;
padding: 0;
}
body {
color: #292929;
font: 90% Roboto, Arial, sans-serif;
font-weight: 300;
}
p {
padding: 0 10px;
line-height: 1.8;
}
ul li {
padding-right: 10px;
line-height: 1.6;
}
h3 {
padding: 5px 20px;
margin: 0;
}
div#header {
position: relative;
}
div#header h1 {
height: 100px;
line-height: 80px;
margin: 0;
padding-left: 10px;
background: #e0e0e0;
color: #292929;
}
div#header a {
position: absolute;
right: 0;
top: 23px;
padding: 10px;
color: #006;
}
div#upload li {
list-style: none;
}
div#upload2 {
padding: 15px;
}
div#report {
#background: #147FA9;
}
div#wrapper {
float: right;
width: 70%;
}
div#upload {
float: left;
width: 29.9%;
}
div#report {
clear: both;
width: 100%;
}
input[type=text] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
input[type=file] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
button[type=submit] {
width: 100%;
background-color: #4CAF50;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
border-radius: 4px;
cursor: pointer;
}
button[type=submit]:hover {
background-color: #45a049;
}
#overlay {
position: fixed;
display: none;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0,0,0,0.5);
z-index: 2;
cursor: pointer;
}
#overlay_text{
position: absolute;
top: 50%;
left: 50%;
font-size: 30px;
color: black;
transform: translate(-50%,-50%);
-ms-transform: translate(-50%,-50%);
width: 100%;
height: 150px;
border: 1px solid #000000;
background-color: #f7f7f7;
text-align: center;
height: 3rem;
line-height: 3rem;
}
</style>
</head>
<body>
<div id="container">
<div id="header">
<div style="width: 100%; white-space:nowrap;">
<div style="float:left; width: 60%; display:inline-block;l">
<h1>Practical 2 - Student Submissions Grading Assistant</h1>
</div>
<img src=https://ancientbrain.com/uploads/dastis/top.png>
<div style="float:right; display:inline-block;">
</div>
</div>
<div style="clear:both"></div>
<p><strong></strong></p>
<p><strong>Functionality of this tool</strong></p>
<p>This tool analyses text based student submission documents and provides short summary, evaluates if document was students work by checking if text in the document was generated using AI tools and detects if specific topics were adressed. There are 3 steps required to be performed by the user: enter API key, upload assignment file (in .pdf or .txt format) and enter a list of requirements that were outlined for the assignment i.e. certain topics covered. Multiple API queries are performed to generate the report and GPT4 API is used, so it takes a while...</p>
<hr>
</div>
<div id="wrapper">
<div id="requirements">
<div id="upload2">
<p><strong>2. Enter submission requirements:</strong></p>
<p>List of topics required to be covered in students submission.</p>
<input name="topic_1" id="topic_1" type="text" placeholder="Required topic 1...">
<input name="topic_2" id="topic_2" type="text" placeholder="Required topic 2...">
<input name="topic_3" id="topic_3" type="text" placeholder="Required topic 3...">
<button type="submit" onclick="create_report()">Generate report</button>
</div>
</div>
</div>
<div id="upload">
<div id="upload2">
<p><strong>Step 0. Enter API Key:</strong></p>
<input name="api_key" id="api_key" type="text" placeholder="API Key...">
<p><strong>Step 1. Upload report file for review:</strong></p>
<p style="color:red">NOTE: Do not upload any files that have sensitive information!</p>
<form action="https://api.openai.com/v1/files" method="post" enctype="multipart/form-data">
<input name="file" type="file" multiple>
<input name="purpose" id="purpose" type="hidden" value="assistants">
<button type="submit">Submit</button>
</form>
</div>
</div>
<div id="report">
<hr>
<p><strong>Step 3. Read the assistants report.</strong></p>
<ul>
<li>
<i>Students name: </i>
<p id="authors_name"></p>
</li>
<li>
<i>Submission date: </i>
<p id="document_date"></p>
</li>
<li>
<i>Overview: </i>
<p id="overview"></p>
</li>
<li>
<i>Evaluation if required topics were addressed by the student: </i>
<p id="topic_1_cover"></p>
<p id="topic_2_cover"></p>
<p id="topic_3_cover"></p>
</li>
</ul>
<div id="overlay" onclick="overlay_off()">
<div id="overlay_text"></div>
</div>
</div>
</div>
</body>
`);
var API_KEY = "";
var assistant_id = "";
var thread_id = "";
var file_id = "";
var run_id = "";
var assistants_response = "";
var run_interval; // Undefined for now, thats fine
//------------------------------------------------------------------------------
// --- AI API related functions
function set_api_key()
{
API_KEY = jQuery("input#api_key").val();
API_KEY = API_KEY.trim();
console.info("API key set.");
}
function create_assistant()
{
overlay_on("Creating asistant...", false);
// 1. build a request as JSON
var request_json = {
"instructions": "You are a assignment marking and grading assistant. You will support lecturer by reviewing and evaluating student submissions.",
"name": "Assignment Marking Assistant",
"file_ids": [file_id],
"tools": [{"type": "retrieval"}],
"model": "gpt-4-1106-preview"
};
// 2. convert JSON to string
var request_string = JSON.stringify(request_json);
// 3. set up HTTP headers
$.ajaxSetup({
headers:
{
"Content-Type": "application/json",
"Authorization": "Bearer " + API_KEY,
"OpenAI-Beta": "assistants=v1"
}
});
// 4. perform POST request
$.ajax({
type: "POST",
async: true, // force async execution
url: "https://api.openai.com/v1/assistants",
data: request_string,
dataType: "json",
success: function(d, rc)
{
//resolve(d);
assistant_id = d['id'];
console.log(assistant_id);
// Next report generation step
report_generation_step = 2;
create_report();
},
error: function(d, rc)
{
console.log(d)
if ( API_KEY === "" ) overlay_on("Error: Failed to create assistant. No API key entered.", true);
else overlay_on("Error: Failed to create assistant. Unknown error.", true);
}
});
}
function create_thread()
{
overlay_on("Creating thread...", false);
// 1. request string - empty
var request_string = "";
// 2. set up HTTP headers
$.ajaxSetup({
headers:
{
"Content-Type": "application/json",
"Authorization": "Bearer " + API_KEY,
"OpenAI-Beta": "assistants=v1"
}
});
// 3. perform POST request
$.ajax({
type: "POST",
async: true, // force async execution
url: "https://api.openai.com/v1/threads",
data: request_string,
dataType: "json",
success: function(d, rc)
{
//resolve(d);
thread_id = d['id'];
console.log(thread_id);
// Next report generation step
report_generation_step = 3;
create_report();
},
error: function(d, rc)
{
if ( API_KEY === "" ) overlay_on("Error: Failed to create thread. No API key entered.", true);
else overlay_on("Error: Failed to create thread. Unknown error.", true);
}
});
}
function add_message(thread_id, message)
{
overlay_on("Adding message...", false);
// 1. build a request as JSON
var request_json = {
"role": "user",
"file_ids": [file_id],
"content": message
};
// 2. convert JSON to string
var request_string = JSON.stringify(request_json);
// 3. set up HTTP headers
$.ajaxSetup({
headers:
{
"Content-Type": "application/json",
"Authorization": "Bearer " + API_KEY,
"OpenAI-Beta": "assistants=v1"
}
});
// 4. perform POST request
$.ajax({
type: "POST",
async: true, // force async execution
url: `https://api.openai.com/v1/threads/${thread_id}/messages`,
data: request_string,
dataType: "json",
success: function(d, rc)
{
console.log("Message with file " + file_id + " added.");
// Next report generation step
report_generation_step = report_generation_step+1;
create_report();
},
error: function(d, rc)
{
console.log(d)
if ( API_KEY === "" ) overlay_on("Error: Failed to add message. No API key entered.", true);
else overlay_on("Error: Failed to add message. Unknown error.", true);
}
});
}
function run_assistant(thread_id)
{
overlay_on("Running assistant...", false);
// 1. build a request as JSON
var request_json = {
"assistant_id": assistant_id
//"instructions": message
};
// 2. convert JSON to string
var request_string = JSON.stringify(request_json);
// 3. set up HTTP headers
$.ajaxSetup({
headers:
{
"Content-Type": "application/json",
"Authorization": "Bearer " + API_KEY,
"OpenAI-Beta": "assistants=v1"
}
});
// 4. perform POST request
$.ajax({
type: "POST",
async: true, // force async execution
url: `https://api.openai.com/v1/threads/${thread_id}/runs`,
data: request_string,
dataType: "json",
success: function(d, rc)
{
run_id = d['id'];
console.log(run_id);
// Next report generation step
report_generation_step = report_generation_step + 1;
create_report();
},
error: function(d, rc)
{
console.log(d)
if ( API_KEY === "" ) overlay_on("Error: Failed to run assistant. No API key entered.", true);
else overlay_on("Error: Failed to run assistant. Unknown error.", true);
}
});
}
function is_run_complete(thread_id, run_id)
{
var status = "unknown";
// 1. empty string
var request_string = "";
// 2. set up HTTP headers
$.ajaxSetup({
headers:
{
"Authorization": "Bearer " + API_KEY,
"OpenAI-Beta": "assistants=v1"
}
});
// 3. perform GET request
$.ajax({
type: "GET",
async: false, // force sync execution
url: `https://api.openai.com/v1/threads/${thread_id}/runs/${run_id}`,
data: request_string,
dataType: "json",
success: function(d, rc) {
status = d['status'];
console.log(status);
},
error: function(d, rc){
console.log(d)
if ( API_KEY === "" ) overlay_on("Error: Failed to get run status. No API key entered.", true);
else overlay_on("Error: Failed to get run status. Unknown error.", true);
}
});
if (status == "completed")
{
return true;
} else {
return false;
}
}
function waiting_for_run()
{
if (is_run_complete(thread_id, run_id))
{
clearInterval(run_interval);
report_generation_step = report_generation_step + 1;
create_report();
}
}
function get_response(thread_id)
{
// 1. empty body
var request_string = "";
// 2. set up HTTP headers
$.ajaxSetup({
headers:
{
"Content-Type": "application/json",
"Authorization": "Bearer " + API_KEY,
"OpenAI-Beta": "assistants=v1"
}
});
// 3. perform POST request
$.ajax({
type: "GET",
async: true, // force async execution
url: `https://api.openai.com/v1/threads/${thread_id}/messages`,
data: request_string,
dataType: "json",
success: function(d, rc) {
assistants_response = d['data'][0]['content'][0].text.value;
console.log(assistants_response);
// Next report generation step
report_generation_step = report_generation_step + 1;
create_report();
},
error: function(d, rc){
console.log(d)
if ( API_KEY === "" ) overlay_on("Error: Failed to get assistants response. No API key entered.", true);
else overlay_on("Error: Failed to get assistants response. Unknown error.", true);
}
});
}
//------------------------------------------------------------------------------
// --- Handling file uploads
const form = document.querySelector('form');
form.addEventListener('submit', handle_submit);
function handle_submit(event) {
event.preventDefault();
overlay_on("Uploading file...", false);
try {
set_api_key(); // retrieves and sets api key global
const url = 'https://api.openai.com/v1/files';
const formData = new FormData(form);
const fetchOptions = {
method: 'post',
headers: {
"Authorization": "Bearer " + API_KEY,
"OpenAI-Beta": "assistants=v1"
},
body: formData
};
fetch(url, fetchOptions).then(response => response.json()).then(confirm_upload);
} catch (error) {
console.error(error);
overlay_on("Error uploading file. Did you set correct API key?", true);
}
}
function confirm_upload(json_data)
{
console.log(json_data);
file_id = json_data['id'];
console.log(file_id);
overlay_off();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// --- controlling overlay messages
// enable overlay message
// msg - custom message string
// err - boolean indicating if this is error message
function overlay_on(msg, err) {
if (err)
{
document.getElementById('overlay_text').style.color = 'red';
}
document.getElementById("overlay_text").innerHTML = msg;
document.getElementById("overlay").style.display = "block";
}
// disable overlay message
function overlay_off() {
document.getElementById("overlay").style.display = "none";
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// --- handling report generation
var report_generation_step = 1;
function create_report()
{
var prompt_2 = "Please tell me this document author name. It should be on the first page.";
var prompt_3 = "Please tell me this document submission date. It should be on the first page.";
var prompt_5 = "Does this document has any information about following topic <>? Please provide short summary.";
var prompt_6 = "Can you evaluate the originality of the document?";
// Step 1: Create an Assistant
// Step 2: Create a Thread
// Step 3: Add a Message to a Thread
// Step 4: Run the Assistant
// Step 5: Check the Run status
// Step 6: Get the Assistant's Response
if (report_generation_step == 1) create_assistant();
if (report_generation_step == 2) create_thread();
// Get the short summary of the submission
var prompt_msg = "Please summarise this file in a few short bulletpoints. Do not use more than 10 sentences. Mark most important keywords in red html colour tags.";
if (report_generation_step == 3) add_message(thread_id, prompt_msg);
if (report_generation_step == 4) run_assistant(thread_id);
if (report_generation_step == 5)
{
run_interval = setInterval(waiting_for_run, 2000);
}
if (report_generation_step == 6) get_response(thread_id);
if (report_generation_step == 7)
{
report_generation_step = report_generation_step + 1;
$("#overview").html(assistants_response);
}
// Extract authors name information...
prompt_msg = "Extract the authors name from the document. Respond with -could not extract the authors name- if you cant find it.";
if (report_generation_step == 8) add_message(thread_id, prompt_msg);
if (report_generation_step == 9) run_assistant(thread_id);
if (report_generation_step == 10)
{
run_interval = setInterval(waiting_for_run, 2000);
}
if (report_generation_step == 11) get_response(thread_id);
if (report_generation_step == 12)
{
report_generation_step = report_generation_step + 1;
$("#authors_name").html(assistants_response);
}
// When document was dated ...
prompt_msg = "Extract the date the document was written. Respond with -could not extract the date- if you cant find it.";
if (report_generation_step == 13) add_message(thread_id, prompt_msg);
if (report_generation_step == 14) run_assistant(thread_id);
if (report_generation_step == 15)
{
run_interval = setInterval(waiting_for_run, 2000);
}
if (report_generation_step == 16) get_response(thread_id);
if (report_generation_step == 17)
{
report_generation_step = report_generation_step + 1;
$("#document_date").html(assistants_response);
}
// Does document include required topic 1?
prompt_msg = "Tell me if document author talks about following topic and what: " + jQuery("input#topic_1").val();
if (report_generation_step == 18) add_message(thread_id, prompt_msg);
if (report_generation_step == 19) run_assistant(thread_id);
if (report_generation_step == 20)
{
run_interval = setInterval(waiting_for_run, 2000);
}
if (report_generation_step == 21) get_response(thread_id);
if (report_generation_step == 22)
{
report_generation_step = report_generation_step + 1;
$("#topic_1_cover").html(assistants_response);
}
// Does document include required topic 2?
prompt_msg = "Tell me if document author talks about following topic and what: " + jQuery("input#topic_2").val();
if (report_generation_step == 23) add_message(thread_id, prompt_msg);
if (report_generation_step == 24) run_assistant(thread_id);
if (report_generation_step == 25)
{
run_interval = setInterval(waiting_for_run, 2000);
}
if (report_generation_step == 26) get_response(thread_id);
if (report_generation_step == 27)
{
report_generation_step = report_generation_step + 1;
$("#topic_2_cover").html(assistants_response);
}
// Does document include required topic 3?
prompt_msg = "Tell me if document author talks about following topic and what: " + jQuery("input#topic_3").val();
if (report_generation_step == 28) add_message(thread_id, prompt_msg);
if (report_generation_step == 29) run_assistant(thread_id);
if (report_generation_step == 30)
{
run_interval = setInterval(waiting_for_run, 2000);
}
if (report_generation_step == 31) get_response(thread_id);
if (report_generation_step == 32)
{
report_generation_step = report_generation_step + 1;
$("#topic_3_cover").html(assistants_response);
}
// Finish the report generation
if (report_generation_step == 33)
{
report_generation_step = 1;
overlay_off();
console.log("Report generation completed.");
}
}
//------------------------------------------------------------------------------