owo-parse 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.
Files changed (42) hide show
  1. owo_parse-0.1.0/LICENSE +21 -0
  2. owo_parse-0.1.0/PKG-INFO +292 -0
  3. owo_parse-0.1.0/README.md +235 -0
  4. owo_parse-0.1.0/pyproject.toml +68 -0
  5. owo_parse-0.1.0/setup.cfg +4 -0
  6. owo_parse-0.1.0/src/owo/__init__.py +30 -0
  7. owo_parse-0.1.0/src/owo/_heuristic.py +439 -0
  8. owo_parse-0.1.0/src/owo/_prompt.py +43 -0
  9. owo_parse-0.1.0/src/owo/eval/__init__.py +1 -0
  10. owo_parse-0.1.0/src/owo/eval/__main__.py +247 -0
  11. owo_parse-0.1.0/src/owo/eval/fixtures/balance_en.yaml +26 -0
  12. owo_parse-0.1.0/src/owo/eval/fixtures/balance_ha.yaml +19 -0
  13. owo_parse-0.1.0/src/owo/eval/fixtures/balance_ig.yaml +19 -0
  14. owo_parse-0.1.0/src/owo/eval/fixtures/balance_pcm.yaml +29 -0
  15. owo_parse-0.1.0/src/owo/eval/fixtures/balance_yo.yaml +19 -0
  16. owo_parse-0.1.0/src/owo/eval/fixtures/bill_pay.yaml +49 -0
  17. owo_parse-0.1.0/src/owo/eval/fixtures/buy_airtime.yaml +40 -0
  18. owo_parse-0.1.0/src/owo/eval/fixtures/buy_data.yaml +38 -0
  19. owo_parse-0.1.0/src/owo/eval/fixtures/crypto_sell.yaml +35 -0
  20. owo_parse-0.1.0/src/owo/eval/fixtures/edge_cases.yaml +95 -0
  21. owo_parse-0.1.0/src/owo/eval/fixtures/fallback_unknown.yaml +7 -0
  22. owo_parse-0.1.0/src/owo/eval/fixtures/transfer_en_extended.yaml +47 -0
  23. owo_parse-0.1.0/src/owo/eval/fixtures/transfer_en_missing_amount.yaml +10 -0
  24. owo_parse-0.1.0/src/owo/eval/fixtures/transfer_en_sample.yaml +14 -0
  25. owo_parse-0.1.0/src/owo/eval/fixtures/transfer_ha.yaml +32 -0
  26. owo_parse-0.1.0/src/owo/eval/fixtures/transfer_ig.yaml +32 -0
  27. owo_parse-0.1.0/src/owo/eval/fixtures/transfer_pcm.yaml +55 -0
  28. owo_parse-0.1.0/src/owo/eval/fixtures/transfer_yo.yaml +32 -0
  29. owo_parse-0.1.0/src/owo/providers/__init__.py +21 -0
  30. owo_parse-0.1.0/src/owo/providers/anthropic.py +65 -0
  31. owo_parse-0.1.0/src/owo/providers/openai.py +67 -0
  32. owo_parse-0.1.0/src/owo/providers/openrouter.py +73 -0
  33. owo_parse-0.1.0/src/owo/py.typed +0 -0
  34. owo_parse-0.1.0/src/owo/result.py +3 -0
  35. owo_parse-0.1.0/src/owo/schema.py +39 -0
  36. owo_parse-0.1.0/src/owo_parse.egg-info/PKG-INFO +292 -0
  37. owo_parse-0.1.0/src/owo_parse.egg-info/SOURCES.txt +40 -0
  38. owo_parse-0.1.0/src/owo_parse.egg-info/dependency_links.txt +1 -0
  39. owo_parse-0.1.0/src/owo_parse.egg-info/requires.txt +16 -0
  40. owo_parse-0.1.0/src/owo_parse.egg-info/top_level.txt +1 -0
  41. owo_parse-0.1.0/tests/test_parse.py +304 -0
  42. owo_parse-0.1.0/tests/test_providers.py +260 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 owo contributors
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,292 @@
1
+ Metadata-Version: 2.4
2
+ Name: owo-parse
3
+ Version: 0.1.0
4
+ Summary: Nigerian-language financial intent parser
5
+ Author: owo contributors
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 owo contributors
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/LPMatrix/owo
29
+ Project-URL: Repository, https://github.com/LPMatrix/owo
30
+ Project-URL: Issues, https://github.com/LPMatrix/owo/issues
31
+ Project-URL: Changelog, https://github.com/LPMatrix/owo/blob/main/CHANGELOG.md
32
+ Keywords: nlp,fintech,nigeria,pidgin,yoruba,hausa,igbo,intent-parsing
33
+ Classifier: Development Status :: 3 - Alpha
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.10
37
+ Classifier: Programming Language :: Python :: 3.11
38
+ Classifier: Programming Language :: Python :: 3.12
39
+ Classifier: Programming Language :: Python :: 3.13
40
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
41
+ Classifier: Typing :: Typed
42
+ Requires-Python: >=3.10
43
+ Description-Content-Type: text/markdown
44
+ License-File: LICENSE
45
+ Provides-Extra: dev
46
+ Requires-Dist: pytest>=8; extra == "dev"
47
+ Requires-Dist: ruff>=0.8; extra == "dev"
48
+ Provides-Extra: eval
49
+ Requires-Dist: pyyaml>=6; extra == "eval"
50
+ Provides-Extra: anthropic
51
+ Requires-Dist: anthropic>=0.40; extra == "anthropic"
52
+ Provides-Extra: openai
53
+ Requires-Dist: openai>=1.0; extra == "openai"
54
+ Provides-Extra: openrouter
55
+ Requires-Dist: openai>=1.0; extra == "openrouter"
56
+ Dynamic: license-file
57
+
58
+ # owo
59
+
60
+ **Nigerian-language financial intent parser.**
61
+
62
+ `owo` takes a free-form financial instruction in English, Pidgin, Yoruba, Hausa, or Igbo — and returns structured JSON that any payment backend can consume.
63
+
64
+ ```python
65
+ from owo import parse
66
+
67
+ result = parse("Send 20k to Mama")
68
+
69
+ # OwoResult(intent='transfer', amount=20000.0, currency='NGN',
70
+ # recipient='Mama', confidence=0.85, flags=[], ...)
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Why owo?
76
+
77
+ Nigerian fintech products that want a conversational layer have to solve the same hard problem: users don't speak in structured commands. They say *"abeg send 5k to Chidi"*, or *"jẹ kí n san owo ina mi"*, or *"biya wutar lantarki"*. Most NLU libraries weren't built for this. `owo` was.
78
+
79
+ It handles:
80
+
81
+ - **Code-switching** — mid-sentence language mixing ("Send am 5k abeg, GTBank")
82
+ - **Naija numerics** — `5k`, `2 bags`, `half a milli`
83
+ - **Intent ambiguity** — flags underspecified fields rather than guessing
84
+ - **Backend agnosticism** — plug in your own LLM provider
85
+
86
+ ---
87
+
88
+ ## Installation
89
+
90
+ ```bash
91
+ pip install owo-parse
92
+ ```
93
+
94
+ Requires Python 3.10+.
95
+
96
+ ---
97
+
98
+ ## Quickstart
99
+
100
+ ```python
101
+ from owo import parse
102
+
103
+ # English
104
+ parse("Buy 2GB data for 08012345678 on MTN")
105
+
106
+ # Pidgin
107
+ parse("Abeg top up my light, meter number 4512345678")
108
+
109
+ # Yoruba
110
+ parse("Jẹ kí n san ₦5,000 fún DSTV mi")
111
+
112
+ # Hausa
113
+ parse("Aika dubu goma zuwa ga Ahmad")
114
+
115
+ # Igbo
116
+ parse("Zipụ ego nde ise nye Emeka")
117
+ ```
118
+
119
+ Every call returns an `OwoResult`:
120
+
121
+ ```python
122
+ @dataclass
123
+ class OwoResult:
124
+ intent: str # transfer | bill_pay | buy_airtime | buy_data | crypto_sell | balance_check | unknown
125
+ amount: float | None
126
+ currency: str # always "NGN" for now
127
+ recipient: str | None
128
+ account_number: str | None
129
+ bank: str | None
130
+ service: str | None # MTN | DSTV | EKEDC | ...
131
+ language_detected: str # en | pcm | yo | ha | ig
132
+ confidence: float # 0.0 – 1.0
133
+ flags: list[str] # ["missing_amount", "ambiguous_recipient", ...]
134
+ raw: dict # parser metadata for debugging
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Configuration
140
+
141
+ By default, `parse()` runs an **offline heuristic** covering common transfer and
142
+ balance patterns across all five supported languages (English, Pidgin, Yoruba,
143
+ Hausa, and Igbo). No API key needed. Inputs that fall outside the heuristic's
144
+ rule set return `intent: "unknown"` with `needs_llm_provider` in `flags` — pass
145
+ a provider to handle those cases.
146
+
147
+ ```python
148
+ # Offline — works for common patterns in all five languages
149
+ parse("Abeg send 5k to Chidi, GTBank")
150
+ parse("Aika dubu goma zuwa ga Ahmad")
151
+ parse("Send half a milli to Kemi")
152
+ ```
153
+
154
+ To handle complex or ambiguous inputs, plug in an LLM provider. Three providers
155
+ ship with the package:
156
+
157
+ ```bash
158
+ pip install 'owo-parse[anthropic]' # Anthropic
159
+ pip install 'owo-parse[openai]' # OpenAI
160
+ pip install 'owo-parse[openrouter]' # OpenRouter (access to 200+ models)
161
+ ```
162
+
163
+ ```python
164
+ from owo import parse
165
+ from owo.providers.anthropic import AnthropicProvider # ANTHROPIC_API_KEY
166
+ from owo.providers.openai import OpenAIProvider # OPENAI_API_KEY
167
+ from owo.providers.openrouter import OpenRouterProvider # OPENROUTER_API_KEY
168
+
169
+ result = parse(
170
+ "Buy 2GB data for 08012345678 on MTN",
171
+ provider=AnthropicProvider(), # or OpenAIProvider() / OpenRouterProvider()
172
+ )
173
+ ```
174
+
175
+ The heuristic always runs first — the provider is only called when the input falls
176
+ outside the rule set (i.e. `needs_llm_provider` is in `result.flags`). This keeps
177
+ costs low for common transfer and balance patterns.
178
+
179
+ Or bring your own by subclassing `BaseProvider`:
180
+
181
+ ```python
182
+ from owo import BaseProvider
183
+
184
+ class MyProvider(BaseProvider):
185
+ def complete(self, prompt: str) -> str:
186
+ # Fallback — called when complete_messages() is not overridden.
187
+ # Receives the full system + user prompt as a single string.
188
+ ...
189
+
190
+ def complete_messages(self, user_text: str) -> str:
191
+ # Preferred override — gives you the user text directly so you can
192
+ # pass the system prompt via your SDK's native system-message field.
193
+ response = my_llm_client.chat(
194
+ system=MY_SYSTEM_PROMPT, # use owo._prompt.SYSTEM_PROMPT
195
+ user=user_text,
196
+ )
197
+ return response.text
198
+ ```
199
+
200
+ `SYSTEM_PROMPT` from `owo._prompt` contains the full instruction block with few-shot examples across all five languages — use it as-is or extend it.
201
+
202
+ ---
203
+
204
+ ## Handling ambiguity
205
+
206
+ `owo` never silently fills in missing fields. If it can't determine the amount, it says so:
207
+
208
+ ```python
209
+ result = parse("Send money to Tunde")
210
+
211
+ result.amount # None
212
+ result.flags # ["missing_amount"]
213
+ result.confidence # 0.61
214
+ ```
215
+
216
+ Use `confidence` and `flags` to decide whether to ask the user for clarification before passing the result downstream.
217
+
218
+ ---
219
+
220
+ ## Supported intents
221
+
222
+
223
+ | Intent | Example |
224
+ | --------------- | --------------------------------- |
225
+ | `transfer` | "Send 20k to Mama" |
226
+ | `bill_pay` | "Pay my DSTV, smart card 1234567" |
227
+ | `buy_airtime` | "Recharge 500 naira on Airtel" |
228
+ | `buy_data` | "Buy 5GB MTN data for my line" |
229
+ | `crypto_sell` | "Sell 50 USDT" |
230
+ | `balance_check` | "How much I get?" |
231
+ | `unknown` | Heuristic could not classify; use `flags` (`needs_llm_provider`) or an LLM provider |
232
+
233
+
234
+ ---
235
+
236
+ ## Supported languages
237
+
238
+
239
+ | Code | Language |
240
+ | ----- | --------------- |
241
+ | `en` | English |
242
+ | `pcm` | Nigerian Pidgin |
243
+ | `yo` | Yoruba |
244
+ | `ha` | Hausa |
245
+ | `ig` | Igbo |
246
+
247
+
248
+ Mixed-language input (code-switching) is handled automatically — `owo` detects the dominant language and resolves cross-language entities.
249
+
250
+ ---
251
+
252
+ ## Running the eval suite
253
+
254
+ `owo` ships with a benchmark suite of curated test fixtures across all five languages:
255
+
256
+ ```bash
257
+ pip install owo-parse[eval]
258
+ python -m owo.eval
259
+ ```
260
+
261
+ Results are printed per-language, per-intent, with a breakdown of field-level accuracy.
262
+
263
+ ---
264
+
265
+ ## Roadmap
266
+
267
+
268
+ | Version | Focus |
269
+ | ------- | ----------------------------------------------------- |
270
+ | `v0.1` | Core intent + entity extraction (English + Pidgin) |
271
+ | `v0.2` | Full multilingual support (Yoruba, Hausa, Igbo) |
272
+ | `v0.3` | Confidence scores, ambiguity flags, graceful fallback |
273
+ | `v1.0` | Provider abstraction, eval suite, docs, OSS-ready |
274
+
275
+
276
+ ---
277
+
278
+ ## Contributing
279
+
280
+ Contributions welcome — especially test fixtures in Yoruba, Hausa, and Igbo, which are the hardest to source.
281
+
282
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for the fixture format and how to add a new language normalization map.
283
+
284
+ This project follows the [Contributor Covenant](./CODE_OF_CONDUCT.md). Security
285
+ disclosures: [SECURITY.md](./SECURITY.md). Changes are summarized in
286
+ [CHANGELOG.md](./CHANGELOG.md).
287
+
288
+ ---
289
+
290
+ ## License
291
+
292
+ [MIT](./LICENSE)
@@ -0,0 +1,235 @@
1
+ # owo
2
+
3
+ **Nigerian-language financial intent parser.**
4
+
5
+ `owo` takes a free-form financial instruction in English, Pidgin, Yoruba, Hausa, or Igbo — and returns structured JSON that any payment backend can consume.
6
+
7
+ ```python
8
+ from owo import parse
9
+
10
+ result = parse("Send 20k to Mama")
11
+
12
+ # OwoResult(intent='transfer', amount=20000.0, currency='NGN',
13
+ # recipient='Mama', confidence=0.85, flags=[], ...)
14
+ ```
15
+
16
+ ---
17
+
18
+ ## Why owo?
19
+
20
+ Nigerian fintech products that want a conversational layer have to solve the same hard problem: users don't speak in structured commands. They say *"abeg send 5k to Chidi"*, or *"jẹ kí n san owo ina mi"*, or *"biya wutar lantarki"*. Most NLU libraries weren't built for this. `owo` was.
21
+
22
+ It handles:
23
+
24
+ - **Code-switching** — mid-sentence language mixing ("Send am 5k abeg, GTBank")
25
+ - **Naija numerics** — `5k`, `2 bags`, `half a milli`
26
+ - **Intent ambiguity** — flags underspecified fields rather than guessing
27
+ - **Backend agnosticism** — plug in your own LLM provider
28
+
29
+ ---
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ pip install owo-parse
35
+ ```
36
+
37
+ Requires Python 3.10+.
38
+
39
+ ---
40
+
41
+ ## Quickstart
42
+
43
+ ```python
44
+ from owo import parse
45
+
46
+ # English
47
+ parse("Buy 2GB data for 08012345678 on MTN")
48
+
49
+ # Pidgin
50
+ parse("Abeg top up my light, meter number 4512345678")
51
+
52
+ # Yoruba
53
+ parse("Jẹ kí n san ₦5,000 fún DSTV mi")
54
+
55
+ # Hausa
56
+ parse("Aika dubu goma zuwa ga Ahmad")
57
+
58
+ # Igbo
59
+ parse("Zipụ ego nde ise nye Emeka")
60
+ ```
61
+
62
+ Every call returns an `OwoResult`:
63
+
64
+ ```python
65
+ @dataclass
66
+ class OwoResult:
67
+ intent: str # transfer | bill_pay | buy_airtime | buy_data | crypto_sell | balance_check | unknown
68
+ amount: float | None
69
+ currency: str # always "NGN" for now
70
+ recipient: str | None
71
+ account_number: str | None
72
+ bank: str | None
73
+ service: str | None # MTN | DSTV | EKEDC | ...
74
+ language_detected: str # en | pcm | yo | ha | ig
75
+ confidence: float # 0.0 – 1.0
76
+ flags: list[str] # ["missing_amount", "ambiguous_recipient", ...]
77
+ raw: dict # parser metadata for debugging
78
+ ```
79
+
80
+ ---
81
+
82
+ ## Configuration
83
+
84
+ By default, `parse()` runs an **offline heuristic** covering common transfer and
85
+ balance patterns across all five supported languages (English, Pidgin, Yoruba,
86
+ Hausa, and Igbo). No API key needed. Inputs that fall outside the heuristic's
87
+ rule set return `intent: "unknown"` with `needs_llm_provider` in `flags` — pass
88
+ a provider to handle those cases.
89
+
90
+ ```python
91
+ # Offline — works for common patterns in all five languages
92
+ parse("Abeg send 5k to Chidi, GTBank")
93
+ parse("Aika dubu goma zuwa ga Ahmad")
94
+ parse("Send half a milli to Kemi")
95
+ ```
96
+
97
+ To handle complex or ambiguous inputs, plug in an LLM provider. Three providers
98
+ ship with the package:
99
+
100
+ ```bash
101
+ pip install 'owo-parse[anthropic]' # Anthropic
102
+ pip install 'owo-parse[openai]' # OpenAI
103
+ pip install 'owo-parse[openrouter]' # OpenRouter (access to 200+ models)
104
+ ```
105
+
106
+ ```python
107
+ from owo import parse
108
+ from owo.providers.anthropic import AnthropicProvider # ANTHROPIC_API_KEY
109
+ from owo.providers.openai import OpenAIProvider # OPENAI_API_KEY
110
+ from owo.providers.openrouter import OpenRouterProvider # OPENROUTER_API_KEY
111
+
112
+ result = parse(
113
+ "Buy 2GB data for 08012345678 on MTN",
114
+ provider=AnthropicProvider(), # or OpenAIProvider() / OpenRouterProvider()
115
+ )
116
+ ```
117
+
118
+ The heuristic always runs first — the provider is only called when the input falls
119
+ outside the rule set (i.e. `needs_llm_provider` is in `result.flags`). This keeps
120
+ costs low for common transfer and balance patterns.
121
+
122
+ Or bring your own by subclassing `BaseProvider`:
123
+
124
+ ```python
125
+ from owo import BaseProvider
126
+
127
+ class MyProvider(BaseProvider):
128
+ def complete(self, prompt: str) -> str:
129
+ # Fallback — called when complete_messages() is not overridden.
130
+ # Receives the full system + user prompt as a single string.
131
+ ...
132
+
133
+ def complete_messages(self, user_text: str) -> str:
134
+ # Preferred override — gives you the user text directly so you can
135
+ # pass the system prompt via your SDK's native system-message field.
136
+ response = my_llm_client.chat(
137
+ system=MY_SYSTEM_PROMPT, # use owo._prompt.SYSTEM_PROMPT
138
+ user=user_text,
139
+ )
140
+ return response.text
141
+ ```
142
+
143
+ `SYSTEM_PROMPT` from `owo._prompt` contains the full instruction block with few-shot examples across all five languages — use it as-is or extend it.
144
+
145
+ ---
146
+
147
+ ## Handling ambiguity
148
+
149
+ `owo` never silently fills in missing fields. If it can't determine the amount, it says so:
150
+
151
+ ```python
152
+ result = parse("Send money to Tunde")
153
+
154
+ result.amount # None
155
+ result.flags # ["missing_amount"]
156
+ result.confidence # 0.61
157
+ ```
158
+
159
+ Use `confidence` and `flags` to decide whether to ask the user for clarification before passing the result downstream.
160
+
161
+ ---
162
+
163
+ ## Supported intents
164
+
165
+
166
+ | Intent | Example |
167
+ | --------------- | --------------------------------- |
168
+ | `transfer` | "Send 20k to Mama" |
169
+ | `bill_pay` | "Pay my DSTV, smart card 1234567" |
170
+ | `buy_airtime` | "Recharge 500 naira on Airtel" |
171
+ | `buy_data` | "Buy 5GB MTN data for my line" |
172
+ | `crypto_sell` | "Sell 50 USDT" |
173
+ | `balance_check` | "How much I get?" |
174
+ | `unknown` | Heuristic could not classify; use `flags` (`needs_llm_provider`) or an LLM provider |
175
+
176
+
177
+ ---
178
+
179
+ ## Supported languages
180
+
181
+
182
+ | Code | Language |
183
+ | ----- | --------------- |
184
+ | `en` | English |
185
+ | `pcm` | Nigerian Pidgin |
186
+ | `yo` | Yoruba |
187
+ | `ha` | Hausa |
188
+ | `ig` | Igbo |
189
+
190
+
191
+ Mixed-language input (code-switching) is handled automatically — `owo` detects the dominant language and resolves cross-language entities.
192
+
193
+ ---
194
+
195
+ ## Running the eval suite
196
+
197
+ `owo` ships with a benchmark suite of curated test fixtures across all five languages:
198
+
199
+ ```bash
200
+ pip install owo-parse[eval]
201
+ python -m owo.eval
202
+ ```
203
+
204
+ Results are printed per-language, per-intent, with a breakdown of field-level accuracy.
205
+
206
+ ---
207
+
208
+ ## Roadmap
209
+
210
+
211
+ | Version | Focus |
212
+ | ------- | ----------------------------------------------------- |
213
+ | `v0.1` | Core intent + entity extraction (English + Pidgin) |
214
+ | `v0.2` | Full multilingual support (Yoruba, Hausa, Igbo) |
215
+ | `v0.3` | Confidence scores, ambiguity flags, graceful fallback |
216
+ | `v1.0` | Provider abstraction, eval suite, docs, OSS-ready |
217
+
218
+
219
+ ---
220
+
221
+ ## Contributing
222
+
223
+ Contributions welcome — especially test fixtures in Yoruba, Hausa, and Igbo, which are the hardest to source.
224
+
225
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for the fixture format and how to add a new language normalization map.
226
+
227
+ This project follows the [Contributor Covenant](./CODE_OF_CONDUCT.md). Security
228
+ disclosures: [SECURITY.md](./SECURITY.md). Changes are summarized in
229
+ [CHANGELOG.md](./CHANGELOG.md).
230
+
231
+ ---
232
+
233
+ ## License
234
+
235
+ [MIT](./LICENSE)
@@ -0,0 +1,68 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "owo-parse"
7
+ version = "0.1.0"
8
+ description = "Nigerian-language financial intent parser"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { file = "LICENSE" }
12
+ authors = [{ name = "owo contributors" }]
13
+ keywords = [
14
+ "nlp",
15
+ "fintech",
16
+ "nigeria",
17
+ "pidgin",
18
+ "yoruba",
19
+ "hausa",
20
+ "igbo",
21
+ "intent-parsing",
22
+ ]
23
+ classifiers = [
24
+ "Development Status :: 3 - Alpha",
25
+ "Intended Audience :: Developers",
26
+ "Programming Language :: Python :: 3",
27
+ "Programming Language :: Python :: 3.10",
28
+ "Programming Language :: Python :: 3.11",
29
+ "Programming Language :: Python :: 3.12",
30
+ "Programming Language :: Python :: 3.13",
31
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
32
+ "Typing :: Typed",
33
+ ]
34
+
35
+ dependencies = []
36
+
37
+ [project.optional-dependencies]
38
+ dev = ["pytest>=8", "ruff>=0.8"]
39
+ eval = ["pyyaml>=6"]
40
+ anthropic = ["anthropic>=0.40"]
41
+ openai = ["openai>=1.0"]
42
+ openrouter = ["openai>=1.0"]
43
+
44
+ [project.urls]
45
+ Homepage = "https://github.com/LPMatrix/owo"
46
+ Repository = "https://github.com/LPMatrix/owo"
47
+ Issues = "https://github.com/LPMatrix/owo/issues"
48
+ Changelog = "https://github.com/LPMatrix/owo/blob/main/CHANGELOG.md"
49
+
50
+ [project.scripts]
51
+
52
+ [tool.setuptools.packages.find]
53
+ where = ["src"]
54
+
55
+ [tool.setuptools.package-data]
56
+ owo = ["py.typed", "eval/fixtures/*.yaml"]
57
+
58
+ [tool.pytest.ini_options]
59
+ testpaths = ["tests"]
60
+ pythonpath = ["src"]
61
+
62
+ [tool.ruff]
63
+ target-version = "py310"
64
+ src = ["src", "tests"]
65
+
66
+ [tool.ruff.lint]
67
+ select = ["E", "F", "I", "UP", "B"]
68
+ ignore = ["E501"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+
3
+ from owo._heuristic import heuristic_parse as _heuristic_parse
4
+ from owo._heuristic import result_from_provider_json as _result_from_provider_json
5
+ from owo.providers import BaseProvider
6
+ from owo.schema import Intent, Language, OwoResult
7
+
8
+
9
+ def parse(text: str, *, provider: BaseProvider | None = None) -> OwoResult:
10
+ """
11
+ Parse a free-form financial instruction into structured fields.
12
+
13
+ The heuristic runs first in all cases. When a *provider* is supplied,
14
+ it is called only for inputs the heuristic cannot confidently handle
15
+ (i.e. the result carries a ``needs_llm_provider`` flag).
16
+ """
17
+ result = _heuristic_parse(text)
18
+ if provider is None or "needs_llm_provider" not in result.flags:
19
+ return result
20
+ out = provider.complete_messages(text)
21
+ return _result_from_provider_json(out, text)
22
+
23
+
24
+ __all__ = [
25
+ "BaseProvider",
26
+ "Intent",
27
+ "Language",
28
+ "OwoResult",
29
+ "parse",
30
+ ]