flavor_engine
Vape Cart Flavor Engine — 11D gustatory interpolation and NCM coupling.
- Implements the 6-phase blend pipeline:
Raw weighted vector summation
Interaction matrix corrections (suppression/synergy/cross-modal)
Temporal phase reconstruction → TDS string
NCM cascade computation (Hill saturation + receptor synergies)
Nearest-neighbor classification + novelty score
Derived metrics (palatability, reward_density, cling, nostalgia)
Also: morph, temperature modification, cascade trigger detection, emergence.
- class flavor_engine.FlavorProfile(name, vector, delta_str, temporal, norimaki_inv=None, retronasal=0.5, category='other')[source]
Bases:
objectA single named flavour entry loaded from the vape-cart catalogue.
Holds the immutable sensory description of one flavour: its 11D gustatory
vector, a compact NCM (neurochemical-modulation)delta_strparsed lazily byncm_delta_parser, atemporalenvelope dict (onset/peak/decay), optional Norimaki inverse coordinates, the retronasal fraction, and a coarse category. Instances are constructed byFlavorEngine._ensure_loadedfrom the parsedvape_cart.yamland are also produced fresh byFlavorEngine.apply_temperatureto represent a temperature-shifted variant. Consumed by the blend pipeline and surfaced to the bot viatools/flavor_tool.py(thelookupaction serialises a profile to JSON).- Parameters:
- property dominant_axis: str
Name of the strongest gustatory axis in this flavour’s vector.
Scans the 11D
vectorand returns the label of the axis with the largest magnitude, giving a quick one-word characterisation of what the flavour tastes of most. Pure computation overself.vectorand the module-levelAXESlist with no side effects. Called bytools/flavor_tool.pyin thelookupaction to enrich the JSON it returns to the bot.- Returns:
The
AXESlabel of the highest-valued component.- Return type:
- class flavor_engine.CompositeResult(vector, raw_vector, ncm_deltas, tds_string, temporal_phases, derived_metrics, nearest_flavor, nearest_similarity, novelty_score, emergence_flags, cascade_triggers, attractor=None, ingredients=<factory>)[source]
Bases:
objectFull output bundle of a blend or morph computation.
Aggregates every artefact produced by
FlavorEngine.blend(and thereforeFlavorEngine.morph, which delegates to it): the interaction-corrected and raw 11D vectors, the resolved NCM delta dict, the temporal-dominance string and its underlying phase list, the derived hedonic metrics, the nearest known flavour with its cosine similarity and the complementary novelty score, plus any triggered emergence flags, cascade IDs, and attractor basin. Theto_dictmethod renders a rounded JSON-friendly view;tools/flavor_tool.pyconsumes the dataclass directly (readingncm_deltasto inject limbic deltas) and serialises it for the bot.- Parameters:
- to_dict()[source]
Render this result as a rounded, JSON-serialisable dictionary.
Produces a compact view of the composite for transport to the bot: vector components and NCM deltas are rounded to three decimals and keys are renamed to short forms (
metrics,nearest,similarity,novelty,cascades). Pure transformation ofselfwith no side effects. Called bytools/flavor_tool.py(theblendandmorphactions) which wraps the output injson.dumpsfor the tool response.- Returns:
A flat dictionary of rounded vectors, deltas, the TDS string, temporal phases, derived metrics, nearest-flavour info, and the emergence/cascade/attractor fields.
- Return type:
- class flavor_engine.FlavorEngine(yaml_path=None)[source]
Bases:
objectStateless-per-call 11D gustatory computation engine for the vape cart.
Loads the
vape_cart.yamlcatalogue (flavours, interaction matrix, temporal/temperature/preparation models, NCM synergy rules, emergence rules, and attractor basins) on first use and exposes the blend pipeline plus flavour lookups. The engine is the analytical core behindtools/flavor_tool.py, which instantiates a freshFlavorEngineper tool call and routes the bot’slist/lookup/blend/morphactions tolist_flavors,get_flavor,blend, andmorph. It leans onutils.cosinefor similarity and lazily importsncm_delta_parserfor delta strings and neurochemical node names; it does no Redis, network, or event-bus work itself (those side effects live in the tool wrapper).- Parameters:
yaml_path (Optional[str])
- __init__(yaml_path=None)[source]
Construct an engine bound to a catalogue path, loading nothing yet.
Records where
vape_cart.yamllives (defaulting to the copy beside this module) and sets up empty caches; the YAML is not read until the first public call triggers_ensure_loaded, so construction is cheap and side-effect free. Instantiated per tool invocation bytools/flavor_tool.py.
- get_flavor(name)[source]
Look up one flavour profile by name, case- and space-insensitively.
Ensures the catalogue is loaded, then normalises
nameto the catalogue key form (uppercased with spaces replaced by underscores) and returns the matchingFlavorProfileorNoneif absent. Called bytools/flavor_tool.pyfor the bot’slookupaction.- Parameters:
name (
str) – A flavour name in any casing, e.g."breast milk"or"BREAST_MILK".- Returns:
The matching profile, or
Noneif the name is not in the catalogue.- Return type:
- list_flavors()[source]
Return the sorted catalogue keys of every loaded flavour.
Ensures the YAML is parsed, then returns the flavour names (catalogue-key form) in alphabetical order. Called by
tools/flavor_tool.pyfor the bot’slistaction, which wraps the names plus a count in JSON.
- blend(recipe)[source]
Run the full 6-phase blend pipeline.
- morph(flavor_a, flavor_b, t=0.5)[source]
Interpolate between two flavours, returning the blend at fraction
t.Clamps
tto[0, 1]and delegates toblendwith a two-item recipe weighted1 - tforflavor_aandtforflavor_b, sot = 0yields flavour A,t = 1yields flavour B, and intermediate values cross-fade through the full six-phase pipeline (including all NCM and emergence side effects ofblend). Called bytools/flavor_tool.pyfor the bot’smorphaction.- Parameters:
- Returns:
The blended composite at the requested point.
- Return type:
- apply_temperature(profile, temp_c)[source]
Return a temperature-shifted copy of a flavour profile.
Runs the private temperature model (
_apply_temperature) over a copy of the profile’s vector and packages the result as a freshFlavorProfilenamed"<name>@<temp_c>C", leaving the original untouched. The retronasal scale computed internally is discarded here (it only matters during a weighted blend). This public helper has no in-repo callers found viagrep(the blend path uses the private_apply_temperaturedirectly); it is exposed for external/programmatic use.- Parameters:
profile (
FlavorProfile) – The source flavour to transform.temp_c (
float) – Serving temperature in degrees Celsius.
- Returns:
A new profile carrying the temperature-adjusted vector and the original’s delta string, temporal envelope, and metadata.
- Return type: