feat: jigsawstack bundle integration (#8832)

* fix: formatting errors.

* fix: formmating errors for jigsawstack components.

* fix: bugs identified by coderabbitai.

* fix: formatting issues on JigsawStack icon gradient.

* fix: project starters.

* fix: value errors.

* fix: app startup

* fix: resolve merge conflicts, accept incoming changes.

* fix:  follow lexicographical order for bundle names.

Co-authored-by: Edwin Jose <edwinjose900@gmail.com>

* feat: add JigsawStack bundle to the sidebar, following lexographical order.

* fix: remove duplicate changes, by rebasing to main/src/.../styleUtils.ts

* fix: apply suggested fixes for potential issues identified from coderabbitai.

---------

Co-authored-by: Edwin Jose <edwinjose900@gmail.com>
This commit is contained in:
Harsha Vardhan Khurdula 2025-07-09 15:53:12 -04:00 • committed by GitHub
commit 8c72ea087c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 1356 additions and 0 deletions

View file

@ -0,0 +1,23 @@
from .ai_scrape import JigsawStackAIScraperComponent
from .ai_web_search import JigsawStackAIWebSearchComponent
from .file_read import JigsawStackFileReadComponent
from .file_upload import JigsawStackFileUploadComponent
from .image_generation import JigsawStackImageGenerationComponent
from .nsfw import JigsawStackNSFWComponent
from .object_detection import JigsawStackObjectDetectionComponent
from .sentiment import JigsawStackSentimentComponent
from .text_to_sql import JigsawStackTextToSQLComponent
from .vocr import JigsawStackVOCRComponent
__all__ = [
"JigsawStackAIScraperComponent",
"JigsawStackAIWebSearchComponent",
"JigsawStackFileReadComponent",
"JigsawStackFileUploadComponent",
"JigsawStackImageGenerationComponent",
"JigsawStackNSFWComponent",
"JigsawStackObjectDetectionComponent",
"JigsawStackSentimentComponent",
"JigsawStackTextToSQLComponent",
"JigsawStackVOCRComponent",
]

View file

@ -0,0 +1,126 @@
from langflow.custom.custom_component.component import Component
from langflow.io import MessageTextInput, Output, SecretStrInput
from langflow.schema.data import Data
MAX_ELEMENT_PROMPTS = 5
class JigsawStackAIScraperComponent(Component):
display_name = "AI Scraper"
description = "Scrape any website instantly and get consistent structured data \
in seconds without writing any css selector code"
documentation = "https://jigsawstack.com/docs/api-reference/ai/scrape"
icon = "JigsawStack"
name = "JigsawStackAIScraper"
inputs = [
SecretStrInput(
name="api_key",
display_name="JigsawStack API Key",
info="Your JigsawStack API key for authentication",
required=True,
),
MessageTextInput(
name="url",
display_name="URL",
info="URL of the page to scrape. Either url or html is required, but not both.",
required=False,
tool_mode=True,
),
MessageTextInput(
name="html",
display_name="HTML",
info="HTML content to scrape. Either url or html is required, but not both.",
required=False,
tool_mode=True,
),
MessageTextInput(
name="element_prompts",
display_name="Element Prompts",
info="Items on the page to be scraped (maximum 5). E.g. 'Plan price', 'Plan title'",
required=True,
tool_mode=True,
),
MessageTextInput(
name="root_element_selector",
display_name="Root Element Selector",
info="CSS selector to limit the scope of scraping to a specific element and its children",
required=False,
value="main",
),
]
outputs = [
Output(display_name="AI Scraper Results", name="scrape_results", method="scrape"),
]
def scrape(self) -> Data:
try:
from jigsawstack import JigsawStack, JigsawStackError
except ImportError as e:
jigsawstack_import_error = (
"JigsawStack package not found. Please install it using: pip install jigsawstack>=0.2.7"
)
raise ImportError(jigsawstack_import_error) from e
try:
client = JigsawStack(api_key=self.api_key)
# Build request object
scrape_params: dict = {}
if self.url:
scrape_params["url"] = self.url
if self.html:
scrape_params["html"] = self.html
url_value = scrape_params.get("url", "")
html_value = scrape_params.get("html", "")
if (not url_value or not url_value.strip()) and (not html_value or not html_value.strip()):
url_or_html_error = "Either 'url' or 'html' must be provided for scraping"
raise ValueError(url_or_html_error)
# Process element_prompts with proper type handling
element_prompts_list: list[str] = []
if self.element_prompts:
element_prompts_value: str | list[str] = self.element_prompts
if isinstance(element_prompts_value, str):
if "," not in element_prompts_value:
element_prompts_list = [element_prompts_value]
else:
element_prompts_list = element_prompts_value.split(",")
elif isinstance(element_prompts_value, list):
element_prompts_list = element_prompts_value
else:
# Fallback for other types
element_prompts_list = str(element_prompts_value).split(",")
if len(element_prompts_list) > MAX_ELEMENT_PROMPTS:
max_elements_error = "Maximum of 5 element prompts allowed"
raise ValueError(max_elements_error)
if len(element_prompts_list) == 0:
invalid_elements_error = "Element prompts cannot be empty"
raise ValueError(invalid_elements_error)
scrape_params["element_prompts"] = element_prompts_list
if self.root_element_selector:
scrape_params["root_element_selector"] = self.root_element_selector
# Call web scraping
response = client.web.ai_scrape(scrape_params)
if not response.get("success", False):
fail_error = "JigsawStack API request failed."
raise ValueError(fail_error)
result_data = response
self.status = "AI scrape process is now complete."
return Data(data=result_data)
except JigsawStackError as e:
error_data = {"error": str(e), "success": False}
self.status = f"Error: {e!s}"
return Data(data=error_data)

View file

@ -0,0 +1,136 @@
from langflow.custom.custom_component.component import Component
from langflow.io import BoolInput, DropdownInput, Output, QueryInput, SecretStrInput
from langflow.schema.data import Data
from langflow.schema.message import Message
class JigsawStackAIWebSearchComponent(Component):
display_name = "AI Web Search"
description = "Effortlessly search the Web and get access to high-quality results powered with AI."
documentation = "https://jigsawstack.com/docs/api-reference/web/ai-search"
icon = "JigsawStack"
name = "JigsawStackAISearch"
inputs = [
SecretStrInput(
name="api_key",
display_name="JigsawStack API Key",
info="Your JigsawStack API key for authentication",
required=True,
),
QueryInput(
name="query",
display_name="Query",
info="The search value. The maximum query character length is 400",
required=True,
tool_mode=True,
),
BoolInput(
name="ai_overview",
display_name="AI Overview",
info="Include AI powered overview in the search results",
required=False,
value=True,
),
DropdownInput(
name="safe_search",
display_name="Safe Search",
info="Enable safe search to filter out adult content",
required=False,
options=["moderate", "strict", "off"],
value="off",
),
BoolInput(
name="spell_check",
display_name="Spell Check",
info="Spell check the search query",
required=False,
value=True,
),
]
outputs = [
Output(display_name="AI Search Results", name="search_results", method="search"),
Output(display_name="Content Text", name="content_text", method="get_content_text"),
]
def search(self) -> Data:
try:
from jigsawstack import JigsawStack, JigsawStackError
except ImportError as e:
jigsawstack_import_error = (
"JigsawStack package not found. Please install it using: pip install jigsawstack>=0.2.7"
)
raise ImportError(jigsawstack_import_error) from e
try:
client = JigsawStack(api_key=self.api_key)
# build request object
search_params = {}
if self.query:
search_params["query"] = self.query
if self.ai_overview is not None:
search_params["ai_overview"] = self.ai_overview
if self.safe_search:
search_params["safe_search"] = self.safe_search
if self.spell_check is not None:
search_params["spell_check"] = self.spell_check
# Call web scraping
response = client.web.search(search_params)
api_error_msg = "JigsawStack API returned unsuccessful response"
if not response.get("success", False):
raise ValueError(api_error_msg)
# Create comprehensive data object
result_data = {
"query": self.query,
"ai_overview": response.get("ai_overview", ""),
"spell_fixed": response.get("spell_fixed", False),
"is_safe": response.get("is_safe", True),
"results": response.get("results", []),
"success": True,
}
self.status = f"Search complete for: {response.get('query', '')}"
return Data(data=result_data)
except JigsawStackError as e:
error_data = {"error": str(e), "success": False}
self.status = f"Error: {e!s}"
return Data(data=error_data)
def get_content_text(self) -> Message:
try:
from jigsawstack import JigsawStack, JigsawStackError
except ImportError:
return Message(text="Error: JigsawStack package not found.")
try:
# Initialize JigsawStack client
client = JigsawStack(api_key=self.api_key)
search_params = {}
if self.query:
search_params["query"] = self.query
if self.ai_overview is not None:
search_params["ai_overview"] = self.ai_overview
if self.safe_search:
search_params["safe_search"] = self.safe_search
if self.spell_check is not None:
search_params["spell_check"] = self.spell_check
# Call web scraping
response = client.web.search(search_params)
request_failed_msg = "Request Failed"
if not response.get("success", False):
raise JigsawStackError(request_failed_msg)
# Return the content as text
content = response.get("ai_overview", "")
return Message(text=content)
except JigsawStackError as e:
return Message(text=f"Error while using AI Search: {e!s}")

View file

@ -0,0 +1,115 @@
import tempfile
from langflow.custom.custom_component.component import Component
from langflow.io import Output, SecretStrInput, StrInput
from langflow.schema.data import Data
class JigsawStackFileReadComponent(Component):
display_name = "File Read"
description = "Read any previously uploaded file seamlessly from \
JigsawStack File Storage and use it in your AI applications."
documentation = "https://jigsawstack.com/docs/api-reference/store/file/get"
icon = "JigsawStack"
name = "JigsawStackFileRead"
inputs = [
SecretStrInput(
name="api_key",
display_name="JigsawStack API Key",
info="Your JigsawStack API key for authentication",
required=True,
),
StrInput(
name="key",
display_name="Key",
info="The key used to retrieve the file from JigsawStack File Storage.",
required=True,
tool_mode=True,
),
]
outputs = [
Output(display_name="File Path", name="file_path", method="read_and_save_file"),
]
def read_and_save_file(self) -> Data:
"""Read file from JigsawStack and save to temp file, return file path."""
try:
from jigsawstack import JigsawStack, JigsawStackError
except ImportError as e:
jigsawstack_import_error = (
"JigsawStack package not found. Please install it using: pip install jigsawstack>=0.2.7"
)
raise ImportError(jigsawstack_import_error) from e
try:
client = JigsawStack(api_key=self.api_key)
if not self.key or self.key.strip() == "":
invalid_key_error = "Key is required to read a file from JigsawStack File Storage."
raise ValueError(invalid_key_error)
# Download file content
response = client.store.get(self.key)
# Determine file extension
file_extension = self._detect_file_extension(response)
# Create temporary file
with tempfile.NamedTemporaryFile(
delete=False, suffix=file_extension, prefix=f"jigsawstack_{self.key}_"
) as temp_file:
if isinstance(response, bytes):
temp_file.write(response)
else:
# Handle string content
temp_file.write(response.encode("utf-8"))
temp_path = temp_file.name
return Data(
data={
"file_path": temp_path,
"key": self.key,
"file_extension": file_extension,
"size": len(response) if isinstance(response, bytes) else len(str(response)),
"success": True,
}
)
except JigsawStackError as e:
error_data = {"error": str(e), "success": False}
self.status = f"Error: {e!s}"
return Data(data=error_data)
def _detect_file_extension(self, content) -> str:
"""Detect file extension based on content headers."""
if isinstance(content, bytes):
# Check magic numbers for common file types
if content.startswith(b"\xff\xd8\xff"):
return ".jpg"
if content.startswith(b"\x89PNG\r\n\x1a\n"):
return ".png"
if content.startswith((b"GIF87a", b"GIF89a")):
return ".gif"
if content.startswith(b"%PDF"):
return ".pdf"
if content.startswith(b"PK\x03\x04"): # ZIP/DOCX/XLSX
return ".zip"
if content.startswith(b"\x00\x00\x01\x00"): # ICO
return ".ico"
if content.startswith(b"RIFF") and b"WEBP" in content[:12]:
return ".webp"
if content.startswith((b"\xff\xfb", b"\xff\xf3", b"\xff\xf2")):
return ".mp3"
if content.startswith((b"ftypmp4", b"\x00\x00\x00\x20ftypmp4")):
return ".mp4"
# Try to decode as text
try:
content.decode("utf-8")
return ".txt" # noqa: TRY300
except UnicodeDecodeError:
return ".bin" # Binary file
else:
# String content
return ".txt"

View file

@ -0,0 +1,94 @@
from pathlib import Path
from langflow.custom.custom_component.component import Component
from langflow.io import BoolInput, FileInput, Output, SecretStrInput, StrInput
from langflow.schema.data import Data
class JigsawStackFileUploadComponent(Component):
display_name = "File Upload"
description = "Store any file seamlessly on JigsawStack File Storage and use it in your AI applications. \
Supports various file types including images, documents, and more."
documentation = "https://jigsawstack.com/docs/api-reference/store/file/add"
icon = "JigsawStack"
name = "JigsawStackFileUpload"
inputs = [
SecretStrInput(
name="api_key",
display_name="JigsawStack API Key",
info="Your JigsawStack API key for authentication",
required=True,
),
FileInput(
name="file",
display_name="File",
info="Upload file to be stored on JigsawStack File Storage.",
required=True,
file_types=["pdf", "png", "jpg", "jpeg", "mp4", "mp3", "txt", "docx", "xlsx"],
),
StrInput(
name="key",
display_name="Key",
info="The key used to store the file on JigsawStack File Storage. \
If not provided, a unique key will be generated.",
required=False,
tool_mode=True,
),
BoolInput(
name="overwrite",
display_name="Overwrite Existing File",
info="If true, will overwrite the existing file with the same key. \
If false, will return an error if the file already exists.",
required=False,
value=True,
),
BoolInput(
name="temp_public_url",
display_name="Return Temporary Public URL",
info="If true, will return a temporary public URL which lasts for a limited time. \
If false, will return the file store key which can only be accessed by the owner.",
required=False,
value=False,
tool_mode=True,
),
]
outputs = [
Output(display_name="File Store Result", name="file_upload_result", method="upload_file"),
]
def upload_file(self) -> Data:
try:
from jigsawstack import JigsawStack, JigsawStackError
except ImportError as e:
jigsawstack_import_error = (
"JigsawStack package not found. Please install it using: pip install jigsawstack>=0.2.7"
)
raise ImportError(jigsawstack_import_error) from e
try:
client = JigsawStack(api_key=self.api_key)
file_path = Path(self.file)
with Path.open(file_path, "rb") as f:
file_content = f.read()
params = {}
if self.key:
# if key is provided, use it as the file store key
params["key"] = self.key
if self.overwrite is not None:
# if overwrite is provided, use it to determine if the file should be overwritten
params["overwrite"] = self.overwrite
if self.temp_public_url is not None:
# if temp_public_url is provided, use it to determine if a temporary public URL should
params["temp_public_url"] = self.temp_public_url
response = client.store.upload(file_content, params)
return Data(data=response)
except JigsawStackError as e:
error_data = {"error": str(e), "success": False}
self.status = f"Error: {e!s}"
return Data(data=error_data)

View file

@ -0,0 +1,205 @@
from langflow.custom.custom_component.component import Component
from langflow.io import DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput
from langflow.schema.data import Data
class JigsawStackImageGenerationComponent(Component):
display_name = "Image Generation"
description = "Generate an image based on the given text by employing AI models like Flux, \
Stable Diffusion, and other top models."
documentation = "https://jigsawstack.com/docs/api-reference/ai/image-generation"
icon = "JigsawStack"
name = "JigsawStackImageGeneration"
inputs = [
SecretStrInput(
name="api_key",
display_name="JigsawStack API Key",
info="Your JigsawStack API key for authentication",
required=True,
),
MessageTextInput(
name="prompt",
display_name="Prompt",
info="The text prompt to generate the image from. Must be between 1-5000 characters.",
required=True,
tool_mode=True,
),
MessageTextInput(
name="aspect_ratio",
display_name="Aspect Ratio",
info="The aspect ratio of the generated image. Must be one of the following:\
'1:1', '16:9', '21:9', '3:2', '2:3', '4:5', '5:4', '3:4', '4:3', '9:16', '9:21' \
Default is 1:1.",
required=False,
tool_mode=True,
),
MessageTextInput(
name="url",
display_name="URL",
info="A valid URL where the generated image will be sent.",
required=False,
),
MessageTextInput(
name="file_store_key",
display_name="File Store Key",
info="The key used to store the image on Jigsawstack File Storage. Not required if url is specified.",
required=False,
tool_mode=True,
),
IntInput(
name="width",
display_name="Width",
info="The width of the image. Must be between 256-1920 pixels.",
required=False,
),
IntInput(
name="height",
display_name="Height",
info="The height of the image. Must be between 256-1920 pixels.",
required=False,
),
IntInput(
name="steps",
display_name="Steps",
info="The number of denoising steps. Must be between 1-90. \
Higher values produce better quality images but take more time to generate.",
required=False,
),
DropdownInput(
name="output_format",
display_name="Output Format",
info="The output format of the generated image. Must be one of the following values:\
png or svg",
required=False,
options=["png", "svg"],
value="png",
),
MessageTextInput(
name="negative_prompt",
display_name="Negative Prompt",
info="The text prompt to avoid in the generated image. \
Must be between 1-5000 characters.",
required=False,
tool_mode=True,
advanced=True,
),
IntInput(
name="seed",
display_name="Seed",
info="Makes generation deterministic.\
Using the same seed and set of parameters will produce identical image each time.",
required=False,
tool_mode=True,
advanced=True,
),
IntInput(
name="guidance",
display_name="Guidance Scale",
info="Higher guidance forces the model to better follow the prompt, \
but may result in lower quality output. Must be between 1-28.",
required=False,
tool_mode=True,
advanced=True,
),
]
outputs = [
Output(display_name="Image Generation Results", name="image_generation_results", method="generate_image"),
]
def generate_image(self) -> Data:
try:
from jigsawstack import JigsawStack, JigsawStackError
except ImportError as e:
jigsawstack_import_error = (
"JigsawStack package not found. Please install it using: pip install jigsawstack>=0.2.7"
)
raise ImportError(jigsawstack_import_error) from e
try:
min_character_length = 1
max_character_length = 5000
min_width = 256
max_width = 1920
min_height = 256
max_height = 1920
min_steps = 1
max_steps = 90
client = JigsawStack(api_key=self.api_key)
if not self.prompt or len(self.prompt) < min_character_length or len(self.prompt) > max_character_length:
invalid_prompt_error = f"Prompts must be between \
{min_character_length}-{max_character_length} characters."
raise ValueError(invalid_prompt_error)
if self.aspect_ratio and self.aspect_ratio not in [
"1:1",
"16:9",
"21:9",
"3:2",
"2:3",
"4:5",
"5:4",
"3:4",
"4:3",
"9:16",
"9:21",
]:
invalid_aspect_ratio_error = (
"Aspect ratio must be one of the following: '1:1', '16:9', '21:9', '3:2', '2:3', "
"'4:5', '5:4', '3:4', '4:3', '9:16', '9:21'."
)
raise ValueError(invalid_aspect_ratio_error)
if self.width and (self.width < min_width or self.width > max_width):
invalid_width_error = f"Width must be between {min_width}-{max_width} pixels."
raise ValueError(invalid_width_error)
if self.height and (self.height < min_height or self.height > max_height):
invalid_height_error = f"Height must be between {min_height}-{max_height} pixels."
raise ValueError(invalid_height_error)
if self.steps and (self.steps < min_steps or self.steps > max_steps):
invalid_steps_error = f"Steps must be between {min_steps}-{max_steps}."
raise ValueError(invalid_steps_error)
params = {}
if self.prompt:
params["prompt"] = self.prompt.strip()
if self.aspect_ratio:
params["aspect_ratio"] = self.aspect_ratio.strip()
if self.url:
params["url"] = self.url.strip()
if self.file_store_key:
params["file_store_key"] = self.file_store_key.strip()
if self.width:
params["width"] = self.width
if self.height:
params["height"] = self.height
params["return_type"] = "url"
if self.output_format:
params["output_format"] = self.output_format.strip()
if self.steps:
params["steps"] = self.steps
# Initialize advance_config if any advanced parameters are provided
if self.negative_prompt or self.seed or self.guidance:
params["advance_config"] = {}
if self.negative_prompt:
params["advance_config"]["negative_prompt"] = self.negative_prompt
if self.seed:
params["advance_config"]["seed"] = self.seed
if self.guidance:
params["advance_config"]["guidance"] = self.guidance
# Call image generation
response = client.image_generation(params)
if response.get("url", None) is None or response.get("url", None).strip() == "":
failed_response_error = "JigsawStack API returned unsuccessful response"
raise ValueError(failed_response_error)
return Data(data=response)
except JigsawStackError as e:
error_data = {"error": str(e), "success": False}
self.status = f"Error: {e!s}"
return Data(data=error_data)

View file

@ -0,0 +1,60 @@
from langflow.custom.custom_component.component import Component
from langflow.io import Output, SecretStrInput, StrInput
from langflow.schema.data import Data
class JigsawStackNSFWComponent(Component):
display_name = "NSFW Detection"
description = "Detect if image/video contains NSFW content"
documentation = "https://jigsawstack.com/docs/api-reference/ai/nsfw"
icon = "JigsawStack"
name = "JigsawStackNSFW"
inputs = [
SecretStrInput(
name="api_key",
display_name="JigsawStack API Key",
info="Your JigsawStack API key for authentication",
required=True,
),
StrInput(
name="url",
display_name="URL",
info="URL of the image or video to analyze",
required=True,
),
]
outputs = [
Output(display_name="NSFW Analysis", name="nsfw_result", method="detect_nsfw"),
]
def detect_nsfw(self) -> Data:
try:
from jigsawstack import JigsawStack, JigsawStackError
except ImportError as e:
jigsawstack_import_error = (
"JigsawStack package not found. Please install it using: pip install jigsawstack>=0.2.7"
)
raise ImportError(jigsawstack_import_error) from e
try:
client = JigsawStack(api_key=self.api_key)
# Build request parameters
params = {"url": self.url}
response = client.validate.nsfw(params)
api_error_msg = "JigsawStack API returned unsuccessful response"
if not response.get("success", False):
raise ValueError(api_error_msg)
return Data(data=response)
except ValueError:
raise
except JigsawStackError as e:
error_data = {"error": str(e), "success": False}
self.status = f"Error: {e!s}"
return Data(data=error_data)

View file

@ -0,0 +1,124 @@
from langflow.custom.custom_component.component import Component
from langflow.io import BoolInput, DropdownInput, MessageTextInput, Output, SecretStrInput
from langflow.schema.data import Data
class JigsawStackObjectDetectionComponent(Component):
display_name = "Object Detection"
description = "Perform object detection on images using JigsawStack's Object Detection Model, \
capable of image grounding, segmentation and computer use."
documentation = "https://jigsawstack.com/docs/api-reference/ai/object-detection"
icon = "JigsawStack"
name = "JigsawStackObjectDetection"
inputs = [
SecretStrInput(
name="api_key",
display_name="JigsawStack API Key",
info="Your JigsawStack API key for authentication",
required=True,
),
MessageTextInput(
name="prompts",
display_name="Prompts",
info="The prompts to ground the object detection model. \
You can pass a list of comma-separated prompts to extract different information from the image.",
required=False,
tool_mode=True,
),
MessageTextInput(
name="url",
display_name="URL",
info="The image URL. Not required if file_store_key is specified.",
required=False,
tool_mode=True,
),
MessageTextInput(
name="file_store_key",
display_name="File Store Key",
info="The key used to store the image on Jigsawstack File Storage. Not required if url is specified.",
required=False,
tool_mode=True,
),
BoolInput(
name="annotated_image",
display_name="Return Annotated Image",
info="If true, will return an url for annotated image with detected objects.",
required=False,
value=True,
),
DropdownInput(
name="features",
display_name="Features",
info="Select the features to enable for object detection",
required=False,
options=["object_detection", "gui"],
value=["object_detection", "gui"],
),
DropdownInput(
name="return_type",
display_name="Return Type",
info="Select the return type for the object detection results such as masks or annotations.",
required=False,
options=["url", "base64"],
value="url",
),
]
outputs = [
Output(display_name="Object Detection results", name="object_detection_results", method="detect_objects"),
]
def detect_objects(self) -> Data:
try:
from jigsawstack import JigsawStack, JigsawStackError
except ImportError as e:
jigsawstack_import_error = (
"JigsawStack package not found. Please install it using: pip install jigsawstack>=0.2.7"
)
raise ImportError(jigsawstack_import_error) from e
try:
client = JigsawStack(api_key=self.api_key)
# build request object
params = {}
if self.prompts:
if isinstance(self.prompts, list):
params["prompt"] = self.prompts
elif isinstance(self.prompts, str):
if "," in self.prompts:
# Split by comma and strip whitespace
params["prompt"] = [p.strip() for p in self.prompts.split(",")]
else:
params["prompt"] = [self.prompts.strip()]
else:
invalid_prompt_error = "Prompt must be a list of strings or a single string"
raise ValueError(invalid_prompt_error)
if self.url:
params["url"] = self.url
if self.file_store_key:
params["file_store_key"] = self.file_store_key
# if both url and file_store_key are not provided, raise an error
if not self.url and not self.file_store_key:
missing_url_error = "Either URL or File Store Key must be provided to perform object detection"
raise ValueError(missing_url_error)
params["annotated_image"] = self.annotated_image
if self.features:
params["features"] = self.features
# Call web scraping
response = client.vision.object_detection(params)
if not response.get("success", False):
failed_response_error = "JigsawStack API returned unsuccessful response"
raise ValueError(failed_response_error)
return Data(data=response)
except JigsawStackError as e:
error_data = {"error": str(e), "success": False}
self.status = f"Error: {e!s}"
return Data(data=error_data)

View file

@ -0,0 +1,112 @@
from langflow.custom.custom_component.component import Component
from langflow.io import MessageTextInput, Output, SecretStrInput
from langflow.schema.data import Data
from langflow.schema.message import Message
class JigsawStackSentimentComponent(Component):
display_name = "Sentiment Analysis"
description = "Analyze sentiment of text using JigsawStack AI"
documentation = "https://jigsawstack.com/docs/api-reference/ai/sentiment"
icon = "JigsawStack"
name = "JigsawStackSentiment"
inputs = [
SecretStrInput(
name="api_key",
display_name="JigsawStack API Key",
info="Your JigsawStack API key for authentication",
required=True,
),
MessageTextInput(
name="text",
display_name="Text",
info="Text to analyze for sentiment",
required=True,
tool_mode=True,
),
]
outputs = [
Output(display_name="Sentiment Data", name="sentiment_data", method="analyze_sentiment"),
Output(display_name="Sentiment Text", name="sentiment_text", method="get_sentiment_text"),
]
def analyze_sentiment(self) -> Data:
try:
from jigsawstack import JigsawStack, JigsawStackError
except ImportError as e:
jigsawstack_import_error = (
"JigsawStack package not found. Please install it using: pip install jigsawstack>=0.2.7"
)
raise ImportError(jigsawstack_import_error) from e
try:
client = JigsawStack(api_key=self.api_key)
response = client.sentiment({"text": self.text})
api_error_msg = "JigsawStack API returned unsuccessful response"
if not response.get("success", False):
raise ValueError(api_error_msg)
sentiment_data = response.get("sentiment", {})
result_data = {
"text_analyzed": self.text,
"sentiment": sentiment_data.get("sentiment", "Unknown"),
"emotion": sentiment_data.get("emotion", "Unknown"),
"score": sentiment_data.get("score", 0.0),
"sentences": response.get("sentences", []),
"success": True,
}
self.status = (
f"Sentiment: {sentiment_data.get('sentiment', 'Unknown')} | "
f"Emotion: {sentiment_data.get('emotion', 'Unknown')} | "
f"Score: {sentiment_data.get('score', 0.0):.3f}"
)
return Data(data=result_data)
except JigsawStackError as e:
error_data = {"error": str(e), "text_analyzed": self.text, "success": False}
self.status = f"Error: {e!s}"
return Data(data=error_data)
def get_sentiment_text(self) -> Message:
try:
from jigsawstack import JigsawStack, JigsawStackError
except ImportError:
return Message(text="Error: JigsawStack package not found. Please install it with: pip install jigsawstack")
try:
client = JigsawStack(api_key=self.api_key)
response = client.sentiment({"text": self.text})
sentiment_data = response.get("sentiment", {})
sentences = response.get("sentences", [])
# Format the output
formatted_output = f"""Sentiment Analysis Results:
Text: {self.text}
Overall Sentiment: {sentiment_data.get("sentiment", "Unknown")}
Emotion: {sentiment_data.get("emotion", "Unknown")}
Score: {sentiment_data.get("score", 0.0):.3f}
Sentence-by-sentence Analysis:
"""
for i, sentence in enumerate(sentences, 1):
formatted_output += (
f"{i}. {sentence.get('text', '')}\n"
f" Sentiment: {sentence.get('sentiment', 'Unknown')} | "
f"Emotion: {sentence.get('emotion', 'Unknown')} | "
f"Score: {sentence.get('score', 0.0):.3f}\n"
)
return Message(text=formatted_output)
except JigsawStackError as e:
return Message(text=f"Error analyzing sentiment: {e!s}")

View file

@ -0,0 +1,90 @@
from langflow.custom.custom_component.component import Component
from langflow.io import MessageTextInput, Output, QueryInput, SecretStrInput, StrInput
from langflow.schema.data import Data
class JigsawStackTextToSQLComponent(Component):
display_name = "Text to SQL"
description = "Convert natural language to SQL queries using JigsawStack AI"
documentation = "https://jigsawstack.com/docs/api-reference/ai/text-to-sql"
icon = "JigsawStack"
name = "JigsawStackTextToSQL"
inputs = [
SecretStrInput(
name="api_key",
display_name="JigsawStack API Key",
info="Your JigsawStack API key for authentication",
required=True,
),
QueryInput(
name="prompt",
display_name="Prompt",
info="Natural language description of the SQL query you want to generate",
required=True,
tool_mode=True,
),
MessageTextInput(
name="sql_schema",
display_name="SQL Schema",
info=(
"The database schema information. Can be a CREATE TABLE statement or schema description. "
"Specifying this parameter improves SQL generation accuracy by applying "
"database-specific syntax and optimizations."
),
required=False,
tool_mode=True,
),
StrInput(
name="file_store_key",
display_name="File Store Key",
info=(
"The key used to store the database schema on Jigsawstack file Storage. "
"Not required if sql_schema is specified."
),
required=False,
tool_mode=True,
),
]
outputs = [
Output(display_name="SQL Query", name="sql_query", method="generate_sql"),
]
def generate_sql(self) -> Data:
try:
from jigsawstack import JigsawStack, JigsawStackError
except ImportError as e:
jigsawstack_import_error = (
"JigsawStack package not found. Please install it using: pip install jigsawstack>=0.2.7"
)
raise ImportError(jigsawstack_import_error) from e
try:
schema_error = "Either 'sql_schema' or 'file_store_key' must be provided"
if not self.sql_schema and not self.file_store_key:
raise ValueError(schema_error)
# build request object
params = {"prompt": self.prompt}
if self.sql_schema:
params["sql_schema"] = self.sql_schema
if self.file_store_key:
params["file_store_key"] = self.file_store_key
client = JigsawStack(api_key=self.api_key)
response = client.text_to_sql(params)
api_error_msg = "JigsawStack API returned unsuccessful response"
if not response.get("success", False):
raise ValueError(api_error_msg)
return Data(data=response)
except ValueError:
raise
except JigsawStackError as e:
error_data = {"error": str(e), "success": False}
self.status = f"Error: {e!s}"
return Data(data=error_data)

View file

@ -0,0 +1,77 @@
from langflow.custom.custom_component.component import Component
from langflow.io import MessageTextInput, Output, SecretStrInput, StrInput
from langflow.schema.data import Data
class JigsawStackTextTranslateComponent(Component):
display_name = "Text Translate"
description = "Translate text from one language to another with support for multiple text formats."
documentation = "https://jigsawstack.com/docs/api-reference/ai/translate"
icon = "JigsawStack"
name = "JigsawStackTextTranslate"
inputs = [
SecretStrInput(
name="api_key",
display_name="JigsawStack API Key",
info="Your JigsawStack API key for authentication",
required=True,
),
StrInput(
name="target_language",
display_name="Target Language",
info="The language code of the target language to translate to. \
Language code is identified by a unique ISO 639-1 two-letter code",
required=True,
tool_mode=True,
),
MessageTextInput(
name="text",
display_name="Text",
info="The text to translate. This can be a single string or a list of strings. \
If a list is provided, each string will be translated separately.",
required=True,
is_list=True,
tool_mode=True,
),
]
outputs = [
Output(display_name="Translation Results", name="translation_results", method="translation"),
]
def translation(self) -> Data:
try:
from jigsawstack import JigsawStack, JigsawStackError
except ImportError as e:
jigsawstack_import_error = (
"JigsawStack package not found. Please install it using: pip install jigsawstack>=0.2.7"
)
raise ImportError(jigsawstack_import_error) from e
try:
client = JigsawStack(api_key=self.api_key)
# build request object
params = {}
if self.target_language:
params["target_language"] = self.target_language
if self.text:
if isinstance(self.text, list):
params["text"] = self.text
else:
params["text"] = [self.text]
# Call web scraping
response = client.translate.text(params)
if not response.get("success", False):
failed_response_error = "JigsawStack API returned unsuccessful response"
raise ValueError(failed_response_error)
return Data(data=response)
except JigsawStackError as e:
error_data = {"error": str(e), "success": False}
self.status = f"Error: {e!s}"
return Data(data=error_data)

View file

@ -0,0 +1,107 @@
from langflow.custom.custom_component.component import Component
from langflow.io import IntInput, MessageTextInput, Output, SecretStrInput, StrInput
from langflow.schema.data import Data
class JigsawStackVOCRComponent(Component):
display_name = "VOCR"
description = "Extract data from any document type in a consistent structure with fine-tuned \
vLLMs for the highest accuracy"
documentation = "https://jigsawstack.com/docs/api-reference/ai/vocr"
icon = "JigsawStack"
name = "JigsawStackVOCR"
inputs = [
SecretStrInput(
name="api_key",
display_name="JigsawStack API Key",
info="Your JigsawStack API key for authentication",
required=True,
),
MessageTextInput(
name="prompts",
display_name="Prompts",
info="The prompts used to describe the image. Default prompt is Describe the image in detail. \
You can pass a list of comma-separated prompts to extract different information from the image.",
required=False,
tool_mode=True,
),
StrInput(
name="url",
display_name="URL",
info="The image or document url. Not required if file_store_key is specified.",
required=False,
tool_mode=True,
),
StrInput(
name="file_store_key",
display_name="File Store Key",
info="The key used to store the image on Jigsawstack File Storage. Not required if url is specified.",
required=False,
tool_mode=True,
),
IntInput(
name="page_range_start",
display_name="Page Range",
info="Page range start limit for the document. If not specified, all pages will be processed.",
required=False,
),
IntInput(
name="page_range_end",
display_name="Page Range End",
info="Page range end limit for the document. If not specified, all pages will be processed.",
required=False,
),
]
outputs = [
Output(display_name="VOCR results", name="vocr_results", method="vocr"),
]
def vocr(self) -> Data:
try:
from jigsawstack import JigsawStack, JigsawStackError
except ImportError as e:
jigsawstack_import_error = (
"JigsawStack package not found. Please install it using: pip install jigsawstack>=0.2.7"
)
raise ImportError(jigsawstack_import_error) from e
try:
client = JigsawStack(api_key=self.api_key)
# build request object
params = {}
if self.prompts:
if isinstance(self.prompts, list):
params["prompt"] = self.prompts
elif isinstance(self.prompts, str):
if "," in self.prompts:
# Split by comma and strip whitespace
params["prompt"] = [p.strip() for p in self.prompts.split(",")]
else:
params["prompt"] = [self.prompts.strip()]
else:
invalid_prompt_error = "Prompt must be a list of strings or a single string"
raise ValueError(invalid_prompt_error)
if self.url:
params["url"] = self.url
if self.file_store_key:
params["file_store_key"] = self.file_store_key
if self.page_range_start and self.page_range_end:
params["page_range"] = [self.page_range_start, self.page_range_end]
# Call VOCR
response = client.vision.vocr(params)
if not response.get("success", False):
failed_response_error = "JigsawStack API returned unsuccessful response"
raise ValueError(failed_response_error)
return Data(data=response)
except JigsawStackError as e:
error_data = {"error": str(e), "success": False}
self.status = f"Error: {e!s}"
return Data(data=error_data)