kynth 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.
kynth-0.1.0/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ __pycache__/
2
+ *.pyc
3
+ dist/
4
+ build/
5
+ *.egg-info/
6
+ .pytest_cache/
kynth-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,71 @@
1
+ Metadata-Version: 2.4
2
+ Name: kynth
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for Kynth Core — the AI back-end for your product.
5
+ Project-URL: Homepage, https://api.kynth.studio
6
+ Project-URL: Documentation, https://api.kynth.studio/docs
7
+ Project-URL: Source, https://github.com/kyisaiah47/kynth-os
8
+ Author: Kynth Studios
9
+ License: MIT
10
+ Keywords: ai,api,chargeback,contract,document-parsing,kynth,llm,ocr,pii
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+
19
+ # kynth
20
+
21
+ Official Python SDK for **[Kynth Core](https://api.kynth.studio)** — the AI back-end for your product. Parse documents, extract fields, redact PII, analyze contracts, fight chargebacks, and enrich companies.
22
+
23
+ ```bash
24
+ pip install kynth
25
+ ```
26
+
27
+ ## Quickstart
28
+
29
+ ```python
30
+ from kynth import Kynth
31
+
32
+ client = Kynth(api_key="ksk_live_...")
33
+
34
+ doc = client.parse(file_url="https://.../invoice.pdf")
35
+ print(doc["totalAmount"]) # 4820.5
36
+ print(doc["usage"]["balanceRemaining"]) # 490
37
+ ```
38
+
39
+ Get a key (and 500 free credits) at **[api.kynth.studio](https://api.kynth.studio)**. Zero dependencies — stdlib only, Python 3.8+.
40
+
41
+ ## Methods
42
+
43
+ Every method returns the endpoint result as a dict, including a `usage` envelope. A non-2xx response raises a typed `KynthError` (and never burns credits).
44
+
45
+ ```python
46
+ client.parse(file_url=...) # documents → JSON
47
+ client.extract(text=..., fields=["order", "total"]) # pull named fields
48
+ client.classify(text=..., labels=["billing", "tech"]) # label text
49
+ client.summarize(text=..., length="standard") # summary + actions
50
+ client.redact(text=...) # strip PII/PHI
51
+ client.sentiment(text=..., aspects=["product"]) # sentiment + aspects
52
+ client.contract(file_url=...) # contract → terms + risks
53
+ client.chargeback(reason=..., transaction={"amount": 129}) # representment packet
54
+ client.enrich(email="sam@stripe.com") # company profile
55
+ client.account() # balance
56
+ ```
57
+
58
+ ## Error handling
59
+
60
+ ```python
61
+ from kynth import Kynth, KynthError
62
+
63
+ client = Kynth(api_key="ksk_live_...")
64
+ try:
65
+ client.parse(file_url="https://.../invoice.pdf")
66
+ except KynthError as err:
67
+ # err.code: "insufficient_credits" | "rate_limited" | "unauthorized" | ...
68
+ print(err.code, err.status, err.message)
69
+ ```
70
+
71
+ MIT © Kynth Studios
kynth-0.1.0/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # kynth
2
+
3
+ Official Python SDK for **[Kynth Core](https://api.kynth.studio)** — the AI back-end for your product. Parse documents, extract fields, redact PII, analyze contracts, fight chargebacks, and enrich companies.
4
+
5
+ ```bash
6
+ pip install kynth
7
+ ```
8
+
9
+ ## Quickstart
10
+
11
+ ```python
12
+ from kynth import Kynth
13
+
14
+ client = Kynth(api_key="ksk_live_...")
15
+
16
+ doc = client.parse(file_url="https://.../invoice.pdf")
17
+ print(doc["totalAmount"]) # 4820.5
18
+ print(doc["usage"]["balanceRemaining"]) # 490
19
+ ```
20
+
21
+ Get a key (and 500 free credits) at **[api.kynth.studio](https://api.kynth.studio)**. Zero dependencies — stdlib only, Python 3.8+.
22
+
23
+ ## Methods
24
+
25
+ Every method returns the endpoint result as a dict, including a `usage` envelope. A non-2xx response raises a typed `KynthError` (and never burns credits).
26
+
27
+ ```python
28
+ client.parse(file_url=...) # documents → JSON
29
+ client.extract(text=..., fields=["order", "total"]) # pull named fields
30
+ client.classify(text=..., labels=["billing", "tech"]) # label text
31
+ client.summarize(text=..., length="standard") # summary + actions
32
+ client.redact(text=...) # strip PII/PHI
33
+ client.sentiment(text=..., aspects=["product"]) # sentiment + aspects
34
+ client.contract(file_url=...) # contract → terms + risks
35
+ client.chargeback(reason=..., transaction={"amount": 129}) # representment packet
36
+ client.enrich(email="sam@stripe.com") # company profile
37
+ client.account() # balance
38
+ ```
39
+
40
+ ## Error handling
41
+
42
+ ```python
43
+ from kynth import Kynth, KynthError
44
+
45
+ client = Kynth(api_key="ksk_live_...")
46
+ try:
47
+ client.parse(file_url="https://.../invoice.pdf")
48
+ except KynthError as err:
49
+ # err.code: "insufficient_credits" | "rate_limited" | "unauthorized" | ...
50
+ print(err.code, err.status, err.message)
51
+ ```
52
+
53
+ MIT © Kynth Studios
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "kynth"
7
+ version = "0.1.0"
8
+ description = "Official Python SDK for Kynth Core — the AI back-end for your product."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Kynth Studios" }]
13
+ keywords = ["kynth", "ai", "api", "document-parsing", "ocr", "pii", "contract", "chargeback", "llm"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Topic :: Software Development :: Libraries :: Python Modules",
20
+ ]
21
+ dependencies = []
22
+
23
+ [project.urls]
24
+ Homepage = "https://api.kynth.studio"
25
+ Documentation = "https://api.kynth.studio/docs"
26
+ Source = "https://github.com/kyisaiah47/kynth-os"
27
+
28
+ [tool.hatch.build.targets.wheel]
29
+ packages = ["src/kynth"]
@@ -0,0 +1,199 @@
1
+ """Official Python SDK for Kynth Core — the AI back-end for your product.
2
+
3
+ from kynth import Kynth, KynthError
4
+
5
+ client = Kynth(api_key="ksk_live_...")
6
+ doc = client.parse(file_url="https://.../invoice.pdf")
7
+ print(doc["totalAmount"], doc["usage"]["balanceRemaining"])
8
+
9
+ Zero dependencies (stdlib only). Every method returns the endpoint result as a
10
+ dict including a ``usage`` envelope; failures raise a typed ``KynthError`` and
11
+ never burn credits. Get a key + 500 free credits at https://api.kynth.studio.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import urllib.error
18
+ import urllib.request
19
+ from typing import Any, Dict, List, Optional
20
+
21
+ __all__ = ["Kynth", "KynthError", "__version__"]
22
+ __version__ = "0.1.0"
23
+
24
+ _DEFAULT_BASE_URL = "https://api.kynth.studio"
25
+
26
+
27
+ class KynthError(Exception):
28
+ """Raised for any non-2xx API response. Mirrors ``{"error": {"code", "message"}}``."""
29
+
30
+ def __init__(self, code: str, message: str, status: int) -> None:
31
+ super().__init__(message)
32
+ self.code = code
33
+ self.message = message
34
+ self.status = status
35
+
36
+ def __repr__(self) -> str: # pragma: no cover - trivial
37
+ return f"KynthError(code={self.code!r}, status={self.status}, message={self.message!r})"
38
+
39
+
40
+ def _document(file_url: Optional[str], text: Optional[str], file: Optional[Dict[str, str]]) -> Dict[str, Any]:
41
+ if file_url:
42
+ return {"fileUrl": file_url}
43
+ if file:
44
+ return {"file": file}
45
+ if text:
46
+ return {"text": text}
47
+ raise ValueError("Provide one of: file_url, text, or file={'data','mimeType'}.")
48
+
49
+
50
+ class Kynth:
51
+ """Synchronous client for the Kynth Core API."""
52
+
53
+ def __init__(
54
+ self,
55
+ api_key: str,
56
+ base_url: str = _DEFAULT_BASE_URL,
57
+ timeout: float = 60.0,
58
+ ) -> None:
59
+ if not api_key:
60
+ raise ValueError(
61
+ "Kynth: `api_key` is required. Mint one at https://api.kynth.studio/dashboard."
62
+ )
63
+ self.api_key = api_key
64
+ self.base_url = base_url.rstrip("/")
65
+ self.timeout = timeout
66
+
67
+ # -- transport ---------------------------------------------------------
68
+ def _request(self, method: str, path: str, body: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
69
+ url = f"{self.base_url}{path}"
70
+ data = json.dumps(body).encode("utf-8") if body is not None else None
71
+ headers = {"Authorization": f"Bearer {self.api_key}"}
72
+ if data is not None:
73
+ headers["Content-Type"] = "application/json"
74
+ req = urllib.request.Request(url, data=data, headers=headers, method=method)
75
+ try:
76
+ with urllib.request.urlopen(req, timeout=self.timeout) as resp:
77
+ payload = resp.read().decode("utf-8")
78
+ return json.loads(payload) if payload else {}
79
+ except urllib.error.HTTPError as exc:
80
+ raw = exc.read().decode("utf-8", errors="replace")
81
+ code, message = "unknown", f"Request failed with status {exc.code}."
82
+ try:
83
+ err = json.loads(raw).get("error") or {}
84
+ code = err.get("code", code)
85
+ message = err.get("message", message)
86
+ except (ValueError, AttributeError):
87
+ pass
88
+ raise KynthError(code, message, exc.code) from None
89
+ except urllib.error.URLError as exc:
90
+ raise KynthError("unknown", str(exc.reason), 0) from None
91
+
92
+ def _post(self, path: str, body: Dict[str, Any]) -> Dict[str, Any]:
93
+ # Drop None values so optional params are omitted.
94
+ clean = {k: v for k, v in body.items() if v is not None}
95
+ return self._request("POST", path, clean)
96
+
97
+ # -- capabilities ------------------------------------------------------
98
+ def parse(
99
+ self,
100
+ *,
101
+ file_url: Optional[str] = None,
102
+ text: Optional[str] = None,
103
+ file: Optional[Dict[str, str]] = None,
104
+ doc_type: Optional[str] = None,
105
+ ) -> Dict[str, Any]:
106
+ """Parse a document (PDF/image/text) into structured, validated JSON."""
107
+ body = _document(file_url, text, file)
108
+ if doc_type:
109
+ body["docType"] = doc_type
110
+ return self._post("/v1/parse", body)
111
+
112
+ def extract(
113
+ self, *, text: str, fields: List[str], instructions: Optional[str] = None
114
+ ) -> Dict[str, Any]:
115
+ """Pull a caller-defined set of fields out of any text."""
116
+ return self._post("/v1/extract", {"text": text, "fields": fields, "instructions": instructions})
117
+
118
+ def classify(
119
+ self,
120
+ *,
121
+ text: str,
122
+ labels: List[str],
123
+ multi: Optional[bool] = None,
124
+ instructions: Optional[str] = None,
125
+ ) -> Dict[str, Any]:
126
+ """Classify text against your own taxonomy."""
127
+ return self._post(
128
+ "/v1/classify",
129
+ {"text": text, "labels": labels, "multi": multi, "instructions": instructions},
130
+ )
131
+
132
+ def summarize(
133
+ self,
134
+ *,
135
+ text: str,
136
+ length: Optional[str] = None,
137
+ action_items: Optional[bool] = None,
138
+ ) -> Dict[str, Any]:
139
+ """Summarize long text into a summary, key points, and action items."""
140
+ return self._post(
141
+ "/v1/summarize", {"text": text, "length": length, "actionItems": action_items}
142
+ )
143
+
144
+ def redact(
145
+ self,
146
+ *,
147
+ text: str,
148
+ types: Optional[List[str]] = None,
149
+ placeholder: Optional[str] = None,
150
+ ) -> Dict[str, Any]:
151
+ """Detect and strip PII/PHI from text."""
152
+ return self._post("/v1/redact", {"text": text, "types": types, "placeholder": placeholder})
153
+
154
+ def sentiment(self, *, text: str, aspects: Optional[List[str]] = None) -> Dict[str, Any]:
155
+ """Sentiment, aspects, and themes from feedback text."""
156
+ return self._post("/v1/sentiment", {"text": text, "aspects": aspects})
157
+
158
+ def contract(
159
+ self,
160
+ *,
161
+ file_url: Optional[str] = None,
162
+ text: Optional[str] = None,
163
+ file: Optional[Dict[str, str]] = None,
164
+ ) -> Dict[str, Any]:
165
+ """Analyze a contract into parties, terms, obligations, and risk flags."""
166
+ return self._post("/v1/contract", _document(file_url, text, file))
167
+
168
+ def chargeback(
169
+ self,
170
+ *,
171
+ reason: str,
172
+ transaction: Dict[str, Any],
173
+ evidence: Optional[List[str]] = None,
174
+ context: Optional[str] = None,
175
+ network: Optional[str] = None,
176
+ ) -> Dict[str, Any]:
177
+ """Turn dispute details into a chargeback representment packet."""
178
+ return self._post(
179
+ "/v1/chargeback",
180
+ {
181
+ "reason": reason,
182
+ "transaction": transaction,
183
+ "evidence": evidence,
184
+ "context": context,
185
+ "network": network,
186
+ },
187
+ )
188
+
189
+ def enrich(
190
+ self, *, domain: Optional[str] = None, email: Optional[str] = None
191
+ ) -> Dict[str, Any]:
192
+ """Enrich a domain or work email into a structured company profile."""
193
+ if not domain and not email:
194
+ raise ValueError("Provide one of: domain or email.")
195
+ return self._post("/v1/enrich", {"domain": domain, "email": email})
196
+
197
+ def account(self) -> Dict[str, Any]:
198
+ """Fetch the authenticated account's credit balance."""
199
+ return self._request("GET", "/v1/account")