feat: support OCR handwriting recognition feature (#50)

Co-authored-by: mengqian <cherish_a_meng@163.com>
This commit is contained in:
code-c-light 2025-11-24 17:44:33 +08:00 committed by GitHub
parent fec2f2bd7b
commit 8b5cdaa132
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 178 additions and 24 deletions

View file

@ -0,0 +1,31 @@
from zai import ZaiClient
client = ZaiClient(
base_url="",
api_key=""
)
def handwriting_ocr_example():
"""
Full Example: Submit image for recognition and wait for the result to be returned.
"""
# Create recognition task
# Please modify the local file path
file_path = 'Your image path'
with open(file_path, 'rb') as f:
print("Submitting a handwriting recognition task ...")
response = client.ocr.handwriting_ocr(
file=f,
tool_type="hand_write",
probability=True
)
print("Task created successfully. Response:")
print(response)
print("Handwriting OCR demo completed.")
if __name__ == "__main__":
print("=== Handwriting recognition quick demo ===\n")
handwriting_ocr_example()

View file

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "zai-sdk" name = "zai-sdk"
version = "0.0.4.2" version = "0.0.4.3"
description = "A SDK library for accessing big model apis from Z.ai" description = "A SDK library for accessing big model apis from Z.ai"
authors = ["Z.ai"] authors = ["Z.ai"]
readme = "README.md" readme = "README.md"

0
src/__init__.py Normal file
View file

View file

@ -24,6 +24,7 @@ if TYPE_CHECKING:
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.web_reader import WebReaderApi
from zai.api_resource.file_parser import FileParser from zai.api_resource.file_parser import FileParser
from zai.api_resource.ocr import HandwritingOCR
from .core import ( from .core import (
NOT_GIVEN, NOT_GIVEN,
@ -200,6 +201,11 @@ class BaseClient(HttpClient):
from zai.api_resource.file_parser import FileParser from zai.api_resource.file_parser import FileParser
return FileParser(self) return FileParser(self)
@cached_property
def ocr(self) -> HandwritingOCR:
from zai.api_resource.ocr import HandwritingOCR
return HandwritingOCR(self)
@property @property
@override @override
def auth_headers(self) -> dict[str, str]: def auth_headers(self) -> dict[str, str]:
@ -208,7 +214,7 @@ class BaseClient(HttpClient):
if self.disable_token_cache: if self.disable_token_cache:
return { return {
'Authorization': f'Bearer {api_key}', 'Authorization': f'Bearer {api_key}',
'x-source-channel': source_channel, 'x-source-channel': source_channel,
} }
else: else:
return { return {

View file

@ -1,2 +1,2 @@
__title__ = 'Z.ai' __title__ = 'Z.ai'
__version__ = '0.0.4.2' __version__ = '0.0.4.3'

View file

@ -10,34 +10,35 @@ from .chat import (
Completions, Completions,
) )
from .embeddings import Embeddings from .embeddings import Embeddings
from .file_parser import FileParser
from .files import Files, FilesWithRawResponse from .files import Files, FilesWithRawResponse
from .images import Images from .images import Images
from .moderations import Moderations from .moderations import Moderations
from .ocr import HandwritingOCR
from .tools import Tools from .tools import Tools
from .videos import ( from .videos import (
Videos, Videos,
) )
from .web_search import WebSearchApi
from .web_reader import WebReaderApi from .web_reader import WebReaderApi
from .file_parser import FileParser from .web_search import WebSearchApi
__all__ = [ __all__ = [
'Videos', 'Videos',
'AsyncCompletions', 'AsyncCompletions',
'Chat', 'Chat',
'Completions', 'Completions',
'Images', 'Images',
'Embeddings', 'Embeddings',
'Files', 'Files',
'FilesWithRawResponse', 'FilesWithRawResponse',
'Batches', 'Batches',
'Tools', 'Tools',
'Assistant', 'Assistant',
'Audio', 'Audio',
'Moderations', 'Moderations',
'WebSearchApi', 'WebSearchApi',
'WebReaderApi', 'WebReaderApi',
'Agents', 'Agents',
'FileParser', 'FileParser',
'HandwritingOCR'
] ]

View file

@ -1,3 +1,3 @@
from .file_parser import FileParser from .file_parser import FileParser
__all__ = ['FileParser'] __all__ = ['FileParser']

View file

@ -0,0 +1,3 @@
from .handwriting_ocr import HandwritingOCR
__all__ = ["HandwritingOCR"]

View file

@ -0,0 +1,67 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Mapping, cast
import httpx
from typing_extensions import Literal
from zai.core import (
BaseAPI,
maybe_transform,
NOT_GIVEN,
Body,
Headers,
NotGiven,
FileTypes,
deepcopy_minimal,
extract_files,
make_request_options
)
from zai.types.ocr.handwriting_ocr_params import HandwritingOCRParams
from zai.types.ocr.handwriting_ocr_resp import HandwritingOCRResp
if TYPE_CHECKING:
from zai._client import ZaiClient
__all__ = ["HandwritingOCR"]
class HandwritingOCR(BaseAPI):
def __init__(self, client: "ZaiClient") -> None:
super().__init__(client)
def handwriting_ocr(
self,
*,
file: FileTypes,
tool_type: Literal["hand_write"],
language_type: str = None, # optional,
probability: bool = None,
extra_headers: Headers | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> HandwritingOCRResp:
if not file:
raise ValueError("`file` must be provided.")
if not tool_type:
raise ValueError("`tool_type` must be provided.")
body = deepcopy_minimal(
{
"file": file,
"tool_type": tool_type,
"language_type": language_type,
"probability": probability
}
)
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
if files:
extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
return self._post(
"/files/ocr",
body=maybe_transform(body, HandwritingOCRParams),
files=files,
options=make_request_options(
extra_headers=extra_headers, extra_body=extra_body, timeout=timeout
),
cast_type=HandwritingOCRResp,
)

View file

View file

@ -0,0 +1,13 @@
from __future__ import annotations
from typing_extensions import Literal, TypedDict
from zai.core import FileTypes
__all__ = ["HandwritingOCRParams"]
class HandwritingOCRParams(TypedDict, total=False):
file: FileTypes # Required
tool_type: Literal["hand_write"] # Required
language_type: str # Optional
probability: bool

View file

@ -0,0 +1,33 @@
from typing import List
from typing import Optional
from zai.core import BaseModel
__all__ = ["HandwritingOCRResp"]
class Location(BaseModel):
left: int
top: int
width: int
height: int
class Probability(BaseModel):
average: float
variance: float
min: float
class WordsResult(BaseModel):
location: Location
words: str
probability: Probability
class HandwritingOCRResp(BaseModel):
task_id: str # Task ID or Result ID
message: str # Status message
status: str # OCR task status
words_result_num: int # Number of recognition results
words_result: Optional[List[WordsResult]] = None # List of recognition resultst details (if any)