TeLLMgramBot 2.3.0__tar.gz → 2.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/PKG-INFO +53 -35
  2. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/README.md +50 -33
  3. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/TeLLMgramBot/TeLLMgramBot.py +30 -36
  4. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/TeLLMgramBot/conversation.py +4 -4
  5. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/TeLLMgramBot/initialize.py +27 -13
  6. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/TeLLMgramBot/message_handlers.py +5 -10
  7. tellmgrambot-2.4.0/TeLLMgramBot/providers/__init__.py +0 -0
  8. tellmgrambot-2.4.0/TeLLMgramBot/providers/anthropic_provider.py +53 -0
  9. tellmgrambot-2.4.0/TeLLMgramBot/providers/base.py +27 -0
  10. tellmgrambot-2.4.0/TeLLMgramBot/providers/factory.py +23 -0
  11. tellmgrambot-2.4.0/TeLLMgramBot/providers/openai_provider.py +34 -0
  12. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/TeLLMgramBot/tokenGPT.py +33 -24
  13. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/TeLLMgramBot/web_utils.py +0 -1
  14. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/TeLLMgramBot.egg-info/PKG-INFO +53 -35
  15. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/TeLLMgramBot.egg-info/SOURCES.txt +6 -2
  16. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/TeLLMgramBot.egg-info/requires.txt +1 -0
  17. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/setup.py +3 -2
  18. tellmgrambot-2.3.0/TeLLMgramBot/openai_singleton.py +0 -12
  19. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/LICENSE +0 -0
  20. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/TeLLMgramBot/__init__.py +0 -0
  21. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/TeLLMgramBot/utils.py +0 -0
  22. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/TeLLMgramBot.egg-info/dependency_links.txt +0 -0
  23. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/TeLLMgramBot.egg-info/top_level.txt +0 -0
  24. {tellmgrambot-2.3.0 → tellmgrambot-2.4.0}/setup.cfg +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TeLLMgramBot
3
- Version: 2.3.0
4
- Summary: OpenAI GPT, driven by Telegram
3
+ Version: 2.4.0
4
+ Summary: LLM-powered Telegram bot (OpenAI + Anthropic)
5
5
  Home-page: https://github.com/Digital-Heresy/TeLLMgramBot
6
6
  Author: Digital Heresy
7
7
  Author-email: ronin.atx@gmail.com
@@ -10,6 +10,7 @@ Requires-Python: >=3.12
10
10
  Description-Content-Type: text/markdown
11
11
  License-File: LICENSE
12
12
  Requires-Dist: openai>2.0
13
+ Requires-Dist: anthropic>=0.40
13
14
  Requires-Dist: PyYAML
14
15
  Requires-Dist: httpx
15
16
  Requires-Dist: beautifulsoup4
@@ -29,9 +30,9 @@ Dynamic: requires-python
29
30
  Dynamic: summary
30
31
 
31
32
  # TeLLMgramBot
32
- The basic goal of this project is to create a bridge between a Telegram Bot and a Large Langage Model (LLM), like OpenAI's GPT models.
33
+ The basic goal of this project is to create a bridge between a Telegram Bot and a Large Language Model (LLM), supporting both OpenAI's GPT models and Anthropic's Claude models.
33
34
  * To use this library, you must have a Telegram account **with a user name**, not just a phone number. If you don't have one, [create one online](https://telegram.org/).
