Improve prompt comparison functionality with usability enhancements (#716)
# PR Checklist - [ ] Have you checked if it works normally in all models? *Ignore this if it doesn't use models.* - [x] Have you checked if it works normally in all web, local, and node hosted versions? If it doesn't, have you blocked it in those versions? - [x] Have you added type definitions? # Description This PR introduces a couple of usability improvements to the prompt comparison functionality. 1. If the two prompts are identical Instead of showing the content right away, an alert is displayed saying the two prompts are the same. Only when the user clicks "Yes" the content will be shown. This avoids unnecessary confirmation of identical prompts. <img width="519" alt="a" src="https://github.com/user-attachments/assets/bf48420e-bf69-4c8a-b700-754e1c38b6a6" /> 2. If the two prompts are different A summary of the number of modified, added, and removed lines is displayed. <img width="598" alt="b" src="https://github.com/user-attachments/assets/c3269ee8-25e7-4ba9-957d-4e377d523795" /> When hovering over the summary, a quick overview of the changes appears. When only a single word or character is modified, it was previously hard to identify the line that was changed. Now, the overview improves clarity, making it easier to understand the changes. <img width="595" alt="e" src="https://github.com/user-attachments/assets/1b55a3bc-70d2-43fa-ab4c-754e6fd4a85d" /> On mobile devices (tested on iOS 16.7), tapping on the 'Differences detected. Please review the changes.' section will display the changes. --- As a future improvement, it might be useful to display line numbers or allow users to click and navigate to the specific parts of the differences. I hope these changes make it easier to use, but feel free to reject this PR if you find it unnecessary or if the code feels too messy. I completely understand and appreciate your feedback. Thank you for your time!
This commit is contained in:
@@ -111,11 +111,15 @@
|
||||
return prompt
|
||||
}
|
||||
|
||||
async function checkDiff(prompt1: string, prompt2: string): Promise<string> {
|
||||
async function checkDiff(prompt1: string, prompt2: string): Promise<void> {
|
||||
const { diffLines } = await import('diff')
|
||||
const lineDiffs = diffLines(prompt1, prompt2)
|
||||
|
||||
let resultHtml = '';
|
||||
let changedLines: string[] = []
|
||||
let modifiedLinesCount = 0
|
||||
let addedLinesCount = 0
|
||||
let removedLinesCount = 0
|
||||
|
||||
for (let i = 0; i < lineDiffs.length; i++) {
|
||||
const linePart = lineDiffs[i]
|
||||
@@ -123,15 +127,24 @@
|
||||
if(linePart.removed){
|
||||
const nextPart = lineDiffs[i + 1]
|
||||
if(nextPart?.added){
|
||||
resultHtml += `<div style="border-left: 4px solid blue; padding-left: 8px;">${await highlightChanges(linePart.value, nextPart.value)}</div>`
|
||||
const modifiedLine = `<div style="border-left: 4px solid blue; padding-left: 8px;">${await highlightChanges(linePart.value, nextPart.value)}</div>`
|
||||
changedLines.push(modifiedLine)
|
||||
resultHtml += modifiedLine
|
||||
i++;
|
||||
modifiedLinesCount += 1
|
||||
}
|
||||
else{
|
||||
resultHtml += `<div style="color: red; background-color: #ffe6e6; border-left: 4px solid red; padding-left: 8px;">${escapeHtml(linePart.value)}</div>`
|
||||
const removedLine = `<div style="color: red; background-color: #ffe6e6; border-left: 4px solid red; padding-left: 8px;">${escapeHtml(linePart.value)}</div>`
|
||||
changedLines.push(removedLine)
|
||||
resultHtml += removedLine
|
||||
removedLinesCount += 1
|
||||
}
|
||||
}
|
||||
else if(linePart.added){
|
||||
resultHtml += `<div style="color: green; background-color: #e6ffe6; border-left: 4px solid green; padding-left: 8px;">${escapeHtml(linePart.value)}</div>`
|
||||
const addedLine = `<div style="color: green; background-color: #e6ffe6; border-left: 4px solid green; padding-left: 8px;">${escapeHtml(linePart.value)}</div>`
|
||||
changedLines.push(addedLine)
|
||||
resultHtml += addedLine
|
||||
addedLinesCount += 1
|
||||
}
|
||||
else{
|
||||
resultHtml += `<div>${escapeHtml(linePart.value)}</div>`
|
||||
@@ -139,13 +152,29 @@
|
||||
}
|
||||
|
||||
if(lineDiffs.length === 1 && !lineDiffs[0].added && !lineDiffs[0].removed) {
|
||||
resultHtml = `<div style="background-color: #4caf50; color: white; padding: 10px 20px; border-radius: 5px; text-align: center;">No differences detected.</div>` + resultHtml
|
||||
const userResponse = await alertConfirm('The two prompts are identical. Would you like to review the content?')
|
||||
|
||||
if(userResponse){
|
||||
resultHtml = `<div style="background-color: #4caf50; color: white; padding: 10px 20px; border-radius: 5px; text-align: center;">No differences detected.</div>` + resultHtml
|
||||
alertMd(resultHtml)
|
||||
}
|
||||
}
|
||||
else{
|
||||
resultHtml = `<div style="background-color: #ff9800; color: white; padding: 10px 20px; border-radius: 5px; text-align: center;">Differences detected. Please review the changes.</div>` + resultHtml
|
||||
}
|
||||
const modifiedCount = `<span style="border-left: 4px solid blue; padding-left: 8px; padding-right: 8px;">${modifiedLinesCount}</span>`
|
||||
const addedCount = `<span style="border-left: 4px solid green; padding-left: 8px; padding-right: 8px;">${addedLinesCount}</span>`
|
||||
const removedCount = `<span style="border-left: 4px solid red; padding-left: 8px; padding-right: 8px;">${removedLinesCount}</span>`
|
||||
const diffCounts = `<div>${modifiedCount}${addedCount}${removedCount}</div>`
|
||||
|
||||
return resultHtml
|
||||
resultHtml = `<div id="differences-detected" style="background-color: #ff9800; color: white; padding: 10px 20px; border-radius: 5px; text-align: center;">Differences detected. Please review the changes.${diffCounts}</div>` + resultHtml
|
||||
alertMd(resultHtml)
|
||||
|
||||
setTimeout(() => {
|
||||
const differencesDetected = document.querySelector('#differences-detected');
|
||||
if (differencesDetected) {
|
||||
differencesTooltip(changedLines)
|
||||
}
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
|
||||
async function highlightChanges(string1: string, string2: string) {
|
||||
@@ -168,6 +197,40 @@
|
||||
})
|
||||
.join('')
|
||||
}
|
||||
|
||||
function differencesTooltip(changedLines: string[]) {
|
||||
const differencesDetected = document.querySelector('#differences-detected')
|
||||
if(!differencesDetected){
|
||||
return
|
||||
}
|
||||
|
||||
const tooltip = document.createElement('div')
|
||||
tooltip.id = 'diff-tooltip'
|
||||
tooltip.style.display = 'none'
|
||||
tooltip.style.position = 'absolute'
|
||||
tooltip.style.backgroundColor = '#282a36'
|
||||
tooltip.style.padding = '10px'
|
||||
tooltip.style.borderRadius = '5px'
|
||||
tooltip.style.boxShadow = '0px 5px 5px rgba(0, 0, 0, 1)'
|
||||
tooltip.style.maxWidth = '500px'
|
||||
tooltip.style.overflowY = 'auto'
|
||||
tooltip.style.maxHeight = '300px'
|
||||
tooltip.style.textAlign = 'initial'
|
||||
|
||||
differencesDetected.appendChild(tooltip)
|
||||
|
||||
differencesDetected.addEventListener('mouseenter', () => {
|
||||
const tooltipContent = !changedLines.length ? '' : `<div><strong>Changed Lines</strong></div>
|
||||
<div>${changedLines.join('<br>')}</div>`
|
||||
|
||||
tooltip.innerHTML = tooltipContent;
|
||||
tooltip.style.display = 'block'
|
||||
})
|
||||
|
||||
differencesDetected.addEventListener('mouseleave', () => {
|
||||
tooltip.style.display = 'none'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
async function handleDiffMode(id: number) {
|
||||
@@ -194,8 +257,8 @@
|
||||
}
|
||||
else{
|
||||
alertWait("Loading...")
|
||||
const result = await checkDiff(selectedPrompts[0], prompt)
|
||||
alertMd(result)
|
||||
await checkDiff(selectedPrompts[0], prompt)
|
||||
|
||||
selectedDiffPreset = -1
|
||||
selectedPrompts = []
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user