fix(chapter4): skip empty choices chunks in streaming response
Some OpenAI-compatible APIs (e.g. AIHubMix) append a final tail packet
with choices=[] containing only usage statistics. Accessing chunk.choices[0]
on this packet raises IndexError, which is caught by the outer try/except
and returns None — silently discarding all previously streamed content.
Adding `if not chunk.choices: continue` skips these packets while
preserving the full response.
Fixes #522