santanavagner's picture
Update static/demo/index.html
8ac840f verified
<!DOCTYPE html>
<html lang="en">
<head>
<title>Responsible Prompting Demo</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/carbon-components/css/carbon-components.min.css">
<script type="text/javascript" src="static/demo/js/d3.v7.min.js"></script>
<script type="text/javascript" src="static/demo/js/jquery-3.7.1.min.js"></script>
<!-- <script type="text/javascript" src="js/d3.v7.min.js"></script>
<script type="text/javascript" src="js/jquery-3.7.1.min.js"></script> -->
<style type="text/css">
div.tooltip {
position: absolute;
text-align: left;
padding: 0.5em;
width: 20em;
min-height: 5em;
background: #fff;
color: #000;
border: 1px solid #000;
border-radius: 5px;
pointer-events: none;
font-size: inherit;
font-family: inherit;
}
</style>
</head>
<body>
<div class="bx--grid">
<div class="bx--row">
<div class="bx--col-lg-10 bx--offset-lg-1">
<h1 class="bx--type-expressive-heading-03" style="margin-top: 1em;">Responsible Prompting</h1>
<p class="bx--type-body-long-01"><br>Please provide a prompt that would be sent to an LLM. Recommendations are performed in prompting-time, before content generation. The recommendations consider a curated dataset of values and prompts sentences. The recommendations are based on the similarity between the input sentences and our prompt sentences dataset.<br><br></p>
<div class="bx--tabs">
<ul class="bx--tabs__nav">
<li class="bx--tabs__nav-item bx--tabs__nav-item--selected" id="tab-1" data-target="#tab-content-1">
<a class="bx--tabs__nav-link" href="#" onclick="$('#tab-content-1').toggle();$('#tab-1').toggleClass('bx--tabs__nav-item--selected');$('#tab-content-2').toggle();$('#tab-2').toggleClass('bx--tabs__nav-item--selected');">Prompt</a>
</li>
<li class="bx--tabs__nav-item" data-target="#tab-content-2" id="tab-2">
<a class="bx--tabs__nav-link" href="#" onclick="$('#tab-content-1').toggle();$('#tab-1').toggleClass('bx--tabs__nav-item--selected');$('#tab-content-2').toggle();$('#tab-2').toggleClass('bx--tabs__nav-item--selected');renderGraph($('#prompt').data('recommendations'))">Graph</a>
</li>
</ul>
</div>
<form class="bx--form" id="demo">
<div class="bx--tab-content">
<div id="tab-content-1" class="bx--tab-content__section">
<div class="bx--form-item">
<textarea id="prompt" name="prompt" class="bx--text-area" rows="15" placeholder="Enter your prompt">Act as a professional designer with 20 years of experience creating and testing UX interfaces and landing sites for a variety of IT applications. We are in need of more people and an increased budget to be able to keep up with clients' needs. What kind of evidence should I gather to support my demands to gain more resources?</textarea>
<div id="recommendation" style="min-height: 3em;" class="bx--form__helper-text"></div>
</div>
</div>
<div id="tab-content-2" class="bx--tab-content__section bx--tab-content--hidden" style="display: none;">
<div class="bx--form-item" id="graph" style="background: #efefef"></div>
</div>
</div>
<div class="bx--form-item" style="margin-bottom: 2em;">
<button id="generate" type="submit" class="bx--btn bx--btn--primary">Generate</button>
</div>
<div class="bx--form-item">
<label for="outcome" id="outcome-label" class="bx--label">Generated text</label>
<textarea id="outcome" name="outcome" class="bx--text-area" rows="12" placeholder=""></textarea>
</div>
</form>
</div>
</div>
</div>
<script src="./js/jquery-3.7.1.min.js"></script>
<script lang="javascript">
const width = 600;
const height = 200;
const marginTop = 30;
const marginRight = 30;
const marginBottom = 30;
const marginLeft = 30;
const nodeRadius = 3;
const svg = d3.select("#graph").append("svg")
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto; font: 8px sans-serif;");
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
const renderGraph = (recommendations) => {
if( !recommendations ){
return ;
}
svg.selectAll("*").remove(); // Clearing previous plots
var graphData = {nodes: [], edges: []}
var i = j = 0;
if( recommendations['input'].length > 0 ){
graphData.nodes.push({
id: 0,
x: Number(recommendations['input'][0].x),
y: Number(recommendations['input'][0].y),
text: recommendations['input'][0].sentence,
label: 'S' + (i+1),
type: 'input'
})
for( i = 1; i < recommendations['input'].length; i++ ){
graphData.nodes.push({
id: i,
x: Number(recommendations['input'][i].x),
y: Number(recommendations['input'][i].y),
text: recommendations['input'][i].sentence,
label: 'S' + (i+1),
type: 'input'
});
graphData.edges.push({ source: (i-1), target: i, type: 'input' });
}
}
// Adding nodes & edges for inclusion recommendations
if( recommendations['add'].length > 0 ){
for( j = 0; j < recommendations['add'].length; j++ ){
graphData.nodes.push({
id: i + j + 1,
x: Number(recommendations['add'][j].x),
y: Number(recommendations['add'][j].y),
text: recommendations['add'][j].prompt,
label: recommendations['add'][j].value,
type: 'add'
});
graphData.edges.push({ source: (i-1), target: (i+j+1), type: 'add' });
}
}
// Adding nodes & edges for removal recommendations
if( recommendations['remove'].length > 0 ){
// Showing only the first removal recommendation
graphData.nodes.push({
id: i + j,
x: Number(recommendations['remove'][0].x),
y: Number(recommendations['remove'][0].y),
text: recommendations['remove'][0].closest_harmful_sentence,
label: recommendations['remove'][0].value,
type: 'remove'
});
}
// Convert edge references to actual node objects
graphData.edges = graphData.edges.map(edge => ({
source: graphData.nodes.find(n => n.id === edge.source),
target: graphData.nodes.find(n => n.id === edge.target)
}));
const { nodes, edges } = graphData;
// Prepare the ranges of values for the axes
const xDomain = d3.extent(nodes, d => d.x);
const yDomain = d3.extent(nodes, d => d.y);
const xPadding = 2
const yPadding = 2
// Prepare the scales for positional encoding.
const x = d3.scaleLinear()
.domain([xDomain[0]-xPadding,xDomain[1]+xPadding]).nice()
.range([marginLeft, width - marginRight]);
const y = d3.scaleLinear()
.domain([yDomain[0]-yPadding,yDomain[1]+yPadding]).nice()
.range([height - marginBottom, marginTop]);
// Create the axes.
svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(d3.axisBottom(x).ticks(width / 80))
.call(g => g.select(".domain").remove())
.call(g => g.append("text")
.attr("x", width)
.attr("y", marginBottom - 4)
.attr("fill", "currentColor")
.attr("text-anchor", "end")
.text("Semantic dimension 1"));
svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(d3.axisLeft(y))
.call(g => g.select(".domain").remove())
.call(g => g.append("text")
.attr("x", -marginLeft)
.attr("y", 10)
.attr("fill", "currentColor")
.attr("text-anchor", "start")
.text("Semantic dimension 2"));
// Create the grid.
svg.append("g")
.attr("stroke", "#cccccc")
.attr("stroke-opacity", 0.5)
.call(g => g.append("g")
.selectAll("line")
.data(x.ticks())
.join("line")
.attr("x1", d => 0.5 + x(d))
.attr("x2", d => 0.5 + x(d))
.attr("y1", marginTop)
.attr("y2", height - marginBottom))
.call(g => g.append("g")
.selectAll("line")
.data(y.ticks())
.join("line")
.attr("y1", d => 0.5 + y(d))
.attr("y2", d => 0.5 + y(d))
.attr("x1", marginLeft)
.attr("x2", width - marginRight));
// Add a layer of dots.
svg.append("g")
.attr("stroke-width", 2.5)
.attr("stroke-opacity", 0.5)
.attr("fill", "none")
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("stroke", d => d.type == "add" ? "green" : d.type == "input"? "#666" : "red" )
.attr("cx", d => x(d.x))
.attr("cy", d => y(d.y))
.attr("r", nodeRadius);
// Add a layer of labels.
svg.append("g")
.attr("font-family", "sans-serif")
.attr("text-opacity", 0.5)
.attr("font-size", 8)
.selectAll("text")
.data(nodes)
.join("text")
.attr("dy", "0.35em")
.attr("x", d => x(d.x)+5)
.attr("y", d => y(d.y))
.text(d => d.label)
.on('mousemove', function (d, i) {
d3.select(this).transition()
.duration("50")
.attr("text-opacity", 1.0)
.attr("stroke", "white")
.attr("stroke-width", 3)
.style("paint-order", "stroke fill")
.attr("fill", d => d.type == "add" ? "green" : d.type == "input"? "black" : "red" )
tooltip.transition()
.duration(50)
.style("opacity", 1);
tooltip.html( "<strong>" + i.label + ":</strong><br>" + i.text )
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY + 10) + "px");
;
})
.on('mouseout', function (d, i) {
d3.select(this).transition()
.duration("50")
.attr("text-opacity", 0.5)
.attr("stroke-width", 0)
.style("paint-order", "stroke fill")
.attr("fill", "black")
tooltip.transition()
.duration(50)
.style("opacity", 0);
});
// Adding edges
svg.append("g")
.selectAll("line")
.data(edges)
.join("line")
.attr("stroke", "#666")
.attr("stroke-opacity", 0.5)
.attr("x1", d => x(d.source.x)+(d.source.x<d.target.x?1.3*nodeRadius:nodeRadius*-1.3))
.attr("y1", d => y(d.source.y))
.attr("x2", d => x(d.target.x)+(d.source.x>d.target.x?1.3*nodeRadius:nodeRadius*-1.3))
.attr("y2", d => y(d.target.y))
.style("stroke-dasharray", d => d.target.type == "add" ? "3,3" : "");
};
// ------------------------------------------------
// Init state
if( $( "#prompt" ).val() == "" ){
$( "#generate" ).attr( "disabled", true ) ;
}
var last_request = Date.now() - 60 * 60 * 1000 ;
var last_prompt = $( "#prompt" ).val().trim() ;
// Add recommendations to the prompt
function add_recommendation( p ){
preview_add_recommendation( p, "hide" )
$( "#prompt" ).val( $( "#prompt" ).val() + " " + p ) ;
$( "#recommendation" ).html( "" ) ;
$( "#prompt" ).trigger( "keyup" ) ; // Looking for recommendations after accepting a recommendation
}
// Preview for add recommendation
function preview_add_recommendation( p, flag ){
if( flag == "show" ){
$( "#prompt" ).val( $( "#prompt" ).val() + " " + p ) ;
}
else{
$( "#prompt" ).val( $( "#prompt" ).val().replace( " " + p, "" ) ) ;
}
}
// Remove adversarial sentences from prompt
function remove_recommendation( p ){
$( "#prompt" ).val( $( "#prompt" ).val().replace( p, "" ) ) ;
$( "#prompt" ).val( $( "#prompt" ).val().replace( " ", " " ) ) ;
$( "#recommendation" ).html( "" ) ;
$( "#prompt" ).trigger( "keyup" ) ; // Looking for recommendations after accepting a recommendation
}
// Preview for add recommendation
function preview_remove_recommendation( p, flag ){
if( flag == "show" ){
$( "#prompt" ).data( "previous_prompt", $( "#prompt" ).val() ) ;
$( "#prompt" ).val( $( "#prompt" ).val().replace( p, "" ) ) ;
}
else{
$( "#prompt" ).val( $( "#prompt" ).data( "previous_prompt" ) ) ;
}
}
// Listening to changes performed on the prompt input field
$( "#prompt" ).on( "keyup", function( e ){
// Updating the generate button state based on prompt length
if( $( "#prompt" ).val().length > 0 ){
$( "#generate" ).removeAttr( "disabled" ) ;
}
else{
$( "#generate" ).attr( "disabled", true ) ;
}
// Minimum timeout between the requests
if( Date.now() - last_request > 500 && last_prompt != $( "#prompt" ).val().trim() ){
last_request = Date.now() ;
last_prompt = $( "#prompt" ).val().trim() ;
// Getting the last typed char
var last_char = $( "#prompt" ).val().trim().slice( -1 ) ;
// Triggering the API request when ending of a sentence is found, e.g., .?!
if( last_char == "." || last_char == "?" || last_char == "!" ){
$( "#recommendation" ).html( 'Requesting recommendations: <div class="bx--tag bx--tag--gray bx--tag--deletable">...</div>' ) ;
var api_url = "/recommend?prompt="
// var api_url = "/recommend_local?prompt="
var p = $( "#prompt" ).val() ;
// API request
$.getJSON( api_url + encodeURI( p ), function( data ) {
$( "#recommendation" ).html( "Recommendations: " ) ;
// Looking first for removal recommendations
// if( data["remove"].length > 0 && data["remove"][0].similarity > 0.5 ){
if( data["remove"].length > 0 ){
for( var i = 0; i < data["remove"].length ; i++ ){
// $( "#prompt" ).html( $( "#prompt" ).html().replace( data["remove"][i].sentence, '<span style="text-decoration: underline red">' + data["remove"][i].sentence + '</span>' ) ) ;
var sentence = data["remove"][i].sentence.replaceAll( "'", "\\'" ) ;
var sentence_entity = data["remove"][i].sentence.replaceAll( "'", "&apos;" ) ;
var sentence_value = data["remove"][i].value.replaceAll( "'", "\\'" ) ;
$( "#recommendation" ).append( '<div class="bx--tag bx--tag--red bx--tag--deletable" style="cursor: pointer;" onmouseover="preview_remove_recommendation(\''+ sentence + '\', \'show\')" onmouseout="preview_remove_recommendation(\''+ sentence + '\', \'hide\')" onclick="remove_recommendation(\''+ sentence + '\')">x ' + sentence_value + '</div>' ) ;
break ; // Showing only once removal recommendation at a time
}
}
// else if( data["add"].length > 0 ){ // After the removal recommendations are dealt with, then we show recommendations for inclusion
if( data["add"].length > 0 ){ // Think Demo UX
for( var i = 0; i < data["add"].length; i++ ){
if( $( "#prompt" ).val().indexOf( data["add"][i].prompt ) == -1 ){
// Adding only recommendations that are not present in the prompt
var sentence = data["add"][i].prompt.replaceAll( "'", "\\'" ) ;
var sentence_entity = data["add"][i].prompt.replaceAll( "'", "&apos;" ) ;
var sentence_value = data["add"][i].value.replaceAll( "'", "\\'" ) ;
$( "#recommendation" ).append( '<div class="bx--tag bx--tag--green" style="cursor: pointer;" onmouseover="preview_add_recommendation(\''+ sentence + '\', \'show\')" onmouseout="preview_add_recommendation(\''+ sentence + '\', \'hide\')" onclick="add_recommendation(\''+ sentence + '\')">+ ' + sentence_value + '</div>' ) ;
}
}
}
// User status message about recommendations found
if( data["add"].length == 0 && data["remove"].length == 0 ){
$( "#recommendation" ).html( "No recommendations found." ) ;
}
$("#prompt").data( "recommendations", data );
// renderGraph(data);
});
}
}
});
// Generation request
$( "#demo" ).on( "submit", function(e){ // Hugging Face
$( "#generate" ).toggleClass( "bx--btn--disabled" ) ;
( function loading_animation(){
if( $( "#outcome" ).attr( "placeholder" ) == "" ){
$( "#outcome" ).attr( "placeholder", "Requesting content." ) ;
}
else if( $( "#outcome" ).attr( "placeholder" ).length < 21 ){
$( "#outcome" ).attr( "placeholder", $( "#outcome" ).attr( "placeholder") + "." ) ;
}
else{
$( "#outcome" ).attr( "placeholder", "Requesting content." ) ;
}
setTimeout( loading_animation, 500 );
} )()
$.ajax({
url: encodeURI("/demo_inference?prompt=" + $("#prompt").val()),
dataType: 'json',
success: function(data){
console.log("Inference response")
console.log(data)
// Resetting the status of the button
$( "#generate" ).toggleClass( "bx--btn--disabled" ) ;
// Clearing the previous timeout
if( $( "#demo" ).data( "timeoutId" ) != "" ){
clearTimeout( $( "#demo" ).data( "timeoutId" ) );
$( "#demo" ).data( "timeoutId", "" ) ;
}
out = data.content.split("");
model_id = data.model_id;
temperature = data.temperature
max_new_tokens = data.max_new_tokens
$( "#outcome" ).append( "\n\n+ ------------------------------------\n| Model: " + model_id + "\n| Temperature: " + temperature + "\n| Max new tokens: " + max_new_tokens + "\n+ ------------------------------------\n\n" ) ;
// Animating the generated output
( function typing_animation(){
$( "#outcome" ).append( out.shift() ) ;
$( "#outcome" ).scrollTop( $( "#outcome" )[0].scrollHeight ) ;
if( out.length > 0 ) {
const timeoutId = setTimeout( typing_animation, 5 );
$( "#demo" ).data( "timeoutId", timeoutId ) ;
}
} )()
},
error: function(data) {
out = data.responseJSON.error.message
$( "#outcome" ).val(out);
}
})
// Returning false so the form keeps user in the same page
return false;
});
</script>
<!-- <script src="https://unpkg.com/carbon-components/scripts/carbon-components.min.js"></script> -->
</body>
</html>