kodari 1.0.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.
@@ -0,0 +1,5 @@
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Editor-based HTTP Client requests
5
+ /httpRequests/
@@ -0,0 +1,6 @@
1
+ <component name="InspectionProjectProfileManager">
2
+ <settings>
3
+ <option name="USE_PROJECT_PROFILE" value="false" />
4
+ <version value="1.0" />
5
+ </settings>
6
+ </component>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="PYTHON_MODULE" version="4">
3
+ <component name="NewModuleRootManager">
4
+ <content url="file://$MODULE_DIR$">
5
+ <excludeFolder url="file://$MODULE_DIR$/.venv" />
6
+ </content>
7
+ <orderEntry type="jdk" jdkName="Python 3.13 (kodaripython)" jdkType="Python SDK" />
8
+ <orderEntry type="sourceFolder" forTests="false" />
9
+ </component>
10
+ </module>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="Black">
4
+ <option name="sdkName" value="Python 3.13 (kodaripython)" />
5
+ </component>
6
+ <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (kodaripython)" project-jdk-type="Python SDK" />
7
+ </project>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/kodaripython.iml" filepath="$PROJECT_DIR$/.idea/kodaripython.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
@@ -0,0 +1,46 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="AutoImportSettings">
4
+ <option name="autoReloadType" value="SELECTIVE" />
5
+ </component>
6
+ <component name="ChangeListManager">
7
+ <list default="true" id="ef19ca08-3230-4d7f-9a7b-462908395666" name="Changes" comment="" />
8
+ <option name="SHOW_DIALOG" value="false" />
9
+ <option name="HIGHLIGHT_CONFLICTS" value="true" />
10
+ <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
11
+ <option name="LAST_RESOLUTION" value="IGNORE" />
12
+ </component>
13
+ <component name="ProjectColorInfo"><![CDATA[{
14
+ "associatedIndex": 5
15
+ }]]></component>
16
+ <component name="ProjectId" id="3BcQjIqEAu0J4IWeTPoXMrGq6xw" />
17
+ <component name="ProjectViewState">
18
+ <option name="hideEmptyMiddlePackages" value="true" />
19
+ <option name="showLibraryContents" value="true" />
20
+ </component>
21
+ <component name="PropertiesComponent"><![CDATA[{
22
+ "keyToString": {
23
+ "ModuleVcsDetector.initialDetectionPerformed": "true",
24
+ "RunOnceActivity.ShowReadmeOnStart": "true",
25
+ "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
26
+ "ignore.virus.scanning.warn.message": "true"
27
+ }
28
+ }]]></component>
29
+ <component name="SharedIndexes">
30
+ <attachedChunks>
31
+ <set>
32
+ <option value="bundled-python-sdk-164cda30dcd9-0af03a5fa574-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-252.26830.99" />
33
+ </set>
34
+ </attachedChunks>
35
+ </component>
36
+ <component name="TaskManager">
37
+ <task active="true" id="Default" summary="Default task">
38
+ <changelist id="ef19ca08-3230-4d7f-9a7b-462908395666" name="Changes" comment="" />
39
+ <created>1774786011668</created>
40
+ <option name="number" value="Default" />
41
+ <option name="presentableId" value="Default" />
42
+ <updated>1774786011668</updated>
43
+ </task>
44
+ <servers />
45
+ </component>
46
+ </project>
kodari-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.4
2
+ Name: kodari
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for the Kodari API
5
+ Project-URL: Homepage, https://kodari.ai
6
+ Project-URL: Repository, https://github.com/kodari-ai/kodaripython
7
+ Author-email: Kodari <support@kodari.ai>
8
+ License-Expression: MIT
9
+ Keywords: ai,api,kodari,moderation
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Requires-Python: >=3.10
14
+ Requires-Dist: httpx>=0.28.0
15
+ Description-Content-Type: text/markdown
16
+
17
+ # kodaripython
18
+
19
+ Official Python SDK for the [Kodari API](https://kodari.ai). Fully async, built on httpx.
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install kodari
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ Get your API key at [kodari.ai/api-keys](https://kodari.ai/api-keys).
30
+
31
+ ```python
32
+ import asyncio
33
+ from kodari import KodariClient, KodariCredentials
34
+
35
+ async def main():
36
+ async with KodariClient(KodariCredentials("kod-your-api-key")) as client:
37
+ result = await client.moderate("hello everyone")
38
+
39
+ if not result.safe:
40
+ print(f"Flagged: {result.category}") # toxicity, threat, doxxing, advertising, spam
41
+ print(f"Severity: {result.severity}") # low, medium, high
42
+
43
+ asyncio.run(main())
44
+ ```
45
+
46
+ ## Moderation
47
+
48
+ Multilingual chat moderation AI that classifies messages for toxicity, threats, doxxing, spam, and advertising.
49
+
50
+ ```python
51
+ result = await client.moderate("some message")
52
+
53
+ result.safe # True/False
54
+ result.category # none, toxicity, threat, doxxing, advertising, spam
55
+ result.severity # none, low, medium, high
56
+
57
+ # Convenience checks
58
+ result.is_toxic
59
+ result.is_threat
60
+ result.is_doxxing
61
+ result.is_advertising
62
+ result.is_spam
63
+ ```
64
+
65
+ ## Batch Moderation
66
+
67
+ Send 5+ messages for a 50% discount on token cost.
68
+
69
+ ```python
70
+ results = await client.moderate_batch([
71
+ "hello everyone",
72
+ "you're terrible at this game",
73
+ "check out my store at scam.com",
74
+ ])
75
+
76
+ for r in results:
77
+ print(f"safe={r.safe} category={r.category}")
78
+ ```
79
+
80
+ ## Generic Model Execution
81
+
82
+ Call any model by name, even ones added after your SDK version:
83
+
84
+ ```python
85
+ response = await client.execute("moderation", "your input")
86
+
87
+ response.kodari_model # "moderation"
88
+ response.tokens_cost # 10
89
+ response.result # raw dict
90
+ ```
91
+
92
+ ## Session Flow (Code Generation)
93
+
94
+ ```python
95
+ session = await client.create_session("My Plugin", "minecraft", "plugin", "claude-sonnet-4-5")
96
+ gen = await client.generate(session.id, "Make a plugin that does X")
97
+ compiled = await client.compile(session.id)
98
+ jar_bytes = await client.download_jar(compiled.jar_id)
99
+
100
+ with open("plugin.jar", "wb") as f:
101
+ f.write(jar_bytes)
102
+ ```
103
+
104
+ ## Other Endpoints
105
+
106
+ ```python
107
+ # Get current user
108
+ user = await client.get_me()
109
+ print(user.name, user.email)
110
+ ```
111
+
112
+ ## Error Handling
113
+
114
+ All exceptions extend `KodariException`:
115
+
116
+ ```python
117
+ from kodari import (
118
+ KodariAuthenticationException,
119
+ KodariRateLimitException,
120
+ KodariInsufficientTokensException,
121
+ )
122
+
123
+ try:
124
+ result = await client.moderate("message")
125
+ except KodariAuthenticationException:
126
+ print("Invalid API key")
127
+ except KodariRateLimitException:
128
+ print("Rate limited, slow down")
129
+ except KodariInsufficientTokensException:
130
+ print("Not enough tokens")
131
+ ```
132
+
133
+ ## Custom Configuration
134
+
135
+ ```python
136
+ client = KodariClient(
137
+ KodariCredentials("kod-your-api-key"),
138
+ base_url="http://localhost:8080",
139
+ user_agent="my-app/2.0",
140
+ )
141
+ ```
142
+
143
+ ## Requirements
144
+
145
+ Python 3.10+
kodari-1.0.0/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # kodaripython
2
+
3
+ Official Python SDK for the [Kodari API](https://kodari.ai). Fully async, built on httpx.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install kodari
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ Get your API key at [kodari.ai/api-keys](https://kodari.ai/api-keys).
14
+
15
+ ```python
16
+ import asyncio
17
+ from kodari import KodariClient, KodariCredentials
18
+
19
+ async def main():
20
+ async with KodariClient(KodariCredentials("kod-your-api-key")) as client:
21
+ result = await client.moderate("hello everyone")
22
+
23
+ if not result.safe:
24
+ print(f"Flagged: {result.category}") # toxicity, threat, doxxing, advertising, spam
25
+ print(f"Severity: {result.severity}") # low, medium, high
26
+
27
+ asyncio.run(main())
28
+ ```
29
+
30
+ ## Moderation
31
+
32
+ Multilingual chat moderation AI that classifies messages for toxicity, threats, doxxing, spam, and advertising.
33
+
34
+ ```python
35
+ result = await client.moderate("some message")
36
+
37
+ result.safe # True/False
38
+ result.category # none, toxicity, threat, doxxing, advertising, spam
39
+ result.severity # none, low, medium, high
40
+
41
+ # Convenience checks
42
+ result.is_toxic
43
+ result.is_threat
44
+ result.is_doxxing
45
+ result.is_advertising
46
+ result.is_spam
47
+ ```
48
+
49
+ ## Batch Moderation
50
+
51
+ Send 5+ messages for a 50% discount on token cost.
52
+
53
+ ```python
54
+ results = await client.moderate_batch([
55
+ "hello everyone",
56
+ "you're terrible at this game",
57
+ "check out my store at scam.com",
58
+ ])
59
+
60
+ for r in results:
61
+ print(f"safe={r.safe} category={r.category}")
62
+ ```
63
+
64
+ ## Generic Model Execution
65
+
66
+ Call any model by name, even ones added after your SDK version:
67
+
68
+ ```python
69
+ response = await client.execute("moderation", "your input")
70
+
71
+ response.kodari_model # "moderation"
72
+ response.tokens_cost # 10
73
+ response.result # raw dict
74
+ ```
75
+
76
+ ## Session Flow (Code Generation)
77
+
78
+ ```python
79
+ session = await client.create_session("My Plugin", "minecraft", "plugin", "claude-sonnet-4-5")
80
+ gen = await client.generate(session.id, "Make a plugin that does X")
81
+ compiled = await client.compile(session.id)
82
+ jar_bytes = await client.download_jar(compiled.jar_id)
83
+
84
+ with open("plugin.jar", "wb") as f:
85
+ f.write(jar_bytes)
86
+ ```
87
+
88
+ ## Other Endpoints
89
+
90
+ ```python
91
+ # Get current user
92
+ user = await client.get_me()
93
+ print(user.name, user.email)
94
+ ```
95
+
96
+ ## Error Handling
97
+
98
+ All exceptions extend `KodariException`:
99
+
100
+ ```python
101
+ from kodari import (
102
+ KodariAuthenticationException,
103
+ KodariRateLimitException,
104
+ KodariInsufficientTokensException,
105
+ )
106
+
107
+ try:
108
+ result = await client.moderate("message")
109
+ except KodariAuthenticationException:
110
+ print("Invalid API key")
111
+ except KodariRateLimitException:
112
+ print("Rate limited, slow down")
113
+ except KodariInsufficientTokensException:
114
+ print("Not enough tokens")
115
+ ```
116
+
117
+ ## Custom Configuration
118
+
119
+ ```python
120
+ client = KodariClient(
121
+ KodariCredentials("kod-your-api-key"),
122
+ base_url="http://localhost:8080",
123
+ user_agent="my-app/2.0",
124
+ )
125
+ ```
126
+
127
+ ## Requirements
128
+
129
+ Python 3.10+
@@ -0,0 +1,17 @@
1
+ from kodari.client import KodariClient
2
+ from kodari.credentials import KodariCredentials
3
+ from kodari.exceptions import (
4
+ KodariException,
5
+ KodariAuthenticationException,
6
+ KodariRateLimitException,
7
+ KodariInsufficientTokensException,
8
+ )
9
+
10
+ __all__ = [
11
+ "KodariClient",
12
+ "KodariCredentials",
13
+ "KodariException",
14
+ "KodariAuthenticationException",
15
+ "KodariRateLimitException",
16
+ "KodariInsufficientTokensException",
17
+ ]
@@ -0,0 +1,194 @@
1
+ from typing import List, Optional
2
+
3
+ import httpx
4
+
5
+ from kodari.credentials import KodariCredentials
6
+ from kodari.exceptions import (
7
+ KodariAuthenticationException,
8
+ KodariException,
9
+ KodariInsufficientTokensException,
10
+ KodariRateLimitException,
11
+ )
12
+ from kodari.models.responses import (
13
+ CompileResponse,
14
+ GenerateResponse,
15
+ ModelResponse,
16
+ ModerationResult,
17
+ SessionResponse,
18
+ UserResponse,
19
+ )
20
+
21
+ _DEFAULT_BASE_URL = "https://api.kodari.ai"
22
+ _API_PREFIX = "/api/v1"
23
+ _DEFAULT_USER_AGENT = "kodari-python/1.0.0"
24
+ _MODERATION = "moderation"
25
+
26
+
27
+ class KodariClient:
28
+
29
+ def __init__(
30
+ self,
31
+ credentials: KodariCredentials,
32
+ base_url: str = _DEFAULT_BASE_URL,
33
+ user_agent: str = _DEFAULT_USER_AGENT,
34
+ ):
35
+ self._credentials = credentials
36
+ self._base_url = base_url
37
+ self._client = httpx.AsyncClient(
38
+ headers={
39
+ "X-API-Key": credentials.api_key,
40
+ "User-Agent": user_agent,
41
+ },
42
+ timeout=60.0, # cf
43
+ )
44
+
45
+ async def close(self):
46
+ await self._client.aclose()
47
+
48
+ async def __aenter__(self):
49
+ return self
50
+
51
+ async def __aexit__(self, *args):
52
+ await self.close()
53
+
54
+ # Normal endpoints
55
+
56
+ async def get_me(self) -> UserResponse:
57
+ data = await self._get("/users/me")
58
+ return UserResponse(
59
+ id=data["id"],
60
+ provider_id=data.get("providerId", ""),
61
+ email=data.get("email", ""),
62
+ name=data.get("name", ""),
63
+ image_url=data.get("imageUrl", ""),
64
+ role=data.get("role", ""),
65
+ discord_id=data.get("discordId", ""),
66
+ bio=data.get("bio", ""),
67
+ created_at=data.get("createdAt", ""),
68
+ banned=data.get("banned", False),
69
+ banned_reason=data.get("bannedReason", ""),
70
+ settings=data.get("settings", {}),
71
+ new_account=data.get("newAccount", False),
72
+ )
73
+
74
+ async def create_session(
75
+ self,
76
+ name: str,
77
+ game_type: str,
78
+ category: str,
79
+ ai_model: str,
80
+ ) -> SessionResponse:
81
+ data = await self._post("/sessions", {
82
+ "name": name,
83
+ "gameType": game_type,
84
+ "category": category,
85
+ "aiModel": ai_model,
86
+ })
87
+ return SessionResponse(
88
+ id=data["id"],
89
+ name=data["name"],
90
+ game_type=data.get("gameType", ""),
91
+ category=data.get("category", ""),
92
+ status=data.get("status", ""),
93
+ )
94
+
95
+ async def generate(
96
+ self,
97
+ session_id: str,
98
+ message: str,
99
+ has_dependencies: bool = False,
100
+ ) -> GenerateResponse:
101
+ data = await self._post(f"/sessions/{session_id}/generate", {
102
+ "message": message,
103
+ "hasDependencies": has_dependencies,
104
+ })
105
+ return GenerateResponse(
106
+ session_id=data["sessionId"],
107
+ success=data["success"],
108
+ message=data["message"],
109
+ )
110
+
111
+ async def compile(self, session_id: str) -> CompileResponse:
112
+ data = await self._post(f"/sessions/{session_id}/compile", {})
113
+ return CompileResponse(
114
+ session_id=data["sessionId"],
115
+ success=data["success"],
116
+ jar_id=data.get("jarId"),
117
+ plugin_name=data.get("pluginName"),
118
+ jar_size=data.get("jarSize"),
119
+ error=data.get("error"),
120
+ )
121
+
122
+ async def download_jar(self, jar_id: int) -> bytes:
123
+ url = f"{self._base_url}{_API_PREFIX}/download/jar/{jar_id}"
124
+ response = await self._client.post(
125
+ url,
126
+ json={},
127
+ headers={"Content-Type": "application/json"},
128
+ )
129
+ self._check_status(response.status_code, response.text)
130
+ return response.content
131
+
132
+ # Kodari Specialized Models
133
+
134
+ async def moderate(self, message: str) -> ModerationResult:
135
+ response = await self.execute(_MODERATION, message)
136
+ result = response.result
137
+ return ModerationResult(
138
+ safe=result["safe"],
139
+ category=result["category"],
140
+ severity=result["severity"],
141
+ )
142
+
143
+ async def moderate_batch(self, messages: List[str]) -> List[ModerationResult]:
144
+ response = await self.execute_batch(_MODERATION, messages)
145
+ return [
146
+ ModerationResult(
147
+ safe=r["safe"],
148
+ category=r["category"],
149
+ severity=r["severity"],
150
+ index=r.get("index", -1),
151
+ )
152
+ for r in response.result
153
+ ]
154
+
155
+ async def execute(self, model: str, input: str) -> ModelResponse:
156
+ data = await self._post(f"/models/{model}", {"input": input})
157
+ return ModelResponse(
158
+ kodari_model=data["kodariModel"],
159
+ tokens_cost=data["tokensCost"],
160
+ result=data["result"],
161
+ )
162
+
163
+ async def execute_batch(self, model: str, inputs: List[str]) -> ModelResponse:
164
+ data = await self._post(f"/models/{model}/batch", {"inputs": inputs})
165
+ return ModelResponse(
166
+ kodari_model=data["kodariModel"],
167
+ tokens_cost=data["tokensCost"],
168
+ result=data["result"],
169
+ )
170
+
171
+ # Generic API access
172
+
173
+ async def _get(self, path: str) -> dict:
174
+ url = f"{self._base_url}{_API_PREFIX}{path}"
175
+ response = await self._client.get(url)
176
+ self._check_status(response.status_code, response.text)
177
+ return response.json()
178
+
179
+ async def _post(self, path: str, body: dict) -> dict:
180
+ url = f"{self._base_url}{_API_PREFIX}{path}"
181
+ response = await self._client.post(url, json=body)
182
+ self._check_status(response.status_code, response.text)
183
+ return response.json()
184
+
185
+ @staticmethod
186
+ def _check_status(status: int, body: str):
187
+ if status == 401:
188
+ raise KodariAuthenticationException("Invalid or expired API key")
189
+ if status == 429:
190
+ raise KodariRateLimitException("Rate limit exceeded")
191
+ if status == 402:
192
+ raise KodariInsufficientTokensException("Insufficient tokens")
193
+ if status != 200:
194
+ raise KodariException(f"API error (HTTP {status}): {body}")
@@ -0,0 +1,14 @@
1
+ class KodariCredentials:
2
+
3
+ def __init__(self, api_key: str):
4
+ if not api_key:
5
+ raise ValueError("api_key must not be None or empty")
6
+
7
+ if not api_key.startswith("kod-"):
8
+ raise ValueError("Invalid API key format. Keys must start with 'kod-'")
9
+
10
+ self._api_key = api_key
11
+
12
+ @property
13
+ def api_key(self) -> str:
14
+ return self._api_key
@@ -0,0 +1,14 @@
1
+ class KodariException(Exception):
2
+ pass
3
+
4
+
5
+ class KodariAuthenticationException(KodariException):
6
+ pass
7
+
8
+
9
+ class KodariRateLimitException(KodariException):
10
+ pass
11
+
12
+
13
+ class KodariInsufficientTokensException(KodariException):
14
+ pass
@@ -0,0 +1,17 @@
1
+ from kodari.models.responses import (
2
+ UserResponse,
3
+ SessionResponse,
4
+ GenerateResponse,
5
+ CompileResponse,
6
+ ModelResponse,
7
+ ModerationResult,
8
+ )
9
+
10
+ __all__ = [
11
+ "UserResponse",
12
+ "SessionResponse",
13
+ "GenerateResponse",
14
+ "CompileResponse",
15
+ "ModelResponse",
16
+ "ModerationResult",
17
+ ]
@@ -0,0 +1,80 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, Optional
3
+
4
+
5
+ @dataclass
6
+ class UserResponse:
7
+ id: str
8
+ provider_id: str
9
+ email: str
10
+ name: str
11
+ image_url: str
12
+ role: str
13
+ discord_id: str
14
+ bio: str
15
+ created_at: str
16
+ banned: bool
17
+ banned_reason: str
18
+ settings: dict
19
+ new_account: bool
20
+
21
+
22
+ @dataclass
23
+ class SessionResponse:
24
+ id: str
25
+ name: str
26
+ game_type: str
27
+ category: str
28
+ status: str
29
+
30
+
31
+ @dataclass
32
+ class GenerateResponse:
33
+ session_id: str
34
+ success: bool
35
+ message: str
36
+
37
+
38
+ @dataclass
39
+ class CompileResponse:
40
+ session_id: str
41
+ success: bool
42
+ jar_id: Optional[int] = None
43
+ plugin_name: Optional[str] = None
44
+ jar_size: Optional[int] = None
45
+ error: Optional[str] = None
46
+
47
+
48
+ @dataclass
49
+ class ModelResponse:
50
+ kodari_model: str
51
+ tokens_cost: int
52
+ result: Any
53
+
54
+
55
+ @dataclass
56
+ class ModerationResult:
57
+ safe: bool
58
+ category: str
59
+ severity: str
60
+ index: int = -1
61
+
62
+ @property
63
+ def is_toxic(self) -> bool:
64
+ return self.category == "toxicity"
65
+
66
+ @property
67
+ def is_threat(self) -> bool:
68
+ return self.category == "threat"
69
+
70
+ @property
71
+ def is_doxxing(self) -> bool:
72
+ return self.category == "doxxing"
73
+
74
+ @property
75
+ def is_advertising(self) -> bool:
76
+ return self.category == "advertising"
77
+
78
+ @property
79
+ def is_spam(self) -> bool:
80
+ return self.category == "spam"
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "kodari"
7
+ version = "1.0.0"
8
+ description = "Official Python SDK for the Kodari API"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ { name = "Kodari", email = "support@kodari.ai" }
14
+ ]
15
+ keywords = ["kodari", "ai", "moderation", "api"]
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: OS Independent",
20
+ ]
21
+ dependencies = [
22
+ "httpx>=0.28.0",
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://kodari.ai"
27
+ Repository = "https://github.com/kodari-ai/kodaripython"