Compare commits

..

3 Commits

Author SHA1 Message Date
Logan Markewich d10b1a82f1 factor out retry decision 2025-12-09 11:00:53 -06:00
Logan Markewich 12dcb71e04 changesets 2025-12-09 10:53:27 -06:00
Logan Markewich b69991603c improve polling 2025-12-09 10:52:45 -06:00
26 changed files with 3335 additions and 309 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"llama-cloud-services": patch
---
Improve parse results polling
+1 -1
View File
@@ -398,6 +398,6 @@ Another option (orthogonal to the above) is to break the document into smaller s
## Additional Resources
- [Extract Documentation](https://docs.cloud.llamaindex.ai/llamaextract/getting_started) - Details on Extract features, API and examples.
- [Example Notebook](examples/extract/resume_screening.ipynb) - Detailed walkthrough of resume parsing
- [Example Notebook](docs/examples-py/extract/resume_screening.ipynb) - Detailed walkthrough of resume parsing
- [Example Application with TypeScript](./examples-ts/extract/) - End-to-end examples using LlamaExtract TypeScript client.
- [Discord Community](https://discord.com/invite/eN6D2HQ4aX) - Get help and share feedback
+5 -5
View File
@@ -97,7 +97,7 @@ for page in result.pages:
print(page.structuredData)
```
See more details about the result object in the [example notebook](./examples/parse/demo_json_tour.ipynb).
See more details about the result object in the [example notebook](./docs/examples-py/parse/demo_json_tour.ipynb).
### Using with file object / bytes
@@ -153,10 +153,10 @@ Full documentation for `SimpleDirectoryReader` can be found on the [LlamaIndex D
Several end-to-end indexing examples can be found in the examples folder
- [Getting Started](examples/parse/demo_basic.ipynb)
- [Advanced RAG Example](examples/parse/demo_advanced.ipynb)
- [Raw API Usage](examples/parse/demo_api.ipynb)
- [Result Object Tour](examples/parse/demo_json_tour.ipynb)
- [Getting Started](docs/examples-py/parse/demo_basic.ipynb)
- [Advanced RAG Example](docs/examples-py/parse/demo_advanced.ipynb)
- [Raw API Usage](docs/examples-py/parse/demo_api.ipynb)
- [Result Object Tour](docs/examples-py/parse/demo_json_tour.ipynb)
## Documentation
+3260 -48
View File
File diff suppressed because it is too large Load Diff
-12
View File
@@ -1,17 +1,5 @@
# llama-cloud-services-py
## 0.6.90
### Patch Changes
- 19cbb25: Remove extension filter
## 0.6.89
### Patch Changes
- b9b83c9: Parse bounding boxes from extract jobs results in agent data
## 0.6.88
### Patch Changes
@@ -11,9 +11,6 @@ from .schema import (
InvalidExtractionData,
ExtractedFieldMetadata,
ExtractedFieldMetaDataDict,
FieldCitation,
BoundingBox,
PageDimensions,
)
from .client import AsyncAgentDataClient
@@ -31,7 +28,4 @@ __all__ = [
"InvalidExtractionData",
"ExtractedFieldMetadata",
"ExtractedFieldMetaDataDict",
"FieldCitation",
"BoundingBox",
"PageDimensions",
]
@@ -174,22 +174,6 @@ class TypedAgentDataItems(BaseModel, Generic[AgentDataT]):
)
class BoundingBox(BaseModel):
"""Bounding box coordinates for a citation location on a page."""
x: float = Field(description="X coordinate of the bounding box origin")
y: float = Field(description="Y coordinate of the bounding box origin")
w: float = Field(description="Width of the bounding box")
h: float = Field(description="Height of the bounding box")
class PageDimensions(BaseModel):
"""Dimensions of a page in the source document."""
width: float = Field(description="Width of the page")
height: float = Field(description="Height of the page")
class FieldCitation(BaseModel):
page: Optional[int] = Field(
None, description="The page number that the field occurred on"
@@ -198,14 +182,6 @@ class FieldCitation(BaseModel):
None,
description="The original text this field's value was derived from",
)
bounding_boxes: Optional[List[BoundingBox]] = Field(
None,
description="Bounding boxes indicating where the citation appears on the page",
)
page_dimensions: Optional[PageDimensions] = Field(
None,
description="Dimensions of the page containing the citation",
)
class ExtractedFieldMetadata(BaseModel):
@@ -225,10 +201,6 @@ class ExtractedFieldMetadata(BaseModel):
None,
description="The confidence score for the field based on the extracted text only",
)
parsing_confidence: Optional[float] = Field(
None,
description="The confidence score for the field based on the parsing/OCR quality",
)
citation: Optional[List[FieldCitation]] = Field(
None,
description="The citation for the field, including page number and matching text",
+5 -3
View File
@@ -751,9 +751,11 @@ class LlamaParse(BasePydanticReader):
file_path = str(file_input)
file_ext = os.path.splitext(file_path)[1].lower()
if file_ext not in SUPPORTED_FILE_TYPES:
mime_type = "application/octet-stream"
else:
mime_type = mimetypes.guess_type(file_path)[0]
raise Exception(
f"Currently, only the following file types are supported: {SUPPORTED_FILE_TYPES}\n"
f"Current file type: {file_ext}"
)
mime_type = mimetypes.guess_type(file_path)[0]
# Open the file here for the duration of the async context
# load data, set the mime type
fs = fs or get_default_fs()
-15
View File
@@ -1,20 +1,5 @@
# llama_parse
## 0.6.90
### Patch Changes
- 19cbb25: Remove extension filter
- Updated dependencies [19cbb25]
- llama-cloud-services-py@0.6.90
## 0.6.89
### Patch Changes
- Updated dependencies [b9b83c9]
- llama-cloud-services-py@0.6.89
## 0.6.88
### Patch Changes
+3 -3
View File
@@ -146,9 +146,9 @@ Full documentation for `SimpleDirectoryReader` can be found on the [LlamaIndex D
Several end-to-end indexing examples can be found in the examples folder
- [Getting Started](../../examples/parse/demo_basic.ipynb)
- [Advanced RAG Example](../../examples/parse/demo_advanced.ipynb)
- [Raw API Usage](../../examples/parse/demo_api.ipynb)
- [Getting Started](/docs/examples-py/parse/demo_basic.ipynb)
- [Advanced RAG Example](/docs/examples-py/parse/demo_advanced.ipynb)
- [Raw API Usage](/docs/examples-py/parse/demo_api.ipynb)
## Documentation
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "llama_parse",
"version": "0.6.90",
"version": "0.6.88",
"description": "",
"main": "index.js",
"private": false,
+2 -2
View File
@@ -11,13 +11,13 @@ dev = [
[project]
name = "llama-parse"
version = "0.6.90"
version = "0.6.88"
description = "Parse files into RAG-Optimized formats."
authors = [{name = "Logan Markewich", email = "logan@llamaindex.ai"}]
requires-python = ">=3.9,<4.0"
readme = "README.md"
license = "MIT"
dependencies = ["llama-cloud-services>=0.6.90"]
dependencies = ["llama-cloud-services>=0.6.88"]
[project.scripts]
llama-parse = "llama_parse.cli.main:parse"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "llama-cloud-services-py",
"version": "0.6.90",
"version": "0.6.88",
"private": false,
"license": "MIT",
"scripts": {},
+1 -1
View File
@@ -23,7 +23,7 @@ dev = [
[project]
name = "llama-cloud-services"
version = "0.6.90"
version = "0.6.88"
description = "Tailored SDK clients for LlamaCloud services."
authors = [{name = "Logan Markewich", email = "logan@runllama.ai"}]
requires-python = ">=3.9,<4.0"
@@ -11,12 +11,10 @@ from llama_cloud.types.aggregate_group import AggregateGroup
from pydantic import BaseModel, Field, ValidationError
from llama_cloud_services.beta.agent_data.schema import (
BoundingBox,
ExtractedData,
ExtractedFieldMetadata,
FieldCitation,
InvalidExtractionData,
PageDimensions,
TypedAgentData,
TypedAggregateGroup,
calculate_overall_confidence,
@@ -665,69 +663,3 @@ def test_field_conflict_in_schema():
assert isinstance(
extracted["majority_opinion"]["reasoning"], ExtractedFieldMetadata
)
def test_parse_extracted_field_metadata_with_bounding_boxes():
"""Test parse_extracted_field_metadata with bounding boxes and page dimensions."""
raw_metadata = {
"document_type": {
"citation": [
{
"page": 1,
"matching_text": "FACTURE ORIGINALE",
"bounding_boxes": [{"x": 77.28, "y": 615.12, "w": 70.6, "h": 7.2}],
"page_dimensions": {"width": 222.24, "height": 736.56},
}
],
"parsing_confidence": 1.0,
"extraction_confidence": 0.7252506422636493,
"confidence": 0.7252506422636493,
},
"summary": {
"citation": [
{
"page": 1,
"matching_text": "FACTURE ORIGINALE",
"bounding_boxes": [{"x": 77.28, "y": 615.12, "w": 70.6, "h": 7.2}],
"page_dimensions": {"width": 222.24, "height": 736.56},
},
{
"page": 1,
"matching_text": "Café filtre assiette — $1.90",
"bounding_boxes": [
{"x": 10.56, "y": 172.83, "w": 171.85, "h": 497.01}
],
"page_dimensions": {"width": 222.24, "height": 736.56},
},
],
"parsing_confidence": 1.0,
"extraction_confidence": 0.5700013128334419,
"confidence": 0.5700013128334419,
},
}
result = parse_extracted_field_metadata(raw_metadata)
# Verify document_type citation with bounding boxes
assert isinstance(result["document_type"], ExtractedFieldMetadata)
assert result["document_type"].parsing_confidence == 1.0
assert result["document_type"].extraction_confidence == 0.7252506422636493
assert result["document_type"].confidence == 0.7252506422636493
assert len(result["document_type"].citation) == 1
citation = result["document_type"].citation[0]
assert citation.page == 1
assert citation.matching_text == "FACTURE ORIGINALE"
assert len(citation.bounding_boxes) == 1
assert citation.bounding_boxes[0] == BoundingBox(x=77.28, y=615.12, w=70.6, h=7.2)
assert citation.page_dimensions == PageDimensions(width=222.24, height=736.56)
# Verify summary citation with multiple bounding boxes
assert isinstance(result["summary"], ExtractedFieldMetadata)
assert len(result["summary"].citation) == 2
assert result["summary"].citation[0].bounding_boxes[0].x == 77.28
assert result["summary"].citation[1].bounding_boxes[0].x == 10.56
# Verify round-trip serialization
result2 = parse_extracted_field_metadata(result)
assert result2 == result
Generated
+2 -2
View File
@@ -1,5 +1,5 @@
version = 1
revision = 3
revision = 2
requires-python = ">=3.9, <4.0"
resolution-markers = [
"python_full_version >= '3.14'",
@@ -1609,7 +1609,7 @@ wheels = [
[[package]]
name = "llama-cloud-services"
version = "0.6.88"
version = "0.6.85"
source = { editable = "." }
dependencies = [
{ name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
-33
View File
@@ -1,38 +1,5 @@
# llama-cloud-services
## 0.5.3
### Patch Changes
- d7864af: bugfixes in retry logic for LlamaExtract and LlamaClassify
## 0.5.2
### Patch Changes
- 997bcc8: Add types for bounding boxes
## 0.5.1
### Patch Changes
- d5b18a0: Fix publishing
## 0.5.0
### Minor Changes
- 576c3d9: feat: support zod v4 & v3
Adds support for zod v4 while maintaining backward compatibility with v3.
- Updated zod peer dependency to accept both v3 and v4: `^3.25.76 || ^4.0.0`
- Migrated all import statements to use `zod/v4` import path for compatibility
### Patch Changes
- c8321d2: Improve parse results polling
- 576c3d9: Support zod v3 an v4
## 0.4.3
### Patch Changes
+8 -9
View File
@@ -1,12 +1,12 @@
{
"name": "llama-cloud-services",
"version": "0.5.3",
"version": "0.4.3",
"type": "module",
"license": "MIT",
"scripts": {
"get-openapi": "node ./scripts/get-openapi.js",
"generate": "./node_modules/.bin/openapi-ts",
"build": "bunchee",
"build": "pnpm run generate && bunchee",
"dev": "bunchee --watch",
"lint": "eslint src/ --ignore-pattern client/*.ts --no-warn-ignored",
"format": "prettier --write ./src/ tests/",
@@ -116,9 +116,9 @@
"@eslint/js": "^9.32.0",
"@hey-api/client-fetch": "^0.10.1",
"@hey-api/openapi-ts": "^0.67.5",
"@llamaindex/core": "^0.6.22",
"@llamaindex/core": "^0.6.19",
"@llamaindex/env": "^0.1.30",
"@llamaindex/workflow-core": "^1.3.3",
"@llamaindex/workflow-core": "^0.4.1",
"@types/node": "^20.19.9",
"@typescript-eslint/eslint-plugin": "^8.38.0",
"@typescript-eslint/parser": "^8.38.0",
@@ -131,19 +131,18 @@
"turbo": "^2.5.5",
"typescript": "^5.8.3",
"typescript-eslint": "^8.38.0",
"vitest": "^2.0.0",
"zod": "^4.1.13"
"vitest": "^2.0.0"
},
"peerDependencies": {
"@llamaindex/core": "^0.6.19",
"@llamaindex/env": "^0.1.30",
"@llamaindex/workflow-core": "^1.3.3",
"zod": "^3.25.0 || ^4.0.0"
"@llamaindex/workflow-core": "^0.4.1"
},
"dependencies": {
"ajv": "^8.17.1",
"file-type": "^21.0.0",
"p-retry": "^6.2.1"
"p-retry": "^6.2.1",
"zod": "^3.25.76"
},
"packageManager": "pnpm@10.8.1"
}
@@ -2,14 +2,11 @@ export { AgentClient, createAgentDataClient } from "./client";
export type {
AggregateAgentDataOptions,
BoundingBox,
ComparisonOperator,
ExtractedData,
ExtractedFieldMetadata,
ExtractedFieldMetadataDict,
FieldCitation,
FilterOperation,
PageDimensions,
SearchAgentDataOptions,
StatusType,
TypedAgentData,
@@ -28,44 +28,6 @@ export type ComparisonOperator =
*/
export type FilterOperation = RawFilterOperation;
/**
* Bounding box coordinates for a citation location on a page
*/
export interface BoundingBox {
/** X coordinate of the bounding box origin */
x: number;
/** Y coordinate of the bounding box origin */
y: number;
/** Width of the bounding box */
w: number;
/** Height of the bounding box */
h: number;
}
/**
* Dimensions of a page in the source document
*/
export interface PageDimensions {
/** Width of the page */
width: number;
/** Height of the page */
height: number;
}
/**
* Citation information for an extracted field
*/
export interface FieldCitation {
/** The page number that the field occurred on */
page?: number;
/** The original text this field's value was derived from */
matching_text?: string;
/** Bounding boxes indicating where the citation appears on the page */
bounding_boxes?: BoundingBox[];
/** Dimensions of the page containing the citation */
page_dimensions?: PageDimensions;
}
/**
* Metadata for an extracted field, including confidence and citation information
*/
@@ -76,11 +38,16 @@ export interface ExtractedFieldMetadata {
confidence?: number;
/** The confidence score for the field based on the extracted text only */
extraction_confidence?: number;
/** The confidence score for the field based on the parsing/OCR quality */
parsing_confidence?: number;
citation?: FieldCitation[];
}
export interface FieldCitation {
/** The page number that the field occurred on */
page?: number;
/** The original text this field's value was derived from */
matching_text?: string;
}
/**
* Dictionary mapping field names to their metadata
* Values can be ExtractedFieldMetadata objects, nested dictionaries, or arrays
+9 -8
View File
@@ -108,19 +108,20 @@ async function pollForJobCompletion({
}
const response =
await getClassifyJobApiV1ClassifierJobsClassifyJobIdGet(jobOptions);
if (!response.response.ok) {
numIterations++;
}
if (typeof response.data != "undefined") {
status = response.data.status as StatusEnum;
if (status == StatusEnum.CANCELLED || status == StatusEnum.ERROR) {
throw new Error("There was an error extracting data from your file.");
} else if (
status == StatusEnum.SUCCESS ||
status == StatusEnum.PARTIAL_SUCCESS
) {
throw new Error("There was an error during the classification job.");
} else if (status == StatusEnum.SUCCESS) {
return true;
} else {
numIterations++;
await sleep(interval * 1000);
}
}
numIterations++;
await sleep(interval * 1000);
}
}
@@ -168,7 +169,7 @@ async function getJobResult({
retries++;
await sleep(retryInterval * 1000);
}
if (response.response.ok && typeof response.data != "undefined") {
if (typeof response.data != "undefined") {
return response.data as ClassifyJobResults;
} else {
throw new Error(
@@ -1,6 +1,6 @@
// This file is auto-generated by @hey-api/openapi-ts
import { z } from "zod/v4";
import { z } from "zod";
export const zNoneSegmentationConfig = z.object({
mode: z.literal("none").optional().default("none"),
@@ -770,7 +770,7 @@ export const zMetadataFilter = z.object({
export const zFilterCondition: z.ZodTypeAny = z.enum(["and", "or", "not"]);
export const zMetadataFilters: z.ZodObject<z.ZodRawShape> = z.object({
export const zMetadataFilters: z.AnyZodObject = z.object({
filters: z.array(z.unknown()),
condition: z.union([zFilterCondition, z.null()]).optional(),
});
@@ -782,7 +782,7 @@ export const zRetrievalMode: z.ZodTypeAny = z.enum([
"auto_routed",
]);
export const zPresetRetrievalParams: z.ZodObject<z.ZodRawShape> = z.object({
export const zPresetRetrievalParams: z.AnyZodObject = z.object({
dense_similarity_top_k: z
.union([z.number().int().gte(1).lte(100), z.null()])
.optional(),
@@ -825,7 +825,7 @@ export const zSupportedLlmModelNames: z.ZodTypeAny = z.enum([
"VERTEX_AI_CLAUDE_3_5_SONNET_V2",
]);
export const zLlmParameters: z.ZodObject<z.ZodRawShape> = z.object({
export const zLlmParameters: z.AnyZodObject = z.object({
model_name: zSupportedLlmModelNames.optional(),
system_prompt: z.union([z.string().max(3000), z.null()]).optional(),
temperature: z.union([z.number(), z.null()]).optional(),
@@ -834,7 +834,7 @@ export const zLlmParameters: z.ZodObject<z.ZodRawShape> = z.object({
class_name: z.string().optional().default("base_component"),
});
export const zChatData: z.ZodObject<z.ZodRawShape> = z.object({
export const zChatData: z.AnyZodObject = z.object({
retrieval_parameters: zPresetRetrievalParams.optional(),
llm_parameters: z.union([zLlmParameters, z.null()]).optional(),
class_name: z.string().optional().default("base_component"),
@@ -2141,7 +2141,7 @@ export const zTextItem = z.object({
value: z.string(),
});
export const zListItem: z.ZodObject<z.ZodRawShape> = z.object({
export const zListItem: z.AnyZodObject = z.object({
type: z.literal("list").optional().default("list"),
bBox: z.union([z.unknown(), z.null()]).optional(),
items: z.array(z.unknown()),
+1 -1
View File
@@ -1,6 +1,6 @@
import { workflowEvent } from "@llamaindex/workflow-core";
import { zodEvent } from "@llamaindex/workflow-core/util/zod";
import { z } from "zod/v4";
import { z } from "zod";
import { parseFormSchema } from "./schema";
export const uploadEvent = zodEvent(
+7 -3
View File
@@ -296,16 +296,20 @@ async function pollForJobCompletion(
return false;
}
const response = await getJobApiV1ExtractionJobsJobIdGet(jobOptions);
if (!response.response.ok) {
numIterations++;
}
if (typeof response.data != "undefined") {
status = response.data.status as StatusEnum;
if (status == StatusEnum.CANCELLED || status == StatusEnum.ERROR) {
throw new Error("There was an error extracting data from your file.");
} else if (status == StatusEnum.SUCCESS) {
return true;
} else {
numIterations++;
await sleep(interval * 1000);
}
}
numIterations++;
await sleep(interval * 1000);
}
}
@@ -346,7 +350,7 @@ async function getJobResult(
retries++;
await sleep(retryInterval * 1000);
}
if (response.response.ok && typeof response.data != "undefined") {
if (typeof response.data != "undefined") {
return {
data: response.data.data,
extractionMetadata: response.data.extraction_metadata,
+4 -2
View File
@@ -2,7 +2,7 @@ import type { JSONValue } from "@llamaindex/core/global";
import type { ToolMetadata } from "@llamaindex/core/llms";
import type { BaseQueryEngine } from "@llamaindex/core/query-engine";
import { tool } from "@llamaindex/core/tools";
import { z } from "zod/v4";
import { z } from "zod";
const DEFAULT_NAME = "llama_cloud_index_tool";
const DEFAULT_DESCRIPTION =
@@ -21,7 +21,9 @@ export function createQueryEngineTool(
name: metadata?.name ?? DEFAULT_NAME,
description: metadata?.description ?? DEFAULT_DESCRIPTION,
parameters: z.object({
query: z.string().describe("The query to search for"),
query: z.string({
description: "The query to search for",
}),
}),
execute: async ({ query }) => {
const response = await queryEngine.query({ query });
+7 -8
View File
@@ -1,6 +1,6 @@
import { FailPageMode, ParserLanguages, ParsingMode } from "./client";
import { z } from "zod/v4";
import { z } from "zod";
type Language = ParserLanguages;
const VALUES: [Language, ...Language[]] = [
@@ -52,10 +52,9 @@ export const parseFormSchema = z.object({
html_remove_navigation_elements: z.boolean().optional(),
http_proxy: z
.string()
.url({
error:
'Set a valid URL for the HTTP proxy, e.g., "http://proxy.example.com:8080"',
})
.url(
'Set a valid URL for the HTTP proxy, e.g., "http://proxy.example.com:8080"',
)
.refine(
(url) => {
try {
@@ -68,7 +67,7 @@ export const parseFormSchema = z.object({
}
},
{
error: "Invalid HTTP proxy URL",
message: "Invalid HTTP proxy URL",
},
)
.optional(),
@@ -101,7 +100,7 @@ export const parseFormSchema = z.object({
vendor_multimodal_model_name: z.string().optional(),
model: z.string().optional(),
webhook_url: z.string().url().optional(),
parse_mode: z.enum(ParsingMode).nullable().optional(),
parse_mode: z.nativeEnum(ParsingMode).nullable().optional(),
system_prompt: z.string().optional(),
system_prompt_append: z.string().optional(),
user_prompt: z.string().optional(),
@@ -130,7 +129,7 @@ export const parseFormSchema = z.object({
compact_markdown_table: z.boolean().optional(),
markdown_table_multiline_header_separator: z.string().optional(),
page_error_tolerance: z.number().min(0).max(1).optional(),
replace_failed_page_mode: z.enum(FailPageMode).nullable().optional(),
replace_failed_page_mode: z.nativeEnum(FailPageMode).nullable().optional(),
replace_failed_page_with_error_message_prefix: z.string().optional(),
replace_failed_page_with_error_message_suffix: z.string().optional(),
});