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.
- {comprobot-2.2.5 → comprobot-2.2.6}/PKG-INFO +2 -3
- {comprobot-2.2.5 → comprobot-2.2.6}/comprobot.egg-info/PKG-INFO +2 -3
- {comprobot-2.2.5 → comprobot-2.2.6}/comprobot.egg-info/requires.txt +1 -2
- {comprobot-2.2.5 → comprobot-2.2.6}/pyproject.toml +2 -3
- {comprobot-2.2.5 → comprobot-2.2.6}/src/config.py +28 -3
- {comprobot-2.2.5 → comprobot-2.2.6}/src/functions.py +46 -26
- {comprobot-2.2.5 → comprobot-2.2.6}/LICENSE +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/README.md +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/comprobot.egg-info/SOURCES.txt +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/comprobot.egg-info/dependency_links.txt +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/comprobot.egg-info/entry_points.txt +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/comprobot.egg-info/top_level.txt +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/setup.cfg +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/src/__init__.py +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/src/__main__.py +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/src/api.py +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/src/bot.py +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/src/commands.py +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/src/data.py +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/src/moderation.py +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/src/money_system.py +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/src/onboarding.py +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/src/process.py +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/src/start.py +0 -0
- {comprobot-2.2.5 → comprobot-2.2.6}/src/templates.py +0 -0
- {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.
|
|
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:
|
|
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.
|
|
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:
|
|
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,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "comprobot"
|
|
7
|
-
version = "2.2.
|
|
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
|
-
"
|
|
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()
|
|
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
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|