diff --git a/CHANGELOG.md b/CHANGELOG.md index b98f81b..a82376d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,28 @@ All notable changes to `chemflow-client` will be documented in this file. ## Unreleased +## 0.1.5 + +- Changed `chat3d(...)` to require `prompt` as a keyword argument and make `atoms` optional, so generation calls can use `chat3d(prompt="generate methane")`. +- Simplified the README examples for `chat3d(...)` and documented the public call signatures in a dedicated section. + +## 0.1.4 + +- Fixed the README notebook widget image for PyPI by switching from a GitHub `blob` page URL to the raw GIF URL pinned to the release tag. + +## 0.1.3 + +- Updated the README notebook widget image to use the GitHub-hosted URL so the animation renders correctly on PyPI. +- Simplified the notebook widget assistant placeholder text from `Thinking harder...` to `Thinking...`. + +## 0.1.2 + +- Published the client and widget improvements that were previously tagged but not released to PyPI because of a package-version mismatch. +- Improved `ChemFlow3DClient` request preparation and response application so notebook background chats can reuse the same state transitions safely. +- Improved `Chat3DWidget` background chat handling to stay responsive and avoid applying results after the widget is closed. +- Improved ASE payload conversion for generated or empty structures so optional arrays, cell data, and periodic boundary flags are preserved more consistently. +- Expanded the public README examples for structure generation workflows and notebook usage. + ## 0.1.0 - Initial public release. diff --git a/README.md b/README.md index b57343a..ed83d01 100644 --- a/README.md +++ b/README.md @@ -32,14 +32,11 @@ from chemflow_client import chat3d atoms = molecule("H2O") updated_atoms, text = chat3d( - atoms, - "change the H-O-H angle to 110 degrees", -) - -generated_atoms, text = chat3d( - atoms=None, - prompt="generate methane", + prompt="change the H-O-H angle to 110 degrees", + atoms=atoms, ) +# or generate one directly. +generated_atoms, text = chat3d(prompt="generate methane") ``` ## JupyterLab @@ -57,7 +54,7 @@ widget widget.get_atoms() ``` -![JupyterLab widget demo](docs/assets/chemflow-widget-demo.gif) +![JupyterLab widget demo](https://raw.githubusercontent.com/SingletC/chemflow-client/v0.1.5/docs/assets/chemflow-widget-demo.gif) ## Configure @@ -76,10 +73,47 @@ You can also pass configuration as arguments to `chat3d(...)` or `Chat3DWidget(. from chemflow_client import Chat3DWidget, chat3d updated_atoms, text = chat3d( - atoms=None, prompt="generate methane", api_key="cfsk_xxx", ) widget = Chat3DWidget(api_key="cfsk_xxx") ``` + +## Call Signatures + +### `chat3d(...)` + +```python +chat3d( + *, + prompt: str, + atoms: Optional[Atoms] = None, + base_url: Optional[str] = None, + api_key: Optional[str] = None, + model: Optional[str] = None, + timeout: float = 300.0, +) -> Tuple[Atoms, str] +``` + +- `prompt`: Required keyword-only editing or generation instruction. +- `atoms`: Optional initial `ase.Atoms` structure. +- `base_url`, `api_key`, `model`, `timeout`: Optional client configuration overrides. +- Returns `(atoms, text)`. + +### `Chat3DWidget(...)` + +```python +Chat3DWidget( + atoms: Optional[Atoms] = None, + *, + base_url: Optional[str] = None, + api_key: Optional[str] = None, + model: Optional[str] = None, + timeout: float = 300.0, +) +``` + +- `atoms`: Optional initial `ase.Atoms` structure. +- `base_url`, `api_key`, `model`, `timeout`: Optional client configuration overrides. +- Returns a notebook widget instance backed by `ChemFlow3DClient`. diff --git a/pyproject.toml b/pyproject.toml index 689b081..1776eab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "chemflow-client" -version = "0.1.0" +version = "0.1.5" description = "Public Python client for ChemFlow 3D chat editing" readme = "README.md" requires-python = ">=3.9" diff --git a/src/chemflow_client/api.py b/src/chemflow_client/api.py index 8647c7a..3a57352 100644 --- a/src/chemflow_client/api.py +++ b/src/chemflow_client/api.py @@ -30,7 +30,7 @@ def __init__( transport=transport, headers={ "X-ChemFlow-Api-Key": resolved_api_key, - "User-Agent": "chemflow-client/0.1.0", + "User-Agent": "chemflow-client/0.1.5", "Accept": "application/json", }, ) diff --git a/src/chemflow_client/client.py b/src/chemflow_client/client.py index b7f0c6f..4d7c03d 100644 --- a/src/chemflow_client/client.py +++ b/src/chemflow_client/client.py @@ -122,9 +122,9 @@ def __exit__(self, exc_type, exc, tb) -> None: def chat3d( - atoms: Optional[Atoms], - prompt: str, *, + prompt: str, + atoms: Optional[Atoms] = None, base_url: Optional[str] = None, api_key: Optional[str] = None, model: Optional[str] = None, diff --git a/src/chemflow_client/widget.py b/src/chemflow_client/widget.py index c304ebe..ccef2ec 100644 --- a/src/chemflow_client/widget.py +++ b/src/chemflow_client/widget.py @@ -64,7 +64,7 @@ def _format_widget_error_message(error: Union[Exception, str]) -> str: _WIDGET_ESM = r''' const THREE_DMOL_URL = "https://cdn.jsdelivr.net/npm/3dmol@2.4.2/build/3Dmol-min.js"; -const THINKING_PLACEHOLDER = "Thinking harder..."; +const THINKING_PLACEHOLDER = "Thinking..."; async function ensure3Dmol() { if (window.$3Dmol) { diff --git a/tests/test_client.py b/tests/test_client.py index 858866e..646754f 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -35,8 +35,8 @@ def fake_chat3d(self, request): atoms = Atoms(symbols=["H", "H"], positions=[[0.0, 0.0, 0.0], [0.0, 0.0, 0.74]]) updated_atoms, text = chat3d( - atoms, - "stretch the bond", + prompt="stretch the bond", + atoms=atoms, base_url="http://localhost:8000", api_key="cfsk_test_key", ) @@ -68,8 +68,7 @@ def fake_chat3d(self, request): monkeypatch.setattr("chemflow_client.api.ChemFlowApi.chat3d", fake_chat3d) updated_atoms, text = chat3d( - None, - "generate methane", + prompt="generate methane", api_key="cfsk_test_key", ) @@ -217,8 +216,8 @@ def fake_chat3d(self, request): monkeypatch.setattr("chemflow_client.api.ChemFlowApi.chat3d", fake_chat3d) atoms, text = chat3d( - Atoms(symbols=["He"], positions=[[0.0, 0.0, 0.0]]), - "leave it as is", + prompt="leave it as is", + atoms=Atoms(symbols=["He"], positions=[[0.0, 0.0, 0.0]]), ) assert atoms.get_chemical_symbols() == ["He"] diff --git a/tests/test_widget_helpers.py b/tests/test_widget_helpers.py index f8670bd..9082add 100644 --- a/tests/test_widget_helpers.py +++ b/tests/test_widget_helpers.py @@ -42,7 +42,7 @@ def test_format_widget_error_message_prefers_structured_message(): def test_widget_esm_uses_chat_thinking_placeholder_instead_of_waiting_banner(): - assert "Thinking harder..." in _WIDGET_ESM + assert "Thinking..." in _WIDGET_ESM assert "Waiting for ChemFlow response:" not in _WIDGET_ESM