comprobot 2.2.5__tar.gz → 2.2.6__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 (26) hide show
  1. {comprobot-2.2.5 → comprobot-2.2.6}/PKG-INFO +2 -3
  2. {comprobot-2.2.5 → comprobot-2.2.6}/comprobot.egg-info/PKG-INFO +2 -3
  3. {comprobot-2.2.5 → comprobot-2.2.6}/comprobot.egg-info/requires.txt +1 -2
  4. {comprobot-2.2.5 → comprobot-2.2.6}/pyproject.toml +2 -3
  5. {comprobot-2.2.5 → comprobot-2.2.6}/src/config.py +28 -3
  6. {comprobot-2.2.5 → comprobot-2.2.6}/src/functions.py +46 -26
  7. {comprobot-2.2.5 → comprobot-2.2.6}/LICENSE +0 -0
  8. {comprobot-2.2.5 → comprobot-2.2.6}/README.md +0 -0
  9. {comprobot-2.2.5 → comprobot-2.2.6}/comprobot.egg-info/SOURCES.txt +0 -0
  10. {comprobot-2.2.5 → comprobot-2.2.6}/comprobot.egg-info/dependency_links.txt +0 -0
  11. {comprobot-2.2.5 → comprobot-2.2.6}/comprobot.egg-info/entry_points.txt +0 -0
  12. {comprobot-2.2.5 → comprobot-2.2.6}/comprobot.egg-info/top_level.txt +0 -0
  13. {comprobot-2.2.5 → comprobot-2.2.6}/setup.cfg +0 -0
  14. {comprobot-2.2.5 → comprobot-2.2.6}/src/__init__.py +0 -0
  15. {comprobot-2.2.5 → comprobot-2.2.6}/src/__main__.py +0 -0
  16. {comprobot-2.2.5 → comprobot-2.2.6}/src/api.py +0 -0
  17. {comprobot-2.2.5 → comprobot-2.2.6}/src/bot.py +0 -0
  18. {comprobot-2.2.5 → comprobot-2.2.6}/src/commands.py +0 -0
  19. {comprobot-2.2.5 → comprobot-2.2.6}/src/data.py +0 -0
  20. {comprobot-2.2.5 → comprobot-2.2.6}/src/moderation.py +0 -0
  21. {comprobot-2.2.5 → comprobot-2.2.6}/src/money_system.py +0 -0
  22. {comprobot-2.2.5 → comprobot-2.2.6}/src/onboarding.py +0 -0
  23. {comprobot-2.2.5 → comprobot-2.2.6}/src/process.py +0 -0
  24. {comprobot-2.2.5 → comprobot-2.2.6}/src/start.py +0 -0
  25. {comprobot-2.2.5 → comprobot-2.2.6}/src/templates.py +0 -0
  26. {comprobot-2.2.5 → comprobot-2.2.6}/src/testing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: comprobot
3
- Version: 2.2.5
3
+ Version: 2.2.6
4
4
  Summary: A self-hostable Discord bot built for maximum customization.
5
5
  Author: badluma
6
6
  License: MIT
@@ -18,8 +18,7 @@ Requires-Dist: requests
18
18
  Requires-Dist: tomlkit
19
19
  Requires-Dist: appdirs
20
20
  Requires-Dist: ollama
21
- Requires-Dist: google-genai
22
- Requires-Dist: groq
21
+ Requires-Dist: httpx
23
22
  Requires-Dist: InquirerPy
24
23
  Provides-Extra: dev
25
24
  Requires-Dist: ruff; extra == "dev"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: comprobot
3
- Version: 2.2.5
3
+ Version: 2.2.6
4
4
  Summary: A self-hostable Discord bot built for maximum customization.
5
5
  Author: badluma
6
6
  License: MIT
@@ -18,8 +18,7 @@ Requires-Dist: requests
18
18
  Requires-Dist: tomlkit
19
19
  Requires-Dist: appdirs
20
20
  Requires-Dist: ollama
21
- Requires-Dist: google-genai
22
- Requires-Dist: groq
21
+ Requires-Dist: httpx
23
22
  Requires-Dist: InquirerPy
24
23
  Provides-Extra: dev
25
24
  Requires-Dist: ruff; extra == "dev"
@@ -4,8 +4,7 @@ requests
4
4
  tomlkit
5
5
  appdirs
6
6
  ollama
7
- google-genai
8
- groq
7
+ httpx
9
8
  InquirerPy
10
9
 
11
10
  [dev]
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "comprobot"
7
- version = "2.2.5"
7
+ version = "2.2.6"
8
8
  authors = [{name = "badluma"}]
9
9
  description = "A self-hostable Discord bot built for maximum customization."
10
10
  readme = "README.md"
@@ -22,8 +22,7 @@ dependencies = [
22
22
  "tomlkit",
23
23
  "appdirs",
24
24
  "ollama",
25
- "google-genai",
26
- "groq",
25
+ "httpx",
27
26
  "InquirerPy",
28
27
  ]
29
28
 
@@ -24,7 +24,8 @@ def make_pretty(string):
24
24
  .replace("_", " ") \
25
25
  .replace("-", " ") \
26
26
  .title() \
27
- .replace("Ai", "AI")
27
+ .replace("Ai", "AI") \
28
+ .replace("Api", "API")
28
29
 
29
30
  def pick_file():
30
31
  data_dir = appdirs.user_data_dir("Comprobot", appauthor=False)
@@ -101,7 +102,7 @@ def pick_key(content, is_secret=False):
101
102
  ).execute()
102
103
  content[key] = value
103
104
 
104
- case str() | int():
105
+ case str():
105
106
  print()
