feat: add web reader api (#48)

This commit is contained in:
Tomsun28 2025-11-15 19:12:16 +08:00 committed by GitHub
parent 25f84e8b86
commit d8e16ae166
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 196 additions and 0 deletions

View file

@ -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()

View file

@ -22,6 +22,7 @@ if TYPE_CHECKING:
from zai.api_resource.videos import Videos from zai.api_resource.videos import Videos
from zai.api_resource.voice import Voice from zai.api_resource.voice import Voice
from zai.api_resource.web_search import WebSearchApi 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 zai.api_resource.file_parser import FileParser
from .core import ( from .core import (
@ -152,6 +153,12 @@ class BaseClient(HttpClient):
return WebSearchApi(self) return WebSearchApi(self)
@cached_property
def web_reader(self) -> WebReaderApi:
from zai.api_resource.web_reader import WebReaderApi
return WebReaderApi(self)
@cached_property @cached_property
def files(self) -> Files: def files(self) -> Files:
from zai.api_resource.files import Files from zai.api_resource.files import Files

View file

@ -18,6 +18,7 @@ from .videos import (
Videos, Videos,
) )
from .web_search import WebSearchApi from .web_search import WebSearchApi
from .web_reader import WebReaderApi
from .file_parser import FileParser from .file_parser import FileParser
@ -36,6 +37,7 @@ __all__ = [
'Audio', 'Audio',
'Moderations', 'Moderations',
'WebSearchApi', 'WebSearchApi',
'WebReaderApi',
'Agents', 'Agents',
'FileParser', 'FileParser',
] ]

View file

@ -0,0 +1,3 @@
from .web_reader import WebReaderApi
__all__ = ["WebReaderApi"]

View file

@ -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,
)

View file

@ -0,0 +1,8 @@
from .web_reader_params import WebReaderParams
from .web_reader_resp import WebReaderResult, ReaderData
__all__ = [
"WebReaderParams",
"ReaderData",
"WebReaderResult",
]

View file

@ -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]

View file

@ -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

View file

@ -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)