Renamed online_log to chat_visualizer
68
chat_visualizer/app.py
Normal file
@ -0,0 +1,68 @@
|
||||
import logging
|
||||
import requests
|
||||
import os
|
||||
from flask import Flask, send_from_directory, request, jsonify
|
||||
import argparse
|
||||
|
||||
app = Flask(__name__, static_folder='static')
|
||||
app.logger.setLevel(logging.ERROR)
|
||||
log = logging.getLogger('werkzeug')
|
||||
log.setLevel(logging.ERROR)
|
||||
messages = []
|
||||
port = [8000]
|
||||
|
||||
def send_msg(role, text):
|
||||
try:
|
||||
data = {"role": role, "text": text}
|
||||
response = requests.post(f"http://127.0.0.1:{port[-1]}/send_message", json=data)
|
||||
except:
|
||||
logging.info("flask app.py did not start for online log")
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
return send_from_directory("static", "index.html")
|
||||
|
||||
|
||||
@app.route("/chain_visualizer")
|
||||
def chain_visualizer():
|
||||
return send_from_directory("static", "chain_visualizer.html")
|
||||
|
||||
|
||||
@app.route("/replay")
|
||||
def replay():
|
||||
return send_from_directory("static", "replay.html")
|
||||
|
||||
|
||||
@app.route("/get_messages")
|
||||
def get_messages():
|
||||
return jsonify(messages)
|
||||
|
||||
|
||||
@app.route("/send_message", methods=["POST"])
|
||||
def send_message():
|
||||
data = request.get_json()
|
||||
role = data.get("role")
|
||||
text = data.get("text")
|
||||
|
||||
avatarUrl = find_avatar_url(role)
|
||||
|
||||
message = {"role": role, "text": text, "avatarUrl": avatarUrl}
|
||||
messages.append(message)
|
||||
return jsonify(message)
|
||||
|
||||
|
||||
def find_avatar_url(role):
|
||||
role = role.replace(" ", "%20")
|
||||
avatar_filename = f"avatars/{role}.png"
|
||||
avatar_url = f"/static/{avatar_filename}"
|
||||
return avatar_url
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='argparse')
|
||||
parser.add_argument('--port', type=int, default=8000, help="port")
|
||||
args = parser.parse_args()
|
||||
port.append(args.port)
|
||||
print(f"Please visit http://127.0.0.1:{port[-1]}/ for the front-end display page. \nIn the event of a port conflict, please modify the port argument (e.g., python3 app.py --port 8012).")
|
||||
app.run(host='0.0.0.0', debug=False, port=port[-1])
|
||||
BIN
chat_visualizer/static/avatars/Chief Creative Officer.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
chat_visualizer/static/avatars/Chief Executive Officer.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
chat_visualizer/static/avatars/Chief Human Resource Officer.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
chat_visualizer/static/avatars/Chief Product Officer.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
chat_visualizer/static/avatars/Chief Technology Officer.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
chat_visualizer/static/avatars/Code Reviewer.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
chat_visualizer/static/avatars/Counselor.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
chat_visualizer/static/avatars/Programmer.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
chat_visualizer/static/avatars/Prompt Engineer.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
chat_visualizer/static/avatars/Software Test Engineer.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
chat_visualizer/static/avatars/System.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
chat_visualizer/static/avatars/User.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
165
chat_visualizer/static/chain_visualizer.html
Normal file
@ -0,0 +1,165 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>ChatChain Visualizer</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
#visualization {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: visible;
|
||||
overflow-y: visible;
|
||||
max-width: 1800px;
|
||||
max-height: 1600px;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin-right: 10px;
|
||||
display: inline-block;
|
||||
min-width: 300px;
|
||||
vertical-align: top;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.simple-phase {
|
||||
background-color: #E8ECEB; /* Light Blue for SimplePhase */
|
||||
}
|
||||
|
||||
.composed-phase {
|
||||
background-color: #A3B4C8; /* Light Red for ComposedPhase */
|
||||
}
|
||||
|
||||
.nested-simple-phase {
|
||||
background-color: #E3DCD2; /* Light Yellow for SimplePhase within ComposedPhase */
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>ChatChain Visualizer</h2>
|
||||
<p>Select your ChatChainConfig.json under CompanyConfig/ to visualize</p>
|
||||
<input type="file" id="fileInput" accept=".json">
|
||||
<button id="exportButton">Export as Image</button>
|
||||
<div id="visualization"></div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.5.0-beta4/html2canvas.min.js"></script>
|
||||
<script>
|
||||
document.getElementById('fileInput').addEventListener('change', handleFileSelect, false);
|
||||
document.getElementById('exportButton').addEventListener('click', exportAsImage, false);
|
||||
|
||||
function handleFileSelect(event) {
|
||||
const file = event.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(event) {
|
||||
try {
|
||||
const jsonContent = JSON.parse(event.target.result);
|
||||
visualizeChain(jsonContent.chain);
|
||||
} catch (error) {
|
||||
alert('Error parsing JSON file.');
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
||||
function createCard(element) {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'card';
|
||||
|
||||
const cardContent = document.createElement('div');
|
||||
cardContent.className = 'card-content';
|
||||
|
||||
if (element.phaseType === "ComposedPhase") {
|
||||
delete element.Composition;
|
||||
}
|
||||
|
||||
const phase = document.createElement('span');
|
||||
phase.innerHTML = `<strong>PhaseName: </strong>${element.phase || 'No PhaseName'}`;
|
||||
|
||||
const phaseType = document.createElement('p');
|
||||
phaseType.innerHTML = `<strong>PhaseType: </strong>${element.phaseType || 'No phaseType'}`;
|
||||
|
||||
delete element.phase;
|
||||
delete element.phaseType;
|
||||
const jsonContent = document.createElement('pre');
|
||||
jsonContent.innerText = JSON.stringify(element, null, 2);
|
||||
|
||||
cardContent.appendChild(phase);
|
||||
cardContent.appendChild(phaseType);
|
||||
cardContent.appendChild(jsonContent);
|
||||
|
||||
card.appendChild(cardContent);
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
function visualizeChain(chain) {
|
||||
const visualization = document.getElementById('visualization');
|
||||
visualization.innerHTML = '';
|
||||
|
||||
chain.forEach(element => {
|
||||
if (element.phaseType === "ComposedPhase") {
|
||||
const composition = element.Composition || [];
|
||||
const card = createCard(element);
|
||||
|
||||
const nestedCards = composition.map(composedElement => {
|
||||
return createCard(composedElement);
|
||||
});
|
||||
|
||||
const nestedCardWrapper = document.createElement('div');
|
||||
nestedCardWrapper.style.marginTop = '10px';
|
||||
|
||||
nestedCards.forEach(nestedCard => {
|
||||
nestedCard.classList.add('nested-simple-phase');
|
||||
nestedCardWrapper.appendChild(nestedCard);
|
||||
});
|
||||
|
||||
card.classList.add('composed-phase');
|
||||
card.appendChild(nestedCardWrapper);
|
||||
visualization.appendChild(card);
|
||||
} else {
|
||||
const card = createCard(element);
|
||||
card.classList.add('simple-phase');
|
||||
visualization.appendChild(card);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function exportAsImage() {
|
||||
const visualization = document.getElementById('visualization');
|
||||
const totalWidth = visualization.scrollWidth;
|
||||
const totalHeight = visualization.scrollHeight;
|
||||
|
||||
console.log(totalWidth, totalHeight)
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = totalWidth + 100;
|
||||
canvas.height = totalHeight + 100;
|
||||
|
||||
html2canvas(visualization, { scrollX: 0, scrollY: 0, width: totalWidth, height: totalHeight, useCORS: true }).then(canvas => {
|
||||
const link = document.createElement('a');
|
||||
link.href = canvas.toDataURL();
|
||||
link.download = 'ChatChain_Visualization.png';
|
||||
link.click();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
137
chat_visualizer/static/css/style.css
Normal file
@ -0,0 +1,137 @@
|
||||
.container {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
width: 2500px;
|
||||
height: 700px;
|
||||
border: 1px solid black;
|
||||
overflow-y: scroll;
|
||||
background-color: white;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.message-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin: 20px;
|
||||
max-width: 95%;
|
||||
word-wrap: break-word;
|
||||
padding-top: 0px; /* Add space for the button */
|
||||
}
|
||||
|
||||
|
||||
.message-text {
|
||||
background-color: #D2D4D3;
|
||||
border-radius: 10px;
|
||||
padding: 8px;
|
||||
margin-left: 40px;
|
||||
font-size: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: -30px;
|
||||
margin-left: 20px;
|
||||
background-color: green;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.role {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
top: -30px;
|
||||
margin-top: 10px;
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
.code-block pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dark {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.line-numbers .line-numbers-rows {
|
||||
border-right-color: #44475a;
|
||||
display: block; /* Add this to ensure line numbers are displayed */
|
||||
}
|
||||
|
||||
.code-block-header {
|
||||
background-color: #5b5656;
|
||||
color: #ffffff;
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
.code-block {
|
||||
background-color: #000000 !important;
|
||||
border-radius: 4px;
|
||||
margin-top: 10px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
color: #000000; /* Add text color for syntax highlighting */
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border: 1px solid black;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.expand-button {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: 65px;
|
||||
border-radius: 4px;
|
||||
background-color: #95A1A1;
|
||||
color: #f8f8f2;
|
||||
border: none;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 8px;
|
||||
width: 50px;
|
||||
height: 20px;
|
||||
line-height: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.expand-button:hover {
|
||||
background-color: #6B9297;
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: 3px;
|
||||
background-color: #A9A9A7;
|
||||
color: #f8f8f2;
|
||||
border: none;
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
width: 55px;
|
||||
height: 20px;
|
||||
line-height: 10px;
|
||||
font-size: 8px;
|
||||
font-weight: bold;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.copy-button:hover {
|
||||
background-color: #866753;
|
||||
}
|
||||
BIN
chat_visualizer/static/figures/background.png
Normal file
|
After Width: | Height: | Size: 2.4 MiB |
BIN
chat_visualizer/static/figures/ceo.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
chat_visualizer/static/figures/chatdev.png
Normal file
|
After Width: | Height: | Size: 3.4 MiB |
BIN
chat_visualizer/static/figures/chatdev2.png
Normal file
|
After Width: | Height: | Size: 523 KiB |
BIN
chat_visualizer/static/figures/company.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
chat_visualizer/static/figures/counselor.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
chat_visualizer/static/figures/cpo.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
chat_visualizer/static/figures/cto.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
chat_visualizer/static/figures/designer.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
chat_visualizer/static/figures/hr.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
chat_visualizer/static/figures/left.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
chat_visualizer/static/figures/pe.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
chat_visualizer/static/figures/programmer.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
chat_visualizer/static/figures/reviewer.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
chat_visualizer/static/figures/right.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
chat_visualizer/static/figures/tester.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
chat_visualizer/static/figures/title.png
Normal file
|
After Width: | Height: | Size: 3.4 MiB |
BIN
chat_visualizer/static/figures/user.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
52
chat_visualizer/static/index.html
Normal file
@ -0,0 +1,52 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>ChatDev</title>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked@3.0.7/marked.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/prism.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/components/prism-markup.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/components/prism-javascript.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.8/clipboard.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.2.0/highlight.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.8/clipboard.min.js"></script>
|
||||
<script src="static/js/main.js"></script>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/themes/prism-okaidia.min.css">
|
||||
<link rel="stylesheet" href="static/css/style.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.2.0/styles/monokai-sublime.min.css">
|
||||
<script>
|
||||
hljs.initHighlightingOnLoad();
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="d-flex justify-content-center">
|
||||
<img src="static/figures/title.png" alt="ChatDev Title" id="title-image" style="width: 100%; max-width: 300px;">
|
||||
</div>
|
||||
<div style="display: flex; width:auto;justify-content: center;align-items: center;">
|
||||
<div style="width: 30%;">
|
||||
<br>
|
||||
<a href="static/chain_visualizer.html">
|
||||
<button>ChatChain Visualizer</button>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<br>
|
||||
<a href="static/replay.html">
|
||||
<button>Chat Replay</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container d-flex flex-column" id="chat-box"></div>
|
||||
<script src="static/js/main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
139
chat_visualizer/static/js/main.js
Normal file
@ -0,0 +1,139 @@
|
||||
function append_message(role, text, avatarUrl) {
|
||||
|
||||
var message_container = $("<div></div>").addClass("message-container");
|
||||
var avatar_element = $("<span></span>").addClass("avatar");
|
||||
var role_element = $("<p></p>").addClass("role").text(role);
|
||||
|
||||
if (avatarUrl) {
|
||||
avatar_element.css("background-image", `url(${avatarUrl})`);
|
||||
} else {
|
||||
avatar_element.css("background-color", "green");
|
||||
}
|
||||
|
||||
message_container.append(role_element);
|
||||
message_container.append(avatar_element);
|
||||
|
||||
|
||||
var parsedText = role === 'System' ? parseSystemMessage(text) : parseCodeBlocks(text, role);
|
||||
|
||||
message_container.append(parsedText);
|
||||
|
||||
var copyButton = $("<button></button>")
|
||||
.addClass("copy-button")
|
||||
.text("Copy")
|
||||
.click(function () {
|
||||
copyToClipboard(parsedText); // Call the copyToClipboard function
|
||||
});
|
||||
|
||||
copyButton.click(function () {
|
||||
copyToClipboard(parsedText);
|
||||
copyButton.text("Copied");
|
||||
setTimeout(function () {
|
||||
copyButton.text("Copy");
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
message_container.append(copyButton); // Append the copy button
|
||||
|
||||
$("#chat-box").append(message_container);
|
||||
}
|
||||
|
||||
function parseCodeBlocks(text, role) {
|
||||
var parts = text.split(/(```[\s\S]*?```)/g);
|
||||
var parsedText = $("<div></div>").addClass("message-text");
|
||||
parts.forEach(part => {
|
||||
if (part.startsWith("```") && role != "System") {
|
||||
var trimmedBlock = part.trim();
|
||||
var language = trimmedBlock.match(/^```(\w+)/);
|
||||
if (language) {
|
||||
language = language[1];
|
||||
var codeContent = trimmedBlock.replace(/^```(\w+)/, '').replace(/```$/, '');
|
||||
var codeBlockHTML = `
|
||||
<div class="code-block">
|
||||
<div class="code-block-header">${role} - ${language}</div>
|
||||
<pre class="language-${language} dark line-numbers" data-line><code>${hljs.highlightAuto(codeContent, [language]).value}</code></pre>
|
||||
</div>
|
||||
`;
|
||||
parsedText.append(codeBlockHTML);
|
||||
}
|
||||
} else {
|
||||
parsedText.append(marked(_.escape(part), {breaks: true}));
|
||||
}
|
||||
});
|
||||
return parsedText;
|
||||
}
|
||||
|
||||
|
||||
function get_new_messages() {
|
||||
|
||||
$.getJSON("/get_messages", function (data) {
|
||||
var lastDisplayedMessageIndex = $("#chat-box .message-container").length;
|
||||
|
||||
for (var i = lastDisplayedMessageIndex; i < data.length; i++) {
|
||||
var role = data[i].role;
|
||||
var text = data[i].text;
|
||||
var avatarUrl = data[i].avatarUrl;
|
||||
|
||||
append_message(role, text, avatarUrl);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function parseSystemMessage(text) {
|
||||
var message = $("<div></div>").addClass("message-text").addClass("system-message");
|
||||
var firstLine = text.split('\n')[0];
|
||||
var collapsed = true;
|
||||
|
||||
var messageContent = $("<div></div>").html(marked(firstLine, { breaks: true })).addClass("original-markdown");
|
||||
var originalMarkdown = $("<div></div>").html(marked(text, { breaks: true })).addClass("original-markdown");
|
||||
|
||||
var expandButton = $("<button></button>")
|
||||
.addClass("expand-button")
|
||||
.text("Expand")
|
||||
.click(function () {
|
||||
if (collapsed) {
|
||||
messageContent.hide();
|
||||
originalMarkdown.show();
|
||||
expandButton.text("Collapse");
|
||||
} else {
|
||||
messageContent.show();
|
||||
originalMarkdown.hide();
|
||||
expandButton.text("Expand");
|
||||
}
|
||||
collapsed = !collapsed;
|
||||
});
|
||||
|
||||
message.append(messageContent);
|
||||
message.append(originalMarkdown);
|
||||
message.append(expandButton);
|
||||
|
||||
originalMarkdown.hide();
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
function copyToClipboard(element) {
|
||||
// Create a temporary textarea element to hold the text
|
||||
var tempTextArea = document.createElement("textarea");
|
||||
tempTextArea.value = element.text();
|
||||
document.body.appendChild(tempTextArea);
|
||||
|
||||
// Select and copy the text from the textarea
|
||||
tempTextArea.select();
|
||||
document.execCommand("copy");
|
||||
|
||||
// Remove the temporary textarea
|
||||
document.body.removeChild(tempTextArea);
|
||||
}
|
||||
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
get_new_messages();
|
||||
setInterval(function () {
|
||||
get_new_messages();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
|
||||
117
chat_visualizer/static/replay.html
Normal file
@ -0,0 +1,117 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="https://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/markdown-it@13.0.1/dist/markdown-it.min.js"></script>
|
||||
<link rel="stylesheet" href="replay/css/use.css">
|
||||
<link rel="stylesheet" href="replay/css/github-markdown-dark.css">
|
||||
|
||||
<head>
|
||||
<title>chatdev demo </title>
|
||||
<link rel="icon" type="image/png" href="figures/ceo.png">
|
||||
</head>
|
||||
|
||||
<body style="display: flex;flex: auto; ">
|
||||
|
||||
<div id="operation">
|
||||
<div id="title" style="display: block;position: relative;height: 100px;">
|
||||
<img src="figures/chatdev.png" style="width: 364px;height: 128px; position: relative;top:40px;left:75px;">
|
||||
<p style="color:aliceblue; font-size: larger;font-weight: bolder;position: relative;top:20px;left:40px;text-shadow: 0px 0px 0px rgb(252, 252, 252);">
|
||||
Communicative Agents for Software Development</p>
|
||||
</div>
|
||||
<div id="imgShow">
|
||||
<img src="figures/company.png" alt="chatdev-company" id="chatdev-company">
|
||||
<img src="figures/right.png" id="right" class="blinking-animation" style="display: none;position: relative; width: 40px;height: 40px;top: -360px;left: 420px">
|
||||
<img src="figures/left.png" id="left" class="blinking-animation" style="display: none;width: 40px;height: 40px;position: relative; top: -465px;left: 125px">
|
||||
</div>
|
||||
<div style="position: relative;top:200px;display: flex;">
|
||||
<div> <input type="file" id="fileInput" accept=".log" onchange="watchfileInput(this.files)">
|
||||
<button id="filebutton" class="button">File Upload</button>
|
||||
</div>
|
||||
<div><button id="replay" class="button">Replay</button></div>
|
||||
</div>
|
||||
<div class="markdown-body"><label for="filebutton" id="successupload">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="show" style="display: grid;">
|
||||
|
||||
<div id="humanRequest" style="position: relative; overflow: auto; padding: 0 10px">
|
||||
<p id="Requesttext" style=" color:aliceblue; display: block;font-weight: 900; max-height: 18px; max-width: 800px;">Task: </p>
|
||||
</div>
|
||||
<div id="dialogBody" style="top:20px;display: flex;flex-direction: column;">
|
||||
</div>
|
||||
<div id="speedcontrol">
|
||||
<input type="range" id="speed" name="speed" min="0" max="100" onchange="speedchange()">
|
||||
<label for="speed">Replaying Speed</label>
|
||||
</div>
|
||||
<div id="dialogStatistic" style="display: flex;flex-direction: column;">
|
||||
<div style="display: flex;width: 2800px;flex-direction: row;height: 60px;">
|
||||
|
||||
<div class="info">
|
||||
<label for="version_updates" style="position: relative;">🔨version_updates</label>
|
||||
<p id="version_updates"></p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<label for="num_code_files" style="position: relative;">📃num_code_files</label>
|
||||
<p id="num_code_files"></p>
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
<label for="num_png_files" style="position: relative;"> 🏞num_png_files</label>
|
||||
<p id="num_png_files"></p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<label for="num_doc_files" style="position: relative;">📚num_doc_files</label>
|
||||
<p id="num_doc_files"></p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<label for="code_lines" style="position: relative;">📃code_lines</label>
|
||||
<p id="code_lines"></p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<label for="env_lines" style="position: relative;">📋env_lines</label>
|
||||
<p id="env_lines"></p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<label for="manual_lines" style="position: relative;">📒manual_lines</label>
|
||||
<p id="manual_lines"></p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<label for="num_utterances" style="position: relative;">🗣num_utterances</label>
|
||||
<p id="num_utterances"></p>
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
<label for="num_self_reflections" style="position: relative;">🤔num_self_reflections</label>
|
||||
<p id="num_self_reflections"></p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<label for="num_prompt_tokens" style="position: relative;">❓num_prompt_tokens</label>
|
||||
<p id="num_prompt_tokens"></p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<label for="num_completion_tokens" style="position: relative;">❗num_completion_tokens</label>
|
||||
<p id="num_completion_tokens"></p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<label for="num_total_tokens" style="position: relative;">⁉️num_total_tokens</label>
|
||||
<p id="num_total_tokens"></p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<label for="cost" style="position: relative;">💰cost</label>
|
||||
<p id="cost"></p>
|
||||
</div>
|
||||
<div class="info">
|
||||
<label for="duration" style="position: relative;">🕑duration</label>
|
||||
<p id="duration"></p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script src="replay/js/app.js"></script>
|
||||
<!--<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
1007
chat_visualizer/static/replay/css/github-markdown-dark.css
Normal file
234
chat_visualizer/static/replay/css/use.css
Normal file
@ -0,0 +1,234 @@
|
||||
p,
|
||||
div,
|
||||
label {
|
||||
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #23252c;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 16px 15px;
|
||||
background: #e2edf0;
|
||||
color: #0b0c0c;
|
||||
font-weight: 800;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
height: 80px;
|
||||
box-shadow: 1px 2px 2px #505757;
|
||||
border-radius: 20px;
|
||||
border: #020202;
|
||||
}
|
||||
|
||||
.blinking-animation {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
animation: blink 1s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#filebutton {
|
||||
position: relative;
|
||||
left: 50px;
|
||||
}
|
||||
|
||||
#title>p {
|
||||
font-size: 30px;
|
||||
color: #fefefe;
|
||||
text-shadow: 0 0 0.5em #0ae642, 0 0 0.2em #5c5c5c;
|
||||
}
|
||||
|
||||
#replay {
|
||||
position: relative;
|
||||
left: 340px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
#successupload {
|
||||
position: absolute;
|
||||
top: 730px;
|
||||
left: 200px;
|
||||
color: antiquewhite;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#successupload>p {
|
||||
position: relative;
|
||||
left: 20px;
|
||||
}
|
||||
|
||||
#fileInput {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#humanRequest {
|
||||
background-color: rgb(30, 39, 46);
|
||||
border: 1px solid #ffffff;
|
||||
border-radius: 10px;
|
||||
box-shadow: 3px 3px 4px black;
|
||||
}
|
||||
|
||||
#dialogBody,
|
||||
#dialogStatistic {
|
||||
width: 790px;
|
||||
height: 570px;
|
||||
background-color: rgb(255, 255, 255);
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 10px;
|
||||
box-shadow: 3px 3px 4px black;
|
||||
overflow: auto;
|
||||
padding: 20px;
|
||||
float: right;
|
||||
position: relative;
|
||||
margin-left: auto;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
#speed {
|
||||
position: relative;
|
||||
width: 600px;
|
||||
top: 35px;
|
||||
right: -150px;
|
||||
}
|
||||
|
||||
#speedcontrol>label {
|
||||
display: block;
|
||||
position: relative;
|
||||
top: 15px;
|
||||
width: 200px;
|
||||
color: aliceblue;
|
||||
font-size: medium;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
[type="range"] {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
background-color: transparent;
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
[type="range"]::-webkit-slider-runnable-track {
|
||||
height: 4px;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
[type="range" i]::-webkit-slider-container {
|
||||
height: 25px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
[type="range"]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 30%;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid transparent;
|
||||
margin-top: -8px;
|
||||
border-image: linear-gradient(#133163, #133163) 0 fill / 8 20 8 0 / 0px 0px 0 2000px;
|
||||
}
|
||||
|
||||
#dialogStatistic {
|
||||
height: 52px;
|
||||
top: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
#test {
|
||||
border: 1px solid rgba(130, 133, 186, 0.3);
|
||||
border-radius: 10px;
|
||||
box-shadow: 1px 2px 2px black;
|
||||
width: 100px;
|
||||
font-size: 18px;
|
||||
display: none;
|
||||
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#imgShow {
|
||||
height: 450px;
|
||||
width: 600px;
|
||||
position: relative;
|
||||
top: 120px;
|
||||
}
|
||||
|
||||
#successupload {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
#show {
|
||||
display: flex;
|
||||
float: right;
|
||||
position: relative;
|
||||
right: -50px;
|
||||
}
|
||||
|
||||
.info>p {
|
||||
font-size: large;
|
||||
font-weight: 900;
|
||||
position: relative;
|
||||
font-style: inherit;
|
||||
color: rgb(12, 13, 13);
|
||||
}
|
||||
|
||||
.info>label {
|
||||
height: 17px;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: block;
|
||||
height: 25px;
|
||||
position: relative;
|
||||
width: 200px;
|
||||
color: rgb(30, 39, 46);
|
||||
border-radius: 10px;
|
||||
font-size: small;
|
||||
font-weight: bold;
|
||||
font-style: inherit;
|
||||
display: block;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
|
||||
/* Optional styles for the text container */
|
||||
|
||||
#text-container {
|
||||
font-size: 24px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
|
||||
/* Animation styles */
|
||||
|
||||
@keyframes revealText {
|
||||
0% {
|
||||
visibility: hidden;
|
||||
}
|
||||
100% {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
578
chat_visualizer/static/replay/js/app.js
Normal file
@ -0,0 +1,578 @@
|
||||
const coordSet = [];
|
||||
coordSet["Chief Executive Officer"] = {
|
||||
"character": "Chief Executive Officer",
|
||||
"imgid": "right",
|
||||
"top": "-315px",
|
||||
"left": "280px"
|
||||
};
|
||||
coordSet["Chief Product Officer"] = {
|
||||
"character": "Chief Product Officer",
|
||||
"imgid": "left",
|
||||
"top": "-165px",
|
||||
"left": "110px"
|
||||
};
|
||||
coordSet["Chief Human Resource Officer"] = {
|
||||
"character": "Chief Human Resource Officer",
|
||||
"imgid": "left",
|
||||
"top": "-305px",
|
||||
"left": "55px"
|
||||
};
|
||||
coordSet["Code Reviewer"] = {
|
||||
"character": "Code Reviewer",
|
||||
"imgid": "left",
|
||||
"top": "-185px",
|
||||
"left": "500px"
|
||||
};
|
||||
coordSet["Programmer"] = {
|
||||
"character": "Programmer",
|
||||
"imgid": "right",
|
||||
"top": "-80px",
|
||||
"left": "300px"
|
||||
};
|
||||
coordSet["Chief Technology Officer"] = {
|
||||
"character": "Chief Technology Officer",
|
||||
"imgid": "right",
|
||||
"top": "-130px",
|
||||
"left": "340px"
|
||||
};
|
||||
coordSet["Chief Creative Officer"] = {
|
||||
"character": "Chief Creative Officer",
|
||||
"imgid": "right",
|
||||
"top": "-95px",
|
||||
"left": "205px"
|
||||
}
|
||||
coordSet["Software Test Engineer"] = {
|
||||
"character": "Software Test Engineer",
|
||||
"imgid": "right",
|
||||
"top": "-90px",
|
||||
"left": "470px"
|
||||
|
||||
}
|
||||
coordSet["User"] = {
|
||||
"character": "User",
|
||||
"imgid": "left",
|
||||
"top": "-465px",
|
||||
"left": "125px"
|
||||
}
|
||||
coordSet["Counselor"] = {
|
||||
"character": "Counselor",
|
||||
"imgid": "right",
|
||||
"top": "-360px",
|
||||
"left": "420px"
|
||||
}
|
||||
coordSet["Prompt Engineer"] = {
|
||||
"character": "Prompt Engineer",
|
||||
"imgid": "right",
|
||||
"top": "-320px",
|
||||
"left": "20px"
|
||||
}
|
||||
const Softwareinfo = {
|
||||
"duration": "-1",
|
||||
"cost": "-1",
|
||||
"version_updates": "-1",
|
||||
"num_code_files": "-1",
|
||||
"num_png_files": "-1",
|
||||
"num_doc_files": "-1",
|
||||
"code_lines": "-1",
|
||||
"env_lines": "-1",
|
||||
"manual_lines": "-1",
|
||||
"num_utterances": "-1",
|
||||
"num_self_reflections": "-1",
|
||||
"num_prompt_tokens": "-1",
|
||||
"num_completion_tokens": "-1",
|
||||
"num_total_tokens": "-1",
|
||||
};
|
||||
|
||||
//control chars appear speed
|
||||
var timeinterval = 5;
|
||||
var charinterval = 1;
|
||||
var scrollinterval = 40;
|
||||
|
||||
var contents;
|
||||
var filename;
|
||||
var curdialog = '';
|
||||
var total_height = 0;
|
||||
|
||||
var cur_para = '';
|
||||
var cur_command = '';
|
||||
var idx = 0;
|
||||
var dialog;
|
||||
|
||||
var replaying = 0;
|
||||
var if_stop = 0;
|
||||
let isPaused = false;
|
||||
let pauseIntervalId;
|
||||
var if_move = true;
|
||||
var md = window.markdownit();
|
||||
|
||||
//watch replay button clicked
|
||||
const button = document.getElementById('replay');
|
||||
button.addEventListener('click', () => {
|
||||
replayDialog(idx);
|
||||
});
|
||||
$(document).ready(function() {
|
||||
$('#filebutton').click(function() {
|
||||
$('#fileInput').click();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
const dialogbody = document.getElementById("dialogBody");
|
||||
dialogbody.addEventListener("mousewheel", handleMouseWheel, false);
|
||||
|
||||
function handleMouseWheel(event) {
|
||||
if (event.wheelDelta > 0) {
|
||||
if_move = false;
|
||||
} else if (event.wheelDelta < 0) {
|
||||
if (dialogbody.scrollTop + dialogbody.clientHeight == dialogbody.scrollHeight) {
|
||||
if_move = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getinterval(speed) {
|
||||
|
||||
if (speed < 80 && speed > 40) {
|
||||
timeinterval = 250 / speed;
|
||||
charinterval = 2;
|
||||
scrollinterval = 80;
|
||||
} else if (speed <= 40 && speed > 0) {
|
||||
timeinterval = 150 / speed;
|
||||
charinterval = 1;
|
||||
scrollinterval = 80;
|
||||
} else if (speed >= 80 && speed < 90) {
|
||||
timeinterval = 100 / speed;
|
||||
charinterval = 1;
|
||||
scrollinterval = 100;
|
||||
} else if (speed >= 90 && speed <= 100) {
|
||||
timeinterval = 5 / speed;
|
||||
charinterval = 1;
|
||||
scrollinterval = 400;
|
||||
}
|
||||
}
|
||||
//use the slider to control the replay speed
|
||||
function speedchange() {
|
||||
var speedbar = document.getElementById("speed");
|
||||
var speed = speedbar.value;
|
||||
if (speed == 0) {
|
||||
if (!isPaused) {
|
||||
isPaused = true;
|
||||
clearInterval(pauseIntervalId);
|
||||
updateCompanyWorking("end");
|
||||
}
|
||||
} else if (speed != 0 && isPaused == true) {
|
||||
getinterval(speed);
|
||||
isPaused = false;
|
||||
idx += 1;
|
||||
replayDialog(idx);
|
||||
} else if (speed != 0) {
|
||||
isPaused = false;
|
||||
getinterval(speed);
|
||||
}
|
||||
}
|
||||
// do replay
|
||||
async function replayDialog(idx) {
|
||||
if (replaying == 1 && idx == 0) {
|
||||
return;
|
||||
}
|
||||
if (idx == 0) {
|
||||
replaying = 1;
|
||||
dialog = extraction(contents);
|
||||
var filelable = document.getElementById("successupload");
|
||||
filelable.style.display = "block";
|
||||
var info = "Replaying `" + filename + "` ......";
|
||||
filelable.innerHTML = md.render(info);
|
||||
}
|
||||
for (let i = idx; i < dialog.length; ++i) {
|
||||
await createPara(dialog[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
//watch .log file input
|
||||
function watchfileInput(files) {
|
||||
if (files.length) {
|
||||
const file = files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function() {
|
||||
contents = this.result;
|
||||
};
|
||||
reader.readAsText(file);
|
||||
var filelable = document.getElementById("successupload");
|
||||
filelable.style.display = "block";
|
||||
var info = "File uploaded (`" + file.name + "`). Please click **\"Replay\"** to show ChatDev's development process";
|
||||
filename = file.name;
|
||||
filelable.innerHTML = md.render(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//extract information
|
||||
function extraction(contents) {
|
||||
const regex = /\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} \w+)\] ([.\s\S\n\r\d\D\t]*?)(?=\n\[\d|$)/g;
|
||||
|
||||
var matches = [];
|
||||
|
||||
let match;
|
||||
var itemp = 0;
|
||||
while ((match = regex.exec(contents))) {
|
||||
console.log(itemp);
|
||||
itemp++;
|
||||
const timestamp = match[1];
|
||||
const text = match[2];
|
||||
matches.push({
|
||||
timestamp,
|
||||
text
|
||||
});
|
||||
}
|
||||
const regex_assistant = /(.*):([.\r\n\s\S\t\d\D]*)<->([.\r\n\s\S\t\d\D]*?)\]([.\r\n\s\S\t\d\D]*)/g;
|
||||
const regex_user = /(.*):(.*)(\[Start Chat\])([.\r\n\s\S\t\d\D]*?)\]([.\r\n\s\S\t\d\D]*)/g;
|
||||
const regex_prompt = /(Prompt Engineer):([\S\s]*)/g
|
||||
|
||||
const regex_end = /(AgentTech Ends|ChatDev Ends)/g;
|
||||
const regex_start = /(ChatDev Starts)([\D\s])*(\d*)/g;
|
||||
|
||||
const regex_task = /(task_prompt)(.*):(.*)/g;
|
||||
const regex_info = /Software Info([\r\n\s\S\t\d\D]*)/g;
|
||||
|
||||
const regex_system = /System/g;
|
||||
const regex_debug = /DEBUG/g;
|
||||
|
||||
var dialog = [];
|
||||
var count = 0;
|
||||
|
||||
for (let i = 0; i < matches.length; ++i) {
|
||||
var if_break = false;
|
||||
console.log(i);
|
||||
if (i == 159 || i == 198 || i == 223 || i == 260 || i == 416 || i == 537) {
|
||||
//console.log(matches[i]);
|
||||
}
|
||||
while ((match = regex_debug.exec(matches[i].timestamp)) !== null) {
|
||||
if_break = true;
|
||||
}
|
||||
while ((match = regex_system.exec(matches[i].text)) !== null) {
|
||||
if_break = true;
|
||||
}
|
||||
while (((match = regex_prompt.exec(matches[i].text)) !== null)) {
|
||||
const type = "assitant";
|
||||
const character = match[1];
|
||||
const command = match[2];
|
||||
const len = match[2].length;
|
||||
count += 1;
|
||||
dialog.push({
|
||||
type,
|
||||
character,
|
||||
command,
|
||||
len,
|
||||
count
|
||||
});
|
||||
if_break = true;
|
||||
}
|
||||
if (if_break) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while ((match = regex_assistant.exec(matches[i].text)) !== null) {
|
||||
const type = "assitant";
|
||||
const character = match[1];
|
||||
const command = match[4];
|
||||
const len = match[4].length;
|
||||
count += 1;
|
||||
dialog.push({
|
||||
type,
|
||||
character,
|
||||
command,
|
||||
len,
|
||||
count
|
||||
});
|
||||
|
||||
}
|
||||
while ((match = regex_user.exec(matches[i].text)) !== null) {
|
||||
const type = "user";
|
||||
const character = match[1];
|
||||
const command = match[5];
|
||||
const len = match[5].length;
|
||||
count += 1;
|
||||
dialog.push({
|
||||
type,
|
||||
character,
|
||||
command,
|
||||
len,
|
||||
count
|
||||
});
|
||||
}
|
||||
while ((match = regex_start.exec(matches[i].text)) !== null) {
|
||||
const start = match[1];
|
||||
const len = match[1].length;
|
||||
dialog.push({
|
||||
start,
|
||||
len,
|
||||
});
|
||||
|
||||
}
|
||||
while ((match = regex_end.exec(matches[i].text)) !== null) {
|
||||
const end = match[1];
|
||||
const len = match[1].length;
|
||||
dialog.push({
|
||||
end,
|
||||
len,
|
||||
});
|
||||
|
||||
}
|
||||
while ((match = regex_task.exec(matches[i].text)) !== null) {
|
||||
const task = match[3];
|
||||
dialog.push({
|
||||
task
|
||||
});
|
||||
|
||||
}
|
||||
while ((match = regex_info.exec(matches[i].text)) !== null) {
|
||||
const info = match[1];
|
||||
if ((/code_lines(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info) != null) {
|
||||
Softwareinfo.code_lines = (/code_lines(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info)[1];
|
||||
}
|
||||
if ((/num_code_files(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info) != null) {
|
||||
Softwareinfo.num_code_files = (/num_code_files(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info)[1];
|
||||
}
|
||||
if ((/num_png_files(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info) != null) {
|
||||
Softwareinfo.num_png_files = (/num_png_files(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info)[1];
|
||||
}
|
||||
if ((/num_doc_files(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info) != null) {
|
||||
Softwareinfo.num_doc_files = (/num_doc_files(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info)[1];
|
||||
}
|
||||
if ((/env_lines(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info) != null) {
|
||||
Softwareinfo.env_lines = (/env_lines(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info)[1];
|
||||
}
|
||||
if ((/manual_lines(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info) != null) {
|
||||
Softwareinfo.manual_lines = (/manual_lines(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info)[1];
|
||||
}
|
||||
if ((/duration(?:[\t\n\r\s\D]*?)=(-?(\d*)(.(\d)*)?s)/g).exec(info) != null) {
|
||||
Softwareinfo.duration = (/duration(?:[\t\n\r\s\D]*?)=(-?(\d*)(.(\d)*)?s)/g).exec(info)[1];
|
||||
}
|
||||
if ((/num_utterances(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info) != null) {
|
||||
Softwareinfo.num_utterances = (/num_utterances(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info)[1];
|
||||
}
|
||||
if ((/num_self_reflections(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info) != null) {
|
||||
Softwareinfo.num_self_reflections = (/num_self_reflections(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info)[1];
|
||||
}
|
||||
if ((/num_prompt_tokens(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info) != null) {
|
||||
Softwareinfo.num_prompt_tokens = (/num_prompt_tokens(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info)[1];
|
||||
}
|
||||
if ((/num_completion_tokens(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info) != null) {
|
||||
Softwareinfo.num_completion_tokens = (/num_completion_tokens(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info)[1];
|
||||
}
|
||||
if ((/num_total_tokens(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info) != null) {
|
||||
Softwareinfo.num_total_tokens = (/num_total_tokens(?:[\t\n\r\s\D]*?)=(-?(\d*))/g).exec(info)[1];
|
||||
}
|
||||
if ((/cost(?:[\t\n\r\s\D]*?)=(.((\d)*\.(\d)*))/g).exec(info) != null) {
|
||||
Softwareinfo.cost = (/cost(?:[\t\n\r\s\D]*?)=(.((\d)*\.(\d)*))/g).exec(info)[1];
|
||||
}
|
||||
if ((/version_updates(?:[\t\n\r\s\D]*?)=(-?\d*)/g).exec(info) != null) {
|
||||
Softwareinfo.version_updates = (/version_updates(?:[\t\n\r\s\D]*?)=(-?\d*)/g).exec(info)[1];
|
||||
}
|
||||
|
||||
dialog.push({
|
||||
info,
|
||||
Softwareinfo
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
//show dailog
|
||||
function createPara(d, i) {
|
||||
const singleDialog = document.createElement("div");
|
||||
singleDialog.style.position = "relative";
|
||||
curdialog = singleDialog;
|
||||
singleDialog.style.display = "flex";
|
||||
singleDialog.style.flexDirection = "column";
|
||||
singleDialog.style.width = "773px";
|
||||
dialogbody.appendChild(singleDialog);
|
||||
var paralen;
|
||||
if (d.type && d.character) {
|
||||
updateCompanyWorking(d.character);
|
||||
var renderedHtml = md.render(d.character);
|
||||
const character = document.createElement("div");
|
||||
character.style.display = "flex";
|
||||
|
||||
character.style.backgroundColor = "lightblue";
|
||||
character.style.width = "fit-content";
|
||||
character.style.padding = "5px 20px";
|
||||
character.style.marginBottom = "5px";
|
||||
character.style.fontSize = "13px ";
|
||||
character.style.border = "1px solid rgba(11, 20, 150, .3)";
|
||||
character.style.borderRadius = "10px";
|
||||
character.style.boxShadow = "2px 2px 2px black";
|
||||
character.style.fontFamily = "'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;";
|
||||
|
||||
if (d.type == "user") {
|
||||
character.style.position = "relative";
|
||||
character.style.marginLeft = "auto";
|
||||
}
|
||||
character.innerHTML = renderedHtml;
|
||||
singleDialog.appendChild(character);
|
||||
|
||||
const characterimg = document.createElement("img");
|
||||
console.log(d.character);
|
||||
if (d.character == "Programmer") {
|
||||
characterimg.src = "figures/programmer.png";
|
||||
} else if (d.character == "Code Reviewer") {
|
||||
characterimg.src = "figures/reviewer.png";
|
||||
} else if (d.character == "Chief Human Resource Officer") {
|
||||
characterimg.src = "figures/hr.png";
|
||||
} else if (d.character == "Chief Executive Officer") {
|
||||
characterimg.src = "figures/ceo.png";
|
||||
} else if (d.character == "Chief Product Officer") {
|
||||
characterimg.src = "figures/cpo.png";
|
||||
} else if (d.character == "Chief Technology Officer") {
|
||||
characterimg.src = "figures/cto.png";
|
||||
} else if (d.character == "Chief Creative Officer") {
|
||||
characterimg.src = "figures/designer.png";
|
||||
} else if (d.character == "Software Test Engineer") {
|
||||
characterimg.src = "figures/tester.png";
|
||||
} else if (d.character == "User") {
|
||||
characterimg.src = "figures/user.png";
|
||||
} else if (d.character == "Counselor") {
|
||||
characterimg.src = "figures/counselor.png";
|
||||
} else if (d.character == "Prompt Engineer") {
|
||||
characterimg.src = "figures/pe.png";
|
||||
}
|
||||
|
||||
characterimg.style.height = "40px";
|
||||
characterimg.style.width = "30px";
|
||||
characterimg.style.position = "relative";
|
||||
characterimg.style.marginLeft = "10px";
|
||||
character.appendChild(characterimg);
|
||||
character.style.width = "fit-content";
|
||||
|
||||
|
||||
var renderedHtml = md.render(d.command);
|
||||
const paragraph = document.createElement("div");
|
||||
paragraph.className = "markdown-body";
|
||||
//paragraph.innerHTML = renderedHtml;
|
||||
paragraph.style.padding = "10px";
|
||||
paragraph.style.border = "3px solid #a08D8D";
|
||||
paragraph.style.width = "750px";
|
||||
paragraph.style.border = "1px solid rgba(11, 20, 150, .3)";
|
||||
paragraph.style.borderRadius = "10px";
|
||||
paragraph.style.boxShadow = "2px 2px 2px black";
|
||||
|
||||
singleDialog.appendChild(paragraph);
|
||||
|
||||
const emptyparagraph = document.createElement("div");
|
||||
emptyparagraph.style.height = "10px";
|
||||
singleDialog.appendChild(emptyparagraph);
|
||||
|
||||
if (d.type == "user") {
|
||||
paragraph.style.backgroundColor = "#4b751a";
|
||||
} else {
|
||||
paragraph.style.backgroundColor = "#133153";
|
||||
}
|
||||
cur_command = d.command;
|
||||
cur_para = paragraph;
|
||||
idx = i;
|
||||
return Promise.resolve(printCommand(paragraph, d.command));
|
||||
|
||||
} else if (d.start) {
|
||||
paralen = 0;
|
||||
var renderedHtml = md.render("----------" + d.start + "----------");
|
||||
const starttext = document.createElement("div");
|
||||
starttext.innerHTML = renderedHtml;
|
||||
singleDialog.appendChild(starttext);
|
||||
|
||||
} else if (d.end) {
|
||||
paralen = 0;
|
||||
updateCompanyWorking("end");
|
||||
var renderedHtml = md.render("----------" + d.end + "----------");
|
||||
const endtext = document.createElement("div");
|
||||
endtext.innerHTML = renderedHtml;
|
||||
singleDialog.appendChild(endtext);
|
||||
var filelable = document.getElementById("successupload");
|
||||
filelable.style.display = "block";
|
||||
var info = "Replayed";
|
||||
filelable.innerHTML = md.render(info);
|
||||
} else if (d.task) {
|
||||
var renderedHtml = md.render("Task: " + d.task);
|
||||
const tasktext = document.getElementById("Requesttext");
|
||||
tasktext.innerHTML = renderedHtml;
|
||||
} else if (d.info) {
|
||||
var renderedHtml = md.render(d.info);
|
||||
const infotext = document.getElementById("dialogStatistic");
|
||||
var temp_label = "";
|
||||
for (var c in Softwareinfo) {
|
||||
temp_label = document.getElementById(c);
|
||||
if (Softwareinfo[c] != "-1" && Softwareinfo[c] != "-1s") {
|
||||
temp_label.innerHTML = Softwareinfo[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//update company image
|
||||
function updateCompanyWorking(character) {
|
||||
if (character == "end") {
|
||||
var img1 = document.getElementById("right");
|
||||
img1.style.display = "none";
|
||||
var img2 = document.getElementById("left");
|
||||
img2.style.display = "none";
|
||||
return;
|
||||
}
|
||||
var imgid = coordSet[character].imgid;
|
||||
var left_bias = coordSet[character].left;
|
||||
var top_bias = coordSet[character].top;
|
||||
var img = document.getElementById(imgid);
|
||||
|
||||
img.style.display = "block";
|
||||
img.style.left = left_bias;
|
||||
img.style.top = top_bias;
|
||||
|
||||
if (imgid == "left") {
|
||||
var another_img = document.getElementById("right");
|
||||
another_img.style.display = "none";
|
||||
} else {
|
||||
var another_img = document.getElementById("left");
|
||||
another_img.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
async function updateParashow(container, command, index, len) {
|
||||
var cur_content;
|
||||
if (index == len - 1) {
|
||||
cur_content = command.slice(0, index);
|
||||
}
|
||||
if (index < len) {
|
||||
cur_content = command.slice(0, index);
|
||||
if (cur_content != null && cur_content != undefined) {
|
||||
container.innerHTML = md.render(cur_content);
|
||||
};
|
||||
}
|
||||
if (index % (scrollinterval) == 0 && if_move == true) {
|
||||
if (curdialog != null && curdialog != '') {
|
||||
const newBoxRect = curdialog.getBoundingClientRect();
|
||||
total_height += newBoxRect.height;
|
||||
dialogbody.scrollTo({ top: total_height, behavior: 'smooth' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function printCommand(paragraph, command) {
|
||||
var paralen = command.length;
|
||||
const tasks = [];
|
||||
|
||||
for (let j = 0; j < paralen; j = j + charinterval) {
|
||||
tasks.push(new Promise(resolve => {
|
||||
pauseIntervalId = setTimeout(() => {
|
||||
updateParashow(paragraph, command, j, paralen);
|
||||
resolve();
|
||||
}, timeinterval * j);
|
||||
}));
|
||||
|
||||
if (isPaused) {
|
||||
await Promise.all(tasks);
|
||||
}
|
||||
}
|
||||
await Promise.all(tasks);
|
||||
return 1;
|
||||
}
|
||||