106
107
  if is_secret:
107
108
  value = secret.SecretPrompt(
@@ -120,6 +121,30 @@ def pick_key(content, is_secret=False):
120
121
  ).execute()
121
122
  content[key] = value
122
123
 
124
+ case int():
125
+ print()
126
+ if is_secret:
127
+ value = secret.SecretPrompt(
128
+ message=f"New value for '{make_pretty(key)}'?",
129
+ style=style,
130
+ amark="!",
131
+ vi_mode=True,
132
+ ).execute()
133
+ else:
134
+ value = input.InputPrompt(
135
+ message=f"What number do you want to assign to '{make_pretty(key)}'?",
136
+ instruction=f"(Current: {content[key]})",
137
+ style=style,
138
+ amark="!",
139
+ vi_mode=True,
140
+ ).execute()
141
+
142
+ if int(value) == None:
143
+ content[key] = 0
144
+ return
145
+
146
+ content[key] = int(value)
147
+
123
148
  case list():
124
149
  print()
125
150
  value = input.InputPrompt(
@@ -129,7 +154,7 @@ def pick_key(content, is_secret=False):
129
154
  amark="!",
130
155
  vi_mode=True,
131
156
  ).execute().split(",")
132
- content[key] = [item.strip() for item in value]
157
+ content[key] = [item.strip() for item in value if item.strip()]
133
158
 
134
159
 
135
160
 
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  import os
2
3
  import re
3
4
  import subprocess
@@ -5,10 +6,8 @@ from typing import Any, Dict, List, cast
5
6
 
6
7
  import appdirs
7
8
  import discord
8
- import groq
9
+ import httpx
9
10
  import ollama
10
- from google import genai
11
- from google.genai.errors import ClientError
12
11
 
13
12
  from .bot import client
14
13
  from .data import ai, system_prompt_text
@@ -144,7 +143,6 @@ async def chat(message):
144
143
  )
145
144
  content = response.message.content or ""
146
145
  elif provider == "gemini":
147
- gemini_client = genai.Client(api_key=os.getenv("GEMINI"))
148
146
  formatted_messages = []
149
147
  for m in messages:
150
148
  formatted_messages.append(
@@ -153,33 +151,55 @@ async def chat(message):
153
151
  "parts": [{"text": m["content"]}],
154
152
  }
155
153
  )
156
-
157
- config = None
154
+ body: Dict[str, Any] = {"contents": formatted_messages}
158
155
  if system_prompt_text:
159
- config = genai.types.GenerateContentConfig(
160
- system_instruction=system_prompt_text
161
- )
162
-
163
- try:
164
- response = gemini_client.models.generate_content(
165
- model=ai["model"], contents=formatted_messages, config=config
166
- )
167
- content = response.text or ""
168
- except ClientError as e:
169
- if "NOT_FOUND" in str(e) or "404" in str(e):
170
- available = gemini_client.models.list()
171
- print(f"Available models: {[m.name for m in available]}")
172
- raise
156
+ body["systemInstruction"] = {"parts": [{"text": system_prompt_text}]}
157
+
158
+ async with httpx.AsyncClient() as http:
159
+ resp = None
160
+ for attempt in range(4):
161
+ resp = await http.post(
162
+ f"https://generativelanguage.googleapis.com/v1beta/models/{ai['model']}:generateContent",
163
+ params={"key": os.getenv("GEMINI")},
164
+ json=body,
165
+ timeout=60,
166
+ )
167
+ if resp.status_code != 429:
168
+ break
169
+ data = resp.json()
170
+ retry_delay = None
171
+ is_daily_quota = False
172
+ for detail in data.get("error", {}).get("details", []):
173
+ if "retryDelay" in detail:
174
+ retry_delay = detail["retryDelay"]
175
+ if "violations" in detail:
176
+ for v in detail["violations"]:
177
+ if "PerDay" in v.get("quotaId", ""):
178
+ is_daily_quota = True
179
+ if is_daily_quota or attempt == 3:
180
+ resp.raise_for_status()
181
+ match = re.search(r"(\d+(?:\.\d+)?)", retry_delay or "")
182
+ wait = float(match.group(1)) if match else min(30 * (2 ** attempt), 120)
183
+ await asyncio.sleep(wait)
184
+ if resp is None:
185
+ raise RuntimeError("Gemini request never sent")
186
+ if resp.status_code == 404:
187
+ print(f"Model '{ai['model']}' not found. Check ai.toml for valid model name.")
188
+ resp.raise_for_status()
189
+ content = resp.json()["candidates"][0]["content"]["parts"][0]["text"]
173
190
  elif provider == "groq":
174
- groq_client = groq.Groq(api_key=os.getenv("GROQ"))
175
191
  formatted_messages = [
176
192
  {"role": "system", "content": system_prompt_text}
177
193
  ] + messages
178
- response = groq_client.chat.completions.create(
179
- model=cast(str, ai["model"]),
180
- messages=cast(Any, formatted_messages),
181
- )
182
- content = response.choices[0].message.content or ""
194
+ async with httpx.AsyncClient() as http:
195
+ resp = await http.post(
196
+ "https://api.groq.com/openai/v1/chat/completions",
197
+ headers={"Authorization": f"Bearer {os.getenv('GROQ')}"},
198
+ json={"model": ai["model"], "messages": formatted_messages},
199
+ timeout=60,
200
+ )
201
+ resp.raise_for_status()
202
+ content = resp.json()["choices"][0]["message"]["content"] or ""
183
203
  else:
184
204
  raise ValueError(f"Unknown provider: {ai['provider']}")
185
205
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes