Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions examples/web_reader_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from zai import ZaiClient


def web_reader_example():
client = ZaiClient()
response = client.web_reader.web_reader(
url="https://www.example.com/",
return_format="markdown", # or "text"
retain_images=True,
with_links_summary=True,
)

# Print full response model
print(response)

# Access structured fields
if response.reader_result:
data = response.reader_result
print("Title:", data.title)
print("Published:", data.published_time)
print("URL:", data.url)
print("Content length:", len(data.content or ""))


if __name__ == "__main__":
web_reader_example()
7 changes: 7 additions & 0 deletions src/zai/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from zai.api_resource.videos import Videos
from zai.api_resource.voice import Voice
from zai.api_resource.web_search import WebSearchApi
from zai.api_resource.web_reader import WebReaderApi
from zai.api_resource.file_parser import FileParser

from .core import (
Expand Down Expand Up @@ -152,6 +153,12 @@ def web_search(self) -> WebSearchApi:

return WebSearchApi(self)

@cached_property
def web_reader(self) -> WebReaderApi:
from zai.api_resource.web_reader import WebReaderApi

return WebReaderApi(self)

@cached_property
def files(self) -> Files:
from zai.api_resource.files import Files
Expand Down
2 changes: 2 additions & 0 deletions src/zai/api_resource/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
Videos,
)
from .web_search import WebSearchApi
from .web_reader import WebReaderApi
from .file_parser import FileParser


Expand All @@ -36,6 +37,7 @@
'Audio',
'Moderations',
'WebSearchApi',
'WebReaderApi',
'Agents',
'FileParser',
]
3 changes: 3 additions & 0 deletions src/zai/api_resource/web_reader/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .web_reader import WebReaderApi

__all__ = ["WebReaderApi"]
68 changes: 68 additions & 0 deletions src/zai/api_resource/web_reader/web_reader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Optional

import httpx

from zai.core import (
NOT_GIVEN,
BaseAPI,
Body,
Headers,
NotGiven,
deepcopy_minimal,
make_request_options,
maybe_transform,
)
from zai.types.web_reader.web_reader_params import WebReaderParams
from zai.types.web_reader.web_reader_resp import WebReaderResult

if TYPE_CHECKING:
from zai._client import ZaiClient


class WebReaderApi(BaseAPI):
def __init__(self, client: "ZaiClient") -> None:
super().__init__(client)

def web_reader(
self,
*,
url: str,
request_id: Optional[str] | NotGiven = NOT_GIVEN,
user_id: Optional[str] | NotGiven = NOT_GIVEN,
timeout: Optional[str] | NotGiven = NOT_GIVEN,
no_cache: Optional[bool] | NotGiven = NOT_GIVEN,
return_format: Optional[str] | NotGiven = NOT_GIVEN,
retain_images: Optional[bool] | NotGiven = NOT_GIVEN,
no_gfm: Optional[bool] | NotGiven = NOT_GIVEN,
keep_img_data_url: Optional[bool] | NotGiven = NOT_GIVEN,
with_images_summary: Optional[bool] | NotGiven = NOT_GIVEN,
with_links_summary: Optional[bool] | NotGiven = NOT_GIVEN,
extra_headers: Headers | None = None,
extra_body: Body | None = None,
timeout_override: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> WebReaderResult:
body = deepcopy_minimal(
{
"url": url,
"request_id": request_id,
"user_id": user_id,
"timeout": timeout,
"no_cache": no_cache,
"return_format": return_format,
"retain_images": retain_images,
"no_gfm": no_gfm,
"keep_img_data_url": keep_img_data_url,
"with_images_summary": with_images_summary,
"with_links_summary": with_links_summary,
}
)
return self._post(
"/reader",
body=maybe_transform(body, WebReaderParams),
options=make_request_options(
extra_headers=extra_headers, extra_body=extra_body, timeout=timeout_override
),
cast_type=WebReaderResult,
)
8 changes: 8 additions & 0 deletions src/zai/types/web_reader/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from .web_reader_params import WebReaderParams
from .web_reader_resp import WebReaderResult, ReaderData

__all__ = [
"WebReaderParams",
"ReaderData",
"WebReaderResult",
]
36 changes: 36 additions & 0 deletions src/zai/types/web_reader/web_reader_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from __future__ import annotations

from typing import Optional

from typing_extensions import TypedDict


class WebReaderParams(TypedDict, total=False):
"""
Web reader request parameters

Attributes:
url (str): Target page URL to read
request_id (str): Unique request task ID (6-64 chars)
user_id (str): Unique end-user ID (6-128 chars)
timeout (str): Request timeout in seconds
no_cache (bool): Disable cache
return_format (str): Return format, e.g. 'markdown' or 'text'
retain_images (bool): Keep images in output
no_gfm (bool): Disable GitHub Flavored Markdown
keep_img_data_url (bool): Keep image data URLs
with_images_summary (bool): Include images summary
with_links_summary (bool): Include links summary
"""

url: str
request_id: Optional[str]
user_id: Optional[str]
timeout: Optional[str]
no_cache: Optional[bool]
return_format: Optional[str]
retain_images: Optional[bool]
no_gfm: Optional[bool]
keep_img_data_url: Optional[bool]
with_images_summary: Optional[bool]
with_links_summary: Optional[bool]
21 changes: 21 additions & 0 deletions src/zai/types/web_reader/web_reader_resp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from typing import Any, Dict, Optional

from pydantic import Field

from zai.core import BaseModel


class ReaderData(BaseModel):
images: Optional[Dict[str, str]] = None
links: Optional[Dict[str, str]] = None
title: Optional[str] = None
description: Optional[str] = None
url: Optional[str] = None
content: Optional[str] = None
published_time: Optional[str] = Field(default=None, alias="publishedTime")
metadata: Optional[Dict[str, Any]] = None
external: Optional[Dict[str, Any]] = None


class WebReaderResult(BaseModel):
reader_result: Optional[ReaderData] = None
25 changes: 25 additions & 0 deletions tests/integration_tests/test_web_reader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import logging
import logging.config

import zai
from zai import ZaiClient


def test_web_reader(logging_conf):
logging.config.dictConfig(logging_conf) # type: ignore
client = ZaiClient() # Fill in your own API Key
try:
response = client.web_reader.web_reader(
url="https://www.example.com/",
return_format="markdown",
retain_images=True,
with_links_summary=True,
)
print(response)

except zai.core._errors.APIRequestFailedError as err:
print(err)
except zai.core._errors.APIInternalError as err:
print(err)
except zai.core._errors.APIStatusError as err:
print(err)