The per-model if/elif chain only ever set tokens_per_message=3 for
supported models (and 4 for the now-removed gpt-3.5 family). Collapse
it to a single assignment since every current chat model shares the
same overhead.
Existing users may have token usage recorded against models that have
since been removed from models.yml. Skip any model key not present in
the config when building the balance breakdown so /balance no longer
raises a KeyError for them.
generate_images now returns raw image bytes, so wrap each in BytesIO
for reply_photo instead of passing a URL. Reference the gpt-image-1
price entry in /balance and relabel it 'GPT Image'.
Replace DALL-E 3 with OpenAI's gpt-image-1 model. gpt-image-1 returns
base64-encoded images instead of URLs, so decode each result to raw
bytes and return the list of images.
Add a GitHub Actions workflow that installs requirements on Python
3.12 and byte-compiles the bot package on every push to main and on
pull requests, catching dependency-resolution and syntax errors early.
Reference the dalle-3 price entry and label balance details as
DALL·E 3, and count actually returned images (len(image_urls))
instead of the configured request count, since DALL-E 3 always
returns a single image.
512x512 is not a valid DALL-E 3 size. Default to 1024x1024 and update
the example config to list the supported DALL-E 3 sizes and note the
one-image-per-request limit.
gpt-4o was priced at its launch rate (0.005/0.015). OpenAI later cut
it to $2.50 / $10 per 1M tokens; update to 0.0025/0.01 so /balance
reflects current cost.
Drop gpt-3.5-turbo-16k, gpt-4-1106-preview and gpt-4-vision-preview
from available_text_models and their info blocks. All three are
deprecated/retired by OpenAI; gpt-4o and gpt-4o-mini cover their use
cases (including vision).
bot.py decided vision handling from hardcoded gpt-4o/gpt-4-vision
checks. Use the models.yml 'vision' flag instead: any vision-capable
model (incl. gpt-5.5 and Claude) now handles images directly, and a
photo sent to a non-vision model still falls back to gpt-4o. The
rejection message in the vision handler is updated to match.
send_vision_message and send_vision_message_stream now accept any
model flagged vision: true in models.yml instead of a hardcoded
gpt-4o/gpt-4-vision set, so Claude and gpt-5.5 can process images.
Add 'vision: true' to models that can read images: gpt-4o,
gpt-4o-mini, gpt-4-vision-preview, gpt-5.5 and the Claude models.
This lets the bot decide vision support from config instead of
hardcoded model names.
Record OpenRouter provider support, Claude models, gpt-5.5, the
config-driven model dispatch, token-counting fallback and the
settings button layout fix.
The settings menu put every model button in a single row. Telegram
rejects rows with more than 8 inline buttons, which would break
/settings now that the model list is longer. Chunk the buttons into
rows of two.
Add Claude Opus 4.8, Claude Sonnet and Claude Haiku as selectable
chat models, routed through OpenRouter (provider: openrouter). Slugs
and pricing taken from the OpenRouter model list. Requires
openrouter_api_key to be set.
Add OpenAI's latest flagship gpt-5.5 as a selectable model, routed
through OpenRouter (provider: openrouter, slug openai/gpt-5.5).
Pricing taken from the OpenRouter model list.
Introduce an optional OpenRouter client (OpenAI-compatible) alongside
the OpenAI one. Models can declare 'provider: openrouter' in
models.yml; ChatGPT now selects the matching client per model via
_get_client_for_model and routes chat completions through it. This
unlocks non-OpenAI models (e.g. Claude) through a single SDK.
Adds openrouter_api_key / openrouter_api_base config options.
Replace the hardcoded model-name sets in __init__, send_message and
send_message_stream with checks against config/models.yml: the assert
now accepts any model defined in models['info'], and the chat path is
taken for any model whose type is 'chat_completion'. Adding a new
chat model is now a models.yml-only change. Vision handling is left
on its explicit model set for now.
tiktoken.encoding_for_model and the per-model token table only know
OpenAI models, so any other model (Claude or anything routed via
OpenRouter) raised. Fall back to the o200k_base encoding and a
default tokens_per_message for unknown models so streaming token
estimates work for every chat model.
Note that gpt-4o-mini is the default model and add a News entry for
the openai 1.x SDK migration, the new default and the Python 3.12
image, linking to CHANGELOG.md.
Document the openai 1.x migration, gpt-4o/gpt-4o-mini support and new
default, Python 3.12 upgrade, dependency bumps, Docker improvements
and the text-davinci-003 removal.
Remove the legacy completion handling now that the model is gone:
- drop text-davinci-003 from the __init__ assert
- remove the legacy completions.create branches in send_message and
send_message_stream
- delete the now-unused _generate_prompt and _count_tokens_from_prompt
helpers
All remaining paths use the chat completions API.
OpenAI shut down the legacy text-davinci-003 completions model in
early 2024, so it can no longer be used. Drop it from the available
models list and remove its info block.
python:3.8-slim is EOL (security support ended Oct 2024). Move to
python:3.12-slim and drop the pinned setuptools==59.5.0, which
predates 3.12 support; use the current setuptools instead.
Keep the ChatGPT class fallback model in sync with the new project
default. Callers always pass an explicit model, so this only affects
the no-argument fallback.
new_dialog_handle pins the model on every /new. Point it at the new
default gpt-4o-mini so starting a new dialog no longer drops users
back onto the outdated gpt-3.5-turbo.
The default model is taken from available_text_models[0] (used by
Database.add_new_user and the registration fallback). Move
gpt-4o-mini to the front so new users start on it; gpt-3.5-turbo is
outdated, while gpt-4o-mini is cheaper, smarter and supports vision.
This also makes it the first option in the /settings menu.
chatgpt_price_per_1000_tokens, gpt_price_per_1000_tokens and
whisper_price_per_1_min are not read by config.py; pricing is defined
per model in config/models.yml. Remove them from the example to avoid
implying they have any effect.
Replace the two bare 'except:' clauses (is_bot_mentioned and the
error handler fallback) with 'except Exception:' so they no longer
swallow KeyboardInterrupt, SystemExit or asyncio.CancelledError,
which must propagate for clean shutdown and task cancellation.
Exclude .git, Python bytecode caches, .DS_Store and the local
config.yml/config.env from the Docker build context so they are not
sent to the daemon or baked into the image.
Mount ./config into the bot container so config.yml / models.yml /
chat_modes.yml changes take effect with a simple restart instead of
a full image rebuild. Addresses #124.
Without unbuffered output the bot's stdout/stderr can sit in a
buffer, so 'docker logs' shows nothing until the buffer flushes.
Set PYTHONUNBUFFERED=1 so log lines appear in real time.
Follow-up to the openai 1.x migration: the legacy
openai.error.InvalidRequestError no longer exists in the 1.x SDK.
Catch openai.BadRequestError when DALL-E rejects a prompt.
gpt-4o and gpt-4o-mini use the o200k_base encoding, which tiktoken
only ships from 0.7.0 onwards. With the previous >=0.3.0 pin
tiktoken.encoding_for_model("gpt-4o") raises, breaking token
counting in streaming mode for those models.
logger.error(current_model) fired on every incoming message and
spammed the error log with the model name; the accompanying
'# What is this? ^^^' note was dead. Drop both; the vision
auto-switch logic is unchanged.
Wire gpt-4o-mini through the bot: register it in models.yml
(available list + pricing/scores entry) and add it to the model
sets in openai_utils (chat, streaming, vision and token counting).
gpt-4o-mini is cheaper and smarter than gpt-3.5-turbo and supports
images, so it is a good default-grade option. Addresses #474.
gpt-4-1106-preview, gpt-4-vision-preview and gpt-4o used lowercase
score keys (smart/fast/cheap) while the rest used capitalized ones.
These keys are shown verbatim as labels in /settings, so normalize
them for consistent display.