|
<!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> |
|
|
|
|
|
<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(); |
|
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' }); |
|
} |
|
} |
|
|
|
|
|
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' }); |
|
} |
|
} |
|
|
|
|
|
if( recommendations['remove'].length > 0 ){ |
|
|
|
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' |
|
}); |
|
} |
|
|
|
|
|
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; |
|
|
|
|
|
const xDomain = d3.extent(nodes, d => d.x); |
|
const yDomain = d3.extent(nodes, d => d.y); |
|
const xPadding = 2 |
|
const yPadding = 2 |
|
|
|
|
|
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]); |
|
|
|
|
|
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")); |
|
|
|
|
|
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)); |
|
|
|
|
|
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); |
|
|
|
|
|
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); |
|
}); |
|
|
|
|
|
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" : ""); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
if( $( "#prompt" ).val() == "" ){ |
|
$( "#generate" ).attr( "disabled", true ) ; |
|
} |
|
var last_request = Date.now() - 60 * 60 * 1000 ; |
|
var last_prompt = $( "#prompt" ).val().trim() ; |
|
|
|
|
|
function add_recommendation( p ){ |
|
preview_add_recommendation( p, "hide" ) |
|
$( "#prompt" ).val( $( "#prompt" ).val() + " " + p ) ; |
|
$( "#recommendation" ).html( "" ) ; |
|
$( "#prompt" ).trigger( "keyup" ) ; |
|
} |
|
|
|
|
|
function preview_add_recommendation( p, flag ){ |
|
if( flag == "show" ){ |
|
$( "#prompt" ).val( $( "#prompt" ).val() + " " + p ) ; |
|
} |
|
else{ |
|
$( "#prompt" ).val( $( "#prompt" ).val().replace( " " + p, "" ) ) ; |
|
} |
|
} |
|
|
|
|
|
function remove_recommendation( p ){ |
|
$( "#prompt" ).val( $( "#prompt" ).val().replace( p, "" ) ) ; |
|
$( "#prompt" ).val( $( "#prompt" ).val().replace( " ", " " ) ) ; |
|
$( "#recommendation" ).html( "" ) ; |
|
$( "#prompt" ).trigger( "keyup" ) ; |
|
} |
|
|
|
|
|
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" ) ) ; |
|
} |
|
} |
|
|
|
|
|
$( "#prompt" ).on( "keyup", function( e ){ |
|
|
|
|
|
if( $( "#prompt" ).val().length > 0 ){ |
|
$( "#generate" ).removeAttr( "disabled" ) ; |
|
} |
|
else{ |
|
$( "#generate" ).attr( "disabled", true ) ; |
|
} |
|
|
|
|
|
if( Date.now() - last_request > 500 && last_prompt != $( "#prompt" ).val().trim() ){ |
|
last_request = Date.now() ; |
|
last_prompt = $( "#prompt" ).val().trim() ; |
|
|
|
var last_char = $( "#prompt" ).val().trim().slice( -1 ) ; |
|
|
|
|
|
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 p = $( "#prompt" ).val() ; |
|
|
|
|
|
$.getJSON( api_url + encodeURI( p ), function( data ) { |
|
$( "#recommendation" ).html( "Recommendations: " ) ; |
|
|
|
|
|
|
|
if( data["remove"].length > 0 ){ |
|
for( var i = 0; i < data["remove"].length ; i++ ){ |
|
|
|
var sentence = data["remove"][i].sentence.replaceAll( "'", "\\'" ) ; |
|
var sentence_entity = data["remove"][i].sentence.replaceAll( "'", "'" ) ; |
|
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 ; |
|
} |
|
} |
|
|
|
|
|
if( data["add"].length > 0 ){ |
|
for( var i = 0; i < data["add"].length; i++ ){ |
|
if( $( "#prompt" ).val().indexOf( data["add"][i].prompt ) == -1 ){ |
|
|
|
var sentence = data["add"][i].prompt.replaceAll( "'", "\\'" ) ; |
|
var sentence_entity = data["add"][i].prompt.replaceAll( "'", "'" ) ; |
|
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>' ) ; |
|
} |
|
} |
|
} |
|
|
|
|
|
if( data["add"].length == 0 && data["remove"].length == 0 ){ |
|
$( "#recommendation" ).html( "No recommendations found." ) ; |
|
} |
|
|
|
$("#prompt").data( "recommendations", data ); |
|
|
|
}); |
|
} |
|
} |
|
}); |
|
|
|
|
|
$( "#demo" ).on( "submit", function(e){ |
|
$( "#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) |
|
|
|
$( "#generate" ).toggleClass( "bx--btn--disabled" ) ; |
|
|
|
|
|
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" ) ; |
|
|
|
( 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); |
|
} |
|
}) |
|
|
|
|
|
return false; |
|
}); |
|
</script> |
|
|
|
</body> |
|
</html> |
|
|