Compare commits

..

19 Commits

Author SHA1 Message Date
Pierre-Loic Doulcet 1ebe1cee67 Add new parameter, fix parse_mode (#660)
* update with new parameters

* lint
2025-03-25 11:14:37 +01:00
Neeraj Pradhan e9252eb48a Update notebook for extract (#658) 2025-03-22 09:34:40 -07:00
Neeraj Pradhan dad7728135 Bump to version 0.6.7 (#656) 2025-03-21 21:26:54 -07:00
Neeraj Pradhan c5111e3335 Revert httpx_client as argument (#657) 2025-03-21 21:16:56 -07:00
Neeraj Pradhan bbbdb98362 Add provision for custom httpx client for LlamaExtract (#654) 2025-03-21 11:37:40 -07:00
Neeraj Pradhan 60cdc2af84 Add xfail for timeout errors in report gen (#655) 2025-03-21 11:06:49 -07:00
Neeraj Pradhan 344c20f331 Bump up version for release (#652) 2025-03-18 15:54:32 -07:00
Neeraj Pradhan 2b0496e947 Update llama cloud for extract endpoints (#651) 2025-03-18 15:43:43 -07:00
Laurie Voss 6c63dba6fb Typos and removing staging URL (#647) 2025-03-13 08:11:09 -07:00
Neeraj Pradhan 734c021a2e Add notebook for extraction from SEC 10-K/Q filings (#646)
* Add notebook for extraction from SEC 10-K/Q filings

* Add notebook for 10 k/q extraction

* Remove unnecessary cell

* fix file link

* fix code rendering

* Add notes for clarity

* fix notes
2025-03-12 20:42:17 -07:00
Neeraj Pradhan eeb034896f Bump to version 0.6.5 (updating llama-cloud dependency) (#645)
* Bump to version 0.6.5 (updating llama-cloud dependency)

* fix other endpoints
2025-03-06 18:22:42 -08:00
Sacha Bron 4c977e8384 Bump version 2025-03-06 17:04:56 +01:00
Sacha Bron c6137713c7 Add adaptive_long_table option (#638) 2025-03-04 22:42:05 +01:00
Neeraj Pradhan fd4b1893f1 Bump version to v0.6.3 (#636) 2025-02-26 15:09:39 -08:00
Neeraj Pradhan e542e6136b Update README.md (#635) 2025-02-26 15:41:19 -06:00
Neeraj Pradhan 393451e304 Add LlamaExtract to llama-cloud-services (#628) 2025-02-25 18:17:29 -08:00
Logan 5084ba27ab v0.6.2 (#632) 2025-02-25 18:35:44 -06:00
Pierre-Loic Doulcet c82771f841 add new parsing mode and prompt parameters (#622) 2025-02-25 18:24:04 -06:00
Logan dc6860535a fix publish flow (#617) 2025-02-24 22:59:02 -10:00
15 changed files with 2254 additions and 996 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ env:
jobs:
build-n-publish:
name: Build and publish to PyPI
if: github.repository == 'run-llama/llama_parse'
if: github.repository == 'run-llama/llama_cloud_services'
runs-on: ubuntu-latest
steps:
+1 -1
View File
@@ -36,7 +36,7 @@ See the quickstart guides for each service for more information:
- [LlamaParse](./parse.md)
- [LlamaReport (beta/invite-only)](./report.md)
- [LlamaExtract (coming soon!)]()
- [LlamaExtract (beta/invite-only)](./extract.md)
## Documentation
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 KiB

File diff suppressed because it is too large Load Diff
+69 -15
View File
@@ -9,16 +9,20 @@ import httpx
from pydantic import BaseModel
from llama_cloud import (
ExtractAgent as CloudExtractAgent,
ExtractAgentCreate,
ExtractConfig,
ExtractJob,
ExtractJobCreate,
ExtractRun,
ExtractSchemaValidateRequest,
ExtractAgentUpdate,
File,
ExtractMode,
StatusEnum,
Project,
ExtractTarget,
LlamaExtractSettings,
PaginatedExtractRunsResponse,
)
from llama_cloud.client import AsyncLlamaCloud
from llama_cloud_services.extract.utils import JSONObjectType, augment_async_errors
@@ -53,6 +57,8 @@ class ExtractionAgent:
num_workers: int = 4,
show_progress: bool = True,
verbose: bool = False,
verify: Optional[bool] = True,
httpx_timeout: Optional[float] = 60,
):
self._client = client
self._agent = agent
@@ -62,6 +68,8 @@ class ExtractionAgent:
self.max_timeout = max_timeout
self.num_workers = num_workers
self.show_progress = show_progress
self.verify = verify
self.httpx_timeout = httpx_timeout
self._verbose = verbose
self._data_schema: Union[JSONObjectType, None] = None
self._config: Union[ExtractConfig, None] = None
@@ -74,14 +82,20 @@ class ExtractionAgent:
def run_coro() -> T:
async def wrapped_coro() -> T:
# Get the original client to preserve its configuration
original_client = self._client._client_wrapper.httpx_client
# Create a new client with the same configuration as the original
async with httpx.AsyncClient(
timeout=self._client._client_wrapper.httpx_client.timeout,
verify=self.verify,
timeout=self.httpx_timeout,
) as client:
original_client = self._client._client_wrapper.httpx_client
# Temporarily replace the client
self._client._client_wrapper.httpx_client = client
try:
return await coro
finally:
# Restore the original client
self._client._client_wrapper.httpx_client = original_client
return asyncio.run(wrapped_coro())
@@ -114,7 +128,7 @@ class ExtractionAgent:
)
validated_schema = self._run_in_thread(
self._client.llama_extract.validate_extraction_schema(
data_schema=processed_schema
request=ExtractSchemaValidateRequest(data_schema=processed_schema)
)
)
self._data_schema = validated_schema.data_schema
@@ -187,8 +201,10 @@ class ExtractionAgent:
self._agent = self._run_in_thread(
self._client.llama_extract.update_extraction_agent(
extraction_agent_id=self.id,
data_schema=self.data_schema,
config=self.config,
request=ExtractAgentUpdate(
data_schema=self.data_schema,
config=self.config,
),
)
)
@@ -375,15 +391,29 @@ class ExtractionAgent:
)
)
def list_extraction_runs(self) -> List[ExtractRun]:
def delete_extraction_run(self, run_id: str) -> None:
"""Delete an extraction run by ID.
Args:
run_id (str): The ID of the extraction run to delete
"""
self._run_in_thread(
self._client.llama_extract.delete_extraction_run(run_id=run_id)
)
def list_extraction_runs(
self, page: int = 0, limit: int = 100
) -> PaginatedExtractRunsResponse:
"""List extraction runs for the extraction agent.
Returns:
List[ExtractRun]: List of extraction runs
PaginatedExtractRunsResponse: Paginated list of extraction runs
"""
return self._run_in_thread(
self._client.llama_extract.list_extract_runs(
extraction_agent_id=self.id,
skip=page * limit,
limit=limit,
)
)
@@ -416,6 +446,12 @@ class LlamaExtract(BaseComponent):
verbose: bool = Field(
default=False, description="Show verbose output when extracting files."
)
verify: Optional[bool] = Field(
default=True, description="Simple SSL verification option."
)
httpx_timeout: Optional[float] = Field(
default=60, description="Timeout for the httpx client."
)
_async_client: AsyncLlamaCloud = PrivateAttr()
_thread_pool: ThreadPoolExecutor = PrivateAttr()
_project_id: Optional[str] = PrivateAttr()
@@ -431,6 +467,8 @@ class LlamaExtract(BaseComponent):
show_progress: bool = True,
project_id: Optional[str] = None,
organization_id: Optional[str] = None,
verify: Optional[bool] = True,
httpx_timeout: Optional[float] = 60,
verbose: bool = False,
):
if not api_key:
@@ -448,11 +486,18 @@ class LlamaExtract(BaseComponent):
max_timeout=max_timeout,
num_workers=num_workers,
show_progress=show_progress,
verify=verify,
httpx_timeout=httpx_timeout,
verbose=verbose,
)
self._httpx_client = httpx.AsyncClient(verify=verify, timeout=httpx_timeout)
self.verify = verify
self.httpx_timeout = httpx_timeout
self._async_client = AsyncLlamaCloud(
token=self.api_key, base_url=self.base_url, timeout=None
token=self.api_key,
base_url=self.base_url,
httpx_client=self._httpx_client,
)
self._thread_pool = ThreadPoolExecutor(
max_workers=min(10, (os.cpu_count() or 1) + 4)
@@ -481,17 +526,22 @@ class LlamaExtract(BaseComponent):
def run_coro() -> T:
# Create a new client for this thread
async def wrapped_coro() -> T:
assert (
self._httpx_client is not None
), "httpx_client should be initialized"
# Create a new client with the same configuration as the original
async with httpx.AsyncClient(
timeout=self._async_client._client_wrapper.httpx_client.timeout,
verify=self.verify,
timeout=self.httpx_timeout,
) as client:
# Replace the client in the coro's context
original_client = self._async_client._client_wrapper.httpx_client
# Temporarily replace the client
self._async_client._client_wrapper.httpx_client = client
try:
return await coro
finally:
# Restore the original client
self._async_client._client_wrapper.httpx_client = (
original_client
self._httpx_client
)
return asyncio.run(wrapped_coro())
@@ -526,11 +576,13 @@ class LlamaExtract(BaseComponent):
agent = self._run_in_thread(
self._async_client.llama_extract.create_extraction_agent(
name=name,
data_schema=data_schema,
config=config or DEFAULT_EXTRACT_CONFIG,
project_id=self._project_id,
organization_id=self._organization_id,
request=ExtractAgentCreate(
name=name,
data_schema=data_schema,
config=config or DEFAULT_EXTRACT_CONFIG,
),
)
)
@@ -592,6 +644,8 @@ class LlamaExtract(BaseComponent):
num_workers=self.num_workers,
show_progress=self.show_progress,
verbose=self.verbose,
verify=self.verify,
httpx_timeout=self.httpx_timeout,
)
def list_agents(self) -> List[ExtractionAgent]:
+72 -18
View File
@@ -111,6 +111,10 @@ class LlamaParse(BasePydanticReader):
)
# Parsing specific configurations (Alphabetical order)
adaptive_long_table: Optional[bool] = Field(
default=False,
description="If set to true, LlamaParse will try to detect long table and adapt the output.",
)
annotate_links: Optional[bool] = Field(
default=False,
description="Annotate links found in the document to extract their URL.",
@@ -163,14 +167,7 @@ class LlamaParse(BasePydanticReader):
default=None,
description="The top margin of the bounding box to use to extract text from documents expressed as a float between 0 and 1 representing the percentage of the page height.",
)
complemental_formatting_instruction: Optional[str] = Field(
default=None,
description="The complemental formatting instruction for the parser. Tell llamaParse how some thing should to be formatted, while retaining the markdown output.",
)
content_guideline_instruction: Optional[str] = Field(
default=None,
description="The content guideline for the parser. Tell LlamaParse how the content should be changed / transformed.",
)
continuous_mode: Optional[bool] = Field(
default=False,
description="Parse documents continuously, leading to better results on documents where tables span across two pages.",
@@ -203,10 +200,7 @@ class LlamaParse(BasePydanticReader):
default=False,
description="Note: Non compatible with gpt-4o. If set to true, the parser will use a faster mode to extract text from documents. This mode will skip OCR of images, and table/heading reconstruction.",
)
formatting_instruction: Optional[str] = Field(
default=None,
description="The Formatting instruction for the parser. Override default llamaParse behavior. In most case you want to use complemental_formatting_instruction instead.",
)
guess_xlsx_sheet_names: Optional[bool] = Field(
default=False,
description="Whether to guess the sheet names of the xlsx file.",
@@ -282,10 +276,18 @@ class LlamaParse(BasePydanticReader):
default=None,
description="A templated suffix to add to the beginning of each page. If it contain `{page_number}`, it will be replaced by the page number.",
)
parse_mode: Optional[str] = Field(
default=None,
description="The parsing mode to use, see ParsingMode enum for possible values ",
)
premium_mode: Optional[bool] = Field(
default=False,
description="Use our best parser mode if set to True.",
)
preserve_layout_alignment_across_pages: Optional[bool] = Field(
default=False,
description="Preserve grid alignment across page in text mode.",
)
skip_diagonal_text: Optional[bool] = Field(
default=False,
description="If set to true, the parser will ignore diagonal text (when the text rotation in degrees modulo 90 is not 0).",
@@ -327,6 +329,14 @@ class LlamaParse(BasePydanticReader):
default=None,
description="The named JSON Schema to use to structure the output of the parsing job. For convenience / testing, LlamaParse provides a few named JSON Schema that can be used directly. Use 'imFeelingLucky' to let llamaParse dream the schema.",
)
system_prompt: Optional[str] = Field(
default=None,
description="The system prompt. Replace llamaParse default system prompt, may impact accuracy",
)
system_prompt_append: Optional[str] = Field(
default=None,
description="String to append to default system prompt.",
)
take_screenshot: Optional[bool] = Field(
default=False,
description="Whether to take screenshot of each page of the document.",
@@ -335,9 +345,9 @@ class LlamaParse(BasePydanticReader):
default=None,
description="The target pages to extract text from documents. Describe as a comma separated list of page numbers. The first page of the document is page 0",
)
use_vendor_multimodal_model: Optional[bool] = Field(
default=False,
description="Whether to use the vendor multimodal API.",
user_prompt: Optional[str] = Field(
default=None,
description="The user prompt. Replace llamaParse default user prompt",
)
vendor_multimodal_api_key: Optional[str] = Field(
default=None,
@@ -357,6 +367,18 @@ class LlamaParse(BasePydanticReader):
default=None,
description="The bounding box to use to extract text from documents describe as a string containing the bounding box margins",
)
complemental_formatting_instruction: Optional[str] = Field(
default=None,
description="The complemental formatting instruction for the parser. Tell llamaParse how some thing should to be formatted, while retaining the markdown output.",
)
content_guideline_instruction: Optional[str] = Field(
default=None,
description="The content guideline for the parser. Tell LlamaParse how the content should be changed / transformed.",
)
formatting_instruction: Optional[str] = Field(
default=None,
description="The Formatting instruction for the parser. Override default llamaParse behavior. In most case you want to use complemental_formatting_instruction instead.",
)
gpt4o_mode: Optional[bool] = Field(
default=False,
description="Whether to use gpt-4o extract text from documents.",
@@ -373,6 +395,11 @@ class LlamaParse(BasePydanticReader):
default="", description="The parsing instruction for the parser."
)
use_vendor_multimodal_model: Optional[bool] = Field(
default=False,
description="Whether to use the vendor multimodal API.",
)
@field_validator("api_key", mode="before", check_fields=True)
@classmethod
def validate_api_key(cls, v: str) -> str:
@@ -501,6 +528,9 @@ class LlamaParse(BasePydanticReader):
data["from_python_package"] = True
if self.adaptive_long_table:
data["adaptive_long_table"] = self.adaptive_long_table
if self.annotate_links:
data["annotate_links"] = self.annotate_links
@@ -552,11 +582,17 @@ class LlamaParse(BasePydanticReader):
data["bbox_top"] = self.bbox_top
if self.complemental_formatting_instruction:
print(
"WARNING: complemental_formatting_instruction is deprecated and may be remove in a future release. Use system_prompt, system_prompt_append or user_prompt instead."
)
data[
"complemental_formatting_instruction"
] = self.complemental_formatting_instruction
if self.content_guideline_instruction:
print(
"WARNING: content_guideline_instruction is deprecated and may be remove in a future release. Use system_prompt, system_prompt_append or user_prompt instead."
)
data["content_guideline_instruction"] = self.content_guideline_instruction
if self.continuous_mode:
@@ -584,6 +620,9 @@ class LlamaParse(BasePydanticReader):
data["fast_mode"] = self.fast_mode
if self.formatting_instruction:
print(
"WARNING: formatting_instruction is deprecated and may be remove in a future release. Use system_prompt, system_prompt_append or user_prompt instead."
)
data["formatting_instruction"] = self.formatting_instruction
if self.guess_xlsx_sheet_names:
@@ -623,6 +662,9 @@ class LlamaParse(BasePydanticReader):
data["invalidate_cache"] = self.invalidate_cache
if self.is_formatting_instruction:
print(
"WARNING: formatting_instruction is deprecated and may be remove in a future release. Use system_prompt, system_prompt_append or user_prompt instead."
)
data["is_formatting_instruction"] = self.is_formatting_instruction
if self.job_timeout_extra_time_per_page_in_seconds is not None:
@@ -664,13 +706,21 @@ class LlamaParse(BasePydanticReader):
if self.parsing_instruction:
print(
"WARNING: parsing_instruction is deprecated. Use complemental_formatting_instruction or content_guideline_instruction instead."
"WARNING: parsing_instruction is deprecated. Use system_prompt, system_prompt_append or user_prompt instead."
)
data["parsing_instruction"] = self.parsing_instruction
if self.parse_mode:
data["parse_mode"] = self.parse_mode
if self.premium_mode:
data["premium_mode"] = self.premium_mode
if self.preserve_layout_alignment_across_pages:
data[
"preserve_layout_alignment_across_pages"
] = self.preserve_layout_alignment_across_pages
if self.skip_diagonal_text:
data["skip_diagonal_text"] = self.skip_diagonal_text
@@ -699,13 +749,17 @@ class LlamaParse(BasePydanticReader):
data[
"structured_output_json_schema_name"
] = self.structured_output_json_schema_name
if self.system_prompt is not None:
data["system_prompt"] = self.system_prompt
if self.system_prompt_append is not None:
data["system_prompt_append"] = self.system_prompt_append
if self.take_screenshot:
data["take_screenshot"] = self.take_screenshot
if self.target_pages is not None:
data["target_pages"] = self.target_pages
if self.user_prompt is not None:
data["user_prompt"] = self.user_prompt
if self.use_vendor_multimodal_model:
data["use_vendor_multimodal_model"] = self.use_vendor_multimodal_model
+10
View File
@@ -14,6 +14,16 @@ class ResultType(str, Enum):
STRUCTURED = "structured"
class ParsingMode(str, Enum):
"""The parsing mode for the parser."""
parse_page_without_llm = "parse_page_without_llm"
parse_page_with_llm = "parse_page_with_llm"
parse_page_with_lvm = "parse_page_with_lvm"
parse_page_with_agent = "parse_page_with_agent"
parse_document_with_llm = "parse_document_with_llm"
class Language(str, Enum):
BAZA = "abq"
ADYGHE = "ady"
+2 -2
View File
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "llama-parse"
version = "0.6.1"
version = "0.6.8"
description = "Parse files into RAG-Optimized formats."
authors = ["Logan Markewich <logan@llamaindex.ai>"]
license = "MIT"
@@ -13,7 +13,7 @@ packages = [{include = "llama_parse"}]
[tool.poetry.dependencies]
python = ">=3.9,<4.0"
llama-cloud-services = ">=0.6.1"
llama-cloud-services = ">=0.6.7"
[tool.poetry.group.dev.dependencies]
pytest = "^8.0.0"
Generated
+961 -955
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -8,7 +8,7 @@ python_version = "3.10"
[tool.poetry]
name = "llama-cloud-services"
version = "0.6.1"
version = "0.6.8"
description = "Tailored SDK clients for LlamaCloud services."
authors = ["Logan Markewich <logan@runllama.ai>"]
license = "MIT"
@@ -18,7 +18,7 @@ packages = [{include = "llama_cloud_services"}]
[tool.poetry.dependencies]
python = ">=3.9,<4.0"
llama-index-core = ">=0.11.0"
llama-cloud = "^0.1.11"
llama-cloud = "^0.1.16"
pydantic = "!=2.10"
click = "^8.1.7"
python-dotenv = "^1.0.1"
+9 -2
View File
@@ -182,7 +182,14 @@ class TestExtractionAgent:
assert "new_field" in updated_agent.data_schema["properties"]
def test_list_extraction_runs(self, test_agent: ExtractionAgent):
assert len(test_agent.list_extraction_runs()) == 0
assert test_agent.list_extraction_runs().total == 0
test_agent.extract(TEST_PDF)
runs = test_agent.list_extraction_runs()
assert len(runs) > 0
assert runs.total > 0
def test_delete_extraction_run(self, test_agent: ExtractionAgent):
assert test_agent.list_extraction_runs().total == 0
run = test_agent.extract(TEST_PDF)
test_agent.delete_extraction_run(run.id)
runs = test_agent.list_extraction_runs()
assert runs.total == 0
+5
View File
@@ -81,6 +81,11 @@ async def test_create_and_delete_report(
@pytest.mark.asyncio
@pytest.mark.xfail(
condition=lambda: os.getenv("CI"),
reason="Report plan sometimes times out",
raises=TimeoutError,
)
async def test_report_plan_workflow(report: ReportClient) -> None:
"""Test the report planning workflow."""
# Wait for the plan