This release is a pre-release and may not be stable for production use.
OVOS Color Parser
Turn natural-language color descriptions into color objects, and color objects back into names, in 23 languages. Pure Python, zero network, no ML model — just bundled wordlists and color math.
from ovos_color_parser import color_from_description
c = color_from_description("dark red", lang="en")
print(c.hex_str) # "#3B1315"
print(c.as_hls) # HLSColor(h=357, l=0.153..., s=0.513..., ...)
It ships as part of the OpenVoiceOS voice stack, but it is a standalone library first: nothing here imports OVOS. It is equally useful for NER over free text, describing colors for text-to-speech, and mapping color descriptions to hex for UI theming or LED control.
Installation
pip install ovos-color-parser
# or, with uv:
uv pip install ovos-color-parser
30-second quickstart
from ovos_color_parser import color_from_description, lookup_name, sRGBAColor
# text -> color
c = color_from_description("warm mustard yellow", lang="en")
print(c.hex_str, (c.r, c.g, c.b)) # #FFDA3E (255, 218, 62)
# color -> text (any supported language)
print(lookup_name(sRGBAColor.from_hex_str("#1E90FF"), lang="pt")) # "Azul furtivo"
# nothing matches -> None
print(color_from_description("qzxwv", lang="en")) # None
Features
- Color extraction —
color_from_description("light blue", lang="fr")matches bundled color wordlists (web colors, xkcd survey, crayola, RAL, Pantone, ISCC-NBS, traditional Japanese colors, ...) and object colors ("carrot", "banana"), then applies modifiers such as light/dark, vivid/muted, warm/cool and transparent/opaque. Names are matched on word boundaries and weighted by specificity, so "moss green" outweighs a bare "green" and "green" is never matched inside "evergreen". - Color naming and namespaces —
lookup_name(color, lang)returns a color's name. Every wordlist is an addressable namespace, so you can ask for the name in a specific palette (namespace="RAL_classic") or fall back to the perceptually nearest named color (nearest=True). - Color models —
sRGBAColor,HLSColor,HSVColorandSpectralColor(wavelength) dataclasses with conversions, stable hex round-trips and validation.SpectralColor.is_visibleseparates real colors from infrared, ultraviolet and beyond. - Gamut handling — choose how a computed color that leaves the sRGB gamut is resolved: clamp per
channel, map towards grey while preserving hue, or reject (
gamut=GamutPolicy.MAP). - Utilities — perceptual color distance (CIEDE2000), linear-light color averaging, Kelvin color temperature to RGB, CMYK conversion, contrasting black/white text color and hex validation.
Use it anywhere
Every snippet below is plain Python — pip install ovos-color-parser and run it. Each has a
matching runnable script in examples/.
Extract colors from free text (NER)
Pull color references out of a sentence and resolve each to a structured color — no ML model, no network. Great for tagging product copy, design briefs or support tickets.
from ovos_color_parser import color_from_description
text = "Paint the fence dark forest green and the door navy blue"
for phrase in ("dark forest green", "navy blue"):
c = color_from_description(phrase, lang="en", fuzzy=False)
print(phrase, "->", c.hex_str) # dark forest green -> #162914 ; navy blue -> #0F43BE
Full sliding-window extractor with span offsets: examples/ner_colors.py.
Describe a color out loud (TTS-adjacent)
Go the other way: a raw RGB/hex value from a color picker, sensor or smart bulb becomes a speakable name.
from ovos_color_parser import sRGBAColor, lookup_name
c = sRGBAColor.from_hex_str("#2E8B57")
print(f"The color is {lookup_name(c, lang='en').lower()}.") # "The color is sea green."
Map descriptions to hex for UI, theming and LEDs
from ovos_color_parser import color_from_description
theme = {var: color_from_description(desc, lang="en").hex_str.lower()
for var, desc in {"--accent": "vivid teal", "--bg": "very dark blue"}.items()}
print(theme) # {'--accent': '#38bfc4', '--bg': '#121a34'}
CSS variables, NeoPixel/WLED tuples and Kelvin white-balance in examples/ui_theming.py.
In an OVOS skill vs. standalone
The same call powers a voice intent and a plain script — only the surrounding code differs:
# standalone color utility
from ovos_color_parser import color_from_description
hex_str = color_from_description("moss green", lang="en").hex_str
# inside an OVOS skill handler
def handle_set_color(self, message):
utterance = message.data["utterance"]
color = color_from_description(utterance, lang=self.lang)
if color:
self.set_lamp(color.hex_str)
Supported languages
23 locales: Aragonese, Arabic, Asturian, Basque, Bulgarian, Catalan, Croatian, Czech, Danish,
Dutch, English, French, German, Italian, Kabyle, Occitan, Polish, Portuguese, Romanian, Russian,
Slovak, Spanish and West Frisian. Any BCP-47 tag resolves to the closest bundled locale (for
example en-GB → en-US). The per-language feature matrix — entry counts, modifier and object
support — is in docs/languages.md.
Documentation
- Usage guide — extraction, impossible colors, comparing colors
- Color description semantics — how hue, saturation, brightness, temperature and opacity keywords map to color math
- Color, language and color spaces — how languages carve up color space, and the color models used
- API reference
- Language support — the 23 locales and their per-language vocabulary
- Extending — custom wordlists, adding a language, integration patterns
Runnable examples
- parse_colors.py — descriptions to colors, modifiers,
cast_to_palette - describe_rgb.py — RGB/hex to a spoken color name (TTS)
- ner_colors.py — extract color spans from free text (NER)
- ui_theming.py — descriptions to CSS/LED/Kelvin values
- multilingual.py — the same colors across all languages
- color_math.py — models, conversions, distance and averaging
Usage notes
Color names are ambiguous — the same name can map to several hex values across wordlists. When several entries match, the parser blends them in linear light, weighted by match specificity. To force a known, named color from the matched candidates instead:
color = color_from_description("red", lang="en", cast_to_palette=True)
print(color.name) # a named wordlist color, e.g. "Dusty Red"
When nothing matches, color_from_description returns None.
Descriptions of impossible colors ("reddish green") still produce an output — the parser blends whatever it matches, which may not be meaningful.
Runnable scripts live in examples/ and the full API reference in docs/api.md.
Related projects
- ovos-number-parser — numbers
- ovos-date-parser — dates and times
- ovos-lang-parser — languages
Credits
Color wordlists include data derived from the xkcd color survey, crayola, RAL, Pantone, ISCC-NBS, traditional Japanese colors and Wikipedia color lists. Spectral color terms follow Wikipedia's spectral color tables.
Metadata
Release files for ovos-color-parser 0.11.3a1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ovos_color_parser-0.11.3a1.tar.gz | 844.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ovos_color_parser-0.11.3a1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.7 MB
Release files / ovos_color_parser-0.11.3a1.tar.gz
| Download URL | ovos_color_parser-0.11.3a1.tar.gz |
|---|---|
| Size | 844.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1c04b02ac2d91e5d419446e174c5503ed335e2ee27c538616f0098d6bc8ae043
|
|
BLAKE2b-256 checksum How to use checksums |
6973446ccb83996e60782ed8c7d612e2db58260f5fc896c4d0d7114ecaaefa10
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / ovos_color_parser-0.11.3a1-py3-none-any.whl
| Download URL | ovos_color_parser-0.11.3a1-py3-none-any.whl |
|---|---|
| Size | 894.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b27b2fbfc23754b49f7e6eafb1ecb7d8dc44b313bc4f6cfc9aefcf6e6cc2681f
|
|
BLAKE2b-256 checksum How to use checksums |
42656efe3aaababaf713c77b47b72d30b75101d737011b39f0e99f9cb248e0fd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|