From bd7ec428d7f7b15a15d70f1747bd3d9420ede5aa Mon Sep 17 00:00:00 2001 From: vishnuszipstack <117254672+vishnuszipstack@users.noreply.github.com> Date: Mon, 23 Dec 2024 09:22:59 +0530 Subject: [PATCH] Feat/prompt key required field (#885) * added required field in prompt key * required fields constant and added required field in promptstudio helper * added frontend required field prompt key functionality * added prompt service required key adding in metadata * added required key in prompt studio registry and removed some unwanted codes * changed required field bool to option with any/all * made changes in frontend to support option required * prompt service changes to support required options field * required field based on enforce type * changed required choices to class * frontend condition fail issue fix in highlight data * required field text changes as per the feedback * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * addressed pr comments * added info for required fields --------- Signed-off-by: vishnuszipstack <117254672+vishnuszipstack@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../prompt_studio_core_v2/constants.py | 1 + .../prompt_studio_helper.py | 1 + .../prompt_studio_registry_v2/constants.py | 1 + .../prompt_studio_registry_helper.py | 1 + .../0003_toolstudioprompt_required.py | 18 ++++++ .../0004_alter_toolstudioprompt_required.py | 24 ++++++++ .../0005_alter_toolstudioprompt_required.py | 24 ++++++++ .../prompt_studio/prompt_studio_v2/models.py | 19 +++++- .../custom-tools/pdf-viewer/PdfViewer.jsx | 4 +- .../custom-tools/prompt-card/Header.jsx | 61 ++++++++++++++++++- .../custom-tools/prompt-card/PromptCard.css | 4 ++ .../prompt-card/PromptCardItems.jsx | 1 + .../src/unstract/prompt_service/constants.py | 2 + .../src/unstract/prompt_service/helper.py | 2 - .../src/unstract/prompt_service/main.py | 6 +- 15 files changed, 162 insertions(+), 7 deletions(-) create mode 100644 backend/prompt_studio/prompt_studio_v2/migrations/0003_toolstudioprompt_required.py create mode 100644 backend/prompt_studio/prompt_studio_v2/migrations/0004_alter_toolstudioprompt_required.py create mode 100644 backend/prompt_studio/prompt_studio_v2/migrations/0005_alter_toolstudioprompt_required.py diff --git a/backend/prompt_studio/prompt_studio_core_v2/constants.py b/backend/prompt_studio/prompt_studio_core_v2/constants.py index 2c6a80ac6..559fe4f7c 100644 --- a/backend/prompt_studio/prompt_studio_core_v2/constants.py +++ b/backend/prompt_studio/prompt_studio_core_v2/constants.py @@ -96,6 +96,7 @@ class ToolStudioPromptKeys: RECORD = "record" FILE_PATH = "file_path" ENABLE_HIGHLIGHT = "enable_highlight" + REQUIRED = "required" EXECUTION_SOURCE = "execution_source" diff --git a/backend/prompt_studio/prompt_studio_core_v2/prompt_studio_helper.py b/backend/prompt_studio/prompt_studio_core_v2/prompt_studio_helper.py index 7985173a1..f3f9e8972 100644 --- a/backend/prompt_studio/prompt_studio_core_v2/prompt_studio_helper.py +++ b/backend/prompt_studio/prompt_studio_core_v2/prompt_studio_helper.py @@ -819,6 +819,7 @@ def _fetch_response( output[TSPKeys.PROMPT] = prompt.prompt output[TSPKeys.ACTIVE] = prompt.active + output[TSPKeys.REQUIRED] = prompt.required output[TSPKeys.CHUNK_SIZE] = profile_manager.chunk_size output[TSPKeys.VECTOR_DB] = vector_db output[TSPKeys.EMBEDDING] = embedding_model diff --git a/backend/prompt_studio/prompt_studio_registry_v2/constants.py b/backend/prompt_studio/prompt_studio_registry_v2/constants.py index ab00a9f2d..49bc1de04 100644 --- a/backend/prompt_studio/prompt_studio_registry_v2/constants.py +++ b/backend/prompt_studio/prompt_studio_registry_v2/constants.py @@ -98,6 +98,7 @@ class JsonSchemaKey: SUMMARIZE_AS_SOURCE = "summarize_as_source" ENABLE_HIGHLIGHT = "enable_highlight" PLATFORM_POSTAMBLE = "platform_postamble" + REQUIRED = "required" class SpecKey: diff --git a/backend/prompt_studio/prompt_studio_registry_v2/prompt_studio_registry_helper.py b/backend/prompt_studio/prompt_studio_registry_v2/prompt_studio_registry_helper.py index 157593cdd..8590c1b03 100644 --- a/backend/prompt_studio/prompt_studio_registry_v2/prompt_studio_registry_helper.py +++ b/backend/prompt_studio/prompt_studio_registry_v2/prompt_studio_registry_helper.py @@ -322,6 +322,7 @@ def frame_export_json( output[JsonSchemaKey.PROMPT] = prompt.prompt output[JsonSchemaKey.ACTIVE] = prompt.active + output[JsonSchemaKey.REQUIRED] = prompt.required output[JsonSchemaKey.CHUNK_SIZE] = prompt.profile_manager.chunk_size output[JsonSchemaKey.VECTOR_DB] = vector_db output[JsonSchemaKey.EMBEDDING] = embedding_model diff --git a/backend/prompt_studio/prompt_studio_v2/migrations/0003_toolstudioprompt_required.py b/backend/prompt_studio/prompt_studio_v2/migrations/0003_toolstudioprompt_required.py new file mode 100644 index 000000000..69a1d0eaf --- /dev/null +++ b/backend/prompt_studio/prompt_studio_v2/migrations/0003_toolstudioprompt_required.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.1 on 2024-12-10 10:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("prompt_studio_v2", "0002_alter_toolstudioprompt_enforce_type"), + ] + + operations = [ + migrations.AddField( + model_name="toolstudioprompt", + name="required", + field=models.BooleanField(default=False), + ), + ] diff --git a/backend/prompt_studio/prompt_studio_v2/migrations/0004_alter_toolstudioprompt_required.py b/backend/prompt_studio/prompt_studio_v2/migrations/0004_alter_toolstudioprompt_required.py new file mode 100644 index 000000000..58dba3d26 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_v2/migrations/0004_alter_toolstudioprompt_required.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.1 on 2024-12-12 08:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("prompt_studio_v2", "0003_toolstudioprompt_required"), + ] + + operations = [ + migrations.AlterField( + model_name="toolstudioprompt", + name="required", + field=models.CharField( + blank=True, + choices=[("all", "All values required"), ("any", "Any value required")], + default=None, + max_length=3, + null=True, + ), + ), + ] diff --git a/backend/prompt_studio/prompt_studio_v2/migrations/0005_alter_toolstudioprompt_required.py b/backend/prompt_studio/prompt_studio_v2/migrations/0005_alter_toolstudioprompt_required.py new file mode 100644 index 000000000..bdd843050 --- /dev/null +++ b/backend/prompt_studio/prompt_studio_v2/migrations/0005_alter_toolstudioprompt_required.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.1 on 2024-12-20 06:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("prompt_studio_v2", "0004_alter_toolstudioprompt_required"), + ] + + operations = [ + migrations.AlterField( + model_name="toolstudioprompt", + name="required", + field=models.CharField( + blank=True, + choices=[("all", "All values required"), ("any", "Any value required")], + db_comment="Field to store weather the values all values or any values required. This is used for HQR, based on the value approve or finish review", + default=None, + null=True, + ), + ), + ] diff --git a/backend/prompt_studio/prompt_studio_v2/models.py b/backend/prompt_studio/prompt_studio_v2/models.py index 9cd37c36f..ccef50ac5 100644 --- a/backend/prompt_studio/prompt_studio_v2/models.py +++ b/backend/prompt_studio/prompt_studio_v2/models.py @@ -35,7 +35,15 @@ class PromptType(models.TextChoices): class Mode(models.TextChoices): DEFAULT = "Default", "Default choice for output" - prompt_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + class RequiredType(models.TextChoices): + ALL = "all", "All values required" + ANY = "any", "Any value required" + + prompt_id = models.UUIDField( + primary_key=True, + default=uuid.uuid4, + editable=False, + ) prompt_key = models.TextField( blank=False, db_comment="Field to store the prompt key", @@ -84,6 +92,15 @@ class Mode(models.TextChoices): db_comment="Field to store the prompt key", unique=False, ) + required = models.CharField( + choices=RequiredType.choices, + null=True, # Allows the field to store NULL in the database + blank=True, # Allows the field to be optional in forms + default=None, # Sets the default value to None + db_comment="Field to store weather the values all values or any \ + values required. This is used for HQR, based on the value approve or finish \ + review", + ) is_assert = models.BooleanField(default=False) active = models.BooleanField(default=True, null=False, blank=False) output_metadata = models.JSONField( diff --git a/frontend/src/components/custom-tools/pdf-viewer/PdfViewer.jsx b/frontend/src/components/custom-tools/pdf-viewer/PdfViewer.jsx index 765e468b7..9103184f6 100644 --- a/frontend/src/components/custom-tools/pdf-viewer/PdfViewer.jsx +++ b/frontend/src/components/custom-tools/pdf-viewer/PdfViewer.jsx @@ -21,7 +21,7 @@ function PdfViewer({ fileUrl, highlightData }) { const { jumpToPage } = pageNavigationPluginInstance; const parentRef = useRef(null); function removeZerosAndDeleteIfAllZero(highlightData) { - return highlightData.filter((innerArray) => + return highlightData?.filter((innerArray) => innerArray.some((value) => value !== 0) ); // Keep arrays that contain at least one non-zero value } @@ -36,8 +36,8 @@ function PdfViewer({ fileUrl, highlightData }) { // Jump to page when highlightData changes useEffect(() => { + highlightData = removeZerosAndDeleteIfAllZero(highlightData); // Removing zeros before checking the highlight data condition if (highlightData && highlightData.length > 0) { - highlightData = removeZerosAndDeleteIfAllZero(highlightData); const pageNumber = highlightData[0][0]; // Assume highlightData[0][0] is the page number if (pageNumber !== null && jumpToPage) { setTimeout(() => { diff --git a/frontend/src/components/custom-tools/prompt-card/Header.jsx b/frontend/src/components/custom-tools/prompt-card/Header.jsx index f72a36083..98b0fd2c1 100644 --- a/frontend/src/components/custom-tools/prompt-card/Header.jsx +++ b/frontend/src/components/custom-tools/prompt-card/Header.jsx @@ -6,6 +6,7 @@ import { PlayCircleFilled, PlayCircleOutlined, SyncOutlined, + InfoCircleOutlined, } from "@ant-design/icons"; import { useEffect, useState } from "react"; import { Button, Checkbox, Col, Dropdown, Row, Tag, Tooltip } from "antd"; @@ -45,6 +46,7 @@ function Header({ setExpandCard, spsLoading, handleSpsLoading, + enforceType, }) { const { selectedDoc, @@ -58,6 +60,7 @@ function Header({ const [items, setItems] = useState([]); const [isDisablePrompt, setIsDisablePrompt] = useState(null); + const [required, setRequired] = useState(false); const handleRunBtnClick = (promptRunType, docId = null) => { setExpandCard(true); @@ -73,8 +76,22 @@ function Header({ } ); }; + const handleRequiredChange = (value) => { + const newValue = value === required ? null : value; // Allow deselection + setRequired(newValue); + handleChange( + newValue, + promptDetails?.prompt_id, + "required", + true, + true + ).catch(() => { + setRequired(promptDetails?.required || null); // Rollback state in case of error + }); + }; useEffect(() => { setIsDisablePrompt(promptDetails?.active); + setRequired(promptDetails?.required); }, [promptDetails, details]); useEffect(() => { @@ -87,6 +104,47 @@ function Header({ ), key: "enable", }, + { + label: ( +