34
- * If added to a Telgram group, the bot must be [adminstrator](https://www.alphr.com/add-admin-telegram/) in order to respond to a user calling out its name, initials, or nickname.
35
+ * If added to a Telegram group, the bot must be [administrator](https://www.alphr.com/add-admin-telegram/) in order to respond to a user calling out its name, initials, or nickname.
35
36
  <img src="assets/TeLLMgramBot_Logo.png" width=200 align=center />
36
37
 
37
38
  ## Telegram Bot + LLM Encapsulation
@@ -39,34 +40,45 @@ The basic goal of this project is to create a bridge between a Telegram Bot and
39
40
  * The more dynamic conversation gets handed off to the LLM to manage prompts and responses, and Telegram acts as the interaction broker.
40
41
  * Pass the URL in [square brackets] and mention how the bot should interpret it.
41
42
  * Example: "What do you think of this article? [https://some_site/article]"
42
- * This uses another GPT model, preferably GPT-5 or GPT-4o, to support more URL content with its higher token limit.
43
+ * This uses a separate model (configurable via `url_model`) to support more URL content with its higher token limit.
43
44
  * Tokens are used to measure the length of all conversation messages between the Telegram bot assistant and the user. This is useful to:
44
45
  * Ensure the length does not go over the model limit. If it does, prune oldest messages to fit within the limit.
45
46
  * Remember 50% of the past conversations when starting up TeLLMgramBot again.
46
47
  * Users can also clear their conversation history for privacy.
47
48
 
48
49
  ## Why Telegram?
49
- Using Telegram as the interface not only solves "exposing" the interface, but gives you boadloads of interactivity over a standard Command Line interface, or trying to create a website with input boxes and submit buttons to try to handle everything:
50
+ Using Telegram as the interface not only solves "exposing" the interface, but gives you boatloads of interactivity over a standard Command Line interface, or trying to create a website with input boxes and submit buttons to try to handle everything:
50
51
  1. Telegram already lets you paste in verbose, multiline messages.
51
52
  2. Telegram already lets you paste in pictures, videos, links, etc.
52
53
  3. Telegram already lets you react with emojis, stickers, etc.
53
54
 
55
+ ## Supported LLM Providers
56
+ TeLLMgramBot selects the LLM provider automatically based on the model name:
57
+
58
+ | Model prefix | Provider | Example models |
59
+ |---|---|---|
60
+ | `gpt-` | OpenAI | `gpt-4o`, `gpt-4o-mini`, `gpt-5-mini` |
61
+ | `claude-` | Anthropic | `claude-sonnet-4-6`, `claude-haiku-4-5` |
62
+
63
+ Simply set `chat_model` (and optionally `url_model`) in your `config.yaml` to any supported model and supply the corresponding API key — no other changes needed.
64
+
54
65
  ## Directories
55
66
  When initializing TeLLMgramBot, the following directories get created:
56
67
  * `configs` - Contains bot configuration files.
57
68
  * `config.yaml` (can be a different name)
58
- * This file sets main OpenAI parameters like naming and GPT models to process.
59
- * The parameter `url_model` is to read URL content, different than `chat_model` that the bot normally uses to interact with the user.
60
- * An empty `token_limit` would do the maximum amount of tokens supported by the `chat_model` (e.g. 128000 for `gpt-4o-mini`).
69
+ * This file sets main bot parameters like naming and the LLM models to use.
70
+ * `chat_model` the model used for normal conversation (e.g. `gpt-5-mini` or `claude-sonnet-4-6`).
71
+ * `url_model` the model used to read and summarize URL content, can differ from `chat_model`.
72
+ * An empty `token_limit` will use the maximum tokens supported by the `chat_model`.
61
73
  * `tokenGPT.yaml`
62
- * This important YAML file contains token size parameters for supported OpenAI models.
63
- * If the first time, `gpt-5`, `gpt-5-mini`, `gpt-5-nano`, `gpt-4o`, and `gpt-4o-mini` get populated, but the user can specify more models with token size parameters as needed.
74
+ * Contains token size parameters for all supported models.
75
+ * On first run, GPT and Claude model families are pre-populated. Additional models can be added manually.
64
76
  * `prompts` - Contains prompt files for how the bot interacts with any user.
65
77
  * `test_personality.prmpt` (can be a different name)
66
- * This is a sample prompt file as a basis to test this library.
67
- * The user can create more prompt files as needed for different personalities. See [OpenAI Playground](https://platform.openai.com/playground) to test some ideas.
78
+ * A sample prompt file as a basis to test this library.
79
+ * The user can create more prompt files as needed for different personalities.
68
80
  * `url_analysis.prmpt`
69
- * This is a crucial prompt file to analyze URL content in brackets `[]` in a different model (such as `gpt-4o` or `gpt-4.1`).
81
+ * Prompt template used to analyze URL content passed in brackets `[]`.
70
82
  * `errorlogs`
71
83
  * Contains a `tellmgrambot_error.log` file to investigate if there are problems during the interaction.
72
84
  * User will also get notified to contact the owner.
@@ -84,24 +96,27 @@ TeLLMgramBot also creates or utilizes the following environment variables that c
84
96
  If neither of these are defined, the initialization would use the top-level execution run directory.
85
97
 
86
98
  ## API Keys
87
- To operate TeLLMgramBot, three API keys are required:
88
- * [OpenAI](https://platform.openai.com/overview) - Drives the actual GPT AI.
89
- * [Telegram](https://core.telegram.org/api) - Offers a Bot API through BotFather for the messaging platform.
90
- * [VirusTotal](https://www.virustotal.com/gui/home/) - Performs safety checks on URLs.
99
+ To operate TeLLMgramBot, the following API keys are required:
100
+ * **[OpenAI](https://platform.openai.com/overview)** required when using a `gpt-*` model.
101
+ * **[Anthropic](https://console.anthropic.com/)** required when using a `claude-*` model.
102
+ * **[Telegram](https://core.telegram.org/api)** always required; offers a Bot API through BotFather.
103
+ * **[VirusTotal](https://www.virustotal.com/gui/home/)** — always required; performs safety checks on URLs.
91
104
 
92
105
  There are two ways to populate each API key: environment variables or `.key` files.
93
106
 
94
107
  ### Environment Variables
95
- TeLLMgramBot uses the following environment variables that can be pre-loaded with the three API keys respectively:
96
- 1. `TELLMGRAMBOT_OPENAI_API_KEY`
97
- 2. `TELLMGRAMBOT_TELEGRAM_API_KEY`
98
- 3. `TELLMGRAMBOT_VIRUSTOTAL_API_KEY`
108
+ TeLLMgramBot uses the following environment variables for API keys:
109
+ 1. `TELLMGRAMBOT_OPENAI_API_KEY` *(OpenAI models)*
110
+ 2. `TELLMGRAMBOT_ANTHROPIC_API_KEY` *(Anthropic models)*
111
+ 3. `TELLMGRAMBOT_TELEGRAM_API_KEY`
112
+ 4. `TELLMGRAMBOT_VIRUSTOTAL_API_KEY`
99
113
 
100
114
  During spin-up time, a user can call out `os.environ[env_var]` to set those variables, like the following example:
101
115
  ```
102
116
  my_keys = Some_Vault_Fetch_Function()
103
117
 
104
- os.environ['TELLMGRAMBOT_OPENAI_API_KEY'] = my_keys['GPTKey']
118
+ os.environ['TELLMGRAMBOT_OPENAI_API_KEY'] = my_keys['OpenAIKey']
119
+ os.environ['TELLMGRAMBOT_ANTHROPIC_API_KEY'] = my_keys['AnthropicKey']
105
120
  os.environ['TELLMGRAMBOT_TELEGRAM_API_KEY'] = my_keys['BotFatherToken']
106
121
  os.environ['TELLMGRAMBOT_VIRUSTOTAL_API_KEY'] = my_keys['VirusTotalToken']
107
122
  ```
@@ -109,15 +124,16 @@ os.environ['TELLMGRAMBOT_VIRUSTOTAL_API_KEY'] = my_keys['VirusTotalToken']
109
124
  This means the user can implement whatever key vault they want to fetch the keys at runtime, without needing files stored in the directory.
110
125
 
111
126
  ### API Key Files
112
- The other route is to create three files by the base path during execution or a specified environment variable `TELLMGRAMBOT_KEYS_PATH`. By default, three files are created for the user to input each API key:
127
+ The other route is to create files by the base path during execution or a specified environment variable `TELLMGRAMBOT_KEYS_PATH`. By default, files are created for the user to input each API key:
113
128
  1. `openai.key`
114
- 2. `telegram.key`
115
- 3. `virustotal.key`
129
+ 2. `anthropic.key` _(planned — env var only for now; see Phase 3)_
130
+ 3. `telegram.key`
131
+ 4. `virustotal.key`
116
132
 
117
133
  Each file with the associated API key will update its respective environment variable if not defined.
118
134
 
119
135
  ## Bot Setup
120
- This library includes an example script `test_local.py`, which uses files from the folders `configs` and `prompts` for TeLLMgramBot to process. The bot communicates with OpenAI via the **Responses API**, which replaces the older Chat Completions endpoint.
136
+ This library includes an example script `test_local.py`, which uses files from the folders `configs` and `prompts` for TeLLMgramBot to process.
121
137
  1. Ensure the previous sections are followed with the proper API keys and your Telegram bot set.
122
138
  2. Install this library via PIP (`pip install TeLLMgramBot`) and then import into your project.
123
139
  3. Instantiate the bot by passing in various configuration pieces needed below.
@@ -127,8 +143,8 @@ This library includes an example script `test_local.py`, which uses files from t
127
143
  bot_owner = <Bot owner's Telegram username>,
128
144
  bot_nickname = <Bot nickname like 'Botty'>,
129
145
  bot_initials = <Bot initials like 'FB'>,
130
- chat_model = <Conversation model like 'gpt-4o-mini'>,
131
- url_model = <URL analysis model like 'gpt-4o'>,
146
+ chat_model = <Conversation model like 'gpt-4o-mini' or 'claude-sonnet-4-6'>,
147
+ url_model = <URL analysis model like 'gpt-4o' or 'claude-haiku-4-5'>,
132
148
  token_limit = <Maximum token count set, by default chat_model max>,
133
149
  persona_temp = <LLM factual to creative value [0-2], by default 1.0>,
134
150
  persona_prompt = <System prompt summarizing bot personality>
@@ -143,9 +159,11 @@ This library includes an example script `test_local.py`, which uses files from t
143
159
 
144
160
  ## Resources
145
161
  * GitHub repository [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) has guides to create a Telegram bot.
146
- * For more information on OpenAI models like `gpt-4o` and token limits, see the following:
147
- * [OpenAI model overview and maximum tokens](https://platform.openai.com/docs/models).
148
- * [OpenAI message conversion to tokens](https://github.com/openai/openai-python).
149
- * [OpenAI custom fine-tuning](https://platform.openai.com/docs/guides/model-optimization).
150
- * [OpenAI's tiktoken library, including some helpful guides](https://github.com/openai/tiktoken/tree/main).
151
- * [OpenAI Playground](https://platform.openai.com/playground) is a great place to test out prompts and responses.
162
+ * For more information on OpenAI models and token limits:
163
+ * [OpenAI model overview and maximum tokens](https://platform.openai.com/docs/models)
164
+ * [OpenAI message conversion to tokens](https://github.com/openai/openai-python)
165
+ * [OpenAI custom fine-tuning](https://platform.openai.com/docs/guides/model-optimization)
166
+ * [OpenAI's tiktoken library](https://github.com/openai/tiktoken/tree/main)
167
+ * For more information on Anthropic Claude models:
168
+ * [Anthropic model overview and context windows](https://docs.anthropic.com/en/docs/about-claude/models)
169
+ * [Anthropic Python SDK](https://github.com/anthropic/anthropic-sdk-python)
@@ -1,7 +1,7 @@
1
1
  # TeLLMgramBot
2
- The basic goal of this project is to create a bridge between a Telegram Bot and a Large Langage Model (LLM), like OpenAI's GPT models.
2
+ The basic goal of this project is to create a bridge between a Telegram Bot and a Large Language Model (LLM), supporting both OpenAI's GPT models and Anthropic's Claude models.
3
3
  * To use this library, you must have a Telegram account **with a user name**, not just a phone number. If you don't have one, [create one online](https://telegram.org/).
4
- * If added to a Telgram group, the bot must be [adminstrator](https://www.alphr.com/add-admin-telegram/) in order to respond to a user calling out its name, initials, or nickname.
4
+ * If added to a Telegram group, the bot must be [administrator](https://www.alphr.com/add-admin-telegram/) in order to respond to a user calling out its name, initials, or nickname.
5
5
  <img src="assets/TeLLMgramBot_Logo.png" width=200 align=center />
6
6
 
7
7
  ## Telegram Bot + LLM Encapsulation
@@ -9,34 +9,45 @@ The basic goal of this project is to create a bridge between a Telegram Bot and
9
9
  * The more dynamic conversation gets handed off to the LLM to manage prompts and responses, and Telegram acts as the interaction broker.
10
10
  * Pass the URL in [square brackets] and mention how the bot should interpret it.
11
11
  * Example: "What do you think of this article? [https://some_site/article]"
12
- * This uses another GPT model, preferably GPT-5 or GPT-4o, to support more URL content with its higher token limit.
12
+ * This uses a separate model (configurable via `url_model`) to support more URL content with its higher token limit.
13
13
  * Tokens are used to measure the length of all conversation messages between the Telegram bot assistant and the user. This is useful to:
14
14
  * Ensure the length does not go over the model limit. If it does, prune oldest messages to fit within the limit.
15
15
  * Remember 50% of the past conversations when starting up TeLLMgramBot again.
16
16
  * Users can also clear their conversation history for privacy.
17
17
 
18
18
  ## Why Telegram?
19
- Using Telegram as the interface not only solves "exposing" the interface, but gives you boadloads of interactivity over a standard Command Line interface, or trying to create a website with input boxes and submit buttons to try to handle everything:
19
+ Using Telegram as the interface not only solves "exposing" the interface, but gives you boatloads of interactivity over a standard Command Line interface, or trying to create a website with input boxes and submit buttons to try to handle everything:
20
20
  1. Telegram already lets you paste in verbose, multiline messages.
21
21
  2. Telegram already lets you paste in pictures, videos, links, etc.
22
22
  3. Telegram already lets you react with emojis, stickers, etc.
23
23
 
24
+ ## Supported LLM Providers
25
+ TeLLMgramBot selects the LLM provider automatically based on the model name:
26
+
27
+ | Model prefix | Provider | Example models |
28
+ |---|---|---|
29
+ | `gpt-` | OpenAI | `gpt-4o`, `gpt-4o-mini`, `gpt-5-mini` |
30
+ | `claude-` | Anthropic | `claude-sonnet-4-6`, `claude-haiku-4-5` |
31
+
32
+ Simply set `chat_model` (and optionally `url_model`) in your `config.yaml` to any supported model and supply the corresponding API key — no other changes needed.
33
+
24
34
  ## Directories
25
35
  When initializing TeLLMgramBot, the following directories get created:
26
36
  * `configs` - Contains bot configuration files.
27
37
  * `config.yaml` (can be a different name)
28
- * This file sets main OpenAI parameters like naming and GPT models to process.
29
- * The parameter `url_model` is to read URL content, different than `chat_model` that the bot normally uses to interact with the user.
30
- * An empty `token_limit` would do the maximum amount of tokens supported by the `chat_model` (e.g. 128000 for `gpt-4o-mini`).
38
+ * This file sets main bot parameters like naming and the LLM models to use.
39
+ * `chat_model` the model used for normal conversation (e.g. `gpt-5-mini` or `claude-sonnet-4-6`).
40
+ * `url_model` the model used to read and summarize URL content, can differ from `chat_model`.
41
+ * An empty `token_limit` will use the maximum tokens supported by the `chat_model`.
31
42
  * `tokenGPT.yaml`
32
- * This important YAML file contains token size parameters for supported OpenAI models.
33
- * If the first time, `gpt-5`, `gpt-5-mini`, `gpt-5-nano`, `gpt-4o`, and `gpt-4o-mini` get populated, but the user can specify more models with token size parameters as needed.
43
+ * Contains token size parameters for all supported models.
44
+ * On first run, GPT and Claude model families are pre-populated. Additional models can be added manually.
34
45
  * `prompts` - Contains prompt files for how the bot interacts with any user.
35
46
  * `test_personality.prmpt` (can be a different name)
36
- * This is a sample prompt file as a basis to test this library.
37
- * The user can create more prompt files as needed for different personalities. See [OpenAI Playground](https://platform.openai.com/playground) to test some ideas.
47
+ * A sample prompt file as a basis to test this library.
48
+ * The user can create more prompt files as needed for different personalities.
38
49
  * `url_analysis.prmpt`
39
- * This is a crucial prompt file to analyze URL content in brackets `[]` in a different model (such as `gpt-4o` or `gpt-4.1`).
50
+ * Prompt template used to analyze URL content passed in brackets `[]`.
40
51
  * `errorlogs`
41
52
  * Contains a `tellmgrambot_error.log` file to investigate if there are problems during the interaction.
42
53
  * User will also get notified to contact the owner.
@@ -54,24 +65,27 @@ TeLLMgramBot also creates or utilizes the following environment variables that c
54
65
  If neither of these are defined, the initialization would use the top-level execution run directory.
55
66
 
56
67
  ## API Keys
57
- To operate TeLLMgramBot, three API keys are required:
58
- * [OpenAI](https://platform.openai.com/overview) - Drives the actual GPT AI.
59
- * [Telegram](https://core.telegram.org/api) - Offers a Bot API through BotFather for the messaging platform.
60
- * [VirusTotal](https://www.virustotal.com/gui/home/) - Performs safety checks on URLs.
68
+ To operate TeLLMgramBot, the following API keys are required:
69
+ * **[OpenAI](https://platform.openai.com/overview)** required when using a `gpt-*` model.
70
+ * **[Anthropic](https://console.anthropic.com/)** required when using a `claude-*` model.
71
+ * **[Telegram](https://core.telegram.org/api)** always required; offers a Bot API through BotFather.
72
+ * **[VirusTotal](https://www.virustotal.com/gui/home/)** — always required; performs safety checks on URLs.
61
73
 
62
74
  There are two ways to populate each API key: environment variables or `.key` files.
63
75
 
64
76
  ### Environment Variables
65
- TeLLMgramBot uses the following environment variables that can be pre-loaded with the three API keys respectively:
66
- 1. `TELLMGRAMBOT_OPENAI_API_KEY`
67
- 2. `TELLMGRAMBOT_TELEGRAM_API_KEY`
68
- 3. `TELLMGRAMBOT_VIRUSTOTAL_API_KEY`
77
+ TeLLMgramBot uses the following environment variables for API keys:
78
+ 1. `TELLMGRAMBOT_OPENAI_API_KEY` *(OpenAI models)*
79
+ 2. `TELLMGRAMBOT_ANTHROPIC_API_KEY` *(Anthropic models)*
80
+ 3. `TELLMGRAMBOT_TELEGRAM_API_KEY`
81
+ 4. `TELLMGRAMBOT_VIRUSTOTAL_API_KEY`
69
82
 
70
83
  During spin-up time, a user can call out `os.environ[env_var]` to set those variables, like the following example:
71
84
  ```
72
85
  my_keys = Some_Vault_Fetch_Function()
73
86
 
74
- os.environ['TELLMGRAMBOT_OPENAI_API_KEY'] = my_keys['GPTKey']
87
+ os.environ['TELLMGRAMBOT_OPENAI_API_KEY'] = my_keys['OpenAIKey']
88
+ os.environ['TELLMGRAMBOT_ANTHROPIC_API_KEY'] = my_keys['AnthropicKey']
75
89
  os.environ['TELLMGRAMBOT_TELEGRAM_API_KEY'] = my_keys['BotFatherToken']
76
90
  os.environ['TELLMGRAMBOT_VIRUSTOTAL_API_KEY'] = my_keys['VirusTotalToken']
77
91
  ```
@@ -79,15 +93,16 @@ os.environ['TELLMGRAMBOT_VIRUSTOTAL_API_KEY'] = my_keys['VirusTotalToken']
79
93
  This means the user can implement whatever key vault they want to fetch the keys at runtime, without needing files stored in the directory.
80
94
 
81
95
  ### API Key Files
82
- The other route is to create three files by the base path during execution or a specified environment variable `TELLMGRAMBOT_KEYS_PATH`. By default, three files are created for the user to input each API key:
96
+ The other route is to create files by the base path during execution or a specified environment variable `TELLMGRAMBOT_KEYS_PATH`. By default, files are created for the user to input each API key:
83
97
  1. `openai.key`
84
- 2. `telegram.key`
85
- 3. `virustotal.key`
98
+ 2. `anthropic.key` _(planned — env var only for now; see Phase 3)_
99
+ 3. `telegram.key`
100
+ 4. `virustotal.key`
86
101
 
87
102
  Each file with the associated API key will update its respective environment variable if not defined.
88
103
 
89
104
  ## Bot Setup
90
- This library includes an example script `test_local.py`, which uses files from the folders `configs` and `prompts` for TeLLMgramBot to process. The bot communicates with OpenAI via the **Responses API**, which replaces the older Chat Completions endpoint.
105
+ This library includes an example script `test_local.py`, which uses files from the folders `configs` and `prompts` for TeLLMgramBot to process.
91
106
  1. Ensure the previous sections are followed with the proper API keys and your Telegram bot set.
92
107
  2. Install this library via PIP (`pip install TeLLMgramBot`) and then import into your project.
93
108
  3. Instantiate the bot by passing in various configuration pieces needed below.
@@ -97,8 +112,8 @@ This library includes an example script `test_local.py`, which uses files from t
97
112
  bot_owner = <Bot owner's Telegram username>,
98
113
  bot_nickname = <Bot nickname like 'Botty'>,
99
114
  bot_initials = <Bot initials like 'FB'>,
100
- chat_model = <Conversation model like 'gpt-4o-mini'>,
101
- url_model = <URL analysis model like 'gpt-4o'>,
115
+ chat_model = <Conversation model like 'gpt-4o-mini' or 'claude-sonnet-4-6'>,
116
+ url_model = <URL analysis model like 'gpt-4o' or 'claude-haiku-4-5'>,
102
117
  token_limit = <Maximum token count set, by default chat_model max>,
103
118
  persona_temp = <LLM factual to creative value [0-2], by default 1.0>,
104
119
  persona_prompt = <System prompt summarizing bot personality>
@@ -113,9 +128,11 @@ This library includes an example script `test_local.py`, which uses files from t
113
128
 
114
129
  ## Resources
115
130
  * GitHub repository [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) has guides to create a Telegram bot.
116
- * For more information on OpenAI models like `gpt-4o` and token limits, see the following:
117
- * [OpenAI model overview and maximum tokens](https://platform.openai.com/docs/models).
118
- * [OpenAI message conversion to tokens](https://github.com/openai/openai-python).
119
- * [OpenAI custom fine-tuning](https://platform.openai.com/docs/guides/model-optimization).
120
- * [OpenAI's tiktoken library, including some helpful guides](https://github.com/openai/tiktoken/tree/main).
121
- * [OpenAI Playground](https://platform.openai.com/playground) is a great place to test out prompts and responses.
131
+ * For more information on OpenAI models and token limits:
132
+ * [OpenAI model overview and maximum tokens](https://platform.openai.com/docs/models)
133
+ * [OpenAI message conversion to tokens](https://github.com/openai/openai-python)
134
+ * [OpenAI custom fine-tuning](https://platform.openai.com/docs/guides/model-optimization)
135
+ * [OpenAI's tiktoken library](https://github.com/openai/tiktoken/tree/main)
136
+ * For more information on Anthropic Claude models:
137
+ * [Anthropic model overview and context windows](https://docs.anthropic.com/en/docs/about-claude/models)
138
+ * [Anthropic Python SDK](https://github.com/anthropic/anthropic-sdk-python)
@@ -8,9 +8,8 @@ from math import floor
8
8
  from telegram import Bot, Update, Message, Chat, User
9
9
  from telegram.constants import MessageLimit
10
10
  from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes
11
- import openai
12
-
13
- from .openai_singleton import OpenAIClientSingleton
11
+ from .providers.factory import get_provider
12
+ from .providers.base import ContextLengthExceededError, ProviderAuthError, ProviderConnectionError
14
13
  from .initialize import INIT_BOT_CONFIG, init_structure, init_bot_config, init_bot_prompt
15
14
  from .conversation import Conversation
16
15
  from .tokenGPT import TokenGPT
@@ -19,7 +18,7 @@ from .utils import read_yaml, read_text, exact_word_match, generate_error_path,
19
18
 
20
19
  class TelegramBot:
21
20
  """
22
- The bridge between the Telegram interface and Large Langage Model (LLM) using OpenAI's GPT models.
21
+ The bridge between the Telegram interface and a Large Language Model (LLM).
23
22
  - Tokens help retain conversation messages between the Telegram bot assistant and the user.
24
23
  - URLs in [square brackets] can be supplied on how the bot should interpret it.
25
24
  - For more information, see README or: https://github.com/Digital-Heresy/TeLLMgramBot
@@ -136,21 +135,18 @@ class TelegramBot:
136
135
  # Check if the user is asking about a [URL]
137
136
  url_match = re.search(r'\[http(s)?://\S+]', text)
138
137
 
139
- # Form the assistant's message based on low level easy stuff or send to GPT
140
- # OpenAI's Responses API relies on the maximum number of tokens the selected model can support
138
+ # Form the assistant's message based on low level easy stuff or send to the LLM
141
139
  reply = "Sorry, I couldn't process your message! Please contact my creator."
142
140
  if handle_greetings(text):
143
141
  reply = handle_greetings(text)
144
142
  elif handle_common_queries(text):
145
143
  reply = handle_common_queries(text)
146
144
  elif url_match:
147
- # URL content is passed into another model to summarize (GPT-4 preferred)
148
145
  await msg.reply_text("Sure, give me a moment to look at that URL...")
149
146
  reply = await handle_url_ask(text, self.chatgpt['url_model'])
150
147
  elif self._online:
151
- # This is essentially the transition point between quick Telegram replies and GPT
152
- response = await self.gpt_completion(uname)
153
- reply = response.choices[0].message.content
148
+ # This is the transition point between quick Telegram replies and the LLM
149
+ reply = await self.llm_completion(uname)
154
150
 
155
151
  # Calculate the total token count of our conversation messages via tiktoken
156
152
  token_count = self.conversations[uname].get_message_token_count()
@@ -246,34 +242,32 @@ class TelegramBot:
246
242
  if msg:
247
243
  await msg.reply_text("Sorry, I ran into an error! Please contact my creator.")
248
244
 
249
- async def gpt_completion(self, uname: str):
250
- """Get the OpenAI response based on bot configuration."""
245
+ async def llm_completion(self, uname: str, _retry: bool = True) -> str:
246
+ """
247
+ Get the LLM response for the given user.
248
+
249
+ Selects the provider (OpenAI or Anthropic) automatically based on the configured model.
250
+ On context length errors, prunes the conversation and retries once. Other errors are
251
+ logged and return a user-facing fallback string.
252
+ """
253
+ provider = get_provider(self.chatgpt['chat_model'])
251
254
  try:
252
- client = OpenAIClientSingleton.get_instance()
253
- response = await client.chat.completions.create(
254
- model=self.chatgpt['chat_model'],
255
- messages=self.conversations[uname].messages,
256
- )
257
- return response
258
- except openai.AuthenticationError as e:
259
- # Handle authentication error
260
- log_error(e, error_type='OpenAI-Authentication', error_filename=self.error_log)
261
- except openai.BadRequestError as e:
262
- # Handle invalid request error
263
- if re.search(r'maximum context.+reduce the length', str(e)):
264
- # Remove older messages and try again since the model's maximum token limit reached
265
- print(f"Response to {uname} reached maximum context length, pruning conversation")
266
- self.conversations[uname].prune_conversation(self.chatgpt['prune_back_to'])
267
- return await self.gpt_completion(uname)
268
- else:
269
- # Another error is actually invalid to investigate
270
- log_error(e, error_type='OpenAI-BadRequest', error_filename=self.error_log)
271
- except openai.APIConnectionError as e:
272
- # Handle API connection error
273
- log_error(e, error_type='OpenAI-APIConnection', error_filename=self.error_log)
255
+ return await provider.complete(self.chatgpt['chat_model'], self.conversations[uname].messages)
256
+ except ContextLengthExceededError:
257
+ if not _retry:
258
+ return "Sorry, your conversation is too long for me to respond to. Try /forget to start fresh."
259
+ print(f"Response to {uname} reached maximum context length, pruning conversation")
260
+ self.conversations[uname].prune_conversation(self.chatgpt['prune_back_to'])
261
+ return await self.llm_completion(uname, _retry=False)
262
+ except ProviderAuthError as e:
263
+ log_error(e, error_type='Authentication', error_filename=self.error_log)
264
+ return "Sorry, I'm having trouble authenticating with the AI provider. Please contact the bot owner."
265
+ except ProviderConnectionError as e:
266
+ log_error(e, error_type='Connection', error_filename=self.error_log)
267
+ return "Sorry, I couldn't reach the AI provider. Please try again in a moment."
274
268
  except Exception as e:
275
- # Catch any other unexpected exceptions
276
269
  log_error(e, error_type='Other', error_filename=self.error_log)
270
+ return "Sorry, something went wrong on my end. Please try again."
277
271
 
278
272
  def start_polling(self):
279
273
  """The main polling "loop" the user interacts with via Telegram."""
@@ -344,7 +338,7 @@ class TelegramBot:
344
338
  self.chatgpt['prune_back_to'] = max(0, self.chatgpt['prune_threshold'] - 500)
345
339
 
346
340
  # Bot is now ready and active by default
347
- self._online = True
341
+ self._online = True
348
342
 
349
343
  def set(config_file='config.yaml', prompt_file='test_personality.prmpt'):
350
344
  """Set TeLLMgramBot object based on its YAML configuration and prompt files."""
@@ -1,4 +1,4 @@
1
- # Provides TeLLMgramBot a way to store and retrieve conversation messages by the OpenAI model
1
+ # Manages per-user conversation history, token counting, and session persistence for any LLM provider
2
2
  import os
3
3
  import re
4
4
  import sys
@@ -10,8 +10,8 @@ from .utils import get_safe_username, read_reverse_order, append_text_file_path,
10
10
  # noinspection RegExpRedundantEscape,PyTypeChecker
11
11
  class Conversation:
12
12
  """
13
- Defines a user-assistant interaction based on the assistant's Generative AI model and prompt to contextualize
14
- with message history. Like memory, if reaching the maximum amount of tokens, prunes earliest messages under limit.
13
+ Manages a user-assistant conversation including message history, token counting, and session log persistence.
14
+ Works with any LLM provider (OpenAI, Anthropic). When the token limit is approached, oldest messages are pruned.
15
15
  """
16
16
  def __init__(self, user_name: str, assist_name: str, system_content: str, system_model="gpt-4o-mini"):
17
17
  self.error_log = generate_error_path()
@@ -21,7 +21,7 @@ class Conversation:
21
21
  self.assist_name = assist_name
22
22
  self.names_print = f"User {self.user_name} & Assistant {self.assist_name}"
23
23
 
24
- # System defines how the assistant will respond to the user by prompt and GPT model
24
+ # System defines how the assistant will respond to the user by prompt and LLM model
25
25
  self.system_content = system_content
26
26
  self.system_model = TokenGPT(system_model)
27
27
  self.messages = [{"role": "system", "content": system_content}]
@@ -50,13 +50,17 @@ def init_directories():
50
50
 
51
51
  def init_keys():
52
52
  """
53
- TeLLMgramBot utilizes three API keys by environment variables:
54
- - TELLMGRAMBOT_OPENAI_API_KEY
55
- - TELLMGRAMBOT_TELEGRAM_API_KEY
56
- - TELLMGRAMBOT_VIRUSTOTAL_API_KEY
53
+ TeLLMgramBot utilizes the following API keys via environment variables:
54
+ - TELLMGRAMBOT_OPENAI_API_KEY (currently required at startup regardless of configured model; Phase 3 will make this conditional)
55
+ - TELLMGRAMBOT_TELEGRAM_API_KEY (always required)
56
+ - TELLMGRAMBOT_VIRUSTOTAL_API_KEY (always required)
57
57
 
58
- If neither one above exists, retrieve its key file by base execution path or
59
- TELLMGRAMBOT_KEYS_PATH. If no such key file, request user input with resources.
58
+ The Anthropic key (TELLMGRAMBOT_ANTHROPIC_API_KEY) is read directly by
59
+ AnthropicProvider at call time and is required when using claude-* models.
60
+ Key file support (anthropic.key) is planned for Phase 3.
61
+
62
+ If an environment variable is not set, its key file is read from the base execution
63
+ path or TELLMGRAMBOT_KEYS_PATH. If no file exists, a placeholder is created.
60
64
  - openai.key
61
65
  - telegram.key
62
66
  - virustotal.key
@@ -128,22 +132,32 @@ def init_tokenGPT_config(file='tokenGPT.yaml') -> str:
128
132
  try:
129
133
  # Create a basic GPT configuration of token parameters by filename
130
134
  return generate_file_path(os.environ[env_var], file, "TokenGPT configuration",
131
- "# Available parameters per base OpenAI model with default values:\n"
135
+ "# Available parameters per model with default values:\n"
132
136
  "# max_tokens: 4097\n"
133
- "# tokens_per_message: 3\n"
134
- "# tokens_per_name: 1\n"
137
+ "# tokens_per_message: 3 (OpenAI models only)\n"
138
+ "# tokens_per_name: 1 (OpenAI models only)\n"
135
139
  "# For OpenAI's updated list of models, please see:\n"
136
140
  "# https://platform.openai.com/docs/models\n"
141
+ "# For Anthropic's updated list of models, please see:\n"
142
+ "# https://docs.anthropic.com/en/docs/about-claude/models\n"
137
143
  "'gpt-4o':\n"
138
144
  " max_tokens: 128000\n"
139
145
  "'gpt-4o-mini':\n"
140
146
  " max_tokens: 128000\n"
141
147
  "'gpt-5':\n"
142
148
  " max_tokens: 400000\n"
143
- "'gpt-5-mini':\n"
149
+ "'gpt-5-mini':\n"
144
150
  " max_tokens: 400000\n"
145
151
  "'gpt-5-nano':\n"
146
152
  " max_tokens: 400000\n"
153
+ "'claude-opus-4-6':\n"
154
+ " max_tokens: 200000\n"
155
+ "'claude-sonnet-4-6':\n"
156
+ " max_tokens: 200000\n"
157
+ "'claude-haiku-4-5':\n"
158
+ " max_tokens: 200000\n"
159
+ "'claude-haiku-4-5-20251001':\n"
160
+ " max_tokens: 200000\n"
147
161
  )
148
162
  except KeyError:
149
163
  sys.exit(f"{env_var} must be defined to create file '{file}'! Exiting...")
@@ -158,9 +172,9 @@ def init_bot_prompt(file='test_personality.prmpt') -> str:
158
172
  env_var = "TELLMGRAMBOT_PROMPTS_PATH"
159
173
  try:
160
174
  return generate_file_path(os.environ[env_var], file, "bot personality prompt",
161
- "You are a test harness bot based on a GPT-5 mini model that can:\n"
162
- "1. Fetch URLs, provided the user supply a URL in [square brackets].\n"
163
- "2. Scrub URLs to ensure they are safe for work via the VirusTotal API.\n"
175
+ "You are a test harness bot that can:\n"
176
+ "1. Fetch and analyze URLs provided in [square brackets].\n"
177
+ "2. Safety-check URLs via VirusTotal.\n"
164
178
  )
165
179
  except KeyError:
166
180
  sys.exit(f"{env_var} must be defined to create file '{file}'! Exiting...")
@@ -6,7 +6,7 @@ import validators
6
6
  from .initialize import init_url_prompt
7
7
  from .tokenGPT import TokenGPT
8
8
  from .web_utils import fetch_url, strip_html_markup, InvalidURLException, InsecureURLException, SusURLException
9
- from .openai_singleton import OpenAIClientSingleton
9
+ from .providers.factory import get_provider
10
10
 
11
11
  def handle_greetings(text: str) -> Optional[str]:
12
12
  """
@@ -55,7 +55,7 @@ async def handle_url_ask(text: str, model='gpt-4o') -> Optional[str]:
55
55
  if not validators.url(url):
56
56
  raise InvalidURLException(f'Invalid URL parsed by message_handlers.handle_url_ask(): {url}')
57
57
 
58
- # Let's begin by building the OpenAI messages to set:
58
+ # Build messages:
59
59
  # 1. URL content to be added into the system prompt template
60
60
  # 2. User message requesting URL in [square brackets]
61
61
  messages = [
@@ -86,16 +86,11 @@ async def handle_url_ask(text: str, model='gpt-4o') -> Optional[str]:
86
86
  template = f.read()
87
87
  messages[0]["content"] = template.format(url_content=messages[0]["content"])
88
88
 
89
- # Call OpenAI API for the response that summarizes URL content
90
- client = OpenAIClientSingleton.get_instance()
89
+ # Call the LLM for the response that summarizes URL content
91
90
  try:
92
- ask_results = await client.chat.completions.create(
93
- model=model,
94
- messages=messages
95
- )
96
- response = ask_results.choices[0].message.content
91
+ response = await get_provider(model).complete(model, messages)
97
92
  except Exception as e:
98
- print(f"Error in calling OpenAI API: {e}")
93
+ print(f"Error calling LLM provider: {e}")
99
94
  return "Something went wrong while fetching the URL. Please try again later."
100
95
 
101
96
  # If the URL content was too long, let the user know
File without changes
@@ -0,0 +1,53 @@
1
+ import os
2
+ import anthropic
3
+ from anthropic import AsyncAnthropic
4
+
5
+ from .base import LLMProvider, ContextLengthExceededError, ProviderAuthError, ProviderConnectionError
6
+
7
+ # Safe default for max output tokens; configurable in Phase 3
8
+ _DEFAULT_MAX_OUTPUT_TOKENS = 8192
9
+
10
+ class AnthropicProvider(LLMProvider):
11
+ """LLM provider implementation for Anthropic Claude models."""
12
+ _client: AsyncAnthropic | None = None
13
+
14
+ def _get_client(self) -> AsyncAnthropic:
15
+ if AnthropicProvider._client is None:
16
+ if not (api_key := os.environ.get('TELLMGRAMBOT_ANTHROPIC_API_KEY')):
17
+ raise ProviderAuthError("Anthropic API key not set. Provide TELLMGRAMBOT_ANTHROPIC_API_KEY.")
18
+ AnthropicProvider._client = AsyncAnthropic(api_key=api_key)
19
+ return AnthropicProvider._client
20
+
21
+ async def complete(self, model: str, messages: list[dict]) -> str:
22
+ client = self._get_client()
23
+
24
+ # Anthropic takes system prompt as a separate parameter, not in the messages list
25
+ system = None
26
+ chat_messages = []
27
+ for msg in messages:
28
+ if msg['role'] == 'system':
29
+ system = msg['content']
30
+ else:
31
+ chat_messages.append(msg)
32
+
33
+ kwargs = {
34
+ 'model': model,
35
+ 'max_tokens': _DEFAULT_MAX_OUTPUT_TOKENS,
36
+ 'messages': chat_messages,
37
+ }
38
+ if system:
39
+ kwargs['system'] = system
40
+
41
+ try:
42
+ response = await client.messages.create(**kwargs)
43
+ if not response.content or response.content[0].type != 'text':
44
+ return ""
45
+ return response.content[0].text
46
+ except anthropic.AuthenticationError as e:
47
+ raise ProviderAuthError(f"Anthropic authentication failed: {e}") from e
48
+ except anthropic.BadRequestError as e:
49
+ if 'too long' in str(e).lower() or 'context' in str(e).lower():
50
+ raise ContextLengthExceededError() from e
51
+ raise
52
+ except anthropic.APIConnectionError as e:
53
+ raise ProviderConnectionError(f"Anthropic connection error: {e}") from e
@@ -0,0 +1,27 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ class ContextLengthExceededError(Exception):
4
+ """Raised when a request exceeds the model's context window."""
5
+ pass
6
+
7
+ class ProviderAuthError(Exception):
8
+ """Raised when an API key is invalid or missing."""
9
+ pass
10
+
11
+ class ProviderConnectionError(Exception):
12
+ """Raised when the provider's API cannot be reached."""
13
+ pass
14
+
15
+ class LLMProvider(ABC):
16
+ """Abstract base class for LLM provider implementations."""
17
+
18
+ @abstractmethod
19
+ async def complete(self, model: str, messages: list[dict]) -> str:
20
+ """Send messages to the model and return the response text.
21
+
22
+ Raises:
23
+ ContextLengthExceededError: if the request exceeds the model's context window.
24
+ ProviderAuthError: if authentication fails.
25
+ ProviderConnectionError: if the API cannot be reached.
26
+ """
27
+ pass
@@ -0,0 +1,23 @@
1
+ from .base import LLMProvider
2
+ from .openai_provider import OpenAIProvider
3
+ from .anthropic_provider import AnthropicProvider
4
+
5
+ _providers: dict[str, LLMProvider] = {}
6
+
7
+ def get_provider(model: str) -> LLMProvider:
8
+ """Return the appropriate LLM provider for the given model name.
9
+
10
+ Provider is inferred from the model name prefix:
11
+ - 'claude-' → AnthropicProvider
12
+ - anything else → OpenAIProvider
13
+ """
14
+ if model.startswith('claude-'):
15
+ key = 'anthropic'
16
+ if key not in _providers:
17
+ _providers[key] = AnthropicProvider()
18
+ return _providers[key]
19
+ else:
20
+ key = 'openai'
21
+ if key not in _providers:
22
+ _providers[key] = OpenAIProvider()
23
+ return _providers[key]
@@ -0,0 +1,34 @@
1
+ import re
2
+ import os
3
+ import openai
4
+ from openai import AsyncOpenAI
5
+
6
+ from .base import LLMProvider, ContextLengthExceededError, ProviderAuthError, ProviderConnectionError
7
+
8
+ class OpenAIProvider(LLMProvider):
9
+ """LLM provider implementation for OpenAI models."""
10
+ _client: AsyncOpenAI | None = None
11
+
12
+ def _get_client(self) -> AsyncOpenAI:
13
+ if OpenAIProvider._client is None:
14
+ if not (api_key := os.environ.get('TELLMGRAMBOT_OPENAI_API_KEY')):
15
+ raise ProviderAuthError("OpenAI API key not set. Provide TELLMGRAMBOT_OPENAI_API_KEY.")
16
+ OpenAIProvider._client = AsyncOpenAI(api_key=api_key)
17
+ return OpenAIProvider._client
18
+
19
+ async def complete(self, model: str, messages: list[dict]) -> str:
20
+ client = self._get_client()
21
+ try:
22
+ response = await client.chat.completions.create(
23
+ model=model,
24
+ messages=messages,
25
+ )
26
+ return response.choices[0].message.content
27
+ except openai.AuthenticationError as e:
28
+ raise ProviderAuthError(f"OpenAI authentication failed: {e}") from e
29
+ except openai.BadRequestError as e:
30
+ if re.search(r'maximum context.+reduce the length', str(e)):
31
+ raise ContextLengthExceededError() from e
32
+ raise
33
+ except openai.APIConnectionError as e:
34
+ raise ProviderConnectionError(f"OpenAI connection error: {e}") from e
@@ -5,19 +5,19 @@ from .initialize import init_tokenGPT_config
5
5
 
6
6
  class TokenGPT:
7
7
  """
8
- Define Generative AI model parameters and token count of messages using OpenAI's tiktoken library.
9
- First-time execution creates a tokenGPT.yaml file with example Generative Pre-trained Transformer (GPT) models,
10
- which can be expanded by the user for additional inputs or modifications like tokens per message.
8
+ Define LLM model parameters and token count of messages.
9
+ First-time execution creates a tokenGPT.yaml file with example models,
10
+ which can be expanded by the user for additional inputs or modifications like tokens per message.
11
+ OpenAI models use tiktoken for counting; other models use a character-based approximation.
11
12
 
12
13
  Sources:
13
14
  - https://platform.openai.com/docs/models
14
- - https://github.com/openai/openai-python
15
- - https://platform.openai.com/docs/guides/model-optimization
15
+ - https://docs.anthropic.com/en/docs/about-claude/models
16
16
  """
17
- def __init__(self, openai_model="gpt-4o-mini", yaml_file="tokenGPT.yaml"):
18
- # The OpenAI model name may also be a fine-tuned model, which has the base model
17
+ def __init__(self, model="gpt-4o-mini", yaml_file="tokenGPT.yaml"):
18
+ # The model name may also be an OpenAI fine-tuned model, which has the base model
19
19
  # after "ft:" up to the next colon (:), like "ft:gpt-4o-mini:..."
20
- self.model = re.search("^ft:([^:]*)", openai_model).group(1) if openai_model.startswith("ft:") else openai_model
20
+ self.model = re.search("^ft:([^:]*)", model).group(1) if model.startswith("ft:") else model
21
21
  self.config_path = init_tokenGPT_config(yaml_file)
22
22
 
23
23
  # Get model parameters by configuration file for the:
@@ -27,18 +27,18 @@ class TokenGPT:
27
27
  self.param = None
28
28
  for key, param in read_yaml(self.config_path).items():
29
29
  # Set parameters if the configuration key matches either:
30
- # > Full OpenAI model name (an exact match to stop searching)
31
- # > Base model name after "ft:" up to next colon (:), part of the OpenAI model name
32
- if key == openai_model or key == self.model:
30
+ # > Full model name (an exact match to stop searching)
31
+ # > Base model name after "ft:" up to next colon (:), for fine-tuned OpenAI models
32
+ if key == model or key == self.model:
33
33
  self.param = param
34
- if key == openai_model:
34
+ if key == model:
35
35
  break
36
36
 
37
- # If the parameters are not set, the OpenAI model name is invalid or
37
+ # If the parameters are not set, the model name is invalid or
38
38
  # has an undefined model configuration not set in the YAML file
39
39
  if self.param is None:
40
40
  raise ValueError(
41
- f"OpenAI model \"{openai_model}\" is invalid or its base model is not in:\n{self.config_path}")
41
+ f"Model \"{model}\" is invalid or its base model is not in:\n{self.config_path}")
42
42
 
43
43
  # Set token model parameter defaults, unless defined in configuration:
44
44
  if 'max_tokens' not in self.param:
@@ -48,16 +48,20 @@ class TokenGPT:
48
48
  if 'tokens_per_name' not in self.param:
49
49
  self.param['tokens_per_name'] = 1
50
50
 
51
- # Get OpenAI's tiktoken encoding of the base model name
52
- try:
53
- self.encoding = tiktoken.encoding_for_model(self.model)
54
- except Exception:
55
- fallback = "o200k_base" if re.search("^gpt-[45]", self.model) else "cl100k_base"
51
+ # Claude models are not supported by tiktoken; use a character-based approximation
52
+ # (~4 chars per token) instead. A future version may add SDK-native Anthropic counting.
53
+ self._use_char_approximation = self.model.startswith('claude-')
54
+ self.encoding = None
55
+ if not self._use_char_approximation:
56
56
  try:
57
- self.encoding = tiktoken.get_encoding(fallback)
57
+ self.encoding = tiktoken.encoding_for_model(self.model)
58
58
  except Exception:
59
- self.encoding = tiktoken.get_encoding("cl100k_base")
60
- print(f"Warning: using {self.encoding.name} encoding for model \"{self.model}\"")
59
+ fallback = "o200k_base" if re.search("^gpt-[45]", self.model) else "cl100k_base"
60
+ try:
61
+ self.encoding = tiktoken.get_encoding(fallback)
62
+ except Exception:
63
+ self.encoding = tiktoken.get_encoding("cl100k_base")
64
+ print(f"Warning: using {self.encoding.name} encoding for model \"{self.model}\"")
61
65
 
62
66
  def max_tokens(self) -> int:
63
67
  """Query the Generative AI model's maximum amount of tokens."""
@@ -65,11 +69,16 @@ class TokenGPT:
65
69
 
66
70
  def num_tokens_from_messages(self, messages: dict[str, str]) -> int:
67
71
  """
68
- Return the number of tokens based on a list of messages and the Generative AI model in use.
69
- Each message size is determined by the number of tokens via OpenAI's tiktoken library.
72
+ Return the number of tokens based on a list of messages and the model in use.
73
+
74
+ For OpenAI models: uses tiktoken for an accurate count.
75
+ For Claude models: uses a character-based approximation (~4 chars per token).
70
76
 
71
77
  Source: https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb
72
78
  """
79
+ if self._use_char_approximation:
80
+ return sum(max(1, len(v) // 4) for msg in messages for v in msg.values())
81
+
73
82
  num_tokens = 0
74
83
  for message in messages:
75
84
  num_tokens += self.param['tokens_per_message']
@@ -20,7 +20,6 @@ class SusURLException(Exception):
20
20
  """Exception raised for insecure URLs."""
21
21
  pass
22
22
 
23
-
24
23
  class FetchingError(Exception):
25
24
  """Exception raised for errors during fetching."""
26
25
  pass
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TeLLMgramBot
3
- Version: 2.3.0
4
- Summary: OpenAI GPT, driven by Telegram
3
+ Version: 2.4.0
4
+ Summary: LLM-powered Telegram bot (OpenAI + Anthropic)
5
5
  Home-page: https://github.com/Digital-Heresy/TeLLMgramBot
6
6
  Author: Digital Heresy
7
7
  Author-email: ronin.atx@gmail.com
@@ -10,6 +10,7 @@ Requires-Python: >=3.12
10
10
  Description-Content-Type: text/markdown
11
11
  License-File: LICENSE
12
12
  Requires-Dist: openai>2.0
13
+ Requires-Dist: anthropic>=0.40
13
14
  Requires-Dist: PyYAML
14
15
  Requires-Dist: httpx
15
16
  Requires-Dist: beautifulsoup4
@@ -29,9 +30,9 @@ Dynamic: requires-python
29
30
  Dynamic: summary
30
31
 
31
32
  # TeLLMgramBot
32
- The basic goal of this project is to create a bridge between a Telegram Bot and a Large Langage Model (LLM), like OpenAI's GPT models.
33
+ The basic goal of this project is to create a bridge between a Telegram Bot and a Large Language Model (LLM), supporting both OpenAI's GPT models and Anthropic's Claude models.
33
34
  * To use this library, you must have a Telegram account **with a user name**, not just a phone number. If you don't have one, [create one online](https://telegram.org/).
34
- * If added to a Telgram group, the bot must be [adminstrator](https://www.alphr.com/add-admin-telegram/) in order to respond to a user calling out its name, initials, or nickname.
35
+ * If added to a Telegram group, the bot must be [administrator](https://www.alphr.com/add-admin-telegram/) in order to respond to a user calling out its name, initials, or nickname.
35
36
  <img src="assets/TeLLMgramBot_Logo.png" width=200 align=center />
36
37
 
37
38
  ## Telegram Bot + LLM Encapsulation
@@ -39,34 +40,45 @@ The basic goal of this project is to create a bridge between a Telegram Bot and
39
40
  * The more dynamic conversation gets handed off to the LLM to manage prompts and responses, and Telegram acts as the interaction broker.
40
41
  * Pass the URL in [square brackets] and mention how the bot should interpret it.
41
42
  * Example: "What do you think of this article? [https://some_site/article]"
42
- * This uses another GPT model, preferably GPT-5 or GPT-4o, to support more URL content with its higher token limit.
43
+ * This uses a separate model (configurable via `url_model`) to support more URL content with its higher token limit.
43
44
  * Tokens are used to measure the length of all conversation messages between the Telegram bot assistant and the user. This is useful to:
44
45
  * Ensure the length does not go over the model limit. If it does, prune oldest messages to fit within the limit.
45
46
  * Remember 50% of the past conversations when starting up TeLLMgramBot again.
46
47
  * Users can also clear their conversation history for privacy.
47
48
 
48
49
  ## Why Telegram?
49
- Using Telegram as the interface not only solves "exposing" the interface, but gives you boadloads of interactivity over a standard Command Line interface, or trying to create a website with input boxes and submit buttons to try to handle everything:
50
+ Using Telegram as the interface not only solves "exposing" the interface, but gives you boatloads of interactivity over a standard Command Line interface, or trying to create a website with input boxes and submit buttons to try to handle everything:
50
51
  1. Telegram already lets you paste in verbose, multiline messages.
51
52
  2. Telegram already lets you paste in pictures, videos, links, etc.
52
53
  3. Telegram already lets you react with emojis, stickers, etc.
53
54
 
55
+ ## Supported LLM Providers
56
+ TeLLMgramBot selects the LLM provider automatically based on the model name:
57
+
58
+ | Model prefix | Provider | Example models |
59
+ |---|---|---|
60
+ | `gpt-` | OpenAI | `gpt-4o`, `gpt-4o-mini`, `gpt-5-mini` |
61
+ | `claude-` | Anthropic | `claude-sonnet-4-6`, `claude-haiku-4-5` |
62
+
63
+ Simply set `chat_model` (and optionally `url_model`) in your `config.yaml` to any supported model and supply the corresponding API key — no other changes needed.
64
+
54
65
  ## Directories
55
66
  When initializing TeLLMgramBot, the following directories get created:
56
67
  * `configs` - Contains bot configuration files.
57
68
  * `config.yaml` (can be a different name)
58
- * This file sets main OpenAI parameters like naming and GPT models to process.
59
- * The parameter `url_model` is to read URL content, different than `chat_model` that the bot normally uses to interact with the user.
60
- * An empty `token_limit` would do the maximum amount of tokens supported by the `chat_model` (e.g. 128000 for `gpt-4o-mini`).
69
+ * This file sets main bot parameters like naming and the LLM models to use.
70
+ * `chat_model` the model used for normal conversation (e.g. `gpt-5-mini` or `claude-sonnet-4-6`).
71
+ * `url_model` the model used to read and summarize URL content, can differ from `chat_model`.
72
+ * An empty `token_limit` will use the maximum tokens supported by the `chat_model`.
61
73
  * `tokenGPT.yaml`
62
- * This important YAML file contains token size parameters for supported OpenAI models.
63
- * If the first time, `gpt-5`, `gpt-5-mini`, `gpt-5-nano`, `gpt-4o`, and `gpt-4o-mini` get populated, but the user can specify more models with token size parameters as needed.
74
+ * Contains token size parameters for all supported models.
75
+ * On first run, GPT and Claude model families are pre-populated. Additional models can be added manually.
64
76
  * `prompts` - Contains prompt files for how the bot interacts with any user.
65
77
  * `test_personality.prmpt` (can be a different name)
66
- * This is a sample prompt file as a basis to test this library.
67
- * The user can create more prompt files as needed for different personalities. See [OpenAI Playground](https://platform.openai.com/playground) to test some ideas.
78
+ * A sample prompt file as a basis to test this library.
79
+ * The user can create more prompt files as needed for different personalities.
68
80
  * `url_analysis.prmpt`
69
- * This is a crucial prompt file to analyze URL content in brackets `[]` in a different model (such as `gpt-4o` or `gpt-4.1`).
81
+ * Prompt template used to analyze URL content passed in brackets `[]`.
70
82
  * `errorlogs`
71
83
  * Contains a `tellmgrambot_error.log` file to investigate if there are problems during the interaction.
72
84
  * User will also get notified to contact the owner.
@@ -84,24 +96,27 @@ TeLLMgramBot also creates or utilizes the following environment variables that c
84
96
  If neither of these are defined, the initialization would use the top-level execution run directory.
85
97
 
86
98
  ## API Keys
87
- To operate TeLLMgramBot, three API keys are required:
88
- * [OpenAI](https://platform.openai.com/overview) - Drives the actual GPT AI.
89
- * [Telegram](https://core.telegram.org/api) - Offers a Bot API through BotFather for the messaging platform.
90
- * [VirusTotal](https://www.virustotal.com/gui/home/) - Performs safety checks on URLs.
99
+ To operate TeLLMgramBot, the following API keys are required:
100
+ * **[OpenAI](https://platform.openai.com/overview)** required when using a `gpt-*` model.
101
+ * **[Anthropic](https://console.anthropic.com/)** required when using a `claude-*` model.
102
+ * **[Telegram](https://core.telegram.org/api)** always required; offers a Bot API through BotFather.
103
+ * **[VirusTotal](https://www.virustotal.com/gui/home/)** — always required; performs safety checks on URLs.
91
104
 
92
105
  There are two ways to populate each API key: environment variables or `.key` files.
93
106
 
94
107
  ### Environment Variables
95
- TeLLMgramBot uses the following environment variables that can be pre-loaded with the three API keys respectively:
96
- 1. `TELLMGRAMBOT_OPENAI_API_KEY`
97
- 2. `TELLMGRAMBOT_TELEGRAM_API_KEY`
98
- 3. `TELLMGRAMBOT_VIRUSTOTAL_API_KEY`
108
+ TeLLMgramBot uses the following environment variables for API keys:
109
+ 1. `TELLMGRAMBOT_OPENAI_API_KEY` *(OpenAI models)*
110
+ 2. `TELLMGRAMBOT_ANTHROPIC_API_KEY` *(Anthropic models)*
111
+ 3. `TELLMGRAMBOT_TELEGRAM_API_KEY`
112
+ 4. `TELLMGRAMBOT_VIRUSTOTAL_API_KEY`
99
113
 
100
114
  During spin-up time, a user can call out `os.environ[env_var]` to set those variables, like the following example:
101
115
  ```
102
116
  my_keys = Some_Vault_Fetch_Function()
103
117
 
104
- os.environ['TELLMGRAMBOT_OPENAI_API_KEY'] = my_keys['GPTKey']
118
+ os.environ['TELLMGRAMBOT_OPENAI_API_KEY'] = my_keys['OpenAIKey']
119
+ os.environ['TELLMGRAMBOT_ANTHROPIC_API_KEY'] = my_keys['AnthropicKey']
105
120
  os.environ['TELLMGRAMBOT_TELEGRAM_API_KEY'] = my_keys['BotFatherToken']
106
121
  os.environ['TELLMGRAMBOT_VIRUSTOTAL_API_KEY'] = my_keys['VirusTotalToken']
107
122
  ```
@@ -109,15 +124,16 @@ os.environ['TELLMGRAMBOT_VIRUSTOTAL_API_KEY'] = my_keys['VirusTotalToken']
109
124
  This means the user can implement whatever key vault they want to fetch the keys at runtime, without needing files stored in the directory.
110
125
 
111
126
  ### API Key Files
112
- The other route is to create three files by the base path during execution or a specified environment variable `TELLMGRAMBOT_KEYS_PATH`. By default, three files are created for the user to input each API key:
127
+ The other route is to create files by the base path during execution or a specified environment variable `TELLMGRAMBOT_KEYS_PATH`. By default, files are created for the user to input each API key:
113
128
  1. `openai.key`
114
- 2. `telegram.key`
115
- 3. `virustotal.key`
129
+ 2. `anthropic.key` _(planned — env var only for now; see Phase 3)_
130
+ 3. `telegram.key`
131
+ 4. `virustotal.key`
116
132
 
117
133
  Each file with the associated API key will update its respective environment variable if not defined.
118
134
 
119
135
  ## Bot Setup
120
- This library includes an example script `test_local.py`, which uses files from the folders `configs` and `prompts` for TeLLMgramBot to process. The bot communicates with OpenAI via the **Responses API**, which replaces the older Chat Completions endpoint.
136
+ This library includes an example script `test_local.py`, which uses files from the folders `configs` and `prompts` for TeLLMgramBot to process.
121
137
  1. Ensure the previous sections are followed with the proper API keys and your Telegram bot set.
122
138
  2. Install this library via PIP (`pip install TeLLMgramBot`) and then import into your project.
123
139
  3. Instantiate the bot by passing in various configuration pieces needed below.
@@ -127,8 +143,8 @@ This library includes an example script `test_local.py`, which uses files from t
127
143
  bot_owner = <Bot owner's Telegram username>,
128
144
  bot_nickname = <Bot nickname like 'Botty'>,
129
145
  bot_initials = <Bot initials like 'FB'>,
130
- chat_model = <Conversation model like 'gpt-4o-mini'>,
131
- url_model = <URL analysis model like 'gpt-4o'>,
146
+ chat_model = <Conversation model like 'gpt-4o-mini' or 'claude-sonnet-4-6'>,
147
+ url_model = <URL analysis model like 'gpt-4o' or 'claude-haiku-4-5'>,
132
148
  token_limit = <Maximum token count set, by default chat_model max>,
133
149
  persona_temp = <LLM factual to creative value [0-2], by default 1.0>,
134
150
  persona_prompt = <System prompt summarizing bot personality>
@@ -143,9 +159,11 @@ This library includes an example script `test_local.py`, which uses files from t
143
159
 
144
160
  ## Resources
145
161
  * GitHub repository [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) has guides to create a Telegram bot.
146
- * For more information on OpenAI models like `gpt-4o` and token limits, see the following:
147
- * [OpenAI model overview and maximum tokens](https://platform.openai.com/docs/models).
148
- * [OpenAI message conversion to tokens](https://github.com/openai/openai-python).
149
- * [OpenAI custom fine-tuning](https://platform.openai.com/docs/guides/model-optimization).
150
- * [OpenAI's tiktoken library, including some helpful guides](https://github.com/openai/tiktoken/tree/main).
151
- * [OpenAI Playground](https://platform.openai.com/playground) is a great place to test out prompts and responses.
162
+ * For more information on OpenAI models and token limits:
163
+ * [OpenAI model overview and maximum tokens](https://platform.openai.com/docs/models)
164
+ * [OpenAI message conversion to tokens](https://github.com/openai/openai-python)
165
+ * [OpenAI custom fine-tuning](https://platform.openai.com/docs/guides/model-optimization)
166
+ * [OpenAI's tiktoken library](https://github.com/openai/tiktoken/tree/main)
167
+ * For more information on Anthropic Claude models:
168
+ * [Anthropic model overview and context windows](https://docs.anthropic.com/en/docs/about-claude/models)
169
+ * [Anthropic Python SDK](https://github.com/anthropic/anthropic-sdk-python)
@@ -6,7 +6,6 @@ TeLLMgramBot/__init__.py
6
6
  TeLLMgramBot/conversation.py
7
7
  TeLLMgramBot/initialize.py
8
8
  TeLLMgramBot/message_handlers.py
9
- TeLLMgramBot/openai_singleton.py
10
9
  TeLLMgramBot/tokenGPT.py
11
10
  TeLLMgramBot/utils.py
12
11
  TeLLMgramBot/web_utils.py
@@ -14,4 +13,9 @@ TeLLMgramBot.egg-info/PKG-INFO
14
13
  TeLLMgramBot.egg-info/SOURCES.txt
15
14
  TeLLMgramBot.egg-info/dependency_links.txt
16
15
  TeLLMgramBot.egg-info/requires.txt
17
- TeLLMgramBot.egg-info/top_level.txt
16
+ TeLLMgramBot.egg-info/top_level.txt
17
+ TeLLMgramBot/providers/__init__.py
18
+ TeLLMgramBot/providers/anthropic_provider.py
19
+ TeLLMgramBot/providers/base.py
20
+ TeLLMgramBot/providers/factory.py
21
+ TeLLMgramBot/providers/openai_provider.py
@@ -1,4 +1,5 @@
1
1
  openai>2.0
2
+ anthropic>=0.40
2
3
  PyYAML
3
4
  httpx
4
5
  beautifulsoup4
@@ -5,17 +5,18 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setup(
7
7
  name='TeLLMgramBot',
8
- version='2.3.0',
8
+ version='2.4.0',
9
9
  packages=find_packages(),
10
10
  license='MIT',
11
11
  author='Digital Heresy',
12
12
  author_email='ronin.atx@gmail.com',
13
- description='OpenAI GPT, driven by Telegram',
13
+ description='LLM-powered Telegram bot (OpenAI + Anthropic)',
14
14
  long_description=long_description,
15
15
  long_description_content_type="text/markdown",
16
16
  url='https://github.com/Digital-Heresy/TeLLMgramBot',
17
17
  install_requires=[
18
18
  'openai>2.0',
19
+ 'anthropic>=0.40',
19
20
  'PyYAML',
20
21
  'httpx',
21
22
  'beautifulsoup4',
@@ -1,12 +0,0 @@
1
- import os
2
- from openai import AsyncOpenAI
3
-
4
- class OpenAIClientSingleton:
5
- """Call the OpenAI Client API for processing every asynchronous function."""
6
- _instance = None
7
-
8
- @classmethod
9
- def get_instance(cls):
10
- if cls._instance is None:
11
- cls._instance = AsyncOpenAI(api_key=os.environ['TELLMGRAMBOT_OPENAI_API_KEY'])
12
- return cls._instance
File without changes
File without changes