smart-artificial-intelligence-local 0.0b7__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.
Files changed (16) hide show
  1. smart_artificial_intelligence_local-0.0b7/PKG-INFO +22 -0
  2. smart_artificial_intelligence_local-0.0b7/README.md +25 -0
  3. smart_artificial_intelligence_local-0.0b7/pyproject.toml +29 -0
  4. smart_artificial_intelligence_local-0.0b7/setup.cfg +4 -0
  5. smart_artificial_intelligence_local-0.0b7/setup.py +30 -0
  6. smart_artificial_intelligence_local-0.0b7/smart_artificial_intelligence_local/__init__.py +0 -0
  7. smart_artificial_intelligence_local-0.0b7/smart_artificial_intelligence_local/src/__init__.py +3 -0
  8. smart_artificial_intelligence_local-0.0b7/smart_artificial_intelligence_local/src/constants.py +28 -0
  9. smart_artificial_intelligence_local-0.0b7/smart_artificial_intelligence_local/src/smart_artificial_intelligence_local.py +167 -0
  10. smart_artificial_intelligence_local-0.0b7/smart_artificial_intelligence_local/tests/__init__.py +0 -0
  11. smart_artificial_intelligence_local-0.0b7/smart_artificial_intelligence_local/tests/smart_artificial_intelligence_local_test.py +128 -0
  12. smart_artificial_intelligence_local-0.0b7/smart_artificial_intelligence_local.egg-info/PKG-INFO +22 -0
  13. smart_artificial_intelligence_local-0.0b7/smart_artificial_intelligence_local.egg-info/SOURCES.txt +14 -0
  14. smart_artificial_intelligence_local-0.0b7/smart_artificial_intelligence_local.egg-info/dependency_links.txt +1 -0
  15. smart_artificial_intelligence_local-0.0b7/smart_artificial_intelligence_local.egg-info/requires.txt +2 -0
  16. smart_artificial_intelligence_local-0.0b7/smart_artificial_intelligence_local.egg-info/top_level.txt +1 -0
