lexsi-sdk 0.1.12__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 (92) hide show
  1. lexsi_sdk-0.1.12/.github/scripts/release.py +46 -0
  2. lexsi_sdk-0.1.12/.github/scripts/test-release.py +52 -0
  3. lexsi_sdk-0.1.12/.github/workflows/publish.yml +83 -0
  4. lexsi_sdk-0.1.12/.github/workflows/release.yml +28 -0
  5. lexsi_sdk-0.1.12/.github/workflows/test-publish.yml +93 -0
  6. lexsi_sdk-0.1.12/.github/workflows/test-release.yml +20 -0
  7. lexsi_sdk-0.1.12/.gitignore +29 -0
  8. lexsi_sdk-0.1.12/LICENSE +21 -0
  9. lexsi_sdk-0.1.12/MANIFEST.in +8 -0
  10. lexsi_sdk-0.1.12/PKG-INFO +95 -0
  11. lexsi_sdk-0.1.12/lexsi_sdk/__init__.py +5 -0
  12. lexsi_sdk-0.1.12/lexsi_sdk/client/__init__.py +0 -0
  13. lexsi_sdk-0.1.12/lexsi_sdk/client/client.py +194 -0
  14. lexsi_sdk-0.1.12/lexsi_sdk/common/__init__.py +0 -0
  15. lexsi_sdk-0.1.12/lexsi_sdk/common/config/.env.prod +3 -0
  16. lexsi_sdk-0.1.12/lexsi_sdk/common/constants.py +143 -0
  17. lexsi_sdk-0.1.12/lexsi_sdk/common/enums.py +8 -0
  18. lexsi_sdk-0.1.12/lexsi_sdk/common/environment.py +47 -0
  19. lexsi_sdk-0.1.12/lexsi_sdk/common/monitoring.py +81 -0
  20. lexsi_sdk-0.1.12/lexsi_sdk/common/trigger.py +75 -0
  21. lexsi_sdk-0.1.12/lexsi_sdk/common/types.py +122 -0
  22. lexsi_sdk-0.1.12/lexsi_sdk/common/utils.py +84 -0
  23. lexsi_sdk-0.1.12/lexsi_sdk/common/validation.py +83 -0
  24. lexsi_sdk-0.1.12/lexsi_sdk/common/xai_uris.py +197 -0
  25. lexsi_sdk-0.1.12/lexsi_sdk/core/__init__.py +0 -0
  26. lexsi_sdk-0.1.12/lexsi_sdk/core/agent.py +62 -0
  27. lexsi_sdk-0.1.12/lexsi_sdk/core/alert.py +56 -0
  28. lexsi_sdk-0.1.12/lexsi_sdk/core/case.py +618 -0
  29. lexsi_sdk-0.1.12/lexsi_sdk/core/dashboard.py +131 -0
  30. lexsi_sdk-0.1.12/lexsi_sdk/core/guardrails/__init__.py +0 -0
  31. lexsi_sdk-0.1.12/lexsi_sdk/core/guardrails/guard_template.py +299 -0
  32. lexsi_sdk-0.1.12/lexsi_sdk/core/guardrails/guardrail_autogen.py +554 -0
  33. lexsi_sdk-0.1.12/lexsi_sdk/core/guardrails/guardrails_langgraph.py +525 -0
  34. lexsi_sdk-0.1.12/lexsi_sdk/core/guardrails/guardrails_openai.py +541 -0
  35. lexsi_sdk-0.1.12/lexsi_sdk/core/guardrails/openai_runner.py +1328 -0
  36. lexsi_sdk-0.1.12/lexsi_sdk/core/model_summary.py +110 -0
  37. lexsi_sdk-0.1.12/lexsi_sdk/core/organization.py +549 -0
  38. lexsi_sdk-0.1.12/lexsi_sdk/core/project.py +5131 -0
  39. lexsi_sdk-0.1.12/lexsi_sdk/core/synthetic.py +387 -0
  40. lexsi_sdk-0.1.12/lexsi_sdk/core/text.py +640 -0
  41. lexsi_sdk-0.1.12/lexsi_sdk/core/tracer.py +208 -0
  42. lexsi_sdk-0.1.12/lexsi_sdk/core/utils.py +36 -0
  43. lexsi_sdk-0.1.12/lexsi_sdk/core/workspace.py +325 -0
  44. lexsi_sdk-0.1.12/lexsi_sdk/core/wrapper.py +766 -0
  45. lexsi_sdk-0.1.12/lexsi_sdk/core/xai.py +306 -0
  46. lexsi_sdk-0.1.12/lexsi_sdk/version.py +34 -0
  47. lexsi_sdk-0.1.12/lexsi_sdk.egg-info/PKG-INFO +95 -0
  48. lexsi_sdk-0.1.12/lexsi_sdk.egg-info/SOURCES.txt +90 -0
  49. lexsi_sdk-0.1.12/lexsi_sdk.egg-info/dependency_links.txt +1 -0
  50. lexsi_sdk-0.1.12/lexsi_sdk.egg-info/requires.txt +28 -0
  51. lexsi_sdk-0.1.12/lexsi_sdk.egg-info/top_level.txt +1 -0
  52. lexsi_sdk-0.1.12/lexsiai/__init__.py +5 -0
  53. lexsi_sdk-0.1.12/lexsiai/client/__init__.py +0 -0
  54. lexsi_sdk-0.1.12/lexsiai/client/client.py +194 -0
  55. lexsi_sdk-0.1.12/lexsiai/common/__init__.py +0 -0
  56. lexsi_sdk-0.1.12/lexsiai/common/config/.env.prod +3 -0
  57. lexsi_sdk-0.1.12/lexsiai/common/constants.py +143 -0
  58. lexsi_sdk-0.1.12/lexsiai/common/enums.py +8 -0
  59. lexsi_sdk-0.1.12/lexsiai/common/environment.py +47 -0
  60. lexsi_sdk-0.1.12/lexsiai/common/monitoring.py +81 -0
  61. lexsi_sdk-0.1.12/lexsiai/common/trigger.py +75 -0
  62. lexsi_sdk-0.1.12/lexsiai/common/types.py +122 -0
  63. lexsi_sdk-0.1.12/lexsiai/common/utils.py +84 -0
  64. lexsi_sdk-0.1.12/lexsiai/common/validation.py +83 -0
  65. lexsi_sdk-0.1.12/lexsiai/common/xai_uris.py +197 -0
  66. lexsi_sdk-0.1.12/lexsiai/core/__init__.py +0 -0
  67. lexsi_sdk-0.1.12/lexsiai/core/agent.py +62 -0
  68. lexsi_sdk-0.1.12/lexsiai/core/alert.py +56 -0
  69. lexsi_sdk-0.1.12/lexsiai/core/case.py +618 -0
  70. lexsi_sdk-0.1.12/lexsiai/core/dashboard.py +131 -0
  71. lexsi_sdk-0.1.12/lexsiai/core/guardrails/__init__.py +0 -0
  72. lexsi_sdk-0.1.12/lexsiai/core/guardrails/guard_template.py +299 -0
  73. lexsi_sdk-0.1.12/lexsiai/core/guardrails/guardrail_autogen.py +554 -0
  74. lexsi_sdk-0.1.12/lexsiai/core/guardrails/guardrails_langgraph.py +525 -0
  75. lexsi_sdk-0.1.12/lexsiai/core/guardrails/guardrails_openai.py +541 -0
  76. lexsi_sdk-0.1.12/lexsiai/core/guardrails/openai_runner.py +1328 -0
  77. lexsi_sdk-0.1.12/lexsiai/core/model_summary.py +110 -0
  78. lexsi_sdk-0.1.12/lexsiai/core/organization.py +549 -0
  79. lexsi_sdk-0.1.12/lexsiai/core/project.py +5135 -0
  80. lexsi_sdk-0.1.12/lexsiai/core/synthetic.py +387 -0
  81. lexsi_sdk-0.1.12/lexsiai/core/text.py +640 -0
  82. lexsi_sdk-0.1.12/lexsiai/core/tracer.py +208 -0
  83. lexsi_sdk-0.1.12/lexsiai/core/utils.py +36 -0
  84. lexsi_sdk-0.1.12/lexsiai/core/workspace.py +325 -0
  85. lexsi_sdk-0.1.12/lexsiai/core/wrapper.py +766 -0
  86. lexsi_sdk-0.1.12/lexsiai/core/xai.py +306 -0
  87. lexsi_sdk-0.1.12/lexsiai/version.py +34 -0
  88. lexsi_sdk-0.1.12/pyproject.toml +44 -0
  89. lexsi_sdk-0.1.12/readme.md +49 -0
  90. lexsi_sdk-0.1.12/requirements.txt +28 -0
  91. lexsi_sdk-0.1.12/setup.cfg +4 -0
  92. lexsi_sdk-0.1.12/tests/test_sdk_import.py +4 -0
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env python3
2
+ import subprocess
3
+
4
+ default_version = "0.1.0"
5
+
6
+ def get_last_version() -> str:
7
+ """Return the version number of the last release."""
8
+ result = subprocess.run(
9
+ ["gh", "release", "list", "--limit", "1", "--json", "tagName", "--jq", ".[0].tagName"],
10
+ check=False,
11
+ stdout=subprocess.PIPE,
12
+ stderr=subprocess.PIPE,
13
+ text=True,
14
+ )
15
+ tag = result.stdout.strip()
16
+ if not tag:
17
+ return default_version
18
+ return tag
19
+
20
+
21
+ def bump_patch_number(version_number: str) -> str:
22
+ """Return a copy of `version_number` with the patch number incremented."""
23
+ major, minor, patch = version_number.split(".")
24
+ return f"{major}.{minor}.{int(patch) + 1}"
25
+
26
+
27
+ def create_new_patch_release():
28
+ """Create a new patch release on GitHub."""
29
+ try:
30
+ last_version_number = get_last_version()
31
+ except subprocess.CalledProcessError as err:
32
+ # The project doesn't have any releases yet.
33
+ new_version_number = default_version
34
+ print(err)
35
+ print(f'taking default version: {new_version_number}')
36
+ else:
37
+ new_version_number = bump_patch_number(last_version_number)
38
+
39
+ subprocess.run(
40
+ ["gh", "release", "create", "--generate-notes", f"{new_version_number}"],
41
+ check=True,
42
+ )
43
+
44
+
45
+ if __name__ == "__main__":
46
+ create_new_patch_release()
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env python3
2
+ import subprocess
3
+
4
+ default_version = "0.0.dev1"
5
+
6
+ def get_last_version() -> str:
7
+ """Return the version number of the last release."""
8
+ tag_info = (
9
+ subprocess.run(
10
+ "gh release list | grep -E '^.+\\.dev\\d*' | head -n 1",
11
+ shell=True,
12
+ check=True,
13
+ stdout=subprocess.PIPE,
14
+ stderr=subprocess.PIPE
15
+ )
16
+ .stdout.decode("utf8")
17
+ .strip()
18
+ )
19
+ tag_fields = tag_info.split('\t')
20
+ tag = tag_fields[2] if len(tag_fields) > 2 else default_version
21
+
22
+ return tag
23
+
24
+ def bump_patch_number(version_number: str) -> str:
25
+ """Return a copy of `version_number` with the patch number incremented."""
26
+ major, minor, patch = version_number.split(".")
27
+
28
+ new_patch_version = int(patch[3:]) + 1
29
+
30
+ return f"{major}.{minor}.dev{new_patch_version}"
31
+
32
+
33
+ def create_new_patch_release():
34
+ """Create a new patch release on GitHub."""
35
+ try:
36
+ last_version_number = get_last_version()
37
+ except subprocess.CalledProcessError as err:
38
+ # The project doesn't have any releases yet.
39
+ new_version_number = default_version
40
+ print(err)
41
+ print(f'taking default version: {new_version_number}')
42
+ else:
43
+ new_version_number = bump_patch_number(last_version_number)
44
+
45
+ subprocess.run(
46
+ ["gh", "release", "create", "--generate-notes", f"{new_version_number}"],
47
+ check=True,
48
+ )
49
+
50
+
51
+ if __name__ == "__main__":
52
+ create_new_patch_release()
@@ -0,0 +1,83 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [created]
6
+
7
+ jobs:
8
+ pypi:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ contents: write
12
+ env:
13
+ SETUPTOOLS_SCM_PRETEND_VERSION: ${{ github.event.release.tag_name }}
14
+ steps:
15
+ - name: Checkout
16
+ uses: actions/checkout@v3
17
+ with:
18
+ fetch-depth: 0
19
+ ref: ${{ github.event.release.tag_name }}
20
+
21
+ - name: Clean build artefacts
22
+ run: rm -rf dist build ./*.egg-info
23
+
24
+ - name: Install dependencies and run tests
25
+ run: |
26
+ python -m pip install --upgrade pip
27
+ pip install -r requirements.txt
28
+ pip install .
29
+ pip install pytest
30
+ pytest tests/
31
+ continue-on-error: false
32
+
33
+ - name: Build package
34
+ run: python3 -m pip install --upgrade build && python3 -m build
35
+
36
+ - name: Check version is non-dev
37
+ run: |
38
+ python -m pip install setuptools_scm
39
+ python - << 'PY'
40
+ from setuptools_scm import get_version
41
+ v = get_version()
42
+ print("Computed version:", v)
43
+ if ".dev" in v:
44
+ raise SystemExit(f"Refusing to publish dev version: {v}")
45
+ PY
46
+
47
+ - name: Publish package to PyPI
48
+ if: success()
49
+ run: |
50
+ python -m pip install --upgrade twine
51
+ python -m pip install -U packaging
52
+ python -m twine upload dist/*
53
+ env:
54
+ TWINE_USERNAME: __token__
55
+ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
56
+
57
+ - name: Send release notes to Slack
58
+ id: slack
59
+ uses: slackapi/slack-github-action@v1.24.0
60
+ with:
61
+ channel-id: "lexsi-sdk-prod-release"
62
+ payload: |
63
+ {
64
+ "text": "Lexsi SDK release",
65
+ "blocks": [
66
+ {
67
+ "type": "section",
68
+ "text": {
69
+ "type": "mrkdwn",
70
+ "text": "*Version:* ${{ github.event.release.tag_name }}"
71
+ }
72
+ },
73
+ {
74
+ "type": "section",
75
+ "text": {
76
+ "type": "mrkdwn",
77
+ "text": "*PyPI URL:* https://pypi.org/project/lexsi_sdk/${{ github.event.release.tag_name }}"
78
+ }
79
+ }
80
+ ]
81
+ }
82
+ env:
83
+ SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
@@ -0,0 +1,28 @@
1
+ name: Create release
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main # when you push to main, this runs
7
+
8
+ jobs:
9
+ github:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: write # needed so gh can create tags/releases
13
+
14
+ steps:
15
+ - name: Checkout
16
+ uses: actions/checkout@v3
17
+ with:
18
+ fetch-depth: 0 # full history so setuptools_scm & gh see all tags
19
+
20
+ - name: Set up Python
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: '3.11'
24
+
25
+ - name: Create new patch release
26
+ run: .github/scripts/release.py
27
+ env:
28
+ GH_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
@@ -0,0 +1,93 @@
1
+ name: Publish to test PyPI
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ branch:
7
+ description: "Branch to release from"
8
+ required: true
9
+ default: "main"
10
+
11
+ jobs:
12
+ pypi:
13
+ runs-on: ubuntu-latest
14
+
15
+ steps:
16
+ - name: Checkout
17
+ uses: actions/checkout@v4
18
+ with:
19
+ fetch-depth: 0
20
+ ref: ${{ github.event.inputs.branch }}
21
+
22
+ - name: Fetch all tags
23
+ run: git fetch --tags --force
24
+
25
+ - name: Detect latest stable version
26
+ run: |
27
+ latest_tag=$(git tag --list --sort=-v:refname | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | head -n 1)
28
+
29
+ if [ -z "$latest_tag" ]; then
30
+ echo "No stable tags found. Using fallback 0.1.0"
31
+ base="0.1.0"
32
+ else
33
+ echo "Latest stable tag detected: $latest_tag"
34
+ base="$latest_tag"
35
+ fi
36
+
37
+ echo "BASE_VERSION=$base" >> $GITHUB_ENV
38
+ echo "Using base version: $base"
39
+
40
+ - name: Upgrade packaging stack
41
+ run: |
42
+ python -m pip install --upgrade pip
43
+ pip install --upgrade setuptools wheel setuptools_scm build twine pkginfo readme-renderer requests
44
+
45
+ - name: Compute next dev version
46
+ run: |
47
+ python <<'EOF'
48
+ import os, re, requests
49
+
50
+ base = os.environ["BASE_VERSION"]
51
+ pkg = "lexsi-sdk"
52
+
53
+ url = f"https://test.pypi.org/pypi/{pkg}/json"
54
+
55
+ try:
56
+ data = requests.get(url, timeout=10).json()
57
+ versions = data.get("releases", {}).keys()
58
+ except Exception:
59
+ print("No existing TestPyPI project found. Starting dev counter at 1.")
60
+ versions = []
61
+
62
+ pattern = re.compile(rf"^{re.escape(base)}\.dev(\d+)$")
63
+
64
+ dev_nums = [
65
+ int(m.group(1))
66
+ for v in versions
67
+ if (m := pattern.match(v))
68
+ ]
69
+
70
+ next_dev = max(dev_nums, default=0) + 1
71
+ final_version = f"{base}.dev{next_dev}"
72
+
73
+ print("Next dev version:", final_version)
74
+
75
+ with open(os.environ["GITHUB_ENV"], "a") as f:
76
+ f.write(f"SETUPTOOLS_SCM_PRETEND_VERSION={final_version}\n")
77
+
78
+ EOF
79
+
80
+ - name: Build package
81
+ env:
82
+ XAI_ENV: testing
83
+ run: |
84
+ rm -rf build dist *.egg-info
85
+ python -m build
86
+ twine check dist/*
87
+
88
+ - name: Publish package to Test PyPI
89
+ env:
90
+ TWINE_USERNAME: __token__
91
+ TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }}
92
+ run: |
93
+ python -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*
@@ -0,0 +1,20 @@
1
+ name: Create test release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ branches:
7
+ - testing-main
8
+
9
+ jobs:
10
+ github:
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ contents: write
14
+ steps:
15
+ - name: Checkout
16
+ uses: actions/checkout@v3
17
+ - name: Create new test release
18
+ run: .github/scripts/test-release.py
19
+ env:
20
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,29 @@
1
+ .vscode
2
+
3
+ # Compiled python modules.
4
+ *.pyc
5
+ __pycache__
6
+
7
+ # Setuptools distribution folder.
8
+ /dist/
9
+ build
10
+
11
+ # Python egg metadata, regenerated from source files by setuptools.
12
+ *.egg-info
13
+ .eggs
14
+
15
+ # Documentation files
16
+ _build
17
+ _static
18
+ _templates
19
+
20
+ # Venv
21
+ *venv
22
+
23
+ # env file
24
+ .env.local
25
+ .env.testing
26
+
27
+ # package version file
28
+ lexsi_sdk/version.py
29
+ /workingtest/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Lexsi.ai
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,8 @@
1
+ include LICENSE
2
+ include README.md
3
+ include requirements.txt
4
+ recursive-include lexsi_sdk *.pickle
5
+ recursive-exclude * __pycache__
6
+ recursive-exclude * *.py[co]
7
+ recursive-include docs *.md
8
+ recursive-include tests *.py
@@ -0,0 +1,95 @@
1
+ Metadata-Version: 2.4
2
+ Name: lexsi-sdk
3
+ Version: 0.1.12
4
+ Summary: Full stack ML Observability with Lexsi.ai
5
+ Author-email: Lexsi Labs <support@lexsi.ai>
6
+ License: Lexsi Labs Source Available License (LSAL) v1.0
7
+ Keywords: lexsi,lexsi-sdk,lexsi_sdk,ML observability,observability,machine learning
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Intended Audience :: Science/Research
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: pydantic>=1.10.13
19
+ Requires-Dist: httpx
20
+ Requires-Dist: pyjwt>=2.3.0
21
+ Requires-Dist: python-dotenv>=1.0.0
22
+ Requires-Dist: requests>=2.31.0
23
+ Requires-Dist: pandas>=1.5.3
24
+ Requires-Dist: plotly>=5.15.0
25
+ Requires-Dist: ipython>=7.34.0
26
+ Requires-Dist: Pillow>=10.4.0
27
+ Requires-Dist: google-genai>=1.24.0
28
+ Requires-Dist: anthropic>=0.57.1
29
+ Requires-Dist: openai>=1.93.1
30
+ Requires-Dist: groq>=0.29.0
31
+ Requires-Dist: xai-sdk>=1.0.0
32
+ Requires-Dist: together>=1.3.14
33
+ Requires-Dist: replicate>=1.0.7
34
+ Requires-Dist: huggingface-hub>=0.33.2
35
+ Requires-Dist: mistralai>=1.9.1
36
+ Requires-Dist: boto3>=1.39.4
37
+ Requires-Dist: opentelemetry-sdk>=1.36.0
38
+ Requires-Dist: opentelemetry-exporter-otlp>=1.36.0
39
+ Requires-Dist: openinference-instrumentation-langchain>=0.1.50
40
+ Requires-Dist: openinference-instrumentation-autogen-agentchat>=0.1.4
41
+ Requires-Dist: openinference-instrumentation-crewai>=0.1.11
42
+ Requires-Dist: openinference-instrumentation-dspy>=0.1.28
43
+ Requires-Dist: openinference-instrumentation-llama-index>=4.3.4
44
+ Requires-Dist: openinference-instrumentation-openai-agents>=1.2.0
45
+ Requires-Dist: openinference-instrumentation-smolagents>=0.1.16
46
+
47
+ ## [Lexsi ai](https://lexsi.ai): ML Observability for mission-critical ‘AI’
48
+
49
+ Lexsi Ai is a full-stack ML Observability platform that integrates with your MLOPs platform to Explain, Monitor, Audit and Improve your ML models.
50
+
51
+ Lexsi Ai has multiple components to address the complex observability required for mission-critical ‘AI’.
52
+
53
+ 1. **ML Explainability:** Lexsi Ai offers diverse explainability options like- Bactrace(Specialized for deep learning models), SHAPE, Decision View, Observations (New way to correlate expert functioning vs model functioning) and Similar Cases (reference as explanations).
54
+ 2. **ML Monitoring:** Monitor your models for drifts, performance & bias. The tool offers diverse options for drift (data/model) like - PSI, KL Divergence, Chi-square test,
55
+ 3. **Synthetic ‘AI’:** Deploy advanced synthetic ‘AI’ techniques like GPT-2 & GANs on your tabular data to generate high-quality synthetic datasets. Test the quality and privacy of these data sets using our Anonymity tests, column tests etc.
56
+ 4. **ML Risk policies:** Define advanced risk policies on your models.
57
+ 5. **AutoML:** Lexsi Ai also provides fully low-code and no-code options to build ML models on your data. For advanced users, it also provides more options to fine-tune it.
58
+
59
+ Lexsi Ai also acts as a common workflow and provides insights acceptable by all stakeholders - Data Science, IT, Risk, Operations and compliance teams, making the rollout and maintenance of AI/ML models seamless and clutter-free.
60
+
61
+ ### Quickstart:
62
+ Get started with Lexsi Ai with a few easy steps:
63
+
64
+ 1. Sign up and log in to your new Lexsi Ai account.
65
+ 2. After logging in, generate an Access Token for your user account.
66
+ 3. Set the environment variable **XAI_ACCESS_TOKEN** with the generated value.
67
+
68
+ Once you've completed these steps, you're all set! Now, you can easily log in and start using the Lexsi Ai SDK:
69
+
70
+ 1. Log in by importing the "xai" object instance from the "lexsi_sdk" package.
71
+ 2. Call the "login" method. This method automatically takes the access token value from the "XAI_ACCESS_TOKEN" environment variable and stores the JWT in the object instance. This means that all your future SDK operations will be authorized automatically, making it simple and hassle-free!
72
+
73
+
74
+ ```
75
+ from lexsi_sdk import xai as lexsi
76
+
77
+ ## login() function authenticates user using token that can be generated in app.lexsi_sdk.com/sdk
78
+
79
+
80
+ lexsi.login()
81
+
82
+
83
+ Enter your Lexsi ai Access Token: ··········
84
+ Authenticated successfully.
85
+ ```
86
+
87
+ ### Cookbook:
88
+ In this section, you can review the examples of implementation of Lexsi Ai-SDK.
89
+
90
+ 1. [Full features overview of Lexsi Ai](https://colab.research.google.com/drive/1Dy5eL-FJVnFV0K5yOfGGVoAmiS_Icaz3?usp=sharing)
91
+ 2. Using Lexsi Ai in Loan Underwriting (Coming Soon)
92
+
93
+
94
+ ### Contribution guidelines:
95
+ At Lexsi Ai, we're passionate about open source and value community contributions! Explore our contribution guide for insights into the development workflow and Lexsi Ai library internals. For bug reports or feature requests, head to GitHub Issues or reach out to us at [support@Lexsi Ai.com](support@Lexsi Ai.com).
@@ -0,0 +1,5 @@
1
+ #import core modules so that they can be imported directly
2
+ from __future__ import annotations
3
+ from lexsi_sdk.core.xai import XAI
4
+
5
+ xai = XAI()
File without changes
@@ -0,0 +1,194 @@
1
+ import requests
2
+ import httpx
3
+ from lexsi_sdk.common.xai_uris import LOGIN_URI
4
+ import jwt
5
+ from pydantic import BaseModel
6
+ import json
7
+
8
+
9
+ class APIClient(BaseModel):
10
+ """API client to interact with Lexsi Ai services"""
11
+
12
+ debug: bool = False
13
+ base_url: str = ""
14
+ access_token: str = ""
15
+ auth_token: str = ""
16
+ headers: dict = {}
17
+
18
+ def __init__(self, **kwargs):
19
+ """Initialize the API client with provided configuration."""
20
+ super().__init__(**kwargs)
21
+
22
+ def get_auth_token(self) -> str:
23
+ """get jwt auth token value
24
+
25
+ Returns:
26
+ str: jwt auth token
27
+ """
28
+ return self.auth_token
29
+
30
+ def set_auth_token(self, auth_token):
31
+ """sets jwt auth token value
32
+
33
+ :param auth_token: jwt auth token
34
+ """
35
+ self.auth_token = auth_token
36
+
37
+ def set_access_token(self, access_token):
38
+ """sets access token value
39
+
40
+ :param auth_token: jwt auth token
41
+ """
42
+ self.access_token = access_token
43
+
44
+ def get_url(self, uri) -> str:
45
+ """get url by appending uri to base url
46
+
47
+ :param uri: uri of endpoint
48
+ :return: url
49
+ """
50
+ return f"{self.base_url}/{uri}"
51
+
52
+ def update_headers(self, auth_token):
53
+ """sets jwt auth token and updates headers for all requests"""
54
+ self.set_auth_token(auth_token)
55
+ self.headers = {
56
+ "Authorization": f"Bearer {self.auth_token}",
57
+ }
58
+
59
+ def refresh_bearer_token(self):
60
+ """Refresh the bearer token if the current token is expired."""
61
+ try:
62
+ if self.auth_token:
63
+ jwt.decode(
64
+ self.auth_token,
65
+ options={"verify_signature": False, "verify_exp": True},
66
+ )
67
+ except jwt.exceptions.ExpiredSignatureError as e:
68
+ response = self.base_request(
69
+ "POST", LOGIN_URI, {"access_token": self.access_token}
70
+ ).json()
71
+ self.update_headers(response["access_token"])
72
+
73
+ def base_request(self, method, uri, payload={}, files=None):
74
+ """makes request to xai base service
75
+
76
+ :param uri: api uri
77
+ :param method: GET, POST, PUT, DELETE
78
+ :raises Exception: Request exception
79
+ :return: JSON response
80
+ """
81
+ url = f"{self.base_url}/{uri}"
82
+ try:
83
+ # response = requests.request(
84
+ # method,
85
+ # url,
86
+ # headers=self.headers,
87
+ # json=payload,
88
+ # files=files,
89
+ # stream=stream,
90
+ # )
91
+
92
+ with httpx.Client(http2=True, timeout=None) as client:
93
+ response = client.request(
94
+ method=method,
95
+ url=url,
96
+ headers=self.headers,
97
+ json=payload,
98
+ files=files or None,
99
+ )
100
+ #response.raise_for_status()
101
+ #return response
102
+
103
+ res = None
104
+ try:
105
+ res = response.json().get("details") or response.json()
106
+ except Exception:
107
+ res = response.text
108
+ if 400 <= response.status_code < 500:
109
+ raise Exception(res)
110
+ elif 500 <= response.status_code < 600:
111
+ raise Exception(res)
112
+ else:
113
+ return response
114
+ except Exception as e:
115
+ raise e
116
+
117
+ def request(self, method, uri, payload):
118
+ """Refresh credentials and dispatch a base request."""
119
+ self.refresh_bearer_token()
120
+ response = self.base_request(method, uri, payload)
121
+ return response
122
+
123
+ def get(self, uri):
124
+ """makes get request to xai base service
125
+
126
+ :param uri: api uri
127
+ :raises Exception: Request exception
128
+ :return: JSON response
129
+ """
130
+
131
+ self.refresh_bearer_token()
132
+ response = self.base_request("GET", uri)
133
+ return response.json()
134
+
135
+ def post(self, uri, payload={}):
136
+ """makes post request to xai base service
137
+
138
+ :param uri: api uri
139
+ :param payload: api payload, defaults to {}
140
+ :raises Exception: Request exception
141
+ :return: JSON response
142
+ """
143
+
144
+ self.refresh_bearer_token()
145
+ response = self.base_request("POST", uri, payload)
146
+
147
+ return response.json()
148
+
149
+ # def stream(self, uri):
150
+ # """makes streaming request to xai base service
151
+
152
+ # :param uri: api uri
153
+ # :param payload: api payload, defaults to {}
154
+ # :raises Exception: Request exception
155
+ # :return: JSON response
156
+ # """
157
+
158
+ # self.refresh_bearer_token()
159
+ # response = self.base_request("GET", uri, stream=True)
160
+ # for res in response.iter_lines(decode_unicode=True):
161
+ # if res:
162
+ # if res.startswith("data: "):
163
+ # res = res.split("data: ")[1]
164
+ # yield json.loads(res)
165
+
166
+ def stream(self, uri):
167
+ """Server-Sent Events / line-streaming endpoint."""
168
+ self.refresh_bearer_token()
169
+ url = f"{self.base_url}/{uri}"
170
+ # if SSE, this header helps
171
+ headers = {**self.headers, "Accept": "text/event-stream"}
172
+
173
+ with httpx.Client(http2=True, timeout=None) as client:
174
+ # streaming MUST be consumed inside the context
175
+ with client.stream("GET", url, headers=headers) as response:
176
+ response.raise_for_status()
177
+ for line in response.iter_lines(): # no decode_unicode arg in httpx
178
+ if not line:
179
+ continue
180
+ # httpx.iter_lines() yields str lines
181
+ if line.startswith("data: "): # typical SSE prefix
182
+ line = line[6:]
183
+ yield json.loads(line)
184
+
185
+ def file(self, uri, files):
186
+ """makes multipart request to send files
187
+
188
+ :param uri: api uri
189
+ :param file_path: file path
190
+ :return: JSON response
191
+ """
192
+ self.refresh_bearer_token()
193
+ response = self.base_request("POST", uri, files=files)
194
+ return response.json()
File without changes