pymlsapi 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pymlsapi-0.1.0/.github/workflows/publish.yml +29 -0
- pymlsapi-0.1.0/.github/workflows/test.yml +31 -0
- pymlsapi-0.1.0/.gitignore +38 -0
- pymlsapi-0.1.0/PKG-INFO +570 -0
- pymlsapi-0.1.0/README.md +540 -0
- pymlsapi-0.1.0/SPEC.md +328 -0
- pymlsapi-0.1.0/pyproject.toml +73 -0
- pymlsapi-0.1.0/src/pymlsapi/__init__.py +103 -0
- pymlsapi-0.1.0/src/pymlsapi/async_client.py +67 -0
- pymlsapi-0.1.0/src/pymlsapi/async_http.py +104 -0
- pymlsapi-0.1.0/src/pymlsapi/client.py +67 -0
- pymlsapi-0.1.0/src/pymlsapi/config.py +58 -0
- pymlsapi-0.1.0/src/pymlsapi/errors.py +95 -0
- pymlsapi-0.1.0/src/pymlsapi/http.py +155 -0
- pymlsapi-0.1.0/src/pymlsapi/models/__init__.py +100 -0
- pymlsapi-0.1.0/src/pymlsapi/models/common.py +66 -0
- pymlsapi-0.1.0/src/pymlsapi/models/content.py +92 -0
- pymlsapi-0.1.0/src/pymlsapi/models/intelligence.py +65 -0
- pymlsapi-0.1.0/src/pymlsapi/models/listings.py +91 -0
- pymlsapi-0.1.0/src/pymlsapi/models/studio.py +171 -0
- pymlsapi-0.1.0/src/pymlsapi/poller.py +102 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/__init__.py +20 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/account/__init__.py +38 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/account/billing.py +74 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/account/keys.py +46 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/content.py +77 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/intelligence.py +47 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/listings.py +179 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/studio/__init__.py +56 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/studio/creatives.py +124 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/studio/custom.py +100 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/studio/enhance.py +170 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/studio/floorplan.py +166 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/studio/jobs.py +86 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/studio/render.py +96 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/studio/social.py +57 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/studio/staging.py +694 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/studio/upload.py +93 -0
- pymlsapi-0.1.0/src/pymlsapi/resources/studio/video.py +346 -0
- pymlsapi-0.1.0/tests/conftest.py +6 -0
- pymlsapi-0.1.0/tests/test_account.py +68 -0
- pymlsapi-0.1.0/tests/test_client.py +53 -0
- pymlsapi-0.1.0/tests/test_content.py +73 -0
- pymlsapi-0.1.0/tests/test_errors.py +95 -0
- pymlsapi-0.1.0/tests/test_intelligence.py +73 -0
- pymlsapi-0.1.0/tests/test_listings.py +134 -0
- pymlsapi-0.1.0/tests/test_models.py +64 -0
- pymlsapi-0.1.0/tests/test_poller.py +81 -0
- pymlsapi-0.1.0/tests/test_studio.py +370 -0
- pymlsapi-0.1.0/uv.lock +558 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
pypi-publish:
|
|
10
|
+
name: Build and publish Python 🐍 distribution 📦 to PyPI
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
permissions:
|
|
13
|
+
id-token: write # Mandatory for PyPI Trusted Publishing
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Install uv
|
|
19
|
+
uses: astral-sh/setup-uv@v3
|
|
20
|
+
with:
|
|
21
|
+
version: "latest"
|
|
22
|
+
|
|
23
|
+
- name: Build distributions
|
|
24
|
+
run: uv build
|
|
25
|
+
|
|
26
|
+
- name: Publish to PyPI
|
|
27
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
28
|
+
with:
|
|
29
|
+
packages-dir: dist/
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Test & Lint
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Install uv
|
|
20
|
+
uses: astral-sh/setup-uv@v3
|
|
21
|
+
with:
|
|
22
|
+
version: "latest"
|
|
23
|
+
|
|
24
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
25
|
+
run: uv python install ${{ matrix.python-version }}
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies & run tests
|
|
28
|
+
run: uv run --python ${{ matrix.python-version }} --extra dev pytest
|
|
29
|
+
|
|
30
|
+
- name: Lint check
|
|
31
|
+
run: uv run --python ${{ matrix.python-version }} --with ruff ruff check src tests
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*$py.class
|
|
4
|
+
*.so
|
|
5
|
+
.Python
|
|
6
|
+
build/
|
|
7
|
+
develop-eggs/
|
|
8
|
+
dist/
|
|
9
|
+
downloads/
|
|
10
|
+
eggs/
|
|
11
|
+
.eggs/
|
|
12
|
+
lib/
|
|
13
|
+
lib64/
|
|
14
|
+
parts/
|
|
15
|
+
sdist/
|
|
16
|
+
var/
|
|
17
|
+
wheels/
|
|
18
|
+
share/python-wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
MANIFEST
|
|
23
|
+
|
|
24
|
+
# Virtual environments
|
|
25
|
+
.env
|
|
26
|
+
.venv
|
|
27
|
+
env/
|
|
28
|
+
venv/
|
|
29
|
+
ENV/
|
|
30
|
+
env.bak/
|
|
31
|
+
venv.bak/
|
|
32
|
+
|
|
33
|
+
# Testing
|
|
34
|
+
.pytest_cache/
|
|
35
|
+
.coverage
|
|
36
|
+
htmlcov/
|
|
37
|
+
.mypy_cache/
|
|
38
|
+
.ruff_cache/
|
pymlsapi-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pymlsapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python client library for mlsapi.dev — Real estate MLS listing ingestion, property intelligence, and Studio visual AI
|
|
5
|
+
Project-URL: Homepage, https://mlsapi.dev
|
|
6
|
+
Project-URL: Documentation, https://docs.mlsapi.dev
|
|
7
|
+
Project-URL: Repository, https://github.com/mlsapi/mlsapi-python
|
|
8
|
+
Project-URL: Changelog, https://github.com/mlsapi/mlsapi-python/releases
|
|
9
|
+
Author-email: MLS API Team <support@mlsapi.dev>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
Keywords: 3d-dollhouse,floorplan,generative-ai,mls,property-intelligence,proptech,real-estate,virtual-staging
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Requires-Dist: httpx>=0.25.0
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: respx>=0.21.0; extra == 'dev'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# mlsapi
|
|
32
|
+
|
|
33
|
+
The official Python client library for **[mlsapi.dev](https://mlsapi.dev)**.
|
|
34
|
+
|
|
35
|
+
Access real-time MLS listing data, property intelligence, CapEx lifecycle analysis, AI-generated marketing copy, and the complete suite of **Studio Visual AI** generative tools (virtual staging, twilight conversion, decluttering, 3D dollhouse floor plans, 4K upscaling, ad creatives, and video generation).
|
|
36
|
+
|
|
37
|
+
[](https://pypi.org/project/pymlsapi/)
|
|
38
|
+
[](https://pypi.org/project/pymlsapi/)
|
|
39
|
+
[](https://opensource.org/licenses/MIT)
|
|
40
|
+
[](https://github.com/psf/black)
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Table of Contents
|
|
45
|
+
|
|
46
|
+
- [Features](#features)
|
|
47
|
+
- [Installation](#installation)
|
|
48
|
+
- [Quick Start](#quick-start)
|
|
49
|
+
- [Synchronous Example](#synchronous-example)
|
|
50
|
+
- [Asynchronous (asyncio) Example](#asynchronous-asyncio-example)
|
|
51
|
+
- [Configuration & Authentication](#configuration--authentication)
|
|
52
|
+
- [Core Features & Code Examples](#core-features--code-examples)
|
|
53
|
+
- [1. Real-Time MLS Listing Lookup & Ingestion](#1-real-time-mls-listing-lookup--ingestion)
|
|
54
|
+
- [2. Property Intelligence & CapEx Analysis](#2-property-intelligence--capex-analysis)
|
|
55
|
+
- [3. Marketing Content Generation](#3-marketing-content-generation)
|
|
56
|
+
- [4. Media Upload to Global CDN](#4-media-upload-to-global-cdn)
|
|
57
|
+
- [5. Virtual Room Staging (29 Architectural Styles)](#5-virtual-room-staging-29-architectural-styles)
|
|
58
|
+
- [6. Day-to-Dusk Twilight & Exterior Enhancement](#6-day-to-dusk-twilight--exterior-enhancement)
|
|
59
|
+
- [7. Declutter & Clean Space](#7-declutter--clean-space)
|
|
60
|
+
- [8. De-Staging (Empty Room) & Floor Restoration](#8-de-staging-empty-room--floor-restoration)
|
|
61
|
+
- [9. Furniture & Surface Material Replacement](#9-furniture--surface-material-replacement)
|
|
62
|
+
- [10. 3x3 Designer Wall Paint Swatches](#10-3x3-designer-wall-paint-swatches)
|
|
63
|
+
- [11. 2D Blueprint to 3D Isometric Dollhouse](#11-2d-blueprint-to-3d-isometric-dollhouse)
|
|
64
|
+
- [12. 4K Super-Resolution Upscaling](#12-4k-super-resolution-upscaling)
|
|
65
|
+
- [13. Branded Multi-Placement Ad Creatives](#13-branded-multi-placement-ad-creatives)
|
|
66
|
+
- [14. AI Video Walkthroughs & Voice/Subtitle Polish](#14-ai-video-walkthroughs--voicesubtitle-polish)
|
|
67
|
+
- [Asynchronous Jobs & Progress Callbacks](#asynchronous-jobs--progress-callbacks)
|
|
68
|
+
- [Error Handling](#error-handling)
|
|
69
|
+
- [Supported Presets Reference](#supported-presets-reference)
|
|
70
|
+
- [License](#license)
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Features
|
|
75
|
+
|
|
76
|
+
- **Dual Sync & Async Interfaces:** Native synchronous `MlsApiClient` and async `AsyncMlsApiClient` for high-throughput `asyncio` applications.
|
|
77
|
+
- **Deep Type Safety:** Pydantic v2 domain models with full IDE autocompletion, type hinting, and runtime validation.
|
|
78
|
+
- **Smart Asynchronous Polling:** Auto-waiting helper methods (`*_and_wait(...)`) with exponential backoff, jitter, and real-time progress callbacks.
|
|
79
|
+
- **Resilient Networking:** Built on `httpx` with automatic connection pooling and smart retries on HTTP 429 rate limits and 5xx server errors.
|
|
80
|
+
- **Complete Studio Coverage:** First-class access to all 21+ Studio generative visual endpoints.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Installation
|
|
85
|
+
|
|
86
|
+
Install via pip, uv, or poetry:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# pip
|
|
90
|
+
pip install pymlsapi
|
|
91
|
+
|
|
92
|
+
# uv
|
|
93
|
+
uv add pymlsapi
|
|
94
|
+
|
|
95
|
+
# poetry
|
|
96
|
+
poetry add pymlsapi
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Requires **Python 3.9+**.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Quick Start
|
|
104
|
+
|
|
105
|
+
### Synchronous Example
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
import os
|
|
109
|
+
from pymlsapi import MlsApiClient
|
|
110
|
+
|
|
111
|
+
# Initialize the client with your API key
|
|
112
|
+
mls = MlsApiClient(api_key=os.environ.get("MLSAPI_KEY"))
|
|
113
|
+
|
|
114
|
+
# 1. Fetch normalized MLS listing data
|
|
115
|
+
listing = mls.listings.get_and_wait("A12079565")
|
|
116
|
+
print(f"Property: {listing.address.formatted} - ${listing.price:,.2f}")
|
|
117
|
+
print(f"Downloaded {listing.photo_count} photos: {listing.photos[0]}")
|
|
118
|
+
|
|
119
|
+
# 2. Perform AI Virtual Staging on an empty room photo
|
|
120
|
+
staged = mls.studio.staging.stage_and_wait(
|
|
121
|
+
photo_url=listing.photos[0],
|
|
122
|
+
room_type="living_room",
|
|
123
|
+
style="scandinavian",
|
|
124
|
+
custom_staging_instructions="Oak dining table, bouclé accent chairs, fiddle-leaf fig tree",
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
print(f"Staged photo ready: {staged.staged_photo_url}")
|
|
128
|
+
print(f"Before/after comparison: {staged.before_after_comparison_url}")
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Asynchronous (asyncio) Example
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
import asyncio
|
|
135
|
+
import os
|
|
136
|
+
from pymlsapi import AsyncMlsApiClient
|
|
137
|
+
|
|
138
|
+
async def main():
|
|
139
|
+
async with AsyncMlsApiClient(api_key=os.environ.get("MLSAPI_KEY")) as mls:
|
|
140
|
+
# Ingest listing and synthesize intelligence concurrently
|
|
141
|
+
listing_task = mls.listings.get_and_wait("A12079565")
|
|
142
|
+
intel_task = mls.intelligence.get("A12079565", investor_mode=True)
|
|
143
|
+
|
|
144
|
+
listing, intel = await asyncio.gather(listing_task, intel_task)
|
|
145
|
+
|
|
146
|
+
print(f"Listing: {listing.address.city}, {listing.address.state}")
|
|
147
|
+
print(f"Gross Yield: {intel.llm_derived_intelligence.investor_insights.estimated_gross_yield_pct}%")
|
|
148
|
+
|
|
149
|
+
asyncio.run(main())
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Configuration & Authentication
|
|
155
|
+
|
|
156
|
+
Obtain your API key from the **[mlsapi.dev Dashboard](https://mlsapi.dev)**.
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from pymlsapi import MlsApiClient
|
|
160
|
+
|
|
161
|
+
mls = MlsApiClient(
|
|
162
|
+
api_key="sk_live_...", # Secret API key (or MLSAPI_KEY env var)
|
|
163
|
+
environment="live", # "live" (production) or "test" (sandbox)
|
|
164
|
+
base_url="https://api.mlsapi.dev", # Optional custom base URL or staging endpoint
|
|
165
|
+
timeout_seconds=60.0, # HTTP request timeout (default: 60s)
|
|
166
|
+
max_retries=3, # Automatic retries on rate limits (429) & 5xx errors
|
|
167
|
+
)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Core Features & Code Examples
|
|
173
|
+
|
|
174
|
+
### 1. Real-Time MLS Listing Lookup & Ingestion
|
|
175
|
+
|
|
176
|
+
Ingest property records by MLS number. If the property is not cached, the engine enqueues live scraping and photo downloading.
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
# Auto-wait until scraping completes (recommended)
|
|
180
|
+
listing = mls.listings.get_and_wait(
|
|
181
|
+
"A12079565",
|
|
182
|
+
timeout_seconds=45.0,
|
|
183
|
+
on_progress=lambda job: print(f"Ingestion step: {job.step}"),
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
print(listing.address.city, listing.specifications.beds, listing.specifications.baths_full)
|
|
187
|
+
print(f"Downloaded {listing.photo_count} high-res photos: {listing.photos}")
|
|
188
|
+
|
|
189
|
+
# Or handle the asynchronous job tracker manually
|
|
190
|
+
response = mls.listings.get("A12079565")
|
|
191
|
+
if hasattr(response, "status") and response.status == "processing":
|
|
192
|
+
print(f"Ingestion job queued with tracker ID: {response.job_id}")
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
### 2. Property Intelligence & CapEx Analysis
|
|
198
|
+
|
|
199
|
+
Synthesize public tax records, historical ownership, school zoning, replacement horizons for major structural systems (roof, HVAC, water heater, impact windows), and investor yields.
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
intel = mls.intelligence.get(
|
|
203
|
+
"A12079565",
|
|
204
|
+
include_llm=True, # Deep AI analysis of remarks and conditions
|
|
205
|
+
investor_mode=True, # Include estimated rent, gross yield, and HOA flags
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
insights = intel.llm_derived_intelligence.investor_insights
|
|
209
|
+
capex = intel.llm_derived_intelligence.systems_and_capex
|
|
210
|
+
|
|
211
|
+
print(f"Estimated Monthly Rent: ${insights.estimated_monthly_rent.median:,.2f}")
|
|
212
|
+
print(f"Gross Yield: {insights.estimated_gross_yield_pct}%")
|
|
213
|
+
print(f"Roof Age & Condition: {capex.roof.age_years} years - {capex.roof.condition}")
|
|
214
|
+
print(f"Impact windows detected: {capex.storm_protection.has_impact_windows}")
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
### 3. Marketing Content Generation
|
|
220
|
+
|
|
221
|
+
Generate multi-channel marketing campaigns tailored by tone, target audience, and channel format.
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
copy = mls.content.generate(
|
|
225
|
+
"A12079565",
|
|
226
|
+
outputs=["social", "email_blast", "video_script", "flyer_bullets", "mls_remarks"],
|
|
227
|
+
social_platforms=["instagram", "linkedin", "facebook", "tiktok"],
|
|
228
|
+
tone="luxury",
|
|
229
|
+
target_audience="High-net-worth buyers relocating to South Florida",
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
# Access typed content
|
|
233
|
+
print("Instagram Caption:\n", copy.content.social.instagram.caption)
|
|
234
|
+
print("Instagram Hashtags:\n", copy.content.social.instagram.hashtags)
|
|
235
|
+
print("Video Script Hook:\n", copy.content.video_script.hook)
|
|
236
|
+
print("Optimized MLS Remarks:\n", copy.content.mls_remarks)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
### 4. Media Upload to Global CDN
|
|
242
|
+
|
|
243
|
+
Upload local image files, binary bytes, or open file objects directly to the `mlsapi.dev` CDN to use as inputs for any Studio operation.
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
from pathlib import Path
|
|
247
|
+
|
|
248
|
+
# 1. Upload from a local filesystem path
|
|
249
|
+
upload1 = mls.studio.upload(Path("./photos/vacant_living_room.jpg"))
|
|
250
|
+
print("CDN URL:", upload1.url)
|
|
251
|
+
|
|
252
|
+
# 2. Upload from raw bytes
|
|
253
|
+
with open("./photos/blueprint.png", "rb") as f:
|
|
254
|
+
upload2 = mls.studio.upload(
|
|
255
|
+
f.read(),
|
|
256
|
+
filename="blueprint.png",
|
|
257
|
+
content_type="image/png",
|
|
258
|
+
)
|
|
259
|
+
print("Uploaded blueprint:", upload2.url)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
### 5. Virtual Room Staging (29 Architectural Styles)
|
|
265
|
+
|
|
266
|
+
Furnish vacant room photos with photorealistic staging adhering to real estate staging standards.
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
staged = mls.studio.staging.stage_and_wait(
|
|
270
|
+
photo_url="https://cdn.mlsapi.dev/uploads/vacant_living_room.jpg",
|
|
271
|
+
room_type="living_room",
|
|
272
|
+
style="luxury", # Choose from 29 styles (e.g. 'modern', 'japandi', 'coastal')
|
|
273
|
+
preserve_flooring=True, # Keep original hardwood/tile flooring
|
|
274
|
+
custom_staging_instructions="White boucle sectional, travertine coffee table, minimalist wall art",
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
print("Staged image:", staged.staged_photo_url)
|
|
278
|
+
print("Before/after slider:", staged.before_after_comparison_url)
|
|
279
|
+
print("Staging manifest:", staged.staging_manifest)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
### 6. Day-to-Dusk Twilight & Exterior Enhancement
|
|
285
|
+
|
|
286
|
+
Transform daytime exterior photos into dramatic golden-hour twilight scenes with warm interior illumination, or enhance sunny curb appeal.
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
# 1. Twilight Day-to-Dusk conversion
|
|
290
|
+
twilight = mls.studio.staging.twilight_and_wait(
|
|
291
|
+
photo_url="https://cdn.mlsapi.dev/uploads/exterior_day.jpg",
|
|
292
|
+
mode="day_to_dusk", # Or 'blue_sky_replace'
|
|
293
|
+
)
|
|
294
|
+
print("Twilight exterior:", twilight.enhanced_photo_url)
|
|
295
|
+
|
|
296
|
+
# 2. Exterior enhancements (blue sky, green lawn, pool cleaning)
|
|
297
|
+
enhanced = mls.studio.enhance.exterior_and_wait(
|
|
298
|
+
photo_url="https://cdn.mlsapi.dev/uploads/exterior_overcast.jpg",
|
|
299
|
+
enhancements=["blue_sky", "green_grass", "clean_pool", "tidy_garden"],
|
|
300
|
+
)
|
|
301
|
+
print("Enhanced curb appeal:", enhanced.enhanced_photo_url)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
### 7. Declutter & Clean Space
|
|
307
|
+
|
|
308
|
+
Remove tenant clutter, wires, boxes, children's toys, and moving messes while strictly keeping walls, floors, and primary structural architecture intact.
|
|
309
|
+
|
|
310
|
+
```python
|
|
311
|
+
clean = mls.studio.staging.declutter_and_wait(
|
|
312
|
+
photo_url="https://cdn.mlsapi.dev/uploads/cluttered_kitchen.jpg",
|
|
313
|
+
room_type="kitchen",
|
|
314
|
+
removal_targets=["dishes", "refrigerator magnets", "trash cans", "countertop appliances"],
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
print("Clean photo:", clean.decluttered_photo_url)
|
|
318
|
+
print("Items removed:", clean.items_removed)
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
### 8. De-Staging (Empty Room) & Floor Restoration
|
|
324
|
+
|
|
325
|
+
Strip out outdated furniture to present prospective buyers with a clean architectural canvas, with optional floor restoration.
|
|
326
|
+
|
|
327
|
+
```python
|
|
328
|
+
emptied = mls.studio.staging.empty_and_wait(
|
|
329
|
+
photo_url="https://cdn.mlsapi.dev/uploads/dated_bedroom.jpg",
|
|
330
|
+
room_type="bedroom",
|
|
331
|
+
restore_flooring="hardwood", # 'hardwood' | 'tile' | 'carpet' | 'polished_concrete'
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
print("Empty room canvas:", emptied.empty_photo_url)
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
### 9. Furniture & Surface Material Replacement
|
|
340
|
+
|
|
341
|
+
Replace outdated furniture items with modern pieces or resurface materials like kitchen countertops and flooring.
|
|
342
|
+
|
|
343
|
+
```python
|
|
344
|
+
# 1. Precision furniture swap
|
|
345
|
+
new_sofa = mls.studio.staging.replace_furniture_and_wait(
|
|
346
|
+
room_photo_url="https://cdn.mlsapi.dev/uploads/living.jpg",
|
|
347
|
+
target_furniture="sofa",
|
|
348
|
+
product_description="Low-profile minimalist Italian cream leather sofa",
|
|
349
|
+
# Or pass an exact product catalog photo:
|
|
350
|
+
# reference_product_image_url="https://example.com/catalog-sofa.jpg",
|
|
351
|
+
)
|
|
352
|
+
print("Updated sofa photo:", new_sofa.result_photo_url)
|
|
353
|
+
|
|
354
|
+
# 2. Surface material replacement
|
|
355
|
+
new_kitchen = mls.studio.staging.replace_material_and_wait(
|
|
356
|
+
room_photo_url="https://cdn.mlsapi.dev/uploads/kitchen.jpg",
|
|
357
|
+
surface_type="countertops",
|
|
358
|
+
material_preset="Calacatta Gold Italian Marble with subtle grey and gold veining",
|
|
359
|
+
)
|
|
360
|
+
print("Updated kitchen countertops:", new_kitchen.result_photo_url)
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
### 10. 3x3 Designer Wall Paint Swatches
|
|
366
|
+
|
|
367
|
+
Test curated designer paint colors on room walls with an instant 3x3 comparison grid.
|
|
368
|
+
|
|
369
|
+
```python
|
|
370
|
+
swatches = mls.studio.staging.wall_colors_and_wait(
|
|
371
|
+
photo_url="https://cdn.mlsapi.dev/uploads/living_room.jpg",
|
|
372
|
+
palette_preset="popular_neutrals", # 'popular_neutrals' | 'modern_earth' | 'coastal_breeze' | 'moody_darks'
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
print("3x3 comparison grid:", swatches.comparison_grid_3x3_url)
|
|
376
|
+
for swatch in swatches.swatch_results:
|
|
377
|
+
print(f"Color: {swatch.color_name} ({swatch.hex}) -> {swatch.image_url}")
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
### 11. 2D Blueprint to 3D Isometric Dollhouse
|
|
383
|
+
|
|
384
|
+
Convert 2D floor plans, architectural blueprints, or hand sketches into 3D isometric cutaway dollhouse renders.
|
|
385
|
+
|
|
386
|
+
```python
|
|
387
|
+
# Step 1: Analyze floor plan structural geometry
|
|
388
|
+
analysis = mls.studio.floorplan.analyze(
|
|
389
|
+
floorplan_image_url="https://cdn.mlsapi.dev/uploads/floorplan.png",
|
|
390
|
+
style="modern",
|
|
391
|
+
)
|
|
392
|
+
print(f"Rooms detected: {analysis.spatial_summary.total_rooms_detected}")
|
|
393
|
+
|
|
394
|
+
# Step 2: Render 3D isometric dollhouse view
|
|
395
|
+
dollhouse = mls.studio.floorplan.render_3d_and_wait(
|
|
396
|
+
floorplan_image_url="https://cdn.mlsapi.dev/uploads/floorplan.png",
|
|
397
|
+
style="modern",
|
|
398
|
+
include_room_closeups=True,
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
print("3D Dollhouse Render:", dollhouse.isometric_3d_dollhouse_url)
|
|
402
|
+
for closeup in dollhouse.room_renders:
|
|
403
|
+
print(f"Room {closeup.room_name}: {closeup.image_url}")
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
### 12. 4K Super-Resolution Upscaling
|
|
409
|
+
|
|
410
|
+
Upscale low-resolution or compressed MLS photos up to 4K resolution with AI detail reconstruction.
|
|
411
|
+
|
|
412
|
+
```python
|
|
413
|
+
upscaled = mls.studio.enhance.upscale_and_wait(
|
|
414
|
+
image_url="https://cdn.mlsapi.dev/uploads/lowres_photo.jpg",
|
|
415
|
+
scale_factor=4, # 2 or 4
|
|
416
|
+
enhance_details=True,
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
print("4K Upscaled image:", upscaled.upscaled_image_url)
|
|
420
|
+
print("Target resolution:", upscaled.target_resolution)
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
### 13. Branded Multi-Placement Ad Creatives
|
|
426
|
+
|
|
427
|
+
Generate compliant real estate ad creatives with agent branding kits, MLS property badges, and typography across all social and print dimensions.
|
|
428
|
+
|
|
429
|
+
```python
|
|
430
|
+
ads = mls.studio.creatives.generate_and_wait(
|
|
431
|
+
mls_id="A12079565",
|
|
432
|
+
trigger="just_listed", # 'just_listed' | 'open_house' | 'price_improved' | 'just_sold'
|
|
433
|
+
direction="magazine", # 'magazine' | 'bold' | 'warm'
|
|
434
|
+
placements=["feed_portrait", "square", "link", "flyer"],
|
|
435
|
+
brand_kit={
|
|
436
|
+
"agent_name": "Sarah Connor",
|
|
437
|
+
"brokerage_name": "Compass Beverly Hills",
|
|
438
|
+
"phone": "(310) 555-0199",
|
|
439
|
+
"primary_brand_color": "#0F172A",
|
|
440
|
+
"agent_headshot_url": "https://cdn.example.com/sarah-headshot.jpg",
|
|
441
|
+
},
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
print("1:1 Square Feed Ad:", ads.creatives.get("square").image_url)
|
|
445
|
+
print("9:16 Vertical Story Ad:", ads.creatives.get("feed_portrait").image_url)
|
|
446
|
+
print("Fair Housing compliance passed:", ads.compliance.fair_housing_passed)
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
### 14. AI Video Walkthroughs & Voice/Subtitle Polish
|
|
452
|
+
|
|
453
|
+
Polish realtor walkthrough videos with studio voice leveling, Hormozi-style animated captions, and automatic vertical 9:16 re-framing.
|
|
454
|
+
|
|
455
|
+
```python
|
|
456
|
+
polished_video = mls.studio.video.enhance_and_wait(
|
|
457
|
+
video_url="https://cdn.mlsapi.dev/uploads/raw_walkthrough.mp4",
|
|
458
|
+
features={
|
|
459
|
+
"studio_voice": True, # Wind/echo cleanup & voice mastering
|
|
460
|
+
"animated_subtitles": True, # Word-by-word dynamic animated subtitles
|
|
461
|
+
"smart_reframe": True, # Auto-track agent and reframe to 9:16
|
|
462
|
+
},
|
|
463
|
+
subtitle_style={
|
|
464
|
+
"font_theme": "hormozi_bold",
|
|
465
|
+
"primary_color": "#FFFFFF",
|
|
466
|
+
"highlight_color": "#FFDE59",
|
|
467
|
+
},
|
|
468
|
+
export_aspect_ratios=["9:16", "16:9"],
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
print("Reels / TikTok Video:", polished_video.mastered_videos[0].url)
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## Asynchronous Jobs & Progress Callbacks
|
|
477
|
+
|
|
478
|
+
Every Studio operation returns immediately with an HTTP 202 `StudioJob` when using the standard method (e.g. `stage(...)`), or polls until completion when using the `*_and_wait(...)` companion method.
|
|
479
|
+
|
|
480
|
+
### Custom Polling Options & Progress Hook
|
|
481
|
+
|
|
482
|
+
```python
|
|
483
|
+
def on_progress(job):
|
|
484
|
+
print(f"[{job.progress_percentage}%] Step: {job.current_step}")
|
|
485
|
+
|
|
486
|
+
result = mls.studio.staging.stage_and_wait(
|
|
487
|
+
photo_url="https://cdn.mlsapi.dev/uploads/room.jpg",
|
|
488
|
+
style="japandi",
|
|
489
|
+
poll_interval=2.0, # Poll every 2.0 seconds (default: 2.0s)
|
|
490
|
+
timeout_seconds=120.0, # Maximum wait time (default: 90.0s)
|
|
491
|
+
on_progress=on_progress, # Optional progress callback
|
|
492
|
+
)
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### Manual Job Tracking
|
|
496
|
+
|
|
497
|
+
```python
|
|
498
|
+
# Dispatch without waiting
|
|
499
|
+
job = mls.studio.staging.stage(photo_url="https://cdn.mlsapi.dev/uploads/room.jpg")
|
|
500
|
+
print(f"Track job later: {job.job_id}")
|
|
501
|
+
|
|
502
|
+
# Check status later
|
|
503
|
+
current_status = mls.studio.jobs.get(job.job_id)
|
|
504
|
+
print(f"Status: {current_status.status}, progress: {current_status.progress_percentage}%")
|
|
505
|
+
|
|
506
|
+
# Or wait for it when ready
|
|
507
|
+
completed_job = mls.studio.jobs.wait_for(job.job_id, timeout_seconds=90.0)
|
|
508
|
+
print("Result URL:", completed_job.result.staged_photo_url)
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## Error Handling
|
|
514
|
+
|
|
515
|
+
All API errors inherit from `MlsApiError` and expose the HTTP status code, error code, and server message.
|
|
516
|
+
|
|
517
|
+
```python
|
|
518
|
+
from pymlsapi.errors import (
|
|
519
|
+
MlsApiError,
|
|
520
|
+
AuthenticationError,
|
|
521
|
+
NotFoundError,
|
|
522
|
+
RateLimitError,
|
|
523
|
+
InsufficientCreditsError,
|
|
524
|
+
JobTimeoutError,
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
try:
|
|
528
|
+
listing = mls.listings.get_and_wait("INVALID_ID")
|
|
529
|
+
except AuthenticationError as e:
|
|
530
|
+
print("Invalid API Key:", e.message)
|
|
531
|
+
except NotFoundError as e:
|
|
532
|
+
print("Listing or resource not found:", e.message)
|
|
533
|
+
except RateLimitError as e:
|
|
534
|
+
print(f"Rate limited. Quota resets in {e.retry_after_seconds}s")
|
|
535
|
+
except InsufficientCreditsError as e:
|
|
536
|
+
print("Insufficient credits in workspace balance. Top up at https://mlsapi.dev/billing")
|
|
537
|
+
except JobTimeoutError as e:
|
|
538
|
+
print(f"Job polling timed out after {e.timeout_seconds}s")
|
|
539
|
+
except MlsApiError as e:
|
|
540
|
+
print(f"API Error [{e.code}]: {e.message}")
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## Supported Presets Reference
|
|
546
|
+
|
|
547
|
+
### Interior Design Styles (29 Presets)
|
|
548
|
+
|
|
549
|
+
| | | |
|
|
550
|
+
|---|---|---|
|
|
551
|
+
| `modern` | `luxury` | `scandinavian` |
|
|
552
|
+
| `japandi` | `industrial` | `bohemian` |
|
|
553
|
+
| `minimalist` | `coastal` | `mid_century_modern` |
|
|
554
|
+
| `art_deco` | `farmhouse` | `mediterranean` |
|
|
555
|
+
| `contemporary` | `rustic` | `transitional` |
|
|
556
|
+
| `french_country` | `hollywood_regency` | `eclectic` |
|
|
557
|
+
| `zen` | `bauhaus` | `victorian` |
|
|
558
|
+
| `tropical` | `modern_craftsman` | `southwestern` |
|
|
559
|
+
| `wabi_sabi` | `shabby_chic` | `chalet` |
|
|
560
|
+
| `urban_loft` | `custom` | |
|
|
561
|
+
|
|
562
|
+
### Architectural Room Types (12 Types)
|
|
563
|
+
|
|
564
|
+
`living_room`, `bedroom`, `primary_bedroom`, `dining_room`, `kitchen`, `bathroom`, `patio`, `outdoor_patio`, `home_office`, `entryway`, `basement`, `commercial_lobby`.
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
## License
|
|
569
|
+
|
|
570
|
+
MIT © [mlsapi.dev](https://mlsapi.dev)
|