diff --git a/README.md b/README.md index cbdf6d1..de71f27 100644 --- a/README.md +++ b/README.md @@ -7,135 +7,18 @@ LLMs are powerful, but their output is as good as the input you provide. LLMWhisperer is a technology that presents data from complex documents (different designs and formats) to LLMs in a way that they can best understand. LLMWhisperer features include Layout Preserving Mode, Auto-switching between native text and OCR modes, proper representation of radio buttons and checkboxes in PDF forms as raw text, among other features. You can now extract raw text from complex PDF documents or images without having to worry about whether the document is a native text document, a scanned image or just a picture clicked on a smartphone. Extraction of raw text from invoices, purchase orders, bank statements, etc works easily for structured data extraction with LLMs powered by LLMWhisperer's Layout Preserving mode. -Refer to the client documentation for more information: [LLMWhisperer Client Documentation](https://docs.unstract.com/llmwhisperer/index.html) +Refer to the client documentation for more information: [LLMWhisperer Client Documentation](https://docs.unstract.com/llmwhisperer/llm_whisperer/python_client/llm_whisperer_python_client_intro/) -## Features +## A note on versions -- Easy to use Pythonic interface. -- Handles all the HTTP requests and responses for you. -- Raises Python exceptions for API errors. +There are two versions of the client library available in this package: -## Installation +**LLMWhispererClient**: This is the legacy version of the client library and is recommended for supporting older apps only. This version will be deprecated in the future. -You can install the LLMWhisperer Python Client using pip: +**LLMWhispererClientV2**: This is the latest version of the client library and is recommended for all new users. It is mandatory for all users who are using LLMWhisperer API version 2.0.0 and above (All customers who have signed up after 5th November 2024). -```bash -pip install llmwhisperer-client -``` +Documentation for both versions are available [here](https://docs.unstract.com/llmwhisperer/) -## Usage - -First, import the `LLMWhispererClient` from the `client` module: - -```python -from unstract.llmwhisperer.client import LLMWhispererClient -``` - -Then, create an instance of the `LLMWhispererClient`: - -```python -client = LLMWhispererClient(base_url="https://llmwhisperer-api.unstract.com/v1", api_key="your_api_key") -``` - -Now, you can use the client to interact with the LLMWhisperer API: - -```python -# Get usage info -usage_info = client.get_usage_info() - -# Process a document -# Extracted text is available in the 'extracted_text' field of the result -whisper = client.whisper(file_path="path_to_your_file") - -# Get the status of a whisper operation -# whisper_hash is available in the 'whisper_hash' field of the result of the whisper operation -status = client.whisper_status(whisper_hash) - -# Retrieve the result of a whisper operation -# whisper_hash is available in the 'whisper_hash' field of the result of the whisper operation -whisper = client.whisper_retrieve(whisper_hash) -``` - -### Error Handling - -The client raises `LLMWhispererClientException` for API errors: - -```python -try: - result = client.whisper_retrieve("invalid_hash") -except LLMWhispererClientException as e: - print(f"Error: {e.message}, Status Code: {e.status_code}") -``` - -### Simple use case with defaults - -```python -client = LLMWhispererClient() -try: - result = client.whisper(file_path="sample_files/restaurant_invoice_photo.pdf") - extracted_text = result["extracted_text"] - print(extracted_text) -except LLMWhispererClientException as e: - print(e) -``` - -### Simple use case with more options set -We are forcing text processing and extracting text from the first two pages only. - -```python -client = LLMWhispererClient() -try: - result = client.whisper( - file_path="sample_files/credit_card.pdf", - processing_mode="text", - force_text_processing=True, - pages_to_extract="1,2", - ) - extracted_text = result["extracted_text"] - print(extracted_text) -except LLMWhispererClientException as e: - print(e) -``` - -### Extraction with timeout set - -The platform has a hard timeout of 200 seconds. If the document takes more than 200 seconds to convert (large documents), the platform will switch to async extraction and return a hash. The client can be used to check the status of the extraction and retrieve the result. Also note that the timeout is in seconds and can be set by the caller too. - - -```python -client = LLMWhispererClient() -try: - result = client.whisper( - file_path="sample_files/credit_card.pdf", - pages_to_extract="1,2", - timeout=2, - ) - if result["status_code"] == 202: - print("Timeout occured. Whisper request accepted.") - print(f"Whisper hash: {result['whisper-hash']}") - while True: - print("Polling for whisper status...") - status = client.whisper_status(whisper_hash=result["whisper-hash"]) - if status["status"] == "processing": - print("STATUS: processing...") - elif status["status"] == "delivered": - print("STATUS: Already delivered!") - break - elif status["status"] == "unknown": - print("STATUS: unknown...") - break - elif status["status"] == "processed": - print("STATUS: processed!") - print("Let's retrieve the result of the extraction...") - resultx = client.whisper_retrieve( - whisper_hash=result["whisper-hash"] - ) - print(resultx["extracted_text"]) - break - time.sleep(2) -except LLMWhispererClientException as e: - print(e) -``` ## Questions and Feedback diff --git a/src/unstract/llmwhisperer/__init__.py b/src/unstract/llmwhisperer/__init__.py index 54049f0..4563c5f 100644 --- a/src/unstract/llmwhisperer/__init__.py +++ b/src/unstract/llmwhisperer/__init__.py @@ -1,4 +1,4 @@ -__version__ = "0.23.0" +__version__ = "2.0.0" from .client import LLMWhispererClient # noqa: F401 from .client_v2 import LLMWhispererClientV2 # noqa: F401 diff --git a/src/unstract/llmwhisperer/client_v2.py b/src/unstract/llmwhisperer/client_v2.py index 97210cf..f460ed7 100644 --- a/src/unstract/llmwhisperer/client_v2.py +++ b/src/unstract/llmwhisperer/client_v2.py @@ -27,7 +27,7 @@ import requests -BASE_URL = "https://llmwhisperer-api.unstract.com/api/v2" +BASE_URL_V2 = "https://llmwhisperer-api.us-central.unstract.com/api/v2" class LLMWhispererClientException(Exception): @@ -62,7 +62,9 @@ class LLMWhispererClientV2: client's activities and errors. """ - formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") + formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + ) logger = logging.getLogger(__name__) log_stream_handler = logging.StreamHandler() log_stream_handler.setFormatter(formatter) @@ -108,7 +110,7 @@ def __init__( self.logger.debug("logging_level set to %s", logging_level) if base_url == "": - self.base_url = os.getenv("LLMWHISPERER_BASE_URL_V2", BASE_URL) + self.base_url = os.getenv("LLMWHISPERER_BASE_URL_V2", BASE_URL_V2) else: self.base_url = base_url self.logger.debug("base_url set to %s", self.base_url) @@ -281,7 +283,9 @@ def generate(): ) else: params["url_in_post"] = True - req = requests.Request("POST", api_url, params=params, headers=self.headers, data=url) + req = requests.Request( + "POST", api_url, params=params, headers=self.headers, data=url + ) prepared = req.prepare() s = requests.Session() response = s.send(prepared, timeout=wait_timeout, stream=should_stream) @@ -307,9 +311,13 @@ def generate(): message["extraction"] = {} return message if status["status"] == "processing": - self.logger.debug(f"Whisper-hash:{whisper_hash} | STATUS: processing...") + self.logger.debug( + f"Whisper-hash:{whisper_hash} | STATUS: processing..." + ) elif status["status"] == "delivered": - self.logger.debug(f"Whisper-hash:{whisper_hash} | STATUS: Already delivered!") + self.logger.debug( + f"Whisper-hash:{whisper_hash} | STATUS: Already delivered!" + ) raise LLMWhispererClientException( { "status_code": -1, @@ -317,7 +325,9 @@ def generate(): } ) elif status["status"] == "unknown": - self.logger.debug(f"Whisper-hash:{whisper_hash} | STATUS: unknown...") + self.logger.debug( + f"Whisper-hash:{whisper_hash} | STATUS: unknown..." + ) raise LLMWhispererClientException( { "status_code": -1, @@ -325,13 +335,17 @@ def generate(): } ) elif status["status"] == "failed": - self.logger.debug(f"Whisper-hash:{whisper_hash} | STATUS: failed...") + self.logger.debug( + f"Whisper-hash:{whisper_hash} | STATUS: failed..." + ) message["status_code"] = -1 message["message"] = "Whisper operation failed" message["extraction"] = {} return message elif status["status"] == "processed": - self.logger.debug(f"Whisper-hash:{whisper_hash} | STATUS: processed!") + self.logger.debug( + f"Whisper-hash:{whisper_hash} | STATUS: processed!" + ) resultx = self.whisper_retrieve(whisper_hash=whisper_hash) if resultx["status_code"] == 200: message["status_code"] = 200