Metadata-Version: 2.4
Name: apiworks-astro-py-sdk
Version: 1.1.0
Summary: Python SDK for ApiWorks 星盘 API (www.apiworks.com)：星盘、八字、紫微、奇门、大六壬、星宿、运势、报告等
Project-URL: Homepage, https://github.com/8haoNetwork/apiworks-astro-py-sdk
Project-URL: Documentation, https://github.com/8haoNetwork/apiworks-astro-py-sdk#readme
Project-URL: Repository, https://github.com/8haoNetwork/apiworks-astro-py-sdk
Author: ApiWorks
License-Expression: MIT
License-File: LICENSE
Keywords: apiworks,astro,astrology,bazi,chart,liuren,naks,qimen,sdk,ziwei
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# apiworks-astro-py-sdk

Python SDK for ApiWorks 星盘 API（[www.apiworks.com](https://www.apiworks.com)）。支持星盘、八字、紫微、奇门遁甲、大六壬、星宿、运势、AI 报告等能力（SDK v1.1.0）。

## 功能概览

- **星盘 (Chart)**：本命盘、天象盘、行运盘、比较盘、组合盘、三限/次限/法达/日弧等
- **星座 (Sign)**：我的星座、星座列表、星座配对
- **运势 (Scope)**：日/周/月/年运势
- **星象事件 (Event)**：行运星象事件
- **紫微斗数 (Ziwei)**：本命盘、排盘、含解读的排盘
- **星宿 (Naks)**：27 星宿关系
- **八字 (Bazi)**：命盘、流盘、合盘、总结
- **三式 (Sanshi)**：奇门遁甲、大六壬 / 金口诀
- **报告 (Report)**：桃花、周运、年运、合盘、财运等 AI 报告
- **多语言**：请求体 / 查询参数 `lang`，支持 `zh-Hans`（默认）、`zh-Hant`、`en`（部分接口）

## 安装

```bash
pip install apiworks-astro-py-sdk
```

或从源码安装（在项目目录下）：

```bash
pip install -e .
```

## 依赖

- Python >= 3.9
- httpx >= 0.27
- pydantic >= 2.0

## 凭证（App ID / App Key）

每个 `AstroCloudClient` / `AsyncAstroCloudClient` 实例绑定**一对** `app_id` 与 `app_key`，该实例发出的全部请求都会带上这组凭证。

ApiWorks 网站上，同一开放域下不同能力可能对应**不同**的 App ID / App Key（具体以网站开通为准，分组可能调整）。请按你实际开通的凭证使用：

- 同一对凭证能调用哪些接口 → 以网站控制台为准  
- 需要用多组凭证时 → **为每组各建一个 Client**，不要混用  

```python
from apiworks_astro_sdk import AstroCloudClient, QimenQry, SinglePointQry

# 凭证 A：例如开通了星盘相关接口
chart_client = AstroCloudClient(app_id="chart-app-id", app_key="chart-app-key")
chart_client.chart_natal(SinglePointQry(
    birth_dt="1990-08-14 12:00:00", tz=8, longitude=116.4, latitude=39.9,
))

# 凭证 B：例如开通了奇门 / 六壬相关接口
sanshi_client = AstroCloudClient(app_id="sanshi-app-id", app_key="sanshi-app-key")
sanshi_client.qimen(QimenQry(qry_dt="1999-10-17 21:00:00", tz=8))
```

若返回鉴权失败，请到网站 Token 管理页核对：该组 App ID / App Key 是否有权调用目标接口，且二者是否为一组配套凭证。

## 快速开始

### 同步客户端

```python
from apiworks_astro_sdk import AstroCloudClient, SinglePointQry, TimeAndLocation

# 传入在网站上对该接口有权限的那一对凭证
client = AstroCloudClient(
    app_id="your-app-id",
    app_key="your-app-key",
)
# base_url 默认为 https://cloud.apiworks.com/open/astro，如需可传入 base_url 覆盖

# 本命盘
qry = SinglePointQry(
    birth_dt="1990-08-14 12:00:00",
    tz=8,
    longitude=116.4074,
    latitude=39.9042,
)
resp = client.chart_natal(qry)  # ApiResp[AstroDataVo]，强类型
if resp.code == 0 and resp.data:
    print(resp.data.house, resp.data.planet)
```

### 异步客户端

```python
import asyncio
from apiworks_astro_sdk import AsyncAstroCloudClient, ScopeQryReq, TimeAndLocation, ScopeRespVo

async def main():
    client = AsyncAstroCloudClient(
        app_id="your-app-id",
        app_key="your-app-key",
    )
    qry = ScopeQryReq(
        birth_point=TimeAndLocation(
            birth_dt="1990-01-01 12:00:00", tz=8, longitude=116.4, latitude=39.9
        ),
        transit_point=TimeAndLocation(
            birth_dt="2025-02-26 12:00:00", tz=8, longitude=116.4, latitude=39.9
        ),
    )
    resp = await client.scope_day("user-123", qry)  # ApiResp[ScopeRespVo]
    if resp.code == 0 and resp.data:
        scope: ScopeRespVo = resp.data
        print(scope.scope_total, scope.scope_info)

asyncio.run(main())
```

### 更多示例

**八字命盘：**

```python
from apiworks_astro_sdk import AstroCloudClient, BaziNatalQry, BaziNatalVO

client = AstroCloudClient(app_id="...", app_key="...")
qry = BaziNatalQry(birth_dt="1990-08-14 12:00:00", tz=8, gender="male")
resp = client.bazi_natal(qry)  # ApiResp[BaziNatalVO]
if resp.code == 0 and resp.data:
    natal: BaziNatalVO = resp.data
    print(natal.pillars, natal.flow_decadal)
```

**紫微本命盘：**

```python
from apiworks_astro_sdk import AstroCloudClient, ZiweiNatalQry, ZiweiNatalVo

qry = ZiweiNatalQry(birth_dt="1999-10-17 21:00:00", tz=8, gender="female")
resp = client.ziwei_natal(qry)  # ApiResp[ZiweiNatalVo]
if resp.code == 0 and resp.data:
    ziwei = resp.data
    print(ziwei.natal.palaces, ziwei.patterns)
```

**星宿关系：**

```python
from apiworks_astro_sdk import AstroCloudClient, NaksQry, NaksBirthInfo, NaksVo

qry = NaksQry(
    birth_info=NaksBirthInfo(birth_dt="1990-01-15 00:00:00", tz=8),
    others_birth_info=[
        NaksBirthInfo(birth_dt="1992-03-20 00:00:00", tz=8),
    ],
)
resp = client.naks_relations(qry)  # ApiResp[NaksVo]
if resp.code == 0 and resp.data:
    naks: NaksVo = resp.data
    print(naks.natal_naks_info, naks.others_natal_relation)
```

**奇门遁甲 / 大六壬：**

```python
from apiworks_astro_sdk import AstroCloudClient, QimenQry, LiurenQry

client = AstroCloudClient(app_id="...", app_key="...")

# 时家拆补转盘
qm = client.qimen(QimenQry(
    qry_dt="1999-10-17 21:00:00",
    tz=8,
    type="shijia",
    pai_method="zhuanpan",
    ju_method="chaibu",
    lang="zh-Hans",
))
if qm.code == 0 and qm.data:
    print(qm.data.ju_display, qm.data.jiu_gong.keys())

# 大六壬
lr = client.liuren(LiurenQry(
    qry_dt="1999-10-17 21:00:00",
    tz=8,
    type="daliuren",
    gui_method="tian",
))
if lr.code == 0 and lr.data:
    print(lr.data.ge_ju, lr.data.si_ke, lr.data.san_chuan)
```

**双点星盘（行运/比较盘）：**

```python
from apiworks_astro_sdk import AstroCloudClient, DoublePointQry, TimeAndLocation, AstroDataVo

qry = DoublePointQry(
    user_list=[
        TimeAndLocation(birth_dt="1990-08-14 12:00:00", tz=8, longitude=116.4, latitude=39.9),
        TimeAndLocation(birth_dt="2025-02-26 12:00:00", tz=8, longitude=116.4, latitude=39.9),
    ]
)
resp = client.chart_transit(qry)   # ApiResp[AstroDataVo] 行运盘
resp = client.chart_comparison(qry) # ApiResp[AstroDataVo] 比较盘
if resp.code == 0 and resp.data:
    print(resp.data.planet, resp.data.house)
```

**报告（桃花/合盘/周运等）：**

```python
from apiworks_astro_sdk import AstroCloudClient, RomanticCreateQry, TimeAndLocation, AstroReportVo

qry = RomanticCreateQry(
    user_birth_point=TimeAndLocation(
        birth_dt="1990-01-01 13:14:15", tz=8, longitude=116.4, latitude=39.9
    ),
    user_current_point=TimeAndLocation(
        birth_dt="2025-11-26 13:14:15", tz=8, longitude=116.4, latitude=39.9
    ),
    user_id="user-123",
)
resp = client.report_romantic(qry)  # ApiResp[AstroReportVo]
if resp.code == 0 and resp.data and resp.data.serial_no:
    serial_no = resp.data.serial_no  # 可用 report_get / report_get_html 拉取报告
```

## API 响应格式

所有接口均返回强类型 `ApiResp[T]`，可直接使用 `resp.code`、`resp.msg`、`resp.data`、`resp.exe_time`，其中 `data` 为与接口对应的 Vo 类型（如 `BaziNatalVO`、`NaksVo`、`AstroDataVo` 等）：

```python
resp = client.bazi_natal(qry)  # ApiResp[BaziNatalVO]
assert resp.code == 0
data: BaziNatalVO = resp.data  # 强类型，IDE 可补全
```

## 验证 SDK 是否可用

用真实接口调用一次本命盘，确认网络与凭证正常：

```bash
# 在项目根目录，先安装本包与依赖（含 pytest 可加 --extras dev）
poetry install

# 设置你的 app_id / app_key 后执行（不要提交到仓库）
export APIWORKS_APP_ID="你的app_id"
export APIWORKS_APP_KEY="你的app_key"
poetry run python scripts/verify_sdk.py
```

也可不用 Poetry：

```bash
pip install -e ".[dev]"
APIWORKS_APP_ID=xxx APIWORKS_APP_KEY=xxx python scripts/verify_sdk.py
```

成功会打印 `验证通过，SDK 可用。`；若 `code != 0` 或报错，请检查凭证与网络。

## 项目结构

```
apiworks-astro-py-sdk/
├── pyproject.toml
├── README.md
├── src/
│   └── apiworks_astro_sdk/
│       ├── __init__.py
│       ├── client.py       # AstroCloudClient, AsyncAstroCloudClient
│       └── models/
│           ├── __init__.py
│           ├── common.py            # ApiResp, TimeAndLocation
│           ├── requests.py          # 各类请求 DTO（含 lang / 奇门 / 六壬）
│           ├── responses.py         # 响应 VO
│           └── sanshi_responses.py  # 奇门 / 大六壬响应 VO
└── tests/
```

## License

MIT