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:
parent
ba9740f32a
commit
8c72ea087c
20 changed files with 1356 additions and 0 deletions
|
|
@ -125,6 +125,7 @@ dependencies = [
|
|||
"twelvelabs>=0.4.7",
|
||||
"docling_core>=2.36.1",
|
||||
"filelock>=3.18.0",
|
||||
"jigsawstack==0.2.7",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
|
|
|
|||
23
src/backend/base/langflow/components/jigsawstack/__init__.py
Normal file
23
src/backend/base/langflow/components/jigsawstack/__init__.py
Normal 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",
|
||||
]
|
||||
126
src/backend/base/langflow/components/jigsawstack/ai_scrape.py
Normal file
126
src/backend/base/langflow/components/jigsawstack/ai_scrape.py
Normal 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)
|
||||
|
|
@ -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}")
|
||||
115
src/backend/base/langflow/components/jigsawstack/file_read.py
Normal file
115
src/backend/base/langflow/components/jigsawstack/file_read.py
Normal 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"
|
||||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
60
src/backend/base/langflow/components/jigsawstack/nsfw.py
Normal file
60
src/backend/base/langflow/components/jigsawstack/nsfw.py
Normal 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)
|
||||
|
|
@ -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)
|
||||
112
src/backend/base/langflow/components/jigsawstack/sentiment.py
Normal file
112
src/backend/base/langflow/components/jigsawstack/sentiment.py
Normal 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}")
|
||||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
107
src/backend/base/langflow/components/jigsawstack/vocr.py
Normal file
107
src/backend/base/langflow/components/jigsawstack/vocr.py
Normal 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)
|
||||
45
src/frontend/src/icons/JigsawStack/JigsawStackIcon.jsx
Normal file
45
src/frontend/src/icons/JigsawStack/JigsawStackIcon.jsx
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
const JigsawStackIconSVG = ({ isdark, ...props }) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="278"
|
||||
height="278"
|
||||
fill="none"
|
||||
viewBox="0 0 278 278"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill={
|
||||
isdark
|
||||
? "url(#paint0_linear_102_21_dark)"
|
||||
: "url(#paint0_linear_102_21)"
|
||||
}
|
||||
d="M137.362 262.02c-7.072-4.084-14.015-8.403-21.241-12.189-9.857-5.162-10.456-18.679-.674-23.989 5.93-3.217 10.307-7.977 12.023-14.746 2.414-9.503.058-17.739-7.334-24.089-7.243-6.213-15.746-7.815-24.674-4.145-9.01 3.697-13.87 10.731-14.673 20.486-.086.992-.035 1.993-.062 2.985-.28 10.578-10.759 16.642-19.988 11.398-14.83-8.429-29.553-17.029-44.314-25.577a17 17 0 0 1-2.237-1.535c-8.53-7.04-10.771-18.266-5.282-27.934a3227 3227 0 0 1 25.18-43.611c5.674-9.654 17.976-9.411 23.608.306 8.99 15.517 29.838 16.883 40.16 2.508 5.436-7.567 6.094-15.876 2.007-24.197S88.796 85.04 79.503 84.426c-2.508-.163-5.18-.16-7.455-1.063-7.475-2.947-10.588-11.369-6.572-18.529 8.512-15.193 17.135-30.348 26.172-45.23 5.842-9.623 17.467-12.541 27.69-7.78a48 48 0 0 1 3.609 1.906c13.592 7.84 27.271 15.543 40.725 23.622 4.269 2.566 8.677.123 8.526-4.968-.407-13.953 8.484-26.283 21.361-30.628 13.382-4.523 27.891-.117 36.253 11.007 8.417 11.19 8.922 26.459.582 37.806-2.763 3.753-6.601 7.086-10.641 9.43-4.087 2.367-4.235 7.378.112 9.795 14.03 7.807 27.873 15.951 41.755 24.016 9.273 5.388 13.664 14.085 11.698 23.596-.558 2.7-1.621 5.411-2.983 7.815-7.967 14.047-16.252 27.919-24.125 42.02-5.866 10.508-19.253 10.034-24.462.066-4.683-8.975-14.458-13.377-24.273-11.865-9.472 1.458-17.344 8.81-19.485 18.203-2.157 9.467 1.726 19.333 9.945 24.977 3.992 2.74 8.508 4.357 13.321 3.989 11.701-.896 18.42 11.212 12.146 21.51-8.257 13.561-15.939 27.463-23.897 41.203-7.022 12.134-19.534 15.497-31.651 8.535-6.839-3.931-13.67-7.892-20.502-11.837z"
|
||||
></path>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_102_21"
|
||||
x1="-2.153"
|
||||
x2="368.564"
|
||||
y1="42.449"
|
||||
y2="304.786"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0.184" stopColor="#FA242D"></stop>
|
||||
<stop offset="0.958" stopColor="#EF5B3C"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint0_linear_102_21_dark"
|
||||
x1="-2.153"
|
||||
x2="368.564"
|
||||
y1="42.449"
|
||||
y2="304.786"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0.184" stopColor="#FA242D"></stop>
|
||||
<stop offset="0.958" stopColor="#EF5B3C"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default JigsawStackIconSVG;
|
||||
9
src/frontend/src/icons/JigsawStack/index.tsx
Normal file
9
src/frontend/src/icons/JigsawStack/index.tsx
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import React, { forwardRef } from "react";
|
||||
import JigsawStackIconSVG from "./JigsawStackIcon";
|
||||
|
||||
export const JigsawStackIcon = forwardRef<
|
||||
SVGSVGElement,
|
||||
React.PropsWithChildren<{}>
|
||||
>((props, ref) => {
|
||||
return <JigsawStackIconSVG ref={ref} {...props} />;
|
||||
});
|
||||
9
src/frontend/src/icons/JigsawStack/jigsawstack-icon.svg
Normal file
9
src/frontend/src/icons/JigsawStack/jigsawstack-icon.svg
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="278" height="278" viewBox="0 0 278 278" fill="none">
|
||||
<path d="M137.362 262.02C130.29 257.936 123.347 253.617 116.121 249.831C106.264 244.669 105.665 231.152 115.447 225.842C121.377 222.625 125.754 217.865 127.47 211.096C129.884 201.593 127.528 193.357 120.136 187.007C112.893 180.794 104.39 179.192 95.4621 182.862C86.4514 186.559 81.5925 193.593 80.7888 203.348C80.7033 204.34 80.7538 205.341 80.7267 206.333C80.447 216.911 69.9683 222.975 60.7387 217.731C45.9083 209.302 31.186 200.702 16.4246 192.154C15.6437 191.703 14.8831 191.189 14.1876 190.619C5.65849 183.579 3.41687 172.353 8.90623 162.685C17.1835 148.087 25.5778 133.547 34.0854 119.074C39.7596 109.42 52.0616 109.663 57.6937 119.38C66.6846 134.897 87.5322 136.263 97.8547 121.888C103.29 114.321 103.948 106.012 99.8608 97.6912C95.7738 89.3705 88.7956 85.0394 79.5029 84.4262C76.9946 84.2628 74.3233 84.2653 72.0484 83.3631C64.5734 80.4159 61.4598 71.9941 65.4762 64.8341C73.9879 49.6405 82.6112 34.4864 91.6482 19.6045C97.4899 9.98066 109.115 7.06263 119.338 11.8231C120.568 12.3985 121.77 13.0505 122.947 13.7303C136.539 21.5692 150.218 29.2734 163.672 37.3517C167.941 39.9176 172.349 37.4752 172.198 32.3844C171.791 18.4309 180.682 6.10067 193.559 1.75604C206.941 -2.7667 221.45 1.63853 229.812 12.7632C238.229 23.9529 238.734 39.2218 230.394 50.5688C227.631 54.3218 223.793 57.655 219.753 59.9991C215.666 62.3662 215.518 67.3771 219.865 69.7945C233.895 77.6012 247.738 85.7454 261.62 93.8102C270.893 99.1977 275.284 107.895 273.318 117.406C272.76 120.106 271.697 122.817 270.335 125.221C262.368 139.268 254.083 153.14 246.21 167.241C240.344 177.749 226.957 177.275 221.748 167.307C217.065 158.332 207.29 153.93 197.475 155.442C188.003 156.9 180.131 164.252 177.99 173.645C175.833 183.112 179.716 192.978 187.935 198.622C191.927 201.362 196.443 202.979 201.256 202.611C212.957 201.715 219.676 213.823 213.402 224.121C205.145 237.682 197.463 251.584 189.505 265.324C182.483 277.458 169.971 280.821 157.854 273.859C151.015 269.928 144.184 265.967 137.352 262.022L137.362 262.02Z" fill="url(#paint0_linear_102_21)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_102_21" x1="-2.15279" y1="42.449" x2="368.564" y2="304.786" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.18365" stop-color="#FA242D"/>
|
||||
<stop offset="0.958086" stop-color="#EF5B3C"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
|
@ -112,6 +112,7 @@ import { WolframIcon } from "@/icons/Wolfram";
|
|||
import { XAIIcon } from "@/icons/xAI";
|
||||
import { YouTubeSvgIcon as YouTubeIcon } from "@/icons/Youtube";
|
||||
import { ZepMemoryIcon } from "@/icons/ZepMemory";
|
||||
import { JigsawStackIcon } from "./JigsawStack";
|
||||
import { WindsurfIcon } from "./Windsurf";
|
||||
|
||||
// Export the eagerly loaded icons map
|
||||
|
|
@ -172,6 +173,7 @@ export const eagerIconsMapping = {
|
|||
Icosa: IcosaIcon,
|
||||
IFixIt: IFixIcon,
|
||||
javascript: JSIcon,
|
||||
JigsawStack: JigsawStackIcon,
|
||||
LangChain: LangChainIcon,
|
||||
Langwatch: LangwatchIcon,
|
||||
LMStudio: LMStudioIcon,
|
||||
|
|
|
|||
|
|
@ -155,6 +155,10 @@ export const lazyIconsMapping = {
|
|||
import("@/icons/IFixIt").then((mod) => ({ default: mod.IFixIcon })),
|
||||
javascript: () =>
|
||||
import("@/icons/JSicon").then((mod) => ({ default: mod.JSIcon })),
|
||||
JigsawStack: () =>
|
||||
import("@/icons/JigsawStack").then((mod) => ({
|
||||
default: mod.JigsawStackIcon,
|
||||
})),
|
||||
LangChain: () =>
|
||||
import("@/icons/LangChain").then((mod) => ({ default: mod.LangChainIcon })),
|
||||
Langwatch: () =>
|
||||
|
|
|
|||
|
|
@ -271,6 +271,7 @@ export const SIDEBAR_BUNDLES = [
|
|||
{ display_name: "HuggingFace", name: "huggingface", icon: "HuggingFace" },
|
||||
{ display_name: "IBM", name: "ibm", icon: "WatsonxAI" },
|
||||
{ display_name: "Icosa Computing", name: "icosacomputing", icon: "Icosa" },
|
||||
{ display_name: "JigsawStack", name: "jigsawstack", icon: "JigsawStack" },
|
||||
{ display_name: "LangChain", name: "langchain_utilities", icon: "LangChain" },
|
||||
{ display_name: "LangWatch", name: "langwatch", icon: "Langwatch" },
|
||||
{ display_name: "LMStudio", name: "lmstudio", icon: "LMStudio" },
|
||||
|
|
|
|||
16
uv.lock
generated
16
uv.lock
generated
|
|
@ -3938,6 +3938,20 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jigsawstack"
|
||||
version = "0.2.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "aiohttp" },
|
||||
{ name = "requests" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/11/c6/94806e49af97a0a0313ea3931b0d3a58dd59d1d4afa194c91d9df1c480ff/jigsawstack-0.2.7.tar.gz", hash = "sha256:e4fcafe388c36c5b6785c879e934562df7fe1202bda9ae5c0e729b99e40ad3b4", size = 25410, upload-time = "2025-06-24T17:49:46.08Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/fb/0b9728a6caeb737b2801895b5af6c05a65daaf9d02404e4196fdd8118fda/jigsawstack-0.2.7-py3-none-any.whl", hash = "sha256:295bb5d10e6d686094a594864fd31c95f1a4f50d80e710f2959fc7fef5771f50", size = 30828, upload-time = "2025-06-24T17:49:43.807Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jinja2"
|
||||
version = "3.1.6"
|
||||
|
|
@ -4709,6 +4723,7 @@ dependencies = [
|
|||
{ name = "graph-retriever" },
|
||||
{ name = "huggingface-hub", extra = ["inference"] },
|
||||
{ name = "ibm-watsonx-ai" },
|
||||
{ name = "jigsawstack" },
|
||||
{ name = "jq" },
|
||||
{ name = "json-repair" },
|
||||
{ name = "kubernetes" },
|
||||
|
|
@ -4905,6 +4920,7 @@ requires-dist = [
|
|||
{ name = "graph-retriever", specifier = "==0.6.1" },
|
||||
{ name = "huggingface-hub", extras = ["inference"], specifier = ">=0.23.2,<1.0.0" },
|
||||
{ name = "ibm-watsonx-ai", specifier = ">=1.3.1" },
|
||||
{ name = "jigsawstack", specifier = "==0.2.7" },
|
||||
{ name = "jq", specifier = "==1.8.0" },
|
||||
{ name = "json-repair", specifier = "==0.30.3" },
|
||||
{ name = "kubernetes", specifier = "==31.0.0" },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue