Skip to content

Commit eff8f54

Browse files
jaags-devritwik-g
andauthored
[Feat] Highlight support in prompt studio (#887)
* added highlight feature in prompt studio * fixed hightligh UI * code refactor/optimisation * added highlight data to store --------- Co-authored-by: Ritwik G <100672805+ritwik-g@users.noreply.github.com>
1 parent 0cd3299 commit eff8f54

12 files changed

Lines changed: 306 additions & 191 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Generated by Django 4.2.1 on 2024-12-05 10:21
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("prompt_studio_output_manager_v2", "0001_initial"),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name="promptstudiooutputmanager",
15+
name="highlight_data",
16+
field=models.JSONField(
17+
blank=True, db_comment="Field to store highlight data", null=True
18+
),
19+
),
20+
]

backend/prompt_studio/prompt_studio_output_manager_v2/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ class PromptStudioOutputManager(BaseModel):
2727
challenge_data = models.JSONField(
2828
db_comment="Field to store challenge data", editable=True, null=True, blank=True
2929
)
30+
highlight_data = models.JSONField(
31+
db_comment="Field to store highlight data", editable=True, null=True, blank=True
32+
)
3033
eval_metrics = models.JSONField(
3134
db_column="eval_metrics",
3235
null=False,

backend/prompt_studio/prompt_studio_output_manager_v2/output_manager_helper.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def update_or_create_prompt_output(
6060
tool: CustomTool,
6161
context: str,
6262
challenge_data: Optional[dict[str, Any]],
63+
highlight_data: Optional[dict[str, Any]],
6364
) -> PromptStudioOutputManager:
6465
"""Handles creating or updating a single prompt output and returns
6566
the instance."""
@@ -76,6 +77,7 @@ def update_or_create_prompt_output(
7677
"eval_metrics": eval_metrics,
7778
"context": context,
7879
"challenge_data": challenge_data,
80+
"highlight_data": highlight_data,
7981
},
8082
)
8183
)
@@ -97,6 +99,7 @@ def update_or_create_prompt_output(
9799
"eval_metrics": eval_metrics,
98100
"context": context,
99101
"challenge_data": challenge_data,
102+
"highlight_data": highlight_data,
100103
}
101104
PromptStudioOutputManager.objects.filter(
102105
document_manager=document_manager,
@@ -118,6 +121,7 @@ def update_or_create_prompt_output(
118121
serialized_data: list[dict[str, Any]] = []
119122
context = metadata.get("context")
120123
challenge_data = metadata.get("challenge_data")
124+
highlight_data = metadata.get("highlight_data")
121125

122126
if not prompts:
123127
return serialized_data
@@ -134,6 +138,8 @@ def update_or_create_prompt_output(
134138

135139
if not is_single_pass_extract:
136140
context = context.get(prompt.prompt_key)
141+
if highlight_data:
142+
highlight_data = highlight_data.get(prompt.prompt_key)
137143
if challenge_data:
138144
challenge_data = challenge_data.get(prompt.prompt_key)
139145

@@ -156,6 +162,7 @@ def update_or_create_prompt_output(
156162
tool=tool,
157163
context=json.dumps(context),
158164
challenge_data=challenge_data,
165+
highlight_data=highlight_data,
159166
)
160167

161168
# Serialize the instance

frontend/src/components/custom-tools/document-manager/DocumentManager.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,13 @@ function DocumentManager({ generateIndex, handleUpdateTool, handleDocChange }) {
9595
isSimplePromptStudio,
9696
isPublicSource,
9797
refreshRawView,
98+
selectedHighlight,
9899
} = useCustomToolStore();
99100
const { sessionDetails } = useSessionStore();
100101
const axiosPrivate = useAxiosPrivate();
101102
const { setPostHogCustomEvent } = usePostHogEvents();
102103
const { id } = useParams();
104+
const highlightData = selectedHighlight?.highlight || [];
103105

104106
useEffect(() => {
105107
if (isSimplePromptStudio) {
@@ -386,7 +388,7 @@ function DocumentManager({ generateIndex, handleUpdateTool, handleDocChange }) {
386388
setOpenManageDocsModal={setOpenManageDocsModal}
387389
errMsg={fileErrMsg}
388390
>
389-
<PdfViewer fileUrl={fileUrl} />
391+
<PdfViewer fileUrl={fileUrl} highlightData={highlightData} />
390392
</DocumentViewer>
391393
)}
392394
{activeKey === "2" && (

frontend/src/components/custom-tools/pdf-viewer/PdfViewer.jsx

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useRef } from "react";
1+
import { useEffect, useRef, useMemo } from "react";
22
import { Viewer, Worker } from "@react-pdf-viewer/core";
33
import { defaultLayoutPlugin } from "@react-pdf-viewer/default-layout";
44
import { pageNavigationPlugin } from "@react-pdf-viewer/page-navigation";
@@ -23,29 +23,43 @@ function PdfViewer({ fileUrl, highlightData }) {
2323
function removeZerosAndDeleteIfAllZero(highlightData) {
2424
return highlightData?.filter((innerArray) =>
2525
innerArray.some((value) => value !== 0)
26-
); // Keep arrays that contain at least one non-zero value
27-
}
28-
let highlightPluginInstance = "";
29-
if (RenderHighlights && highlightData) {
30-
highlightPluginInstance = highlightPlugin({
31-
renderHighlights: (props) => (
32-
<RenderHighlights {...props} highlightData={highlightData} />
33-
),
34-
});
26+
);
3527
}
3628

29+
const processHighlightData = highlightData
30+
? removeZerosAndDeleteIfAllZero(highlightData)
31+
: [];
32+
33+
const processedHighlightData =
34+
processHighlightData?.length > 0 ? processHighlightData : [[0, 0, 0, 0]];
35+
36+
const highlightPluginInstance = useMemo(() => {
37+
if (
38+
RenderHighlights &&
39+
Array.isArray(processedHighlightData) &&
40+
processedHighlightData?.length > 0
41+
) {
42+
return highlightPlugin({
43+
renderHighlights: (props) => (
44+
<RenderHighlights {...props} highlightData={processedHighlightData} />
45+
),
46+
});
47+
}
48+
return "";
49+
}, [RenderHighlights, processedHighlightData]);
50+
3751
// Jump to page when highlightData changes
3852
useEffect(() => {
3953
highlightData = removeZerosAndDeleteIfAllZero(highlightData); // Removing zeros before checking the highlight data condition
4054
if (highlightData && highlightData.length > 0) {
4155
const pageNumber = highlightData[0][0]; // Assume highlightData[0][0] is the page number
4256
if (pageNumber !== null && jumpToPage) {
4357
setTimeout(() => {
44-
jumpToPage(pageNumber); // jumpToPage is 0-indexed, so subtract 1
58+
jumpToPage(pageNumber); // jumpToPage is 0-indexed, so subtract 1 if necessary
4559
}, 100); // Add a slight delay to ensure proper page rendering
4660
}
4761
}
48-
}, [highlightData, jumpToPage]);
62+
}, [processedHighlightData, jumpToPage]);
4963

5064
return (
5165
<div ref={parentRef} className="doc-manager-body">

frontend/src/components/custom-tools/prompt-card/PromptCard.css

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,15 @@
300300
color: #f0ad4e;
301301
}
302302

303-
.required-checkbox-padding{
304-
padding-left: 5px;
303+
.highlighted-prompt {
304+
border-width: 1.2px;
305+
border-style: solid;
306+
border-color: #4096ff;
307+
box-shadow: 4px 4px 12.5px 0px rgba(0, 0, 0, 0.08);
308+
}
309+
310+
.highlighted-prompt-cell {
311+
border-width: 1.2px;
312+
border-style: solid;
313+
border-color: #ffb400;
305314
}

frontend/src/components/custom-tools/prompt-card/PromptCard.jsx

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,13 @@ const PromptCard = memo(
4343
const [openOutputForDoc, setOpenOutputForDoc] = useState(false);
4444
const [progressMsg, setProgressMsg] = useState({});
4545
const [spsLoading, setSpsLoading] = useState({});
46-
const { llmProfiles, selectedDoc, details, summarizeIndexStatus } =
47-
useCustomToolStore();
46+
const {
47+
llmProfiles,
48+
selectedDoc,
49+
details,
50+
summarizeIndexStatus,
51+
updateCustomTool,
52+
} = useCustomToolStore();
4853
const { messages } = useSocketCustomToolStore();
4954
const { setAlertDetails } = useAlertStore();
5055
const { setPostHogCustomEvent } = usePostHogEvents();
@@ -161,6 +166,22 @@ const PromptCard = memo(
161166
);
162167
};
163168

169+
const handleSelectHighlight = (
170+
highlightData,
171+
highlightedPrompt,
172+
highlightedProfile
173+
) => {
174+
if (details?.enable_highlight) {
175+
updateCustomTool({
176+
selectedHighlight: {
177+
highlight: highlightData,
178+
highlightedPrompt: highlightedPrompt,
179+
highlightedProfile: highlightedProfile,
180+
},
181+
});
182+
}
183+
};
184+
164185
const handleTypeChange = (value) => {
165186
handleChange(value, promptDetailsState?.prompt_id, "enforce_type", true);
166187
};
@@ -261,6 +282,7 @@ const PromptCard = memo(
261282
promptRunStatus={promptRunStatus}
262283
coverageCountData={coverageCountData}
263284
isChallenge={isChallenge}
285+
handleSelectHighlight={handleSelectHighlight}
264286
/>
265287
<OutputForDocModal
266288
open={openOutputForDoc}

frontend/src/components/custom-tools/prompt-card/PromptCardItems.jsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ function PromptCardItems({
5252
promptRunStatus,
5353
coverageCountData,
5454
isChallenge,
55+
handleSelectHighlight,
5556
}) {
5657
const {
5758
llmProfiles,
@@ -62,6 +63,8 @@ function PromptCardItems({
6263
isSimplePromptStudio,
6364
isPublicSource,
6465
adapters,
66+
selectedHighlight,
67+
details,
6568
singlePassExtractMode,
6669
} = useCustomToolStore();
6770

@@ -171,7 +174,13 @@ function PromptCardItems({
171174
}, [llmProfiles, selectedLlmProfileId, enabledProfiles]);
172175

173176
return (
174-
<Card className="prompt-card">
177+
<Card
178+
className={`prompt-card ${
179+
details?.enable_highlight &&
180+
selectedHighlight?.highlightedPrompt === promptDetails?.prompt_id &&
181+
"highlighted-prompt"
182+
}`}
183+
>
175184
<div className="prompt-card-div prompt-card-bg-col1 prompt-card-rad">
176185
<Space direction="vertical" className="width-100" ref={divRef}>
177186
<Header
@@ -289,6 +298,7 @@ function PromptCardItems({
289298
promptOutputs={promptOutputs}
290299
promptRunStatus={promptRunStatus}
291300
isChallenge={isChallenge}
301+
handleSelectHighlight={handleSelectHighlight}
292302
/>
293303
</Row>
294304
</Collapse.Panel>
@@ -326,6 +336,7 @@ PromptCardItems.propTypes = {
326336
promptRunStatus: PropTypes.object.isRequired,
327337
coverageCountData: PropTypes.object.isRequired,
328338
isChallenge: PropTypes.bool.isRequired,
339+
handleSelectHighlight: PropTypes.func.isRequired,
329340
};
330341

331342
export { PromptCardItems };

0 commit comments

Comments
 (0)