mim-ai 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mim_ai-0.1.0/LICENSE +21 -0
- mim_ai-0.1.0/PKG-INFO +362 -0
- mim_ai-0.1.0/README.md +285 -0
- mim_ai-0.1.0/mim_ai/__init__.py +241 -0
- mim_ai-0.1.0/mim_ai/__main__.py +51 -0
- mim_ai-0.1.0/mim_ai/_http.py +194 -0
- mim_ai-0.1.0/mim_ai/anonymizer/__init__.py +16 -0
- mim_ai-0.1.0/mim_ai/anonymizer/anonymizer.py +142 -0
- mim_ai-0.1.0/mim_ai/anonymizer/config.py +81 -0
- mim_ai-0.1.0/mim_ai/anonymizer/operators.py +92 -0
- mim_ai-0.1.0/mim_ai/anonymizer/recognizers/__init__.py +4 -0
- mim_ai-0.1.0/mim_ai/anonymizer/recognizers/base.py +19 -0
- mim_ai-0.1.0/mim_ai/anonymizer/recognizers/custom.py +36 -0
- mim_ai-0.1.0/mim_ai/anonymizer/recognizers/morocco_patterns.py +41 -0
- mim_ai-0.1.0/mim_ai/audit/__init__.py +25 -0
- mim_ai-0.1.0/mim_ai/audit/audit_logger.py +249 -0
- mim_ai-0.1.0/mim_ai/audit/backends.py +665 -0
- mim_ai-0.1.0/mim_ai/audit/config.py +113 -0
- mim_ai-0.1.0/mim_ai/audit/normalizer_logger.py +137 -0
- mim_ai-0.1.0/mim_ai/audit/redaction.py +35 -0
- mim_ai-0.1.0/mim_ai/audit/schema.sql +41 -0
- mim_ai-0.1.0/mim_ai/audit/verify.py +101 -0
- mim_ai-0.1.0/mim_ai/chatbot/__init__.py +45 -0
- mim_ai-0.1.0/mim_ai/chatbot/chatbot.py +463 -0
- mim_ai-0.1.0/mim_ai/chatbot/config.py +106 -0
- mim_ai-0.1.0/mim_ai/chatbot/history.py +320 -0
- mim_ai-0.1.0/mim_ai/chatbot/llm.py +221 -0
- mim_ai-0.1.0/mim_ai/chatbot/prompt_templates.py +58 -0
- mim_ai-0.1.0/mim_ai/chatbot/tools.py +304 -0
- mim_ai-0.1.0/mim_ai/config.py +298 -0
- mim_ai-0.1.0/mim_ai/default_config.yaml +151 -0
- mim_ai-0.1.0/mim_ai/intents/__init__.py +13 -0
- mim_ai-0.1.0/mim_ai/intents/config.py +51 -0
- mim_ai-0.1.0/mim_ai/intents/example_intents.yaml +49 -0
- mim_ai-0.1.0/mim_ai/intents/registry.py +308 -0
- mim_ai-0.1.0/mim_ai/morocco_patterns.py +6 -0
- mim_ai-0.1.0/mim_ai/normalizer/__init__.py +69 -0
- mim_ai-0.1.0/mim_ai/normalizer/arabizi.py +142 -0
- mim_ai-0.1.0/mim_ai/normalizer/darija_rules.py +320 -0
- mim_ai-0.1.0/mim_ai/normalizer/data/__init__.py +1 -0
- mim_ai-0.1.0/mim_ai/normalizer/data/darija_variants.yaml +146 -0
- mim_ai-0.1.0/mim_ai/normalizer/data/skip_words.yaml +6 -0
- mim_ai-0.1.0/mim_ai/normalizer/dictionary.py +32 -0
- mim_ai-0.1.0/mim_ai/normalizer/layers/__init__.py +6 -0
- mim_ai-0.1.0/mim_ai/normalizer/layers/arabic_rules.py +313 -0
- mim_ai-0.1.0/mim_ai/normalizer/layers/base.py +22 -0
- mim_ai-0.1.0/mim_ai/normalizer/layers/cleaning.py +131 -0
- mim_ai-0.1.0/mim_ai/normalizer/layers/rules.py +28 -0
- mim_ai-0.1.0/mim_ai/normalizer/normalizer.py +104 -0
- mim_ai-0.1.0/mim_ai/normalizer/schema.py +90 -0
- mim_ai-0.1.0/mim_ai/utils/__init__.py +0 -0
- mim_ai-0.1.0/mim_ai/utils/unicode_helpers.py +44 -0
- mim_ai-0.1.0/mim_ai/voice/__init__.py +13 -0
- mim_ai-0.1.0/mim_ai/voice/audio.py +177 -0
- mim_ai-0.1.0/mim_ai/voice/pipeline.py +268 -0
- mim_ai-0.1.0/mim_ai/voice/stt.py +48 -0
- mim_ai-0.1.0/mim_ai/voice/tts.py +66 -0
- mim_ai-0.1.0/mim_ai/voice/voice_agent.py +16 -0
- mim_ai-0.1.0/mim_ai.egg-info/PKG-INFO +362 -0
- mim_ai-0.1.0/mim_ai.egg-info/SOURCES.txt +71 -0
- mim_ai-0.1.0/mim_ai.egg-info/dependency_links.txt +1 -0
- mim_ai-0.1.0/mim_ai.egg-info/entry_points.txt +2 -0
- mim_ai-0.1.0/mim_ai.egg-info/requires.txt +63 -0
- mim_ai-0.1.0/mim_ai.egg-info/top_level.txt +1 -0
- mim_ai-0.1.0/pyproject.toml +129 -0
- mim_ai-0.1.0/setup.cfg +4 -0
- mim_ai-0.1.0/tests/test_audit.py +856 -0
- mim_ai-0.1.0/tests/test_ci_report.py +76 -0
- mim_ai-0.1.0/tests/test_example_auth.py +59 -0
- mim_ai-0.1.0/tests/test_intents.py +804 -0
- mim_ai-0.1.0/tests/test_mim.py +306 -0
- mim_ai-0.1.0/tests/test_normalizer.py +395 -0
- mim_ai-0.1.0/tests/test_voice.py +748 -0
mim_ai-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Salman KHATIB
|
|
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.
|
mim_ai-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mim-ai
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A configuration-first Python SDK for building production-grade Moroccan Darija AI applications β normalizer, anonymizer, chatbot, voice pipeline, and Law 09-08 audit trail.
|
|
5
|
+
Author: Salman KHATIB
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Salmankhatib/mim-ai
|
|
8
|
+
Project-URL: Repository, https://github.com/Salmankhatib/mim-ai
|
|
9
|
+
Project-URL: Documentation, https://github.com/Salmankhatib/mim-ai/tree/main/docs/EN
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/Salmankhatib/mim-ai/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/Salmankhatib/mim-ai/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: darija,arabic,moroccan,chatbot,voice-agent,stt,tts,anonymizer,audit,arabizi,normalizer
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Natural Language :: Arabic
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
25
|
+
Requires-Python: >=3.9
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: pyyaml>=6.0
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
32
|
+
Requires-Dist: black>=23.0; extra == "dev"
|
|
33
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
34
|
+
Requires-Dist: build>=1.2.0; extra == "dev"
|
|
35
|
+
Requires-Dist: twine>=5.0.0; extra == "dev"
|
|
36
|
+
Requires-Dist: fastapi<1.0.0,>=0.115.0; extra == "dev"
|
|
37
|
+
Requires-Dist: pydub<1.0.0,>=0.25.1; extra == "dev"
|
|
38
|
+
Provides-Extra: voice
|
|
39
|
+
Requires-Dist: numpy>=1.26; extra == "voice"
|
|
40
|
+
Requires-Dist: sounddevice>=0.4.6; extra == "voice"
|
|
41
|
+
Requires-Dist: soundfile>=0.12.1; extra == "voice"
|
|
42
|
+
Provides-Extra: anonymizer
|
|
43
|
+
Requires-Dist: presidio-analyzer>=2.2.0; extra == "anonymizer"
|
|
44
|
+
Requires-Dist: presidio-anonymizer>=2.2.0; extra == "anonymizer"
|
|
45
|
+
Requires-Dist: spacy<3.8; python_version < "3.10" and extra == "anonymizer"
|
|
46
|
+
Provides-Extra: redis
|
|
47
|
+
Requires-Dist: redis>=5.0.0; extra == "redis"
|
|
48
|
+
Provides-Extra: postgresql
|
|
49
|
+
Requires-Dist: psycopg[binary]>=3.1.0; extra == "postgresql"
|
|
50
|
+
Provides-Extra: mysql
|
|
51
|
+
Requires-Dist: PyMySQL>=1.1.0; extra == "mysql"
|
|
52
|
+
Provides-Extra: mongodb
|
|
53
|
+
Requires-Dist: pymongo>=4.8.0; extra == "mongodb"
|
|
54
|
+
Provides-Extra: production
|
|
55
|
+
Requires-Dist: psycopg[binary]>=3.1.0; extra == "production"
|
|
56
|
+
Requires-Dist: PyMySQL>=1.1.0; extra == "production"
|
|
57
|
+
Requires-Dist: pymongo>=4.8.0; extra == "production"
|
|
58
|
+
Requires-Dist: numpy>=1.26; extra == "production"
|
|
59
|
+
Requires-Dist: sounddevice>=0.4.6; extra == "production"
|
|
60
|
+
Requires-Dist: soundfile>=0.12.1; extra == "production"
|
|
61
|
+
Requires-Dist: presidio-analyzer>=2.2.0; extra == "production"
|
|
62
|
+
Requires-Dist: presidio-anonymizer>=2.2.0; extra == "production"
|
|
63
|
+
Requires-Dist: spacy<3.8; python_version < "3.10" and extra == "production"
|
|
64
|
+
Requires-Dist: redis>=5.0.0; extra == "production"
|
|
65
|
+
Provides-Extra: all
|
|
66
|
+
Requires-Dist: psycopg[binary]>=3.1.0; extra == "all"
|
|
67
|
+
Requires-Dist: PyMySQL>=1.1.0; extra == "all"
|
|
68
|
+
Requires-Dist: pymongo>=4.8.0; extra == "all"
|
|
69
|
+
Requires-Dist: numpy>=1.26; extra == "all"
|
|
70
|
+
Requires-Dist: sounddevice>=0.4.6; extra == "all"
|
|
71
|
+
Requires-Dist: soundfile>=0.12.1; extra == "all"
|
|
72
|
+
Requires-Dist: presidio-analyzer>=2.2.0; extra == "all"
|
|
73
|
+
Requires-Dist: presidio-anonymizer>=2.2.0; extra == "all"
|
|
74
|
+
Requires-Dist: spacy<3.8; python_version < "3.10" and extra == "all"
|
|
75
|
+
Requires-Dist: redis>=5.0.0; extra == "all"
|
|
76
|
+
Dynamic: license-file
|
|
77
|
+
|
|
78
|
+
# MIM β Mim AI
|
|
79
|
+
|
|
80
|
+
[](https://pypi.org/project/mim-ai/)
|
|
81
|
+
[](https://pypi.org/project/mim-ai/)
|
|
82
|
+
[](https://opensource.org/licenses/MIT)
|
|
83
|
+
[](https://github.com/Salmankhatib/mim-ai/actions/workflows/tests.yml)
|
|
84
|
+
[](https://github.com/Salmankhatib/mim-ai)
|
|
85
|
+
|
|
86
|
+
> **A config-first Python SDK for Moroccan Darija AI.**
|
|
87
|
+
> Built by a Moroccan developer, for Moroccan developers.
|
|
88
|
+
> The last-mile bridge between Morocco's open-source AI models and the apps that use them.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## π²π¦ The Gap
|
|
93
|
+
|
|
94
|
+
Morocco is building its AI foundation fast. The **MTNRAβMistral AI convention** (signed September 2025) has already delivered open-source bricks: a Darija language-identification classifier and a Voxtral-based speech recognition model. The **Sovereign AI Marketplace** and **Idarati AI** are rolling out. The **Maroc IA 2030** roadmap targets 100 billion MAD in GDP contribution and 50,000 new jobs.
|
|
95
|
+
|
|
96
|
+
**The models are arriving. What's missing is the last mile.**
|
|
97
|
+
|
|
98
|
+
A developer who wants to build a voice-enabled Darija app today still has to:
|
|
99
|
+
|
|
100
|
+
1. Find the right model.
|
|
101
|
+
2. Figure out how to run it.
|
|
102
|
+
3. Handle audio I/O.
|
|
103
|
+
4. Clean up messy Darija/Arabizi text before it reaches an LLM.
|
|
104
|
+
5. Anonymize PII before logging.
|
|
105
|
+
6. Log everything so it survives a Law 09-08 compliance review.
|
|
106
|
+
|
|
107
|
+
That's a week of work before the first feature ships. **MIM is an opinionated answer to that gap.**
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## β¨ What MIM Is
|
|
112
|
+
|
|
113
|
+
A small Python SDK that gives Moroccan developers a **drop-in pipeline** for Darija text and voice:
|
|
114
|
+
|
|
115
|
+
- π§Ή **Normalizer** β Cleans real-world Darija (Arabizi, code-switching, inconsistent orthography) before it hits a model. Runs in **under 5 ms**, zero GPU.
|
|
116
|
+
- π‘οΈ **Anonymizer** β Config-first PII redaction using Presidio, with Morocco-specific CIN and phone patterns.
|
|
117
|
+
- π€ **Chatbot** β Wraps any LLM with tools, sessions, and intent classification. Pre-wired for MNTRA/Mistral endpoints.
|
|
118
|
+
- ποΈ **Voice** β STT β Normalizer β Chatbot β TTS full pipeline. Three methods, one config, zero bloat.
|
|
119
|
+
- π **Audit** β Hash-chained audit trail aligned with **Law 09-08** and **ISO 42001**. Out-of-the-box compliance.
|
|
120
|
+
|
|
121
|
+
*One YAML file. Any model. Any endpoint.*
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## π« What MIM Is Not
|
|
126
|
+
|
|
127
|
+
- **Not a model:** We don't train anything.
|
|
128
|
+
- **Not a framework:** We don't want you to learn a new abstraction.
|
|
129
|
+
- **Not the final word:** It's a proposition β open for community contribution.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## π Quick Start
|
|
134
|
+
|
|
135
|
+
### 1. Install
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
pip install mim-ai
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The base install supports the normalizer and config-driven text workflows. Install optional extras only for the features you use:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# Microphone/speaker I/O and optional non-WAV audio decoding
|
|
145
|
+
pip install "mim-ai[voice]"
|
|
146
|
+
|
|
147
|
+
# PII anonymization (also requires the spaCy model described below)
|
|
148
|
+
pip install "mim-ai[anonymizer]"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 2. Generate Your Config
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
mim-init
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
This creates the canonical `mim_config.yaml` in the current project directory. Review its endpoint, model, and enable/disable settings before using remote or optional features.
|
|
158
|
+
|
|
159
|
+
### 3. Use It
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from mim_ai import Mim
|
|
163
|
+
|
|
164
|
+
# Load the config generated above. Components initialize only when used.
|
|
165
|
+
mim = Mim.from_config("mim_config.yaml")
|
|
166
|
+
|
|
167
|
+
# Normalization works with the base install; it does not call a model endpoint.
|
|
168
|
+
normalized = mim.normalizer.normalize("salam wa7ed 3la ekher")
|
|
169
|
+
print(normalized) # salam wa7ed 3la ekher
|
|
170
|
+
|
|
171
|
+
mim.shutdown()
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`load_config()` defaults to `mim_config.yaml`, reads only that exact file, and never creates config files or searches legacy filenames. Run `mim-init` (or call `write_default_config()`) explicitly before loading a generated config.
|
|
175
|
+
|
|
176
|
+
To use chat, set the API key named by `chatbot.llm_api_key_env` in your environment and configure `chatbot.llm_endpoint` and `chatbot.llm_model` in `mim_config.yaml`. The default chatbot endpoint is MNTRA's OpenAI-compatible API and expects `MNTRA_API_KEY`; compatible endpoints that do not require authentication can leave the key unset.
|
|
177
|
+
|
|
178
|
+
### CI and test reports
|
|
179
|
+
|
|
180
|
+
GitHub Actions runs Ruff and the test suites separately for each module. It also uploads a PDF test-results summary with each run. Optional SMTP delivery can be enabled using GitHub Actions secrets; see [CI setup](.github/CI.md) for the secret names and configuration.
|
|
181
|
+
|
|
182
|
+
The generated config starts with chatbot tools and chatbot intent classification disabled, so chat is a regular text-completion flow by default. Voice intent classification is separately enabled in the generated config and uses the configured registry (empty unless you provide an intent file). Set `chatbot.system_prompt` to your full custom prompt; `system_prompt_extra` and `system_prompt_file` let you add reusable instructions:
|
|
183
|
+
|
|
184
|
+
```yaml
|
|
185
|
+
chatbot:
|
|
186
|
+
enabled: true
|
|
187
|
+
llm_endpoint: https://api.mntra.ma/v1
|
|
188
|
+
llm_model: mntra/mistral-darija
|
|
189
|
+
llm_api_key_env: MNTRA_API_KEY
|
|
190
|
+
enable_tools: false
|
|
191
|
+
use_intents: false
|
|
192
|
+
system_prompt: |
|
|
193
|
+
You are a helpful customer support assistant for Acme.
|
|
194
|
+
Answer in the language used by the customer.
|
|
195
|
+
Be clear and concise. Do not invent company policies.
|
|
196
|
+
system_prompt_extra: |
|
|
197
|
+
If you cannot answer from the information provided, say so and offer a human handoff.
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
from mim_ai import Mim
|
|
202
|
+
|
|
203
|
+
mim = Mim.from_config("mim_config.yaml")
|
|
204
|
+
message = input("You: ").strip()
|
|
205
|
+
if message:
|
|
206
|
+
reply = mim.chat(message, session_id="user-42")
|
|
207
|
+
if reply.error:
|
|
208
|
+
raise RuntimeError(reply.error)
|
|
209
|
+
print(f"Assistant: {reply.text}")
|
|
210
|
+
mim.shutdown()
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Voice requires the `voice` extra, an available microphone/speaker (and any OS audio libraries required by `sounddevice`), plus reachable STT/TTS endpoints. The default STT/TTS configs use `OPENAI_API_KEY`; set the environment variables configured by `stt.api_key_env` and `tts.api_key_env` before calling `listen_and_reply()`. If voice also uses chat, configure that endpoint's key as well. A TTS endpoint can be disabled when only a transcript or text reply is needed.
|
|
214
|
+
|
|
215
|
+
Anonymization requires the `anonymizer` extra and its spaCy model; it is not available from the base install alone. See the [anonymizer setup guide](docs/anonymizer/README.md).
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## β‘ The Normalizer β Built for Production
|
|
220
|
+
|
|
221
|
+
Real-time applications don't have 300 ms to spare on text cleaning.
|
|
222
|
+
|
|
223
|
+
The MIM normalizer runs in **under 5 ms on a modern CPU** with **zero model inference**. It is pure Python: Unicode normalization, a hand-curated Arabizi dictionary, and Arabic-script rules. No neural network, no GPU, no warmup.
|
|
224
|
+
|
|
225
|
+
For a voice pipeline, that's the difference between a live conversation and a laggy one.
|
|
226
|
+
|
|
227
|
+
### Pipeline Layers (Cheapest First)
|
|
228
|
+
|
|
229
|
+
| Layer | Speed / Cost | What it does |
|
|
230
|
+
| --- | --- | --- |
|
|
231
|
+
| **1 β Universal Cleaning** | `~0 ms` | Whitespace, control characters, URL protection |
|
|
232
|
+
| **2 β Rule-based Darija** | `< 5 ms` | Alef/Ya unification, Arabizi dictionary lookup *(Default)* |
|
|
233
|
+
|
|
234
|
+
> **Dictionary Customization:** The dictionary is yours to grow. Ship a base of common Darija, add your app's jargon in a side file. Every skipped token is logged so you can refine from real usage, not guesses.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## π‘οΈ Anonymizer β Morocco-Specific PII Redaction
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
from mim_ai import anonymize
|
|
242
|
+
|
|
243
|
+
result = anonymize("Mon CIN est AB58075 et mon tel est 0612345678")
|
|
244
|
+
print(result.text) # Mon CIN est [CIN_MA] et mon tel est ****345678
|
|
245
|
+
print(result.entities_found) # [{'type': 'CIN_MA', 'start': 12, 'end': 19, 'score': 0.85}, ...]
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Built on top of Microsoft Presidio with native Moroccan recognizers:
|
|
249
|
+
- **CIN patterns** (Carte d'IdentitΓ© Nationale) β `AB123456`, `A123456`, etc.
|
|
250
|
+
- **Moroccan phone numbers** β supported mobile and fixed-line prefixes
|
|
251
|
+
- Fully configurable per-entity operators: `replace`, `mask`, `hash`, `redact`
|
|
252
|
+
|
|
253
|
+
Presidio requires the English spaCy model. Install it after `mim-ai` and before using the anonymizer:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
python -m spacy download en_core_web_lg
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
There is no automatic regex-only fallback. See the [anonymizer setup guide](docs/anonymizer/README.md) for details.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## π Compliance β Law 09-08 & ISO 42001
|
|
264
|
+
|
|
265
|
+
MIM provides audit-log features intended to support compliance workflows:
|
|
266
|
+
|
|
267
|
+
```yaml
|
|
268
|
+
audit:
|
|
269
|
+
enabled: true
|
|
270
|
+
backend: sqlite
|
|
271
|
+
hash_chain: true # tamper-evident chain
|
|
272
|
+
retention_days: 90 # auto-purge on schedule
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
When enabled, chat turns are logged with a hash chain and retention is applied automatically. A retention purge appends a hash-chained checkpoint that starts a verifiable new chain segment. SQLite supports access and erasure helpers; erasing records outside the retention purge workflow breaks the chain, so retain and review verification evidence according to your organization's legal and compliance requirements. MIM is a technical component, not a compliance certification or legal guarantee.
|
|
276
|
+
|
|
277
|
+
Verify a configured audit chain with the same backend settings:
|
|
278
|
+
|
|
279
|
+
```python
|
|
280
|
+
from mim_ai import load_config
|
|
281
|
+
from mim_ai.audit import verify_chain
|
|
282
|
+
|
|
283
|
+
audit_config = load_config("mim_config.yaml").audit
|
|
284
|
+
ok, message = verify_chain(config=audit_config)
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
SQLite, JSONL, PostgreSQL, MySQL, and MongoDB have built-in ordered readers. A custom audit adapter must implement `iter_chain_records()` to enable verification; multi-writer custom adapters must also implement the existing atomic `append_chained()` contract.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## π²π¦ Made in Morocco, for Morocco
|
|
292
|
+
|
|
293
|
+
This is a **Made in Morocco** tool, built in step with the national AI strategy:
|
|
294
|
+
|
|
295
|
+
* **Aligned with Maroc IA 2030** β Contributing toward the 100B MAD GDP target, 50,000 jobs, and 200,000 trained talents.
|
|
296
|
+
|
|
297
|
+
* **MTNRAβMistral Partnership** β Pre-configured for the MNTRA/Mistral Darija API endpoint. When Morocco's sovereign models ship, MIM is already wired for them.
|
|
298
|
+
|
|
299
|
+
* **Ecosystem Integration** β Built to plug directly into the Sovereign AI Marketplace and to serve Idarati AI and public-facing government services.
|
|
300
|
+
|
|
301
|
+
* **Compliant by Design** β Aligned with **Law 09-08** (audit logs hash user text, honor erasure requests, and expire on schedule) and **ISO 42001**.
|
|
302
|
+
|
|
303
|
+
*MIM is not infrastructure. It's the glue between the infrastructure Morocco is building and the applications Morocco's developers want to ship.*
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## π What's Inside
|
|
308
|
+
|
|
309
|
+
```text
|
|
310
|
+
mim_ai/
|
|
311
|
+
βββ anonymizer/ # Config-first PII redaction with Presidio + Morocco-specific rules
|
|
312
|
+
βββ normalizer/ # Fast, config-first Darija text normalization (< 5 ms, zero GPU)
|
|
313
|
+
βββ chatbot/ # LLM wrapper with tools, sessions, intents
|
|
314
|
+
βββ voice/ # STT, TTS, VAD, full listen-and-reply pipeline
|
|
315
|
+
βββ intents/ # English-named, multilingual-matched intent registry
|
|
316
|
+
βββ audit/ # Law 09-08 + ISO 42001 aligned logging
|
|
317
|
+
βββ config.py # One YAML, one loader, one Mim object
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
> **Note:** Every subsystem is optional. If your configuration only enables the normalizer, nothing else loads. No torch, no sounddevice, no HTTP client.
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## π Documentation
|
|
325
|
+
|
|
326
|
+
- English: [docs/EN/tutorial.md](docs/EN/tutorial.md)
|
|
327
|
+
- FranΓ§ais: [docs/FR/tutorial.md](docs/FR/tutorial.md)
|
|
328
|
+
- Architecture: [docs/EN/architecture.md](docs/EN/architecture.md) / [docs/FR/architecture.md](docs/FR/architecture.md)
|
|
329
|
+
- Manifesto: [docs/EN/manifesto.md](docs/EN/manifesto.md) / [docs/FR/manifesto.md](docs/FR/manifesto.md)
|
|
330
|
+
- Feature guides: [Normalizer](docs/EN/features/normalizer.md) Β· [Chatbot](docs/EN/features/chatbot.md) Β· [Voice](docs/EN/features/voice.md) Β· [Audit](docs/EN/features/audit.md)
|
|
331
|
+
- Contributing: [docs/EN/contributing.md](docs/EN/contributing.md)
|
|
332
|
+
- Changelog: [CHANGELOG.md](CHANGELOG.md)
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## π§ͺ Minimal Project Example
|
|
337
|
+
|
|
338
|
+
A FastAPI example is included in [examples/project_example.py](examples/project_example.py). It demonstrates how to expose MIM through a simple HTTP service.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## π PyPI Release
|
|
343
|
+
|
|
344
|
+
Before publishing a release candidate:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
python -m pip install --upgrade build twine
|
|
348
|
+
python -m build
|
|
349
|
+
python -m twine check dist/*
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Upload to TestPyPI first:
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
python -m twine upload --repository testpypi dist/*
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Then to PyPI:
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
python -m twine upload dist/*
|
|
362
|
+
```
|
mim_ai-0.1.0/README.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# MIM β Mim AI
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/mim-ai/)
|
|
4
|
+
[](https://pypi.org/project/mim-ai/)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://github.com/Salmankhatib/mim-ai/actions/workflows/tests.yml)
|
|
7
|
+
[](https://github.com/Salmankhatib/mim-ai)
|
|
8
|
+
|
|
9
|
+
> **A config-first Python SDK for Moroccan Darija AI.**
|
|
10
|
+
> Built by a Moroccan developer, for Moroccan developers.
|
|
11
|
+
> The last-mile bridge between Morocco's open-source AI models and the apps that use them.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## π²π¦ The Gap
|
|
16
|
+
|
|
17
|
+
Morocco is building its AI foundation fast. The **MTNRAβMistral AI convention** (signed September 2025) has already delivered open-source bricks: a Darija language-identification classifier and a Voxtral-based speech recognition model. The **Sovereign AI Marketplace** and **Idarati AI** are rolling out. The **Maroc IA 2030** roadmap targets 100 billion MAD in GDP contribution and 50,000 new jobs.
|
|
18
|
+
|
|
19
|
+
**The models are arriving. What's missing is the last mile.**
|
|
20
|
+
|
|
21
|
+
A developer who wants to build a voice-enabled Darija app today still has to:
|
|
22
|
+
|
|
23
|
+
1. Find the right model.
|
|
24
|
+
2. Figure out how to run it.
|
|
25
|
+
3. Handle audio I/O.
|
|
26
|
+
4. Clean up messy Darija/Arabizi text before it reaches an LLM.
|
|
27
|
+
5. Anonymize PII before logging.
|
|
28
|
+
6. Log everything so it survives a Law 09-08 compliance review.
|
|
29
|
+
|
|
30
|
+
That's a week of work before the first feature ships. **MIM is an opinionated answer to that gap.**
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## β¨ What MIM Is
|
|
35
|
+
|
|
36
|
+
A small Python SDK that gives Moroccan developers a **drop-in pipeline** for Darija text and voice:
|
|
37
|
+
|
|
38
|
+
- π§Ή **Normalizer** β Cleans real-world Darija (Arabizi, code-switching, inconsistent orthography) before it hits a model. Runs in **under 5 ms**, zero GPU.
|
|
39
|
+
- π‘οΈ **Anonymizer** β Config-first PII redaction using Presidio, with Morocco-specific CIN and phone patterns.
|
|
40
|
+
- π€ **Chatbot** β Wraps any LLM with tools, sessions, and intent classification. Pre-wired for MNTRA/Mistral endpoints.
|
|
41
|
+
- ποΈ **Voice** β STT β Normalizer β Chatbot β TTS full pipeline. Three methods, one config, zero bloat.
|
|
42
|
+
- π **Audit** β Hash-chained audit trail aligned with **Law 09-08** and **ISO 42001**. Out-of-the-box compliance.
|
|
43
|
+
|
|
44
|
+
*One YAML file. Any model. Any endpoint.*
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## π« What MIM Is Not
|
|
49
|
+
|
|
50
|
+
- **Not a model:** We don't train anything.
|
|
51
|
+
- **Not a framework:** We don't want you to learn a new abstraction.
|
|
52
|
+
- **Not the final word:** It's a proposition β open for community contribution.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## π Quick Start
|
|
57
|
+
|
|
58
|
+
### 1. Install
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install mim-ai
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The base install supports the normalizer and config-driven text workflows. Install optional extras only for the features you use:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Microphone/speaker I/O and optional non-WAV audio decoding
|
|
68
|
+
pip install "mim-ai[voice]"
|
|
69
|
+
|
|
70
|
+
# PII anonymization (also requires the spaCy model described below)
|
|
71
|
+
pip install "mim-ai[anonymizer]"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. Generate Your Config
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
mim-init
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
This creates the canonical `mim_config.yaml` in the current project directory. Review its endpoint, model, and enable/disable settings before using remote or optional features.
|
|
81
|
+
|
|
82
|
+
### 3. Use It
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from mim_ai import Mim
|
|
86
|
+
|
|
87
|
+
# Load the config generated above. Components initialize only when used.
|
|
88
|
+
mim = Mim.from_config("mim_config.yaml")
|
|
89
|
+
|
|
90
|
+
# Normalization works with the base install; it does not call a model endpoint.
|
|
91
|
+
normalized = mim.normalizer.normalize("salam wa7ed 3la ekher")
|
|
92
|
+
print(normalized) # salam wa7ed 3la ekher
|
|
93
|
+
|
|
94
|
+
mim.shutdown()
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`load_config()` defaults to `mim_config.yaml`, reads only that exact file, and never creates config files or searches legacy filenames. Run `mim-init` (or call `write_default_config()`) explicitly before loading a generated config.
|
|
98
|
+
|
|
99
|
+
To use chat, set the API key named by `chatbot.llm_api_key_env` in your environment and configure `chatbot.llm_endpoint` and `chatbot.llm_model` in `mim_config.yaml`. The default chatbot endpoint is MNTRA's OpenAI-compatible API and expects `MNTRA_API_KEY`; compatible endpoints that do not require authentication can leave the key unset.
|
|
100
|
+
|
|
101
|
+
### CI and test reports
|
|
102
|
+
|
|
103
|
+
GitHub Actions runs Ruff and the test suites separately for each module. It also uploads a PDF test-results summary with each run. Optional SMTP delivery can be enabled using GitHub Actions secrets; see [CI setup](.github/CI.md) for the secret names and configuration.
|
|
104
|
+
|
|
105
|
+
The generated config starts with chatbot tools and chatbot intent classification disabled, so chat is a regular text-completion flow by default. Voice intent classification is separately enabled in the generated config and uses the configured registry (empty unless you provide an intent file). Set `chatbot.system_prompt` to your full custom prompt; `system_prompt_extra` and `system_prompt_file` let you add reusable instructions:
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
chatbot:
|
|
109
|
+
enabled: true
|
|
110
|
+
llm_endpoint: https://api.mntra.ma/v1
|
|
111
|
+
llm_model: mntra/mistral-darija
|
|
112
|
+
llm_api_key_env: MNTRA_API_KEY
|
|
113
|
+
enable_tools: false
|
|
114
|
+
use_intents: false
|
|
115
|
+
system_prompt: |
|
|
116
|
+
You are a helpful customer support assistant for Acme.
|
|
117
|
+
Answer in the language used by the customer.
|
|
118
|
+
Be clear and concise. Do not invent company policies.
|
|
119
|
+
system_prompt_extra: |
|
|
120
|
+
If you cannot answer from the information provided, say so and offer a human handoff.
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from mim_ai import Mim
|
|
125
|
+
|
|
126
|
+
mim = Mim.from_config("mim_config.yaml")
|
|
127
|
+
message = input("You: ").strip()
|
|
128
|
+
if message:
|
|
129
|
+
reply = mim.chat(message, session_id="user-42")
|
|
130
|
+
if reply.error:
|
|
131
|
+
raise RuntimeError(reply.error)
|
|
132
|
+
print(f"Assistant: {reply.text}")
|
|
133
|
+
mim.shutdown()
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Voice requires the `voice` extra, an available microphone/speaker (and any OS audio libraries required by `sounddevice`), plus reachable STT/TTS endpoints. The default STT/TTS configs use `OPENAI_API_KEY`; set the environment variables configured by `stt.api_key_env` and `tts.api_key_env` before calling `listen_and_reply()`. If voice also uses chat, configure that endpoint's key as well. A TTS endpoint can be disabled when only a transcript or text reply is needed.
|
|
137
|
+
|
|
138
|
+
Anonymization requires the `anonymizer` extra and its spaCy model; it is not available from the base install alone. See the [anonymizer setup guide](docs/anonymizer/README.md).
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## β‘ The Normalizer β Built for Production
|
|
143
|
+
|
|
144
|
+
Real-time applications don't have 300 ms to spare on text cleaning.
|
|
145
|
+
|
|
146
|
+
The MIM normalizer runs in **under 5 ms on a modern CPU** with **zero model inference**. It is pure Python: Unicode normalization, a hand-curated Arabizi dictionary, and Arabic-script rules. No neural network, no GPU, no warmup.
|
|
147
|
+
|
|
148
|
+
For a voice pipeline, that's the difference between a live conversation and a laggy one.
|
|
149
|
+
|
|
150
|
+
### Pipeline Layers (Cheapest First)
|
|
151
|
+
|
|
152
|
+
| Layer | Speed / Cost | What it does |
|
|
153
|
+
| --- | --- | --- |
|
|
154
|
+
| **1 β Universal Cleaning** | `~0 ms` | Whitespace, control characters, URL protection |
|
|
155
|
+
| **2 β Rule-based Darija** | `< 5 ms` | Alef/Ya unification, Arabizi dictionary lookup *(Default)* |
|
|
156
|
+
|
|
157
|
+
> **Dictionary Customization:** The dictionary is yours to grow. Ship a base of common Darija, add your app's jargon in a side file. Every skipped token is logged so you can refine from real usage, not guesses.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## π‘οΈ Anonymizer β Morocco-Specific PII Redaction
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from mim_ai import anonymize
|
|
165
|
+
|
|
166
|
+
result = anonymize("Mon CIN est AB58075 et mon tel est 0612345678")
|
|
167
|
+
print(result.text) # Mon CIN est [CIN_MA] et mon tel est ****345678
|
|
168
|
+
print(result.entities_found) # [{'type': 'CIN_MA', 'start': 12, 'end': 19, 'score': 0.85}, ...]
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Built on top of Microsoft Presidio with native Moroccan recognizers:
|
|
172
|
+
- **CIN patterns** (Carte d'IdentitΓ© Nationale) β `AB123456`, `A123456`, etc.
|
|
173
|
+
- **Moroccan phone numbers** β supported mobile and fixed-line prefixes
|
|
174
|
+
- Fully configurable per-entity operators: `replace`, `mask`, `hash`, `redact`
|
|
175
|
+
|
|
176
|
+
Presidio requires the English spaCy model. Install it after `mim-ai` and before using the anonymizer:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
python -m spacy download en_core_web_lg
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
There is no automatic regex-only fallback. See the [anonymizer setup guide](docs/anonymizer/README.md) for details.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## π Compliance β Law 09-08 & ISO 42001
|
|
187
|
+
|
|
188
|
+
MIM provides audit-log features intended to support compliance workflows:
|
|
189
|
+
|
|
190
|
+
```yaml
|
|
191
|
+
audit:
|
|
192
|
+
enabled: true
|
|
193
|
+
backend: sqlite
|
|
194
|
+
hash_chain: true # tamper-evident chain
|
|
195
|
+
retention_days: 90 # auto-purge on schedule
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
When enabled, chat turns are logged with a hash chain and retention is applied automatically. A retention purge appends a hash-chained checkpoint that starts a verifiable new chain segment. SQLite supports access and erasure helpers; erasing records outside the retention purge workflow breaks the chain, so retain and review verification evidence according to your organization's legal and compliance requirements. MIM is a technical component, not a compliance certification or legal guarantee.
|
|
199
|
+
|
|
200
|
+
Verify a configured audit chain with the same backend settings:
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
from mim_ai import load_config
|
|
204
|
+
from mim_ai.audit import verify_chain
|
|
205
|
+
|
|
206
|
+
audit_config = load_config("mim_config.yaml").audit
|
|
207
|
+
ok, message = verify_chain(config=audit_config)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
SQLite, JSONL, PostgreSQL, MySQL, and MongoDB have built-in ordered readers. A custom audit adapter must implement `iter_chain_records()` to enable verification; multi-writer custom adapters must also implement the existing atomic `append_chained()` contract.
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## π²π¦ Made in Morocco, for Morocco
|
|
215
|
+
|
|
216
|
+
This is a **Made in Morocco** tool, built in step with the national AI strategy:
|
|
217
|
+
|
|
218
|
+
* **Aligned with Maroc IA 2030** β Contributing toward the 100B MAD GDP target, 50,000 jobs, and 200,000 trained talents.
|
|
219
|
+
|
|
220
|
+
* **MTNRAβMistral Partnership** β Pre-configured for the MNTRA/Mistral Darija API endpoint. When Morocco's sovereign models ship, MIM is already wired for them.
|
|
221
|
+
|
|
222
|
+
* **Ecosystem Integration** β Built to plug directly into the Sovereign AI Marketplace and to serve Idarati AI and public-facing government services.
|
|
223
|
+
|
|
224
|
+
* **Compliant by Design** β Aligned with **Law 09-08** (audit logs hash user text, honor erasure requests, and expire on schedule) and **ISO 42001**.
|
|
225
|
+
|
|
226
|
+
*MIM is not infrastructure. It's the glue between the infrastructure Morocco is building and the applications Morocco's developers want to ship.*
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## π What's Inside
|
|
231
|
+
|
|
232
|
+
```text
|
|
233
|
+
mim_ai/
|
|
234
|
+
βββ anonymizer/ # Config-first PII redaction with Presidio + Morocco-specific rules
|
|
235
|
+
βββ normalizer/ # Fast, config-first Darija text normalization (< 5 ms, zero GPU)
|
|
236
|
+
βββ chatbot/ # LLM wrapper with tools, sessions, intents
|
|
237
|
+
βββ voice/ # STT, TTS, VAD, full listen-and-reply pipeline
|
|
238
|
+
βββ intents/ # English-named, multilingual-matched intent registry
|
|
239
|
+
βββ audit/ # Law 09-08 + ISO 42001 aligned logging
|
|
240
|
+
βββ config.py # One YAML, one loader, one Mim object
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
> **Note:** Every subsystem is optional. If your configuration only enables the normalizer, nothing else loads. No torch, no sounddevice, no HTTP client.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## π Documentation
|
|
248
|
+
|
|
249
|
+
- English: [docs/EN/tutorial.md](docs/EN/tutorial.md)
|
|
250
|
+
- FranΓ§ais: [docs/FR/tutorial.md](docs/FR/tutorial.md)
|
|
251
|
+
- Architecture: [docs/EN/architecture.md](docs/EN/architecture.md) / [docs/FR/architecture.md](docs/FR/architecture.md)
|
|
252
|
+
- Manifesto: [docs/EN/manifesto.md](docs/EN/manifesto.md) / [docs/FR/manifesto.md](docs/FR/manifesto.md)
|
|
253
|
+
- Feature guides: [Normalizer](docs/EN/features/normalizer.md) Β· [Chatbot](docs/EN/features/chatbot.md) Β· [Voice](docs/EN/features/voice.md) Β· [Audit](docs/EN/features/audit.md)
|
|
254
|
+
- Contributing: [docs/EN/contributing.md](docs/EN/contributing.md)
|
|
255
|
+
- Changelog: [CHANGELOG.md](CHANGELOG.md)
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## π§ͺ Minimal Project Example
|
|
260
|
+
|
|
261
|
+
A FastAPI example is included in [examples/project_example.py](examples/project_example.py). It demonstrates how to expose MIM through a simple HTTP service.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## π PyPI Release
|
|
266
|
+
|
|
267
|
+
Before publishing a release candidate:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
python -m pip install --upgrade build twine
|
|
271
|
+
python -m build
|
|
272
|
+
python -m twine check dist/*
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Upload to TestPyPI first:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
python -m twine upload --repository testpypi dist/*
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Then to PyPI:
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
python -m twine upload dist/*
|
|
285
|
+
```
|