Skip to content

Commit 221ca47

Browse files
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
1 parent 16c7466 commit 221ca47

3 files changed

Lines changed: 60 additions & 54 deletions

File tree

docs/notebooks/tutorials/110_openrouter_sample_annotation.ipynb

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"cells": [
33
{
44
"cell_type": "markdown",
5+
"id": "0b7b320c",
56
"metadata": {},
67
"source": [
78
"# OpenRouter sample annotation with Leiden clusters\n",
@@ -13,25 +14,23 @@
1314
"- annotate clusters across samples with `CellAnnotator`.\n",
1415
"\n",
1516
"It follows the same high-level workflow as `100_heart_atlas.ipynb`, but is parameterized for OpenRouter."
16-
],
17-
"id": "0b7b320c"
17+
]
1818
},
1919
{
2020
"cell_type": "code",
21+
"execution_count": null,
22+
"id": "add3858e",
2123
"metadata": {},
24+
"outputs": [],
2225
"source": [
2326
"import scanpy as sc\n",
24-
"import pandas as pd\n",
25-
"from cell_annotator import CellAnnotator\n",
2627
"\n",
2728
"print(\"scanpy:\", sc.__version__)"
28-
],
29-
"execution_count": null,
30-
"outputs": [],
31-
"id": "add3858e"
29+
]
3230
},
3331
{
3432
"cell_type": "markdown",
33+
"id": "a2337a8d",
3534
"metadata": {},
3635
"source": [
3736
"## Configure your run\n",
@@ -41,12 +40,14 @@
4140
"- `OPENROUTER_MODEL`: an OpenRouter model ID (for example: `openai/gpt-4o-mini`)\n",
4241
"- `LEIDEN_KEY`: the Leiden column in `adata.obs`\n",
4342
"- `SAMPLE_KEY`: sample/batch column in `adata.obs` (or `None` for a single-sample dataset)"
44-
],
45-
"id": "a2337a8d"
43+
]
4644
},
4745
{
4846
"cell_type": "code",
47+
"execution_count": null,
48+
"id": "70164ce3",
4949
"metadata": {},
50+
"outputs": [],
5051
"source": [
5152
"# Required\n",
5253
"OPENROUTER_API_KEY = \"\" # e.g. sk-or-v1-...\n",
@@ -66,14 +67,14 @@
6667
" raise ValueError(\"Set OPENROUTER_API_KEY before continuing.\")\n",
6768
"if not OPENROUTER_MODEL:\n",
6869
" raise ValueError(\"Set OPENROUTER_MODEL before continuing.\")"
69-
],
70-
"execution_count": null,
71-
"outputs": [],
72-
"id": "70164ce3"
70+
]
7371
},
7472
{
7573
"cell_type": "code",
74+
"execution_count": null,
75+
"id": "2428de31",
7676
"metadata": {},
77+
"outputs": [],
7778
"source": [
7879
"adata = sc.read_h5ad(ADATA_PATH)\n",
7980
"\n",
@@ -86,34 +87,34 @@
8687
"print(adata)\n",
8788
"print(\"Leiden key:\", LEIDEN_KEY)\n",
8889
"print(\"Sample key:\", SAMPLE_KEY)"
89-
],
90-
"execution_count": null,
91-
"outputs": [],
92-
"id": "2428de31"
90+
]
9391
},
9492
{
9593
"cell_type": "code",
94+
"execution_count": null,
95+
"id": "ffe7a22b-8d3c-4ad2-9dfd-13bc01cb7f6a",
9696
"metadata": {},
97+
"outputs": [],
9798
"source": [
9899
"adata.obs"
99-
],
100-
"execution_count": null,
101-
"outputs": [],
102-
"id": "ffe7a22b-8d3c-4ad2-9dfd-13bc01cb7f6a"
100+
]
103101
},
104102
{
105103
"cell_type": "code",
106-
"metadata": {},
107-
"source": [
108-
"adata.obsm['spatial']"
109-
],
110104
"execution_count": null,
105+
"id": "bd6282fc-2140-4e9f-a81c-1bc0f4200261",
106+
"metadata": {},
111107
"outputs": [],
112-
"id": "bd6282fc-2140-4e9f-a81c-1bc0f4200261"
108+
"source": [
109+
"adata.obsm[\"spatial\"]"
110+
]
113111
},
114112
{
115113
"cell_type": "code",
114+
"execution_count": null,
115+
"id": "6245b49a",
116116
"metadata": {},
117+
"outputs": [],
117118
"source": [
118119
"# 1) Ask the model for expected cell types and marker genes\n",
119120
"cell_ann.get_expected_cell_type_markers()\n",
@@ -123,14 +124,14 @@
123124
"\n",
124125
"# 3) Annotate clusters and write predictions to adata.obs\n",
125126
"cell_ann.annotate_clusters(key_added=\"cell_type_predicted\")"
126-
],
127-
"execution_count": null,
128-
"outputs": [],
129-
"id": "6245b49a"
127+
]
130128
},
131129
{
132130
"cell_type": "code",
131+
"execution_count": null,
132+
"id": "df316877",
133133
"metadata": {},
134+
"outputs": [],
134135
"source": [
135136
"if \"X_umap\" in adata.obsm:\n",
136137
" sc.pl.umap(adata, color=[LEIDEN_KEY, \"cell_type_predicted\"], wspace=0.35)\n",
@@ -140,30 +141,32 @@
140141
"output_path = ADATA_PATH.replace(\".h5ad\", \"_annotated.h5ad\")\n",
141142
"adata.write(output_path)\n",
142143
"print(f\"Saved annotated object to: {output_path}\")"
143-
],
144-
"execution_count": null,
145-
"outputs": [],
146-
"id": "df316877"
144+
]
147145
},
148146
{
149147
"cell_type": "code",
150-
"metadata": {},
151-
"source": [
152-
"fig = sc.pl.embedding(adata, basis='X_umap_drvi', color='cell_type_predicted', title='s', )"
153-
],
154148
"execution_count": null,
149+
"id": "294208db-4c90-4855-b875-2841b23b8a20",
150+
"metadata": {},
155151
"outputs": [],
156-
"id": "294208db-4c90-4855-b875-2841b23b8a20"
152+
"source": [
153+
"fig = sc.pl.embedding(\n",
154+
" adata,\n",
155+
" basis=\"X_umap_drvi\",\n",
156+
" color=\"cell_type_predicted\",\n",
157+
" title=\"s\",\n",
158+
")"
159+
]
157160
},
158161
{
159162
"cell_type": "code",
163+
"execution_count": null,
164+
"id": "a9e74b69-ca17-44c4-a010-6cf149cccb73",
160165
"metadata": {},
166+
"outputs": [],
161167
"source": [
162168
"fig"
163-
],
164-
"execution_count": null,
165-
"outputs": [],
166-
"id": "a9e74b69-ca17-44c4-a010-6cf149cccb73"
169+
]
167170
}
168171
],
169172
"metadata": {

src/cell_annotator/model/_providers.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""LLM provider abstraction layer."""
22

3-
from abc import ABC, abstractmethod
43
import json
4+
from abc import ABC, abstractmethod
55

66
from dotenv import load_dotenv
77

@@ -188,7 +188,9 @@ def query(
188188
logger.warning(failure_reason)
189189
return response_format.default_failure(failure_reason=failure_reason)
190190
except openai.OpenAIError as e:
191-
logger.debug("Structured parse failed for model '%s'. Falling back to JSON-mode query. Error: %s", model, str(e))
191+
logger.debug(
192+
"Structured parse failed for model '%s'. Falling back to JSON-mode query. Error: %s", model, str(e)
193+
)
192194
return self._query_with_json_fallback(
193195
model=model,
194196
response_format=response_format,
@@ -197,7 +199,9 @@ def query(
197199
fallback_error=str(e),
198200
)
199201
except Exception as e: # noqa: BLE001
200-
logger.debug("Non-OpenAI parse failure for model '%s'. Falling back to JSON-mode query. Error: %s", model, str(e))
202+
logger.debug(
203+
"Non-OpenAI parse failure for model '%s'. Falling back to JSON-mode query. Error: %s", model, str(e)
204+
)
201205
return self._query_with_json_fallback(
202206
model=model,
203207
response_format=response_format,
@@ -254,8 +258,7 @@ def _query_with_json_fallback(
254258
if not text:
255259
return response_format.default_failure(
256260
failure_reason=(
257-
"Model returned empty content during JSON fallback. "
258-
f"Original parse error: {fallback_error}"
261+
f"Model returned empty content during JSON fallback. Original parse error: {fallback_error}"
259262
)
260263
)
261264

@@ -378,10 +381,7 @@ def __repr__(self) -> str:
378381
model_preview = ", ".join(models)
379382
if len(self.list_available_models()) > 5:
380383
model_preview += ", ..."
381-
return (
382-
f"OpenRouterProvider(models: {model_preview}). "
383-
"Call .list_available_models() for complete list."
384-
)
384+
return f"OpenRouterProvider(models: {model_preview}). Call .list_available_models() for complete list."
385385
else:
386386
return "OpenRouterProvider(models: none available). Call .list_available_models() for complete list."
387387
except Exception: # noqa: BLE001
@@ -405,6 +405,7 @@ def _list_models_impl(self) -> list[str]:
405405

406406
return sorted(filtered_models)
407407

408+
408409
class GeminiProvider(LLMProvider):
409410
"""Google Gemini provider implementation."""
410411

tests/model/test_providers.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,9 @@ def test_provider_factory_pattern(self):
291291

292292
@flaky
293293
@pytest.mark.skipif(
294-
not any(os.getenv(key) for key in ["OPENAI_API_KEY", "GEMINI_API_KEY", "ANTHROPIC_API_KEY", "OPENROUTER_API_KEY"]),
294+
not any(
295+
os.getenv(key) for key in ["OPENAI_API_KEY", "GEMINI_API_KEY", "ANTHROPIC_API_KEY", "OPENROUTER_API_KEY"]
296+
),
295297
reason="No API keys available for testing",
296298
)
297299
@pytest.mark.real_llm_query()

0 commit comments

Comments
 (0)