instructor-ainative 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,30 @@
1
+ """
2
+ instructor-ainative — Structured output extraction via AINative's free LLM API.
3
+
4
+ Pre-configured instructor client that connects to AINative's OpenAI-compatible
5
+ endpoint. Supports Llama, Qwen, and DeepSeek models with auto-provisioning.
6
+
7
+ Usage:
8
+ from instructor_ainative import get_client
9
+ from pydantic import BaseModel
10
+
11
+ class User(BaseModel):
12
+ name: str
13
+ age: int
14
+
15
+ client = get_client()
16
+ user = client.chat.completions.create(
17
+ model="meta-llama/Llama-3.3-70B-Instruct",
18
+ response_model=User,
19
+ messages=[{"role": "user", "content": "Extract: John is 30"}],
20
+ )
21
+ print(user) # User(name='John', age=30)
22
+
23
+ Refs #3950
24
+ """
25
+
26
+ from instructor_ainative.client import get_client, get_async_client
27
+ from instructor_ainative.models import MODELS, get_model
28
+
29
+ __all__ = ["get_client", "get_async_client", "MODELS", "get_model"]
30
+ __version__ = "0.1.0"
@@ -0,0 +1,118 @@
1
+ """
2
+ instructor-ainative — Client Factory
3
+
4
+ Creates pre-configured instructor clients that connect to AINative's
5
+ OpenAI-compatible API for structured output extraction.
6
+
7
+ Refs #3950
8
+ """
9
+
10
+ from typing import Optional
11
+
12
+ import instructor
13
+ from openai import OpenAI, AsyncOpenAI
14
+
15
+ from instructor_ainative.provision import resolve_api_key
16
+
17
+ BASE_URL = "https://api.ainative.studio/api/v1"
18
+
19
+
20
+ def get_client(
21
+ api_key: Optional[str] = None,
22
+ base_url: Optional[str] = None,
23
+ mode: instructor.Mode = instructor.Mode.JSON,
24
+ **kwargs,
25
+ ) -> instructor.Instructor:
26
+ """
27
+ Create a pre-configured instructor client for structured output extraction.
28
+
29
+ Uses AINative's free OpenAI-compatible API. If no API key is provided,
30
+ auto-provisions a free account.
31
+
32
+ Args:
33
+ api_key: Explicit API key. Falls back to env vars, credentials file,
34
+ or auto-provisioning.
35
+ base_url: Override the API base URL. Defaults to AINative's endpoint.
36
+ mode: instructor mode for structured output. Defaults to JSON mode
37
+ which works best with open-source models.
38
+ **kwargs: Additional arguments passed to instructor.from_openai().
39
+
40
+ Returns:
41
+ An instructor-patched OpenAI client ready for structured output.
42
+
43
+ Example:
44
+ from instructor_ainative import get_client
45
+ from pydantic import BaseModel
46
+
47
+ class User(BaseModel):
48
+ name: str
49
+ age: int
50
+
51
+ client = get_client()
52
+ user = client.chat.completions.create(
53
+ model="meta-llama/Llama-3.3-70B-Instruct",
54
+ response_model=User,
55
+ messages=[{"role": "user", "content": "Extract: John is 30"}],
56
+ )
57
+ """
58
+ key = resolve_api_key(api_key)
59
+ base = base_url or BASE_URL
60
+
61
+ base_client = OpenAI(
62
+ api_key=key,
63
+ base_url=base,
64
+ )
65
+
66
+ return instructor.from_openai(base_client, mode=mode, **kwargs)
67
+
68
+
69
+ def get_async_client(
70
+ api_key: Optional[str] = None,
71
+ base_url: Optional[str] = None,
72
+ mode: instructor.Mode = instructor.Mode.JSON,
73
+ **kwargs,
74
+ ) -> instructor.AsyncInstructor:
75
+ """
76
+ Create a pre-configured async instructor client for structured output extraction.
77
+
78
+ Same as get_client() but uses AsyncOpenAI for async/await usage.
79
+
80
+ Args:
81
+ api_key: Explicit API key. Falls back to env vars, credentials file,
82
+ or auto-provisioning.
83
+ base_url: Override the API base URL. Defaults to AINative's endpoint.
84
+ mode: instructor mode for structured output. Defaults to JSON mode.
85
+ **kwargs: Additional arguments passed to instructor.from_openai().
86
+
87
+ Returns:
88
+ An async instructor-patched OpenAI client.
89
+
90
+ Example:
91
+ import asyncio
92
+ from instructor_ainative import get_async_client
93
+ from pydantic import BaseModel
94
+
95
+ class User(BaseModel):
96
+ name: str
97
+ age: int
98
+
99
+ async def main():
100
+ client = get_async_client()
101
+ user = await client.chat.completions.create(
102
+ model="meta-llama/Llama-3.3-70B-Instruct",
103
+ response_model=User,
104
+ messages=[{"role": "user", "content": "Extract: John is 30"}],
105
+ )
106
+ print(user)
107
+
108
+ asyncio.run(main())
109
+ """
110
+ key = resolve_api_key(api_key)
111
+ base = base_url or BASE_URL
112
+
113
+ base_client = AsyncOpenAI(
114
+ api_key=key,
115
+ base_url=base,
116
+ )
117
+
118
+ return instructor.from_openai(base_client, mode=mode, **kwargs)
@@ -0,0 +1,55 @@
1
+ """
2
+ instructor-ainative — Supported Models
3
+
4
+ Model aliases and catalog for AINative's OpenAI-compatible endpoint.
5
+ All models support structured output extraction via instructor.
6
+
7
+ Refs #3950
8
+ """
9
+
10
+ from typing import Optional
11
+
12
+ # Model aliases -> full model identifiers
13
+ MODELS = {
14
+ # Meta Llama
15
+ "llama": "meta-llama/Llama-3.3-70B-Instruct",
16
+ "llama-70b": "meta-llama/Llama-3.3-70B-Instruct",
17
+ "llama-8b": "meta-llama/Llama-3.1-8B-Instruct",
18
+ # Qwen
19
+ "qwen": "qwen3-coder-flash",
20
+ "qwen-coder": "qwen3-coder-flash",
21
+ # DeepSeek
22
+ "deepseek": "deepseek-4-flash",
23
+ "deepseek-flash": "deepseek-4-flash",
24
+ # Kimi
25
+ "kimi": "kimi-k2",
26
+ }
27
+
28
+ # Default model for get_client()
29
+ DEFAULT_MODEL = "meta-llama/Llama-3.3-70B-Instruct"
30
+
31
+
32
+ def get_model(alias: str) -> str:
33
+ """
34
+ Resolve a model alias to its full identifier.
35
+
36
+ Args:
37
+ alias: Short alias (e.g. "llama", "qwen") or full model ID.
38
+
39
+ Returns:
40
+ Full model identifier string.
41
+
42
+ Examples:
43
+ >>> get_model("llama")
44
+ 'meta-llama/Llama-3.3-70B-Instruct'
45
+ >>> get_model("qwen")
46
+ 'qwen3-coder-flash'
47
+ >>> get_model("meta-llama/Llama-3.3-70B-Instruct")
48
+ 'meta-llama/Llama-3.3-70B-Instruct'
49
+ """
50
+ return MODELS.get(alias, alias)
51
+
52
+
53
+ def list_models() -> dict:
54
+ """Return all available model aliases and their full identifiers."""
55
+ return dict(MODELS)
@@ -0,0 +1,174 @@
1
+ """
2
+ instructor-ainative — Auto-Provisioning
3
+
4
+ Zero-friction provisioning for instructor users.
5
+ On first use, if no API key is found, automatically provisions
6
+ a free AINative account (72-hour TTL) that can be claimed later.
7
+
8
+ Credential resolution order:
9
+ 1. Explicit api_key parameter
10
+ 2. AINATIVE_API_KEY environment variable
11
+ 3. ZERODB_API_KEY environment variable (shared with zerodb ecosystem)
12
+ 4. ~/.zerodb/credentials.json (shared credential store)
13
+ 5. Auto-provision via /api/v1/public/instant-db
14
+
15
+ Refs #3950
16
+ """
17
+
18
+ import json
19
+ import os
20
+ import sys
21
+ from datetime import datetime
22
+ from pathlib import Path
23
+ from typing import Optional
24
+
25
+ import requests
26
+
27
+ ZERODB_DIR = Path.home() / ".zerodb"
28
+ CREDS_PATH = ZERODB_DIR / "credentials.json"
29
+ CONFIG_PATH = ZERODB_DIR / "config.json"
30
+ CLOUD_API_URL = "https://api.ainative.studio"
31
+ PROVISION_ENDPOINT = "/api/v1/public/instant-db"
32
+
33
+
34
+ def resolve_api_key(explicit_key: Optional[str] = None) -> str:
35
+ """
36
+ Resolve an API key from all available sources.
37
+
38
+ Args:
39
+ explicit_key: Key passed directly by the user.
40
+
41
+ Returns:
42
+ A valid API key string.
43
+
44
+ Raises:
45
+ RuntimeError: If auto-provisioning fails and no key is available.
46
+ """
47
+ # 1. Explicit parameter
48
+ if explicit_key:
49
+ return explicit_key
50
+
51
+ # 2. Environment variables
52
+ env_key = (
53
+ os.environ.get("AINATIVE_API_KEY")
54
+ or os.environ.get("ZERODB_API_KEY")
55
+ )
56
+ if env_key:
57
+ return env_key
58
+
59
+ # 3. Credentials file (shared with zerodb ecosystem)
60
+ creds = _load_credentials()
61
+ if creds:
62
+ return creds
63
+
64
+ # 4. Auto-provision
65
+ return _auto_provision()
66
+
67
+
68
+ def _load_credentials() -> Optional[str]:
69
+ """Load API key from ~/.zerodb/credentials.json."""
70
+ if CREDS_PATH.exists():
71
+ try:
72
+ data = json.loads(CREDS_PATH.read_text())
73
+ key = data.get("api_key")
74
+ if key:
75
+ return key
76
+ except (json.JSONDecodeError, KeyError):
77
+ pass
78
+
79
+ if CONFIG_PATH.exists():
80
+ try:
81
+ data = json.loads(CONFIG_PATH.read_text())
82
+ key = data.get("api_key") or data.get("cloud_api_key")
83
+ if key:
84
+ return key
85
+ except (json.JSONDecodeError, KeyError):
86
+ pass
87
+
88
+ return None
89
+
90
+
91
+ def _auto_provision() -> str:
92
+ """
93
+ Auto-provision a free AINative account for structured output extraction.
94
+
95
+ Returns:
96
+ API key string.
97
+
98
+ Raises:
99
+ RuntimeError: If provisioning fails.
100
+ """
101
+ print(
102
+ "\n No API key found — provisioning a free AINative account for structured outputs...",
103
+ file=sys.stderr,
104
+ )
105
+
106
+ try:
107
+ resp = requests.post(
108
+ f"{CLOUD_API_URL}{PROVISION_ENDPOINT}",
109
+ json={"agree_terms": True, "source": "instructor-ainative"},
110
+ timeout=15,
111
+ )
112
+
113
+ if resp.status_code == 429:
114
+ raise RuntimeError(
115
+ "Rate limited — too many provisions from this IP. "
116
+ "Sign up at https://ainative.studio/signup and set AINATIVE_API_KEY."
117
+ )
118
+
119
+ if resp.status_code not in (200, 201):
120
+ raise RuntimeError(
121
+ f"Provisioning failed (HTTP {resp.status_code}). "
122
+ "Sign up at https://ainative.studio/signup and set AINATIVE_API_KEY."
123
+ )
124
+
125
+ data = resp.json()
126
+ api_key = data.get("api_key", "")
127
+ if not api_key:
128
+ raise RuntimeError("Provisioning returned empty API key.")
129
+
130
+ _save_credentials(data)
131
+ _print_success(data)
132
+ return api_key
133
+
134
+ except requests.RequestException as exc:
135
+ raise RuntimeError(
136
+ f"Network error during provisioning: {exc}. "
137
+ "Set AINATIVE_API_KEY manually or sign up at https://ainative.studio/signup"
138
+ ) from exc
139
+
140
+
141
+ def _save_credentials(data: dict) -> None:
142
+ """Save provisioned credentials to ~/.zerodb/ for ecosystem sharing."""
143
+ ZERODB_DIR.mkdir(parents=True, exist_ok=True)
144
+
145
+ creds = {
146
+ "api_key": data.get("api_key", ""),
147
+ "project_id": data.get("project_id", ""),
148
+ "base_url": data.get("base_url", CLOUD_API_URL),
149
+ "expires_at": data.get("expires_at", ""),
150
+ "claim_url": data.get("claim_url", ""),
151
+ "provisioned_at": datetime.now(tz=None).isoformat(),
152
+ "source": "instructor-ainative",
153
+ }
154
+
155
+ CREDS_PATH.write_text(json.dumps(creds, indent=2) + "\n")
156
+
157
+
158
+ def _print_success(data: dict) -> None:
159
+ """Print success message with claim URL."""
160
+ expires = data.get("expires_at", "72 hours")
161
+ claim_url = data.get("claim_url", "https://ainative.studio/signup")
162
+ api_key = data.get("api_key", "")
163
+
164
+ print(
165
+ f"\n Auto-provisioned! Free structured output API ready.\n"
166
+ f"\n"
167
+ f" API Key: {api_key[:12]}...\n"
168
+ f" Expires: {expires}\n"
169
+ f" Saved to: ~/.zerodb/credentials.json\n"
170
+ f"\n"
171
+ f" To keep access permanently, claim your account:\n"
172
+ f" {claim_url}\n",
173
+ file=sys.stderr,
174
+ )
@@ -0,0 +1,189 @@
1
+ Metadata-Version: 2.4
2
+ Name: instructor-ainative
3
+ Version: 0.1.0
4
+ Summary: Pre-configured instructor client for structured output extraction via AINative's free LLM API
5
+ Author-email: AINative Studio <dev@ainative.studio>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/AINative-Studio/instructor-ainative
8
+ Project-URL: Documentation, https://docs.ainative.studio/instructor
9
+ Project-URL: Repository, https://github.com/AINative-Studio/instructor-ainative
10
+ Project-URL: Issues, https://github.com/AINative-Studio/instructor-ainative/issues
11
+ Keywords: instructor,instructor-plugin,structured-output,pydantic,json-extraction,free-llm,ainative,zerodb,openai-compatible,llama,qwen,deepseek,auto-provisioning,claude,cursor,function-calling,schema-extraction,data-extraction,llm-structured,json-mode
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: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Python: >=3.9
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: instructor>=1.0.0
27
+ Requires-Dist: openai>=1.0.0
28
+ Requires-Dist: requests>=2.28
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0; extra == "dev"
31
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
32
+ Requires-Dist: responses>=0.23; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ # instructor-ainative
36
+
37
+ Pre-configured [instructor](https://github.com/jxnl/instructor) client for structured output extraction using AINative's free LLM API.
38
+
39
+ **Zero setup.** Works with Llama 3.3 70B, Qwen3, DeepSeek 4, and Kimi K2 — all free.
40
+
41
+ ## Install
42
+
43
+ ```bash
44
+ pip install instructor-ainative
45
+ ```
46
+
47
+ ## Quick Start
48
+
49
+ ```python
50
+ from instructor_ainative import get_client
51
+ from pydantic import BaseModel
52
+
53
+ class User(BaseModel):
54
+ name: str
55
+ age: int
56
+
57
+ client = get_client() # Auto-provisions free API key
58
+ user = client.chat.completions.create(
59
+ model="meta-llama/Llama-3.3-70B-Instruct",
60
+ response_model=User,
61
+ messages=[{"role": "user", "content": "Extract: John is 30"}],
62
+ )
63
+ print(user) # User(name='John', age=30)
64
+ ```
65
+
66
+ ## How It Works
67
+
68
+ `instructor-ainative` wraps [instructor](https://python.useinstructor.com/) with a pre-configured OpenAI client pointing at AINative's free, OpenAI-compatible API. You get structured Pydantic output extraction from open-source models without any API key setup.
69
+
70
+ On first use, the package auto-provisions a free API key (72-hour TTL). Claim your account at [ainative.studio/signup](https://ainative.studio/signup) for permanent access.
71
+
72
+ ## Available Models
73
+
74
+ Use aliases or full model IDs:
75
+
76
+ ```python
77
+ from instructor_ainative import get_model, MODELS
78
+
79
+ # Aliases
80
+ get_model("llama") # meta-llama/Llama-3.3-70B-Instruct
81
+ get_model("qwen") # qwen3-coder-flash
82
+ get_model("deepseek") # deepseek-4-flash
83
+ get_model("kimi") # kimi-k2
84
+ ```
85
+
86
+ ## Async Support
87
+
88
+ ```python
89
+ import asyncio
90
+ from instructor_ainative import get_async_client
91
+ from pydantic import BaseModel
92
+
93
+ class User(BaseModel):
94
+ name: str
95
+ age: int
96
+
97
+ async def main():
98
+ client = get_async_client()
99
+ user = await client.chat.completions.create(
100
+ model="meta-llama/Llama-3.3-70B-Instruct",
101
+ response_model=User,
102
+ messages=[{"role": "user", "content": "Extract: John is 30"}],
103
+ )
104
+ print(user)
105
+
106
+ asyncio.run(main())
107
+ ```
108
+
109
+ ## Configuration
110
+
111
+ ### API Key Resolution Order
112
+
113
+ 1. Explicit `api_key` parameter
114
+ 2. `AINATIVE_API_KEY` environment variable
115
+ 3. `ZERODB_API_KEY` environment variable
116
+ 4. `~/.zerodb/credentials.json` (shared with ZeroDB ecosystem)
117
+ 5. Auto-provision (free, 72-hour TTL)
118
+
119
+ ### Bring Your Own Key
120
+
121
+ ```bash
122
+ export AINATIVE_API_KEY=your-key-here
123
+ ```
124
+
125
+ ```python
126
+ # Or pass directly
127
+ client = get_client(api_key="your-key-here")
128
+ ```
129
+
130
+ ### Custom Base URL
131
+
132
+ ```python
133
+ client = get_client(base_url="https://your-proxy.example.com/v1")
134
+ ```
135
+
136
+ ### Instructor Mode
137
+
138
+ ```python
139
+ import instructor
140
+ client = get_client(mode=instructor.Mode.TOOLS) # Default is JSON mode
141
+ ```
142
+
143
+ ## Complex Extraction
144
+
145
+ ```python
146
+ from instructor_ainative import get_client
147
+ from pydantic import BaseModel, Field
148
+ from typing import List
149
+
150
+ class Address(BaseModel):
151
+ street: str
152
+ city: str
153
+ state: str
154
+ zip_code: str = Field(description="5-digit ZIP code")
155
+
156
+ class Contact(BaseModel):
157
+ name: str
158
+ email: str
159
+ phone: str
160
+ addresses: List[Address]
161
+
162
+ client = get_client()
163
+ contact = client.chat.completions.create(
164
+ model="meta-llama/Llama-3.3-70B-Instruct",
165
+ response_model=Contact,
166
+ messages=[{
167
+ "role": "user",
168
+ "content": """
169
+ Extract contact info: Jane Smith, jane@example.com, 555-0123.
170
+ Lives at 123 Main St, Austin TX 78701 and
171
+ 456 Oak Ave, Denver CO 80202.
172
+ """
173
+ }],
174
+ )
175
+ ```
176
+
177
+ ## Why instructor-ainative?
178
+
179
+ | Feature | instructor + OpenAI | instructor-ainative |
180
+ |---------|-------------------|-------------------|
181
+ | Setup | Get API key, set env var | `pip install` and go |
182
+ | Cost | Pay per token | Free |
183
+ | Models | GPT-4o, etc. | Llama 70B, Qwen, DeepSeek |
184
+ | Structured output | Yes | Yes |
185
+ | Auto-provisioning | No | Yes |
186
+
187
+ ## License
188
+
189
+ MIT
@@ -0,0 +1,9 @@
1
+ instructor_ainative/__init__.py,sha256=pqAVIQ_TuZrjkA50XFgSZFN2PKgP9nPmn3Sbuf7YOLY,900
2
+ instructor_ainative/client.py,sha256=aAV_eaNT9yjhSrXXDFGhA0KBp1Ywg_U7p-oiU_myWpg,3487
3
+ instructor_ainative/models.py,sha256=nmFSZSXfH5cd157pJVJp9RKCtXgZYpn2-VJ3MvH14KA,1395
4
+ instructor_ainative/provision.py,sha256=IEFBECQLAWvL8W2gyAQlvQyho6MMS_z0MuJL2ki5dhs,5033
5
+ instructor_ainative-0.1.0.dist-info/licenses/LICENSE,sha256=-3M2h1U80S6mPyiuvRG25A0l1xZGpa7eO43lysBIzBY,1072
6
+ instructor_ainative-0.1.0.dist-info/METADATA,sha256=soP4c5jCSqinvCickbLIbF2G89jvwkNllntKaekmgJI,5473
7
+ instructor_ainative-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
8
+ instructor_ainative-0.1.0.dist-info/top_level.txt,sha256=oUoo5v8osWDBUpBhmdPON63zWVdZYnPhIDLgG84gkik,20
9
+ instructor_ainative-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AINative Studio
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ instructor_ainative