2. Install isolated Python dependencies
macOS
Run in a new working directory. This shell variant applies to macOS/Linux; use the separate Windows step on Windows.
python3.11 -m venv .venv
.venv/bin/python -m pip install rdkit==2025.3.1
.venv/bin/python -m pip freeze
Official sourceExpected result
Packages install; record the resolved versions.
3. Install isolated Python dependencies
Linux
Run in a new working directory. This shell variant applies to macOS/Linux; use the separate Windows step on Windows.
python3.11 -m venv .venv
.venv/bin/python -m pip install rdkit==2025.3.1
.venv/bin/python -m pip freeze
Official sourceExpected result
Packages install; record the resolved versions.
4. Install Python dependencies on Windows
Windows
Use PowerShell and the virtual-environment interpreter directly.
py -3.11 -m venv .venv
.\.venv\Scripts\python.exe -m pip install rdkit==2025.3.1
.\.venv\Scripts\python.exe -m pip freeze
Official sourceExpected result
Packages install; record the resolved versions.
6. Save the Python bridge
All platforms
Save as local_chemistry_assistant.py in the working directory. The code computes values before the model request and never executes model-generated code.
"""RDKit calculations followed by explanation using a local Ollama model.
Sources: https://www.rdkit.org/docs/GettingStartedInPython.html
https://docs.ollama.com/api/chat
This example has been source-reviewed, but has not been executed.
"""
import argparse
import json
import urllib.error
import urllib.request
from rdkit import Chem, rdBase
from rdkit.Chem import Descriptors, rdMolDescriptors
def main():
parser = argparse.ArgumentParser()
parser.add_argument("smiles")
parser.add_argument("--model", default="qwen2.5:3b")
parser.add_argument("--prompt", default="Explain the supplied molecular descriptors and their limits.")
args = parser.parse_args()
if not args.smiles.strip():
parser.error("Empty SMILES; no model request was sent.")
molecule = Chem.MolFromSmiles(args.smiles)
if molecule is None:
parser.error("Invalid SMILES; no model request was sent.")
results = {
"smiles": args.smiles,
"rdkit_version": rdBase.rdkitVersion,
"formula": rdMolDescriptors.CalcMolFormula(molecule),
"molecular_weight_g_mol": Descriptors.MolWt(molecule),
"tpsa_square_angstrom": rdMolDescriptors.CalcTPSA(molecule),
}
print(json.dumps(results, ensure_ascii=False, indent=2), flush=True)
request = urllib.request.Request(
"http://127.0.0.1:11434/api/chat",
data=json.dumps({
"model": args.model,
"stream": False,
"messages": [
{"role": "system", "content": "Explain only the supplied RDKit results. Preserve their numbers and units. Do not invent measurements, toxicity, efficacy or additional calculations. Reply in the user's language."},
{"role": "user", "content": args.prompt + "\nRDKit results:\n" + json.dumps(results)},
],
}).encode("utf-8"),
headers={"Content-Type": "application/json"},
method="POST",
)
try:
opener = urllib.request.build_opener(urllib.request.ProxyHandler({}))
with opener.open(request, timeout=180) as response:
body = json.load(response)
message = body.get("message", {}).get("content")
if not isinstance(message, str) or not message.strip():
raise ValueError("Ollama did not return message.content.")
print(message)
except (urllib.error.URLError, ValueError, TimeoutError) as error:
parser.exit(1, "Local Ollama request failed; RDKit results remain available above. " + str(error) + "\n")
if __name__ == "__main__":
main()
Official sourceExpected result
The script is saved next to .venv.
7. Run the aspirin workflow
All platforms
Use .venv/bin/python on macOS/Linux, or ..venv\Scripts\python.exe on Windows. Pass the following prompt via --prompt.
.venv/bin/python local_chemistry_assistant.py "CC(=O)Oc1ccccc1C(=O)O" --prompt "Explain the aspirin results computed by RDKit. Preserve formula, mass and TPSA with units; distinguish computed descriptors from experimental observations."
Official sourceExpected result
First inspect RDKit JSON: C9H8O4, mass about 180.16 g/mol, TPSA about 63.6 Ų. Then inspect the model explanation: numbers must remain consistent and no unsupported toxicity/efficacy claim may be added. These are expected checks, not observed results.
8. Reject malformed input
All platforms
Repeat with not-a-smiles, using the platform interpreter above.
.venv/bin/python local_chemistry_assistant.py "not-a-smiles"
Official sourceExpected result
The script exits with an invalid-SMILES error before any Ollama request.