apala-api 1.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.
- apala_api-1.1.0/.claude/settings.local.json +9 -0
- apala_api-1.1.0/.gitignore +10 -0
- apala_api-1.1.0/.python-version +1 -0
- apala_api-1.1.0/CLAUDE.md +97 -0
- apala_api-1.1.0/PKG-INFO +577 -0
- apala_api-1.1.0/README.md +526 -0
- apala_api-1.1.0/VERIFICATION_RESULTS.md +127 -0
- apala_api-1.1.0/apala_client/__init__.py +58 -0
- apala_api-1.1.0/apala_client/client.py +290 -0
- apala_api-1.1.0/apala_client/metadata.py +136 -0
- apala_api-1.1.0/apala_client/models.py +184 -0
- apala_api-1.1.0/debug_test.py +101 -0
- apala_api-1.1.0/docs/Makefile +32 -0
- apala_api-1.1.0/docs/_build/html/.buildinfo +4 -0
- apala_api-1.1.0/docs/_build/html/.doctrees/api/client.doctree +0 -0
- apala_api-1.1.0/docs/_build/html/.doctrees/api/models.doctree +0 -0
- apala_api-1.1.0/docs/_build/html/.doctrees/api/types.doctree +0 -0
- apala_api-1.1.0/docs/_build/html/.doctrees/authentication.doctree +0 -0
- apala_api-1.1.0/docs/_build/html/.doctrees/environment.pickle +0 -0
- apala_api-1.1.0/docs/_build/html/.doctrees/examples.doctree +0 -0
- apala_api-1.1.0/docs/_build/html/.doctrees/feedback_tracking.doctree +0 -0
- apala_api-1.1.0/docs/_build/html/.doctrees/index.doctree +0 -0
- apala_api-1.1.0/docs/_build/html/.doctrees/message_processing.doctree +0 -0
- apala_api-1.1.0/docs/_build/html/.doctrees/quickstart.doctree +0 -0
- apala_api-1.1.0/docs/_build/html/_modules/apala_client/client.html +478 -0
- apala_api-1.1.0/docs/_build/html/_modules/apala_client/models.html +351 -0
- apala_api-1.1.0/docs/_build/html/_modules/index.html +112 -0
- apala_api-1.1.0/docs/_build/html/_sources/api/client.rst.txt +137 -0
- apala_api-1.1.0/docs/_build/html/_sources/api/models.rst.txt +187 -0
- apala_api-1.1.0/docs/_build/html/_sources/api/types.rst.txt +275 -0
- apala_api-1.1.0/docs/_build/html/_sources/authentication.rst.txt +278 -0
- apala_api-1.1.0/docs/_build/html/_sources/examples.rst.txt +553 -0
- apala_api-1.1.0/docs/_build/html/_sources/feedback_tracking.rst.txt +391 -0
- apala_api-1.1.0/docs/_build/html/_sources/index.rst.txt +122 -0
- apala_api-1.1.0/docs/_build/html/_sources/message_processing.rst.txt +384 -0
- apala_api-1.1.0/docs/_build/html/_sources/quickstart.rst.txt +289 -0
- apala_api-1.1.0/docs/_build/html/_static/_sphinx_javascript_frameworks_compat.js +123 -0
- apala_api-1.1.0/docs/_build/html/_static/basic.css +906 -0
- apala_api-1.1.0/docs/_build/html/_static/css/badge_only.css +1 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/fontawesome-webfont.eot +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/fontawesome-webfont.svg +2671 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/fontawesome-webfont.ttf +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/lato-bold-italic.woff +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/lato-bold-italic.woff2 +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/lato-bold.woff +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/lato-bold.woff2 +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/lato-normal-italic.woff +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/lato-normal-italic.woff2 +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/lato-normal.woff +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/fonts/lato-normal.woff2 +0 -0
- apala_api-1.1.0/docs/_build/html/_static/css/theme.css +4 -0
- apala_api-1.1.0/docs/_build/html/_static/doctools.js +149 -0
- apala_api-1.1.0/docs/_build/html/_static/documentation_options.js +13 -0
- apala_api-1.1.0/docs/_build/html/_static/file.png +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-bold.eot +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-bold.ttf +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-bold.woff +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-bold.woff2 +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-bolditalic.eot +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-bolditalic.ttf +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff2 +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-italic.eot +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-italic.ttf +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-italic.woff +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-italic.woff2 +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-regular.eot +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-regular.ttf +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-regular.woff +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/Lato/lato-regular.woff2 +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +0 -0
- apala_api-1.1.0/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +0 -0
- apala_api-1.1.0/docs/_build/html/_static/jquery.js +2 -0
- apala_api-1.1.0/docs/_build/html/_static/js/badge_only.js +1 -0
- apala_api-1.1.0/docs/_build/html/_static/js/theme.js +1 -0
- apala_api-1.1.0/docs/_build/html/_static/js/versions.js +228 -0
- apala_api-1.1.0/docs/_build/html/_static/language_data.js +192 -0
- apala_api-1.1.0/docs/_build/html/_static/minus.png +0 -0
- apala_api-1.1.0/docs/_build/html/_static/plus.png +0 -0
- apala_api-1.1.0/docs/_build/html/_static/pygments.css +75 -0
- apala_api-1.1.0/docs/_build/html/_static/searchtools.js +635 -0
- apala_api-1.1.0/docs/_build/html/_static/sphinx_highlight.js +154 -0
- apala_api-1.1.0/docs/_build/html/api/client.html +789 -0
- apala_api-1.1.0/docs/_build/html/api/models.html +1157 -0
- apala_api-1.1.0/docs/_build/html/api/types.html +1206 -0
- apala_api-1.1.0/docs/_build/html/authentication.html +394 -0
- apala_api-1.1.0/docs/_build/html/examples.html +660 -0
- apala_api-1.1.0/docs/_build/html/feedback_tracking.html +521 -0
- apala_api-1.1.0/docs/_build/html/genindex.html +465 -0
- apala_api-1.1.0/docs/_build/html/index.html +326 -0
- apala_api-1.1.0/docs/_build/html/message_processing.html +505 -0
- apala_api-1.1.0/docs/_build/html/objects.inv +0 -0
- apala_api-1.1.0/docs/_build/html/py-modindex.html +140 -0
- apala_api-1.1.0/docs/_build/html/quickstart.html +410 -0
- apala_api-1.1.0/docs/_build/html/search.html +130 -0
- apala_api-1.1.0/docs/_build/html/searchindex.js +1 -0
- apala_api-1.1.0/docs/api/client.rst +137 -0
- apala_api-1.1.0/docs/api/models.rst +187 -0
- apala_api-1.1.0/docs/api/types.rst +275 -0
- apala_api-1.1.0/docs/authentication.rst +278 -0
- apala_api-1.1.0/docs/conf.py +111 -0
- apala_api-1.1.0/docs/examples.rst +553 -0
- apala_api-1.1.0/docs/feedback_tracking.rst +334 -0
- apala_api-1.1.0/docs/index.rst +122 -0
- apala_api-1.1.0/docs/make.bat +35 -0
- apala_api-1.1.0/docs/message_processing.rst +384 -0
- apala_api-1.1.0/docs/quickstart.rst +289 -0
- apala_api-1.1.0/main.py +9 -0
- apala_api-1.1.0/notebooks/apala_demo.py +786 -0
- apala_api-1.1.0/notebooks/apala_demo_marimo.py +1139 -0
- apala_api-1.1.0/pyproject.toml +97 -0
- apala_api-1.1.0/test_core_functionality.py +87 -0
- apala_api-1.1.0/test_typed_responses.py +75 -0
- apala_api-1.1.0/tests/__init__.py +1 -0
- apala_api-1.1.0/tests/conftest.py +156 -0
- apala_api-1.1.0/tests/test_client.py +318 -0
- apala_api-1.1.0/tests/test_integration.py +234 -0
- apala_api-1.1.0/tests/test_models.py +256 -0
- apala_api-1.1.0/tox.ini +84 -0
- apala_api-1.1.0/uv.lock +3604 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
This is `apala-api`, a Python API project in its early stages. The codebase is minimal and appears to be a starter template for a loan/financial AI API service.
|
|
8
|
+
|
|
9
|
+
## Development Environment
|
|
10
|
+
|
|
11
|
+
- **Python Version**: 3.12 (specified in `.python-version`)
|
|
12
|
+
- **Package Manager**: Uses `uv` for Python package management
|
|
13
|
+
- **Project Structure**: Simple flat structure with main entry point in `main.py`
|
|
14
|
+
|
|
15
|
+
## Common Commands
|
|
16
|
+
|
|
17
|
+
### Environment Setup
|
|
18
|
+
```bash
|
|
19
|
+
# Install specific Python version if needed
|
|
20
|
+
uv python install 3.12
|
|
21
|
+
|
|
22
|
+
# Create virtual environment (uv handles this automatically)
|
|
23
|
+
uv sync
|
|
24
|
+
|
|
25
|
+
# Add dependencies
|
|
26
|
+
uv add <package-name>
|
|
27
|
+
|
|
28
|
+
# Add development dependencies
|
|
29
|
+
uv add --dev pytest ruff mypy
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Running the Application
|
|
33
|
+
```bash
|
|
34
|
+
# Run the main application
|
|
35
|
+
uv run python main.py
|
|
36
|
+
|
|
37
|
+
# Or run directly
|
|
38
|
+
uv run main.py
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Testing
|
|
42
|
+
```bash
|
|
43
|
+
# Run tests (once pytest is added)
|
|
44
|
+
uv run pytest
|
|
45
|
+
|
|
46
|
+
# Run tests with coverage
|
|
47
|
+
uv run pytest --cov
|
|
48
|
+
|
|
49
|
+
# Run specific test file
|
|
50
|
+
uv run pytest tests/test_example.py
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Development Tools
|
|
54
|
+
```bash
|
|
55
|
+
# Run linting
|
|
56
|
+
uv run ruff check .
|
|
57
|
+
|
|
58
|
+
# Run type checking
|
|
59
|
+
uv run mypy .
|
|
60
|
+
|
|
61
|
+
# Format code
|
|
62
|
+
uv run ruff format .
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Documentation Commands
|
|
66
|
+
```bash
|
|
67
|
+
# Build HTML documentation
|
|
68
|
+
uv run sphinx-build -b html docs docs/_build/html
|
|
69
|
+
|
|
70
|
+
# Clean documentation build directory
|
|
71
|
+
uv run python -c "import shutil; shutil.rmtree('docs/_build', ignore_errors=True)"
|
|
72
|
+
|
|
73
|
+
# Live documentation with auto-reload (opens on http://localhost:8001)
|
|
74
|
+
uv run sphinx-autobuild docs docs/_build/html --port 8001
|
|
75
|
+
|
|
76
|
+
# Check for broken links in documentation
|
|
77
|
+
uv run sphinx-build -b linkcheck docs docs/_build/linkcheck
|
|
78
|
+
|
|
79
|
+
# Open documentation in browser (macOS)
|
|
80
|
+
open docs/_build/html/index.html
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Architecture
|
|
84
|
+
|
|
85
|
+
The current codebase is minimal:
|
|
86
|
+
- `main.py`: Contains a simple entry point with a "Hello World" style function
|
|
87
|
+
- `pyproject.toml`: Basic Python project configuration with no dependencies yet
|
|
88
|
+
- No additional modules, tests, or complex architecture present
|
|
89
|
+
|
|
90
|
+
This appears to be a greenfield project ready for API development, likely intended for loan/financial AI services based on the project name.
|
|
91
|
+
|
|
92
|
+
## Key Files
|
|
93
|
+
|
|
94
|
+
- `main.py`: Application entry point
|
|
95
|
+
- `pyproject.toml`: Python project configuration and dependencies
|
|
96
|
+
- `.python-version`: Specifies Python 3.12 requirement
|
|
97
|
+
- `.gitignore`: Standard Python gitignore patterns
|
apala_api-1.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: apala-api
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Python SDK for Phoenix Message Analysis Services - Loan/Financial AI API Client
|
|
5
|
+
Author: Apala Cap
|
|
6
|
+
Keywords: ai,api,financial,loans,messaging,phoenix
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Requires-Dist: marimo>=0.16.5
|
|
18
|
+
Requires-Dist: pydantic>=2.12.3
|
|
19
|
+
Requires-Dist: requests>=2.28.0
|
|
20
|
+
Provides-Extra: all
|
|
21
|
+
Requires-Dist: jupyter>=1.0.0; extra == 'all'
|
|
22
|
+
Requires-Dist: marimo>=0.3.0; extra == 'all'
|
|
23
|
+
Requires-Dist: mypy>=1.0.0; extra == 'all'
|
|
24
|
+
Requires-Dist: myst-parser>=3.0.1; extra == 'all'
|
|
25
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'all'
|
|
26
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == 'all'
|
|
27
|
+
Requires-Dist: pytest>=7.0.0; extra == 'all'
|
|
28
|
+
Requires-Dist: ruff>=0.1.0; extra == 'all'
|
|
29
|
+
Requires-Dist: sphinx-autodoc-typehints>=2.3.0; extra == 'all'
|
|
30
|
+
Requires-Dist: sphinx-rtd-theme>=3.0.2; extra == 'all'
|
|
31
|
+
Requires-Dist: sphinx>=7.4.7; extra == 'all'
|
|
32
|
+
Requires-Dist: tox>=4.0.0; extra == 'all'
|
|
33
|
+
Requires-Dist: types-requests>=2.28.0; extra == 'all'
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
40
|
+
Requires-Dist: tox>=4.0.0; extra == 'dev'
|
|
41
|
+
Requires-Dist: types-requests>=2.28.0; extra == 'dev'
|
|
42
|
+
Provides-Extra: docs
|
|
43
|
+
Requires-Dist: myst-parser>=3.0.1; extra == 'docs'
|
|
44
|
+
Requires-Dist: sphinx-autodoc-typehints>=2.3.0; extra == 'docs'
|
|
45
|
+
Requires-Dist: sphinx-rtd-theme>=3.0.2; extra == 'docs'
|
|
46
|
+
Requires-Dist: sphinx>=7.4.7; extra == 'docs'
|
|
47
|
+
Provides-Extra: notebook
|
|
48
|
+
Requires-Dist: jupyter>=1.0.0; extra == 'notebook'
|
|
49
|
+
Requires-Dist: marimo>=0.3.0; extra == 'notebook'
|
|
50
|
+
Description-Content-Type: text/markdown
|
|
51
|
+
|
|
52
|
+
# Apala API - Python SDK
|
|
53
|
+
|
|
54
|
+
[](https://www.python.org/downloads/)
|
|
55
|
+
[](https://docs.python.org/3/library/typing.html)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
## 🚀 Quick Start
|
|
59
|
+
|
|
60
|
+
### Installation
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Install from source (package not yet published to PyPI)
|
|
64
|
+
git clone <repository-url>
|
|
65
|
+
cd apala_api
|
|
66
|
+
|
|
67
|
+
# Basic installation
|
|
68
|
+
uv sync
|
|
69
|
+
|
|
70
|
+
# Or install with development tools
|
|
71
|
+
uv sync --group dev
|
|
72
|
+
|
|
73
|
+
# Or install with notebook support
|
|
74
|
+
uv sync --group notebook
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Basic Usage
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from apala_client import ApalaClient, Message
|
|
81
|
+
|
|
82
|
+
# Initialize client
|
|
83
|
+
client = ApalaClient(
|
|
84
|
+
api_key="your-api-key",
|
|
85
|
+
base_url="https://your-server.com"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Authenticate (automatic JWT token management)
|
|
89
|
+
client.authenticate()
|
|
90
|
+
|
|
91
|
+
# Create customer message history
|
|
92
|
+
messages = [
|
|
93
|
+
Message(content="Hi, I need help with my loan application.", channel="EMAIL", reply_or_not=False),
|
|
94
|
+
Message(content="What are the current interest rates?", channel="SMS", reply_or_not=True),
|
|
95
|
+
Message(content="When will I hear back about approval?", channel="EMAIL", reply_or_not=True)
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
# Create your candidate response
|
|
99
|
+
candidate = Message(
|
|
100
|
+
content="Thank you for your inquiry! Our current rates start at 3.5% APR for qualified borrowers. We'll review your application and respond within 2 business days.",
|
|
101
|
+
channel="EMAIL",
|
|
102
|
+
reply_or_not=True
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Optimize message through the AI system
|
|
106
|
+
optimization = client.optimize_message(
|
|
107
|
+
message_history=messages,
|
|
108
|
+
candidate_message=candidate,
|
|
109
|
+
customer_id="550e8400-e29b-41d4-a716-446655440000",
|
|
110
|
+
zip_code="90210",
|
|
111
|
+
company_guid="550e8400-e29b-41d4-a716-446655440001"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
print(f"Original: {optimization.original_message}")
|
|
115
|
+
print(f"Optimized: {optimization.optimized_message}")
|
|
116
|
+
print(f"Message ID: {optimization.message_id}")
|
|
117
|
+
|
|
118
|
+
# Submit feedback after customer interaction
|
|
119
|
+
feedback_result = client.submit_single_feedback(
|
|
120
|
+
message_id=optimization.message_id,
|
|
121
|
+
customer_responded=True,
|
|
122
|
+
score="good", # "good", "bad", or "neutral"
|
|
123
|
+
actual_sent_message=optimization.optimized_message # Optional: what you actually sent
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
print(f"Feedback ID: {feedback_result.id}")
|
|
127
|
+
print(f"Submitted at: {feedback_result.inserted_at}")
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 🎯 Core Features
|
|
131
|
+
|
|
132
|
+
### ✅ **Type-Safe API**
|
|
133
|
+
- Full **TypedDict** responses with IDE autocomplete
|
|
134
|
+
- **mypy** integration catches errors at development time
|
|
135
|
+
- **No runtime surprises** - all response fields are typed
|
|
136
|
+
|
|
137
|
+
### ✅ **Complete Functionality**
|
|
138
|
+
- **Message Optimization**: Enhance messages for maximum engagement (primary endpoint)
|
|
139
|
+
- **Message Processing**: Analyze customer conversations and candidate responses
|
|
140
|
+
- **Feedback Tracking**: Monitor message performance with single or bulk submission
|
|
141
|
+
- **Authentication**: Automatic JWT token management with refresh
|
|
142
|
+
|
|
143
|
+
### ✅ **Production Ready**
|
|
144
|
+
- **Multi-Python Support**: Python 3.9, 3.10, 3.11, 3.12
|
|
145
|
+
- **Comprehensive Testing**: Unit tests, integration tests, type checking
|
|
146
|
+
- **Error Handling**: Uses standard `requests` exceptions (no custom exceptions)
|
|
147
|
+
- **Validation**: Client-side validation of UUIDs, zip codes, channels
|
|
148
|
+
|
|
149
|
+
### ✅ **Developer Experience**
|
|
150
|
+
- **Interactive Demo**: Marimo notebook with complete workflow
|
|
151
|
+
- **Documentation**: Full Sphinx docs with examples
|
|
152
|
+
- **Code Quality**: Ruff formatting, mypy type checking, tox multi-version testing
|
|
153
|
+
|
|
154
|
+
## 📖 Documentation
|
|
155
|
+
|
|
156
|
+
### Authentication
|
|
157
|
+
|
|
158
|
+
The SDK uses a secure two-tier authentication system:
|
|
159
|
+
|
|
160
|
+
1. **API Key**: Your long-lived company credentials
|
|
161
|
+
2. **JWT Tokens**: Short-lived session tokens for API calls (auto-managed)
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
# Authentication is automatic - just provide your API key
|
|
165
|
+
client = ApalaClient(api_key="your-api-key")
|
|
166
|
+
auth_response = client.authenticate()
|
|
167
|
+
|
|
168
|
+
# JWT tokens are automatically refreshed when needed
|
|
169
|
+
# No manual token management required!
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Message Processing Workflow
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
# 1. Create message objects with validation
|
|
176
|
+
customer_messages = [
|
|
177
|
+
Message(
|
|
178
|
+
content="I'm interested in a home loan",
|
|
179
|
+
channel="EMAIL",
|
|
180
|
+
reply_or_not=False
|
|
181
|
+
),
|
|
182
|
+
Message(
|
|
183
|
+
content="What documents do I need?",
|
|
184
|
+
channel="SMS",
|
|
185
|
+
reply_or_not=True
|
|
186
|
+
)
|
|
187
|
+
]
|
|
188
|
+
|
|
189
|
+
# 2. Define your candidate response
|
|
190
|
+
candidate_response = Message(
|
|
191
|
+
content="Great! For a home loan, you'll need: income verification, credit report, and bank statements. We offer competitive rates starting at 3.2% APR.",
|
|
192
|
+
channel="EMAIL",
|
|
193
|
+
reply_or_not=True
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
# 3. Optimize through AI system
|
|
197
|
+
result = client.optimize_message(
|
|
198
|
+
message_history=customer_messages,
|
|
199
|
+
candidate_message=candidate_response,
|
|
200
|
+
customer_id="customer-uuid-here",
|
|
201
|
+
zip_code="12345",
|
|
202
|
+
company_guid="company-uuid-here"
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
# 4. Get typed response with IDE completion
|
|
206
|
+
message_id = result.message_id # Type: str
|
|
207
|
+
optimized_message = result.optimized_message # Type: str
|
|
208
|
+
recommended_channel = result.recommended_channel # Type: str
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Message Optimization
|
|
212
|
+
|
|
213
|
+
Enhance your messages for better customer engagement:
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
# Optimize your message for maximum engagement
|
|
217
|
+
optimization = client.optimize_message(
|
|
218
|
+
message_history=customer_messages,
|
|
219
|
+
candidate_message=candidate_response,
|
|
220
|
+
customer_id="customer-uuid",
|
|
221
|
+
zip_code="12345",
|
|
222
|
+
company_guid="company-uuid"
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
print(f"Original: {optimization.original_message}")
|
|
226
|
+
print(f"Optimized: {optimization.optimized_message}")
|
|
227
|
+
print(f"Recommended channel: {optimization.recommended_channel}")
|
|
228
|
+
print(f"Message ID: {optimization.message_id}")
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Feedback Tracking
|
|
232
|
+
|
|
233
|
+
Monitor message performance and learn from customer interactions:
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
# Track how customers respond to your messages
|
|
237
|
+
result = client.submit_single_feedback(
|
|
238
|
+
message_id="message-id-from-optimization",
|
|
239
|
+
customer_responded=True,
|
|
240
|
+
score="good", # "good", "bad", or "neutral"
|
|
241
|
+
actual_sent_message="The actual message you sent" # Optional
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
print(f"Feedback recorded with ID: {result.id}")
|
|
245
|
+
print(f"Submitted at: {result.inserted_at}")
|
|
246
|
+
|
|
247
|
+
# Or submit multiple feedback items at once
|
|
248
|
+
feedback_list = [
|
|
249
|
+
{
|
|
250
|
+
"message_id": "msg-uuid-1",
|
|
251
|
+
"customer_responded": True,
|
|
252
|
+
"score": "good",
|
|
253
|
+
"actual_sent_message": "Message 1 content"
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"message_id": "msg-uuid-2",
|
|
257
|
+
"customer_responded": False,
|
|
258
|
+
"score": "neutral"
|
|
259
|
+
}
|
|
260
|
+
]
|
|
261
|
+
results = client.submit_feedback_bulk(feedback_list)
|
|
262
|
+
print(f"Submitted {results.count} feedback items")
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## 🔧 Configuration
|
|
266
|
+
|
|
267
|
+
### Environment Variables
|
|
268
|
+
|
|
269
|
+
Set these for production deployment:
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
# Required
|
|
273
|
+
export APALA_API_KEY="your-production-api-key"
|
|
274
|
+
export APALA_BASE_URL="https://your-phoenix-server.com"
|
|
275
|
+
export APALA_COMPANY_GUID="your-company-uuid"
|
|
276
|
+
|
|
277
|
+
# Optional
|
|
278
|
+
export APALA_CUSTOMER_ID="default-customer-uuid" # For testing
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Client Configuration
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
# Basic configuration
|
|
285
|
+
client = ApalaClient(
|
|
286
|
+
api_key="your-key",
|
|
287
|
+
base_url="https://api.yourcompany.com"
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
# Advanced usage with custom session
|
|
291
|
+
import requests
|
|
292
|
+
session = requests.Session()
|
|
293
|
+
session.timeout = 30 # Custom timeout
|
|
294
|
+
client = ApalaClient(api_key="your-key")
|
|
295
|
+
client._session = session
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## 🧪 Testing & Development
|
|
299
|
+
|
|
300
|
+
### Setup
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
# Clone and install in development mode with uv
|
|
304
|
+
git clone <repository-url>
|
|
305
|
+
cd apala_api
|
|
306
|
+
uv sync --group dev
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Running Tests
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
# Run unit tests
|
|
313
|
+
uv run pytest tests/test_models.py tests/test_client.py -v
|
|
314
|
+
|
|
315
|
+
# Run with coverage
|
|
316
|
+
uv run pytest --cov=apala_client --cov-report=html
|
|
317
|
+
|
|
318
|
+
# Run integration tests (requires running server)
|
|
319
|
+
# In Fish shell:
|
|
320
|
+
env RUN_INTEGRATION_TESTS=1 APALA_API_KEY=test-key APALA_COMPANY_GUID=test-company-uuid uv run pytest tests/test_integration.py
|
|
321
|
+
|
|
322
|
+
# In Bash/Zsh:
|
|
323
|
+
export RUN_INTEGRATION_TESTS=1 APALA_API_KEY=test-key APALA_COMPANY_GUID=test-company-uuid
|
|
324
|
+
uv run pytest tests/test_integration.py
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Code Quality
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
# Static type checking
|
|
331
|
+
uv run mypy .
|
|
332
|
+
|
|
333
|
+
# Linting
|
|
334
|
+
uv run ruff check .
|
|
335
|
+
|
|
336
|
+
# Code formatting
|
|
337
|
+
uv run ruff format .
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Documentation
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
# Build HTML documentation
|
|
344
|
+
uv run sphinx-build -b html docs docs/_build/html
|
|
345
|
+
|
|
346
|
+
# Build with live reload (auto-refreshes on changes)
|
|
347
|
+
uv run sphinx-autobuild docs docs/_build/html --port 8001
|
|
348
|
+
|
|
349
|
+
# Clean build directory
|
|
350
|
+
uv run python -c "import shutil; shutil.rmtree('docs/_build', ignore_errors=True)"
|
|
351
|
+
|
|
352
|
+
# Check for broken links
|
|
353
|
+
uv run sphinx-build -b linkcheck docs docs/_build/linkcheck
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Multi-Python Testing
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
# Test across Python versions
|
|
360
|
+
uv run tox
|
|
361
|
+
|
|
362
|
+
# Test specific version
|
|
363
|
+
uv run tox -e py311
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## 📊 Interactive Demo
|
|
367
|
+
|
|
368
|
+
Try the complete workflow in an interactive notebook:
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
# Install notebook dependencies
|
|
372
|
+
uv sync --group notebook
|
|
373
|
+
|
|
374
|
+
# Run the interactive demo
|
|
375
|
+
cd notebooks
|
|
376
|
+
marimo run apala_demo_marimo.py
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
The demo covers:
|
|
380
|
+
- 🔐 Authentication setup
|
|
381
|
+
- 📝 Creating message history
|
|
382
|
+
- 🎯 Message optimization (with optional metadata)
|
|
383
|
+
- 📊 Feedback submission
|
|
384
|
+
- 🔄 Complete end-to-end workflow example
|
|
385
|
+
|
|
386
|
+
## 🛡️ Error Handling
|
|
387
|
+
|
|
388
|
+
The SDK uses standard Python exceptions - no custom error types to learn:
|
|
389
|
+
|
|
390
|
+
```python
|
|
391
|
+
import requests
|
|
392
|
+
from apala_client import ApalaClient
|
|
393
|
+
|
|
394
|
+
client = ApalaClient(api_key="your-key")
|
|
395
|
+
|
|
396
|
+
try:
|
|
397
|
+
# All SDK methods may raise requests exceptions
|
|
398
|
+
response = client.optimize_message(...)
|
|
399
|
+
|
|
400
|
+
except requests.HTTPError as e:
|
|
401
|
+
# HTTP errors (4xx, 5xx responses)
|
|
402
|
+
print(f"HTTP {e.response.status_code}: {e}")
|
|
403
|
+
|
|
404
|
+
except requests.ConnectionError as e:
|
|
405
|
+
# Network connectivity issues
|
|
406
|
+
print(f"Connection failed: {e}")
|
|
407
|
+
|
|
408
|
+
except requests.Timeout as e:
|
|
409
|
+
# Request timeout
|
|
410
|
+
print(f"Request timed out: {e}")
|
|
411
|
+
|
|
412
|
+
except requests.RequestException as e:
|
|
413
|
+
# Any other requests-related error
|
|
414
|
+
print(f"Request error: {e}")
|
|
415
|
+
|
|
416
|
+
except ValueError as e:
|
|
417
|
+
# Data validation errors (invalid UUIDs, etc.)
|
|
418
|
+
print(f"Invalid data: {e}")
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
## 🔍 API Reference
|
|
422
|
+
|
|
423
|
+
### ApalaClient
|
|
424
|
+
|
|
425
|
+
Main client class for all API interactions.
|
|
426
|
+
|
|
427
|
+
#### Constructor
|
|
428
|
+
```python
|
|
429
|
+
ApalaClient(api_key: str, base_url: str = "http://localhost:4000")
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
#### Methods
|
|
433
|
+
|
|
434
|
+
| Method | Return Type | Description |
|
|
435
|
+
|--------|-------------|-------------|
|
|
436
|
+
| `authenticate()` | `AuthResponse` | Exchange API key for JWT tokens |
|
|
437
|
+
| `refresh_access_token()` | `RefreshResponse` | Refresh access token |
|
|
438
|
+
| `message_process(...)` | `MessageProcessingResponse` | Process customer messages |
|
|
439
|
+
| `optimize_message(...)` | `MessageOptimizationResponse` | Optimize message content |
|
|
440
|
+
| `submit_single_feedback(...)` | `FeedbackResponse` | Submit single feedback |
|
|
441
|
+
| `submit_feedback_bulk(...)` | `BulkFeedbackResponse` | Submit multiple feedback items |
|
|
442
|
+
| `message_feedback(...)` | `BulkFeedbackResponse` | Alias for submit_feedback_bulk |
|
|
443
|
+
| `close()` | `None` | Close HTTP session |
|
|
444
|
+
|
|
445
|
+
### Data Models
|
|
446
|
+
|
|
447
|
+
#### Message
|
|
448
|
+
Customer or candidate message with validation.
|
|
449
|
+
|
|
450
|
+
```python
|
|
451
|
+
@dataclass
|
|
452
|
+
class Message:
|
|
453
|
+
content: str # Message text
|
|
454
|
+
channel: str # "SMS", "EMAIL", "OTHER"
|
|
455
|
+
message_id: Optional[str] = None # Auto-generated if None
|
|
456
|
+
send_timestamp: Optional[str] = None # Auto-generated if None
|
|
457
|
+
reply_or_not: bool = False # Whether this is a reply
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
#### Feedback Submission
|
|
461
|
+
Submit feedback using the client methods directly (no model class needed):
|
|
462
|
+
|
|
463
|
+
```python
|
|
464
|
+
# Single feedback submission
|
|
465
|
+
client.submit_single_feedback(
|
|
466
|
+
message_id: str, # ID from optimization response
|
|
467
|
+
customer_responded: bool, # Did customer respond?
|
|
468
|
+
score: str, # Quality rating: "good", "bad", or "neutral"
|
|
469
|
+
actual_sent_message: Optional[str] = None # What you actually sent
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
# Bulk feedback submission
|
|
473
|
+
client.submit_feedback_bulk([
|
|
474
|
+
{
|
|
475
|
+
"message_id": str,
|
|
476
|
+
"customer_responded": bool,
|
|
477
|
+
"score": str, # "good", "bad", or "neutral"
|
|
478
|
+
"actual_sent_message": str # Optional
|
|
479
|
+
},
|
|
480
|
+
# ... more feedback items
|
|
481
|
+
])
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Response Types
|
|
485
|
+
|
|
486
|
+
All API responses are fully typed with Pydantic models:
|
|
487
|
+
|
|
488
|
+
#### AuthResponse
|
|
489
|
+
```python
|
|
490
|
+
class AuthResponse(BaseModel):
|
|
491
|
+
access_token: str
|
|
492
|
+
refresh_token: str
|
|
493
|
+
token_type: str
|
|
494
|
+
expires_in: int
|
|
495
|
+
company_id: str
|
|
496
|
+
company_name: str
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
#### MessageOptimizationResponse
|
|
500
|
+
```python
|
|
501
|
+
class MessageOptimizationResponse(BaseModel):
|
|
502
|
+
message_id: str
|
|
503
|
+
optimized_message: str
|
|
504
|
+
recommended_channel: str
|
|
505
|
+
original_message: str
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
#### FeedbackResponse
|
|
509
|
+
```python
|
|
510
|
+
class FeedbackResponse(BaseModel):
|
|
511
|
+
id: str
|
|
512
|
+
message_id: str
|
|
513
|
+
customer_responded: bool
|
|
514
|
+
score: Literal["good", "bad", "neutral"]
|
|
515
|
+
actual_sent_message: Optional[str]
|
|
516
|
+
inserted_at: str
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
#### BulkFeedbackResponse
|
|
520
|
+
```python
|
|
521
|
+
class BulkFeedbackResponse(BaseModel):
|
|
522
|
+
success: bool
|
|
523
|
+
count: int
|
|
524
|
+
feedback: List[FeedbackItemResponse]
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
*See full API documentation for complete type definitions.*
|
|
528
|
+
|
|
529
|
+
## 🤝 Contributing
|
|
530
|
+
|
|
531
|
+
We welcome contributions! Please see our contributing guidelines:
|
|
532
|
+
|
|
533
|
+
1. **Fork** the repository
|
|
534
|
+
2. **Create** a feature branch (`git checkout -b feature/amazing-feature`)
|
|
535
|
+
3. **Add tests** for new functionality
|
|
536
|
+
4. **Run the test suite** (`pytest` and `mypy apala_client`)
|
|
537
|
+
5. **Commit** your changes (`git commit -m 'Add amazing feature'`)
|
|
538
|
+
6. **Push** to your branch (`git push origin feature/amazing-feature`)
|
|
539
|
+
7. **Create** a Pull Request
|
|
540
|
+
|
|
541
|
+
### Development Setup
|
|
542
|
+
|
|
543
|
+
```bash
|
|
544
|
+
git clone <your-fork>
|
|
545
|
+
cd apala_api
|
|
546
|
+
uv sync --group dev
|
|
547
|
+
|
|
548
|
+
# Run all checks before submitting
|
|
549
|
+
uv run pytest # Unit tests
|
|
550
|
+
uv run mypy apala_client # Type checking
|
|
551
|
+
uv run ruff check apala_client # Linting
|
|
552
|
+
uv run ruff format apala_client # Formatting
|
|
553
|
+
uv run tox # Multi-Python testing
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
## 📄 License
|
|
557
|
+
|
|
558
|
+
Copyright (c) 2025 Apala Cap. All rights reserved.
|
|
559
|
+
|
|
560
|
+
This software is proprietary and confidential. Unauthorized copying, distribution, or use of this software, via any medium, is strictly prohibited.
|
|
561
|
+
|
|
562
|
+
## 🔗 Links
|
|
563
|
+
|
|
564
|
+
- **Documentation**: [Full API Documentation](docs/)
|
|
565
|
+
- **Source Code**: [GitHub Repository](#)
|
|
566
|
+
- **Issue Tracker**: [GitHub Issues](#)
|
|
567
|
+
- **PyPI Package**: [apala-api](#)
|
|
568
|
+
|
|
569
|
+
## 💬 Support
|
|
570
|
+
|
|
571
|
+
- **GitHub Issues**: For bugs and feature requests
|
|
572
|
+
- **Documentation**: Complete API reference and guides
|
|
573
|
+
- **Type Safety**: Full mypy support for development-time error catching
|
|
574
|
+
|
|
575
|
+
---
|
|
576
|
+
|
|
577
|
+
*Apala API - Proprietary Software by Apala Cap*
|