@@ -0,0 +1,22 @@
1
+ Metadata-Version: 2.4
2
+ Name: smart-artificial-intelligence-local
3
+ Version: 0.0b7
4
+ Summary: PyPI smart-artificial-intelligence-local Python Package owned by Circlez.ai
5
+ Home-page: https://github.com/circles-zone/smart-artificial-intelligence-local-python-package
6
+ Author: Circles
7
+ Author-email: info@circlez.ai
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: python-sdk-remote
12
+ Requires-Dist: logger-local
13
+ Dynamic: author
14
+ Dynamic: author-email
15
+ Dynamic: classifier
16
+ Dynamic: description
17
+ Dynamic: description-content-type
18
+ Dynamic: home-page
19
+ Dynamic: requires-dist
20
+ Dynamic: summary
21
+
22
+ PyPI smart-artificial-intelligence-local Python Package owned by Circlez.ai
@@ -0,0 +1,25 @@
1
+ # General
2
+
3
+ Unlike the README.md in the root directory, this is a README.md of this specific repo/package<br>
4
+
5
+ TODO Please update this README.md of this specific repo/package and not the README.md in the root directory based on the python-package-template repo<br>
6
+
7
+ ## TODOs
8
+
9
+ TODO Like smart-datastore package smark-ai should allow to run prompt with multiple LLMs using ai repo instances.<br>
10
+ TODO use API-management to perform API-type, so if an API failed we try other APIs from the same API type.
11
+ TODO use cost allocation tags or equivant to measure the costs.
12
+
13
+ ## Versions
14
+
15
+ [pub] 0.0.1 Initial version (change the directories, files, setup.py, .github/workflows/*.yml)<br>
16
+
17
+ ## Installing instructions
18
+
19
+ It's advised to use venv<br>
20
+ If you have Windows, it's also advised to use Windows Subsystem for Linux<br>
21
+
22
+ ## Install dependencies
23
+
24
+ Run ./download-beta-sdk.sh from the bash terminal<br>
25
+ Run pip install -r requirements.txt from the bash terminal<br>
@@ -0,0 +1,29 @@
1
+ # This file should be in the future instead of setup.py
2
+ # https://python-poetry.org/docs/pyproject
3
+ # https://stackoverflow.com/questions/78048223/adding-folder-with-data-with-pyproject-toml
4
+ # https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license
5
+
6
+ # This file is mandatory for the `poetry version patch`
7
+
8
+ # It seems we need to copy this file also to serverless-com repo, as required by dialog-workflow-python-package
9
+
10
+ [build-system]
11
+ requires = ["setuptools>=61.0"]
12
+ build-backend = "setuptools.build_meta"
13
+
14
+ [tool.pytest.ini_options]
15
+ pythonpath = ["."]
16
+
17
+ [tool.poetry]
18
+ name = "smart-artificial-intelligence-local"
19
+ # I believe we are still using the version from setup.py and not from here until Potery will work
20
+ version = "0.0.3" # https://pypi.org/project/smart-artificial-intelligence-local/
21
+ description = "smart-artificial-intelligence-local Python Package"
22
+ readme = "README.md"
23
+ authors = [
24
+ "Circlez.ai <info@circlez.ai>",
25
+ ]
26
+
27
+ [tool.poetry.dev-dependencies]
28
+ pytest = "^8.0"
29
+ pytest-cov = "^5.0"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,30 @@
1
+ import setuptools
2
+
3
+ PACKAGE_NAME = "smart-artificial-intelligence-local"
4
+
5
+ package_dir = PACKAGE_NAME.replace("-", "_")
6
+
7
+ PACKAGE_DESCRIPTION = f"PyPI {PACKAGE_NAME} Python Package owned by Circlez.ai"
8
+
9
+ setuptools.setup(
10
+ name=PACKAGE_NAME,
11
+ version="0.0b7", # https://pypi.org/project/smart-artificial-intelligence-local/
12
+ author="Circles",
13
+ author_email="info@circlez.ai",
14
+ description=PACKAGE_DESCRIPTION,
15
+ long_description=PACKAGE_DESCRIPTION,
16
+ long_description_content_type='text/markdown',
17
+ url=f"https://github.com/circles-zone/{PACKAGE_NAME}-python-package",
18
+ packages=setuptools.find_packages(),
19
+ package_data={package_dir: ['*.py']},
20
+ classifiers=[
21
+ "Programming Language :: Python :: 3",
22
+ "Operating System :: OS Independent",
23
+ ],
24
+ # The Smart-LLM reconciler is transport-agnostic: models/judge/reaction-sink are injected
25
+ # callables, so strands/ollama are NOT runtime deps (the orchestrator supplies real models).
26
+ install_requires=[
27
+ 'python-sdk-remote',
28
+ 'logger-local',
29
+ ]
30
+ )
@@ -0,0 +1,3 @@
1
+ from .smart_artificial_intelligence_local import SmartArtificialIntelligenceLocal
2
+
3
+ __all__ = ["SmartArtificialIntelligenceLocal"]
@@ -0,0 +1,28 @@
1
+ from typing import Any
2
+
3
+ from logger_local.LoggerComponentEnum import LoggerComponentEnum
4
+
5
+
6
+ class ConstantsSrcSmartArtificialIntelligenceLocal:
7
+ """This is a class of all the constants of SmartArtificialIntelligenceLocal"""
8
+
9
+ DEVELOPER_EMAIL_ADDRESS: str = 'tal.r@circ.zone'
10
+
11
+ SMART_ARTIFICIAL_INTELLIGENCE_LOCAL_PYTHON_CODE_COMPONENT_ID: int = 10105
12
+
13
+ SMART_ARTIFICIAL_INTELLIGENCE_LOCAL_PYTHON_COMPONENT_NAME = 'Smart Artificial Intelligence local Python package'
14
+ # TODO SMART_ARTIFICIAL_INTELLIGENCE_LOCAL_PYTHON_CODE_LOGGER_INIT-OBJECT
15
+ SMART_ARTIFICIAL_INTELLIGENCE_LOCAL_PYTHON_CODE_LOGGER_OBJECT: dict[str, Any] = {
16
+ 'component_id': SMART_ARTIFICIAL_INTELLIGENCE_LOCAL_PYTHON_CODE_COMPONENT_ID,
17
+ 'component_name': SMART_ARTIFICIAL_INTELLIGENCE_LOCAL_PYTHON_COMPONENT_NAME,
18
+ 'component_category': LoggerComponentEnum.ComponentCategory.Code.value,
19
+ 'developer_email_address': DEVELOPER_EMAIL_ADDRESS
20
+ }
21
+
22
+ # Smart-LLM orchestration modes (page-2 design).
23
+ MODE_JUDGE: str = 'judge' # Mode 1: run N models, an LLM-as-judge picks the best answer
24
+ MODE_REACTION: str = 'reaction' # Mode 2: run N models, keep all answers + log to reaction store
25
+ MODE_CASCADE: str = 'cascade' # Efficient: cheapest model first; escalate only when unsure
26
+
27
+ # Cascade: escalate to the next model only if the current one's confidence is below this.
28
+ DEFAULT_ESCALATE_CONFIDENCE: float = 0.75
@@ -0,0 +1,167 @@
1
+ """Smart-LLM: run a prompt across several models and reconcile -- efficiently.
2
+
3
+ Three modes (page-2 "Analyzer LLM Serving" design):
4
+
5
+ * Mode CASCADE (efficient default): call the CHEAPEST model first; if it is confident, stop -- one
6
+ call. Only when it is unsure do we escalate to the next (different, stronger)
7
+ model; and only when the two DISAGREE do we invoke the judge. Easy lines cost
8
+ one call; the panel + judge fire just for the hard ones.
9
+ * Mode JUDGE: query every model, then an LLM-as-judge picks the best answer set (majority-vote
10
+ fallback when no judge is supplied).
11
+ * Mode REACTION: query every model, keep every answer, log each to a reaction store (injected sink)
12
+ with a flag for the selected one -- signal to improve later.
13
+
14
+ Everything is injected -- a "model" is any ``callable(prompt) -> answer`` where ``answer`` is either a
15
+ ``list[str]`` (names) or a ``(list[str], confidence_float)`` tuple (cascade needs the confidence). The
16
+ judge is ``callable(prompt, [(model_name, answer)]) -> list[str]`` and the reaction sink is
17
+ ``callable(model_name, prompt, answer, is_selected)``. So this package has no hard dependency on a
18
+ running model / a database: the orchestrator wires real ones, tests wire fakes.
19
+
20
+ After each ``smart_identify`` the ``last_trace`` attribute holds a decision trace (calls made, whether
21
+ it escalated / agreed / used the judge) so the caller can meter cost.
22
+ """
23
+ from __future__ import annotations
24
+
25
+ import math
26
+ from typing import Callable, List, Optional, Sequence, Tuple
27
+
28
+ from logger_local.MetaLogger import MetaLogger
29
+
30
+ from .constants import ConstantsSrcSmartArtificialIntelligenceLocal as Consts
31
+
32
+ Model = Callable[[str], Sequence]
33
+ Judge = Callable[[str, List[Tuple[str, List[str]]]], Sequence[str]]
34
+ ReactionSink = Callable[[str, str, List[str], bool], None]
35
+
36
+
37
+ def _normalize(answer) -> Tuple[List[str], float]:
38
+ """Coerce a model's return into (names, confidence). A bare list -> confidence 1.0."""
39
+ if (isinstance(answer, tuple) and len(answer) == 2
40
+ and isinstance(answer[1], (int, float)) and not isinstance(answer[1], bool)
41
+ and isinstance(answer[0], (list, tuple))):
42
+ return [str(name) for name in answer[0]], float(answer[1])
43
+ return [str(name) for name in answer], 1.0
44
+
45
+
46
+ class SmartArtificialIntelligenceLocal( # type: ignore[call-arg] # MetaLogger takes object=
47
+ metaclass=MetaLogger,
48
+ object=Consts.SMART_ARTIFICIAL_INTELLIGENCE_LOCAL_PYTHON_CODE_LOGGER_OBJECT):
49
+ """Reconcile several models' answers for one prompt (cascade / judge / reaction)."""
50
+
51
+ def __init__(self, models: Optional[Sequence[Model]] = None, judge: Optional[Judge] = None,
52
+ reaction_sink: Optional[ReactionSink] = None,
53
+ escalate_confidence: float = Consts.DEFAULT_ESCALATE_CONFIDENCE,
54
+ is_test_data: bool = False) -> None:
55
+ self._models = list(models or [])
56
+ self._judge = judge
57
+ self._reaction_sink = reaction_sink
58
+ self.escalate_confidence = escalate_confidence
59
+ self.is_test_data = is_test_data
60
+ self.last_trace: dict = {}
61
+
62
+ def smart_identify(self, prompt: str, *, mode: str = Consts.MODE_JUDGE) -> List[str]:
63
+ """Return the reconciled answer (list of names) for `prompt` across the models."""
64
+ if not self._models:
65
+ self.last_trace = {"calls": 0}
66
+ return []
67
+ if mode == Consts.MODE_CASCADE:
68
+ return self._cascade(prompt)
69
+ return self._panel(prompt, mode)
70
+
71
+ # ---------------------------------------------------------------- cascade (efficient) --
72
+ def _cascade(self, prompt: str) -> List[str]:
73
+ names0, confidence0, name0, ok0 = self._invoke(0, prompt)
74
+ trace: dict = {"calls": 1 if ok0 else 0, "escalated": False, "agreed": None,
75
+ "judged": False, "answered_by": name0}
76
+
77
+ # Tier-1 confident enough (or no second tier) -> stop at one call.
78
+ if ok0 and (confidence0 >= self.escalate_confidence or len(self._models) < 2):
79
+ self.last_trace = trace
80
+ return names0
81
+
82
+ if len(self._models) < 2:
83
+ self.last_trace = trace
84
+ return names0 if ok0 else []
85
+
86
+ # Escalate to a different, stronger model.
87
+ names1, _confidence1, name1, ok1 = self._invoke(1, prompt)
88
+ trace["escalated"] = True
89
+ trace["calls"] += 1 if ok1 else 0
90
+ if not ok1:
91
+ self.last_trace = trace
92
+ return names0 if ok0 else []
93
+ if not ok0:
94
+ self.last_trace = trace
95
+ return names1
96
+
97
+ # Agree -> done (judge skipped). Disagree -> judge / reaction resolves it.
98
+ if set(names0) == set(names1):
99
+ trace["agreed"] = True
100
+ self.last_trace = trace
101
+ return names1
102
+
103
+ trace["agreed"] = False
104
+ answers = [(name0, names0), (name1, names1)]
105
+ if self._judge is not None:
106
+ selected = list(self._judge(prompt, answers))
107
+ trace["judged"] = True
108
+ trace["calls"] += 1
109
+ else:
110
+ selected = self._majority_vote(answers)
111
+ if self._reaction_sink is not None:
112
+ for model_name, answer in answers:
113
+ self._reaction_sink(model_name, prompt, answer, set(answer) == set(selected))
114
+ self.last_trace = trace
115
+ return selected
116
+
117
+ # ------------------------------------------------------------- panel (judge / reaction) --
118
+ def _panel(self, prompt: str, mode: str) -> List[str]:
119
+ answers: List[Tuple[str, List[str]]] = []
120
+ for index in range(len(self._models)):
121
+ names, _confidence, model_name, ok = self._invoke(index, prompt)
122
+ if ok:
123
+ answers.append((model_name, names))
124
+ if not answers:
125
+ self.last_trace = {"calls": 0}
126
+ return []
127
+
128
+ if mode == Consts.MODE_JUDGE and self._judge is not None:
129
+ selected = list(self._judge(prompt, answers))
130
+ judged = True
131
+ else:
132
+ selected = self._majority_vote(answers)
133
+ judged = False
134
+
135
+ if mode == Consts.MODE_REACTION and self._reaction_sink is not None:
136
+ for model_name, answer in answers:
137
+ self._reaction_sink(model_name, prompt, answer, set(answer) == set(selected))
138
+
139
+ self.last_trace = {"calls": len(answers) + (1 if judged else 0),
140
+ "escalated": True, "judged": judged}
141
+ return selected
142
+
143
+ # --------------------------------------------------------------------------- helpers --
144
+ def _invoke(self, index: int, prompt: str) -> Tuple[List[str], float, str, bool]:
145
+ """Call model `index`; return (names, confidence, name, ok). ok=False if it raised."""
146
+ model = self._models[index]
147
+ model_name = getattr(model, "name", f"model_{index}")
148
+ try:
149
+ names, confidence = _normalize(model(prompt))
150
+ return names, confidence, model_name, True
151
+ except Exception as exception: # noqa: BLE001 -- one bad model must not sink the call
152
+ self.logger.warning(f"model '{model_name}' failed: {exception}") # type: ignore[attr-defined]
153
+ return [], 0.0, model_name, False
154
+
155
+ @staticmethod
156
+ def _majority_vote(answers: List[Tuple[str, List[str]]]) -> List[str]:
157
+ """Keep every item that at least half of the models returned (union fallback for ties)."""
158
+ threshold = math.ceil(len(answers) / 2)
159
+ counts: dict = {}
160
+ order: List[str] = []
161
+ for _model_name, answer in answers:
162
+ for item in dict.fromkeys(answer): # de-dup within a model
163
+ if item not in counts:
164
+ order.append(item)
165
+ counts[item] = counts.get(item, 0) + 1
166
+ voted = [item for item in order if counts[item] >= threshold]
167
+ return voted or order # if nothing reaches the threshold, return the union
@@ -0,0 +1,128 @@
1
+ """Tests for the Smart-LLM multi-model reconciler (judge + reaction), no models/DB required."""
2
+ from smart_artificial_intelligence_local.src.constants import (
3
+ ConstantsSrcSmartArtificialIntelligenceLocal as Consts,
4
+ )
5
+ from smart_artificial_intelligence_local.src.smart_artificial_intelligence_local import (
6
+ SmartArtificialIntelligenceLocal,
7
+ )
8
+
9
+
10
+ def _model(name, answer):
11
+ fn = lambda prompt: list(answer) # noqa: E731 -- tiny fake model
12
+ fn.name = name
13
+ return fn
14
+
15
+
16
+ def _cmodel(name, answer, confidence):
17
+ """A fake model returning (names, confidence) -- the cascade form."""
18
+ fn = lambda prompt: (list(answer), confidence) # noqa: E731
19
+ fn.name = name
20
+ return fn
21
+
22
+
23
+ def _counting(name, answer, confidence):
24
+ """Like _cmodel but records how many times it was called (to prove no wasted calls)."""
25
+ calls = {"n": 0}
26
+
27
+ def fn(prompt):
28
+ calls["n"] += 1
29
+ return list(answer), confidence
30
+ fn.name = name
31
+ fn.calls = calls
32
+ return fn
33
+
34
+
35
+ def test_judge_mode_uses_the_judge_choice():
36
+ models = [_model("a", ["Dave", "Berlin"]), _model("b", ["Dave"])]
37
+ judge = lambda prompt, answers: ["Dave"] # noqa: E731
38
+ smart = SmartArtificialIntelligenceLocal(models=models, judge=judge, is_test_data=True)
39
+ assert smart.smart_identify("p", mode=Consts.MODE_JUDGE) == ["Dave"]
40
+
41
+
42
+ def test_judge_mode_without_judge_falls_back_to_majority_vote():
43
+ # "Dave" in 2/3 models (kept), "Berlin" in 1/3 (dropped)
44
+ models = [_model("a", ["Dave", "Berlin"]), _model("b", ["Dave"]), _model("c", ["Dave"])]
45
+ smart = SmartArtificialIntelligenceLocal(models=models, is_test_data=True)
46
+ assert smart.smart_identify("p") == ["Dave"]
47
+
48
+
49
+ def test_reaction_mode_logs_every_answer_with_selection_flag():
50
+ logged = []
51
+ sink = lambda model, prompt, answer, selected: logged.append((model, tuple(answer), selected)) # noqa: E731
52
+ models = [_model("a", ["Dave"]), _model("b", ["Dave"]), _model("b2", ["Nadia"])]
53
+ smart = SmartArtificialIntelligenceLocal(models=models, reaction_sink=sink, is_test_data=True)
54
+
55
+ result = smart.smart_identify("p", mode=Consts.MODE_REACTION)
56
+ assert result == ["Dave"] # majority (2/3)
57
+ assert len(logged) == 3 # one reaction row per model
58
+ assert ("a", ("Dave",), True) in logged # the selected answer is flagged
59
+ assert ("b2", ("Nadia",), False) in logged # a losing answer is flagged False
60
+
61
+
62
+ def test_a_failing_model_is_skipped_not_fatal():
63
+ def boom(prompt):
64
+ raise RuntimeError("model down")
65
+ models = [boom, _model("ok", ["Dave"])]
66
+ smart = SmartArtificialIntelligenceLocal(models=models, is_test_data=True)
67
+ assert smart.smart_identify("p") == ["Dave"]
68
+
69
+
70
+ def test_no_models_returns_empty():
71
+ assert SmartArtificialIntelligenceLocal(models=[], is_test_data=True).smart_identify("p") == []
72
+
73
+
74
+ # --------------------------------------------------------------------- cascade (efficiency) --
75
+ def test_cascade_stops_at_tier1_when_confident():
76
+ tier2 = _counting("cloud", ["Nadia"], 0.9)
77
+ models = [_cmodel("local", ["Dave"], 0.95), tier2]
78
+ smart = SmartArtificialIntelligenceLocal(models=models, escalate_confidence=0.75,
79
+ is_test_data=True)
80
+ result = smart.smart_identify("p", mode=Consts.MODE_CASCADE)
81
+ assert result == ["Dave"]
82
+ assert tier2.calls["n"] == 0 # never escalated -> no second call
83
+ assert smart.last_trace["calls"] == 1
84
+ assert smart.last_trace["escalated"] is False
85
+
86
+
87
+ def test_cascade_escalates_when_unsure_and_agreement_skips_judge():
88
+ judge_calls = {"n": 0}
89
+
90
+ def judge(prompt, answers):
91
+ judge_calls["n"] += 1
92
+ return ["Dave"]
93
+ models = [_cmodel("local", ["Dave"], 0.40), _cmodel("cloud", ["Dave"], 0.90)]
94
+ smart = SmartArtificialIntelligenceLocal(models=models, judge=judge,
95
+ escalate_confidence=0.75, is_test_data=True)
96
+ result = smart.smart_identify("p", mode=Consts.MODE_CASCADE)
97
+ assert result == ["Dave"]
98
+ assert judge_calls["n"] == 0 # models agreed -> judge NOT invoked
99
+ assert smart.last_trace["escalated"] is True
100
+ assert smart.last_trace["agreed"] is True
101
+ assert smart.last_trace["calls"] == 2
102
+
103
+
104
+ def test_cascade_invokes_judge_on_disagreement():
105
+ judge_calls = {"n": 0}
106
+
107
+ def judge(prompt, answers):
108
+ judge_calls["n"] += 1
109
+ return ["Nadia"]
110
+ models = [_cmodel("local", ["Dave"], 0.40), _cmodel("cloud", ["Nadia"], 0.90)]
111
+ smart = SmartArtificialIntelligenceLocal(models=models, judge=judge,
112
+ escalate_confidence=0.75, is_test_data=True)
113
+ result = smart.smart_identify("p", mode=Consts.MODE_CASCADE)
114
+ assert result == ["Nadia"]
115
+ assert judge_calls["n"] == 1 # disagreement -> judge decides
116
+ assert smart.last_trace["judged"] is True
117
+ assert smart.last_trace["calls"] == 3
118
+
119
+
120
+ def test_cascade_logs_reaction_on_disagreement_without_judge():
121
+ logged = []
122
+ sink = lambda m, p, a, s: logged.append((m, tuple(a), s)) # noqa: E731
123
+ models = [_cmodel("local", ["Dave"], 0.40), _cmodel("cloud", ["Nadia"], 0.90)]
124
+ smart = SmartArtificialIntelligenceLocal(models=models, reaction_sink=sink,
125
+ escalate_confidence=0.75, is_test_data=True)
126
+ smart.smart_identify("p", mode=Consts.MODE_CASCADE)
127
+ assert len(logged) == 2 # both tiers logged on disagreement
128
+ assert smart.last_trace["judged"] is False
@@ -0,0 +1,22 @@
1
+ Metadata-Version: 2.4
2
+ Name: smart-artificial-intelligence-local
3
+ Version: 0.0b7
4
+ Summary: PyPI smart-artificial-intelligence-local Python Package owned by Circlez.ai
5
+ Home-page: https://github.com/circles-zone/smart-artificial-intelligence-local-python-package
6
+ Author: Circles
7
+ Author-email: info@circlez.ai
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: python-sdk-remote
12
+ Requires-Dist: logger-local
13
+ Dynamic: author
14
+ Dynamic: author-email
15
+ Dynamic: classifier
16
+ Dynamic: description
17
+ Dynamic: description-content-type
18
+ Dynamic: home-page
19
+ Dynamic: requires-dist
20
+ Dynamic: summary
21
+
22
+ PyPI smart-artificial-intelligence-local Python Package owned by Circlez.ai
@@ -0,0 +1,14 @@
1
+ README.md
2
+ pyproject.toml
3
+ setup.py
4
+ smart_artificial_intelligence_local/__init__.py
5
+ smart_artificial_intelligence_local.egg-info/PKG-INFO
6
+ smart_artificial_intelligence_local.egg-info/SOURCES.txt
7
+ smart_artificial_intelligence_local.egg-info/dependency_links.txt
8
+ smart_artificial_intelligence_local.egg-info/requires.txt
9
+ smart_artificial_intelligence_local.egg-info/top_level.txt
10
+ smart_artificial_intelligence_local/src/__init__.py
11
+ smart_artificial_intelligence_local/src/constants.py
12
+ smart_artificial_intelligence_local/src/smart_artificial_intelligence_local.py
13
+ smart_artificial_intelligence_local/tests/__init__.py
14
+ smart_artificial_intelligence_local/tests/smart_artificial_intelligence_local_test.py