chatbot1-3 Exercise 2: Fail Early With a Helpful Message =========================================================== ex2.py (save in the project root): import asyncio from bot.providers import ProviderUnavailable from bot.providers.local import list_models from tests.support import ScriptedServer from tests.test_providers import closed_port_url async def require_model(base_url: str, model: str) -> None: """Fail early, with a message that says what to do, instead of on the first user's message.""" try: available = await list_models(base_url, timeout=2) except ProviderUnavailable as e: raise SystemExit(f"Cannot reach a model server: {e}\nStart it (for Ollama: `ollama serve`) and try again.") if model not in available: raise SystemExit(f"The server has no model called {model!r}. It offers: {', '.join(available) or 'nothing'}.\n" f"Download it first (for Ollama: `ollama pull {model}`).") print(f"ok: {model!r} is available") async def main(): with ScriptedServer() as srv: for model in ("llama-a", "missing-model"): srv.respond(200, {"data": [{"id": "llama-a"}, {"id": "qwen-b"}]}) try: await require_model(srv.url, model) except SystemExit as e: print("exit:", e) try: await require_model(closed_port_url(), "llama-a") except SystemExit as e: print("exit:", e) asyncio.run(main()) Run with: py ex2.py Output (the port number in the last message changes on every run, and the address that cannot be reached took about two seconds to give up): ok: 'llama-a' is available exit: The server has no model called 'missing-model'. It offers: llama-a, qwen-b. Download it first (for Ollama: `ollama pull missing-model`). exit: Cannot reach a model server: no model server at http://127.0.0.1:53993: ConnectTimeout('') Start it (for Ollama: `ollama serve`) and try again. WHY THIS WORKS AS AN ANSWER --------------------------- There are three situations, each with its own fix, and the function tells them apart: the server is up and has the model (print ok), the server is up but the model has not been downloaded (say which models it does have and how to get the missing one), and no server answers at all (say so and how to start one). list_models already turns the "nothing answers" case into a typed ProviderUnavailable, so require_model only needs to catch that one error. Doing this once when the bot starts means the person who runs the bot sees a clear instruction instead of the first user getting a failure. The messages mention Ollama commands because that is the server this chapter uses; they come from Ollama's documentation and were not run here.