comprobot 1.0.0__py3-none-any.whl
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/__init__.py +0 -0
- Comprobot/__main__.py +4 -0
- Comprobot/api.py +200 -0
- Comprobot/bot.py +16 -0
- Comprobot/commands.py +20 -0
- Comprobot/data.py +79 -0
- Comprobot/functions.py +182 -0
- Comprobot/main.py +95 -0
- Comprobot/moderation.py +42 -0
- Comprobot/money_system.py +35 -0
- Comprobot/process.py +197 -0
- Comprobot/templates.py +137 -0
- comprobot-1.0.0.dist-info/METADATA +39 -0
- comprobot-1.0.0.dist-info/RECORD +17 -0
- comprobot-1.0.0.dist-info/WHEEL +5 -0
- comprobot-1.0.0.dist-info/entry_points.txt +2 -0
- comprobot-1.0.0.dist-info/top_level.txt +1 -0
Comprobot/__init__.py
ADDED
|
File without changes
|
Comprobot/__main__.py
ADDED
Comprobot/api.py
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
|
|
3
|
+
from data import error_messages
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def access_api(url, parameter, error_message, headers=None):
|
|
7
|
+
if headers:
|
|
8
|
+
raw = requests.get(url, headers=headers)
|
|
9
|
+
else:
|
|
10
|
+
raw = requests.get(url)
|
|
11
|
+
if raw.status_code == 200:
|
|
12
|
+
try:
|
|
13
|
+
data = raw.json()
|
|
14
|
+
response = data[parameter]
|
|
15
|
+
except (requests.exceptions.JSONDecodeError, KeyError):
|
|
16
|
+
response = str(f"{error_message}")
|
|
17
|
+
except Exception as e:
|
|
18
|
+
response = str(f"{error_message} (Error {str(e)})")
|
|
19
|
+
else:
|
|
20
|
+
response = str(f"{error_message} (HTTP {raw.status_code})")
|
|
21
|
+
|
|
22
|
+
return response
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# ---------- Commands ----------
|
|
26
|
+
def quote():
|
|
27
|
+
quote_response = requests.get("https://zenquotes.io/api/random")
|
|
28
|
+
try:
|
|
29
|
+
data = quote_response.json()
|
|
30
|
+
fetched_quote = data[0]["q"]
|
|
31
|
+
author = data[0]["a"]
|
|
32
|
+
response = f"""{fetched_quote}\n~{author}"""
|
|
33
|
+
except (requests.exceptions.JSONDecodeError, KeyError, IndexError):
|
|
34
|
+
response = error_messages["quote"]
|
|
35
|
+
return response
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def meme():
|
|
39
|
+
return access_api("https://meme-api.com/gimme", "url", error_messages["meme"])
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def waifu():
|
|
43
|
+
waifu1 = access_api(
|
|
44
|
+
"https://api.waifu.pics/sfw/waifu", "url", error_messages["waifu"]
|
|
45
|
+
)
|
|
46
|
+
waifu2 = access_api(
|
|
47
|
+
"https://api.waifu.pics/sfw/waifu", "url", error_messages["waifu"]
|
|
48
|
+
)
|
|
49
|
+
return f"""### Which one is better?
|
|
50
|
+
|
|
51
|
+
{waifu1}
|
|
52
|
+
{waifu2}"""
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def duck():
|
|
56
|
+
return access_api("https://random-d.uk/api/random", "url", error_messages["duck"])
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def dog():
|
|
60
|
+
return access_api("https://random.dog/woojson", "url", error_messages["dog"])
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def cat():
|
|
64
|
+
raw = requests.get("https://api.thecatapi.com/v1/images/search")
|
|
65
|
+
if raw.status_code == 200:
|
|
66
|
+
try:
|
|
67
|
+
data = raw.json()
|
|
68
|
+
response = data[0]["url"]
|
|
69
|
+
except (requests.exceptions.JSONDecodeError, KeyError, IndexError):
|
|
70
|
+
response = error_messages["cat"]
|
|
71
|
+
else:
|
|
72
|
+
response = error_messages["cat"]
|
|
73
|
+
return response
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def chuck():
|
|
77
|
+
return access_api(
|
|
78
|
+
"https://api.chucknorris.io/jokes/random", "value", error_messages["chuck"]
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def fact():
|
|
83
|
+
return access_api(
|
|
84
|
+
"https://uselessfacts.jsph.pl/api/v2/facts/random",
|
|
85
|
+
"text",
|
|
86
|
+
error_messages["fact"],
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def bible(
|
|
91
|
+
is_random, book_arg: str = "John", chapter_arg: int = 16, verse_arg: int = 32
|
|
92
|
+
):
|
|
93
|
+
|
|
94
|
+
if is_random:
|
|
95
|
+
url = "https://bible-api.com/data/web/random"
|
|
96
|
+
else:
|
|
97
|
+
url = f"https://bible-api.com/{book_arg} {chapter_arg}:{verse_arg}"
|
|
98
|
+
|
|
99
|
+
bible_response = requests.get(url)
|
|
100
|
+
if bible_response.status_code == 200:
|
|
101
|
+
try:
|
|
102
|
+
data = bible_response.json()
|
|
103
|
+
if "random_verse" in data:
|
|
104
|
+
verse = data["random_verse"]
|
|
105
|
+
response = f"{verse['text']}\n{verse['book']} {verse['chapter']}:{verse['verse']}"
|
|
106
|
+
elif "text" in data and "reference" in data:
|
|
107
|
+
response = f"{data['text']}\n{data['reference']}"
|
|
108
|
+
else:
|
|
109
|
+
response = error_messages["passage_not_found"].replace(
|
|
110
|
+
r"{{PASSAGE}}", f"{book_arg} {chapter_arg}:{verse_arg}"
|
|
111
|
+
)
|
|
112
|
+
except (requests.exceptions.JSONDecodeError, KeyError):
|
|
113
|
+
response = error_messages["bible"]
|
|
114
|
+
elif bible_response.status_code == 404:
|
|
115
|
+
response = error_messages["passage_not_found"].replace(
|
|
116
|
+
r"{{PASSAGE}}", f"{book_arg} {chapter_arg}:{verse_arg}"
|
|
117
|
+
)
|
|
118
|
+
else:
|
|
119
|
+
response = f"{error_messages['bible']} (HTTP {bible_response.status_code})"
|
|
120
|
+
return response
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def bitcoin(currency_parameter):
|
|
124
|
+
currency = currency_parameter.lower() if len(str(currency_parameter)) > 1 else "usd"
|
|
125
|
+
bitcoin_price = requests.get(
|
|
126
|
+
f"https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies={currency}"
|
|
127
|
+
)
|
|
128
|
+
if bitcoin_price.status_code == 200:
|
|
129
|
+
data = bitcoin_price.json()
|
|
130
|
+
if "bitcoin" in data and currency in data["bitcoin"]:
|
|
131
|
+
response = f"bitcoin is at {data['bitcoin'][currency]} {currency} rn"
|
|
132
|
+
else:
|
|
133
|
+
response = error_messages["currency"]
|
|
134
|
+
else:
|
|
135
|
+
response = error_messages["bitcoin"]
|
|
136
|
+
return response
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def tord(url, rating, max_retries=10):
|
|
140
|
+
for _ in range(max_retries):
|
|
141
|
+
response = requests.get(url)
|
|
142
|
+
if response.status_code != 200:
|
|
143
|
+
continue
|
|
144
|
+
data = response.json()
|
|
145
|
+
if not rating or data.get("rating") == rating:
|
|
146
|
+
return data["question"]
|
|
147
|
+
return None
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def joke():
|
|
151
|
+
raw = requests.get("https://official-joke-api.appspot.com/jokes/random")
|
|
152
|
+
if raw.status_code == 200:
|
|
153
|
+
try:
|
|
154
|
+
data = raw.json()
|
|
155
|
+
response = f"{data['setup']} ||{data['punchline']}||"
|
|
156
|
+
except (requests.exceptions.JSONDecodeError, KeyError):
|
|
157
|
+
response = error_messages["joke"]
|
|
158
|
+
else:
|
|
159
|
+
response = error_messages["joke"]
|
|
160
|
+
return response
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def currency(currency1, currency2, amount):
|
|
164
|
+
try:
|
|
165
|
+
amount = float(amount)
|
|
166
|
+
except (TypeError, ValueError):
|
|
167
|
+
return error_messages["currency"]
|
|
168
|
+
|
|
169
|
+
currency1 = currency1.lower()
|
|
170
|
+
currency2 = currency2.lower()
|
|
171
|
+
|
|
172
|
+
available_currencies = requests.get(
|
|
173
|
+
"https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies.json"
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
if available_currencies.status_code != 200:
|
|
177
|
+
return error_messages["unavailable"]
|
|
178
|
+
|
|
179
|
+
available_currencies = available_currencies.json()
|
|
180
|
+
|
|
181
|
+
if currency1 not in available_currencies:
|
|
182
|
+
return f"{error_messages['currency']} ({currency1})"
|
|
183
|
+
if currency2 not in available_currencies:
|
|
184
|
+
return f"{error_messages['currency']} ({currency2})"
|
|
185
|
+
|
|
186
|
+
raw_response = requests.get(
|
|
187
|
+
f"https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/{currency1}.json"
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
if raw_response.status_code != 200:
|
|
191
|
+
return error_messages["unavailable"]
|
|
192
|
+
|
|
193
|
+
raw_response = raw_response.json()
|
|
194
|
+
|
|
195
|
+
if currency1 not in raw_response or currency2 not in raw_response[currency1]:
|
|
196
|
+
return error_messages["currency"]
|
|
197
|
+
|
|
198
|
+
rate = raw_response[currency1][currency2]
|
|
199
|
+
response = rate * amount
|
|
200
|
+
return f"{amount} {currency1.upper()} = {response:.2f} {currency2.upper()}"
|
Comprobot/bot.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import discord
|
|
2
|
+
import os
|
|
3
|
+
import dotenv
|
|
4
|
+
import appdirs
|
|
5
|
+
|
|
6
|
+
dotenv.load_dotenv(
|
|
7
|
+
dotenv.find_dotenv(
|
|
8
|
+
os.path.join(
|
|
9
|
+
appdirs.user_data_dir(appname="Comprobot", appauthor=False), ".env"
|
|
10
|
+
)
|
|
11
|
+
)
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
intents = discord.Intents.default()
|
|
15
|
+
intents.message_content = True
|
|
16
|
+
client = discord.Client(intents=intents)
|
Comprobot/commands.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import random
|
|
2
|
+
|
|
3
|
+
from data import config, error_messages
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def qr(link):
|
|
7
|
+
return f"https://api.qrserver.com/v1/create-qr-code/?size=150x150&data={link}"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def calculate(calculation):
|
|
11
|
+
try:
|
|
12
|
+
result = eval(calculation)
|
|
13
|
+
response = f"Result: {result}"
|
|
14
|
+
except Exception as e:
|
|
15
|
+
response = f"{error_messages['calculate']} (error {str(e)})"
|
|
16
|
+
return response
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def ascii():
|
|
20
|
+
return random.choice(config["ascii_art"])
|
Comprobot/data.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Any, Dict, List
|
|
3
|
+
|
|
4
|
+
import appdirs
|
|
5
|
+
import tomlkit
|
|
6
|
+
|
|
7
|
+
import templates
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _get_data_path(filename):
|
|
11
|
+
|
|
12
|
+
base_dir = appdirs.user_data_dir(appname="Comprobot", appauthor=False)
|
|
13
|
+
return os.path.join(base_dir, filename)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _ensure_file(path, content):
|
|
17
|
+
|
|
18
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
19
|
+
if not os.path.isfile(path):
|
|
20
|
+
with open(path, "w") as f:
|
|
21
|
+
f.write(content)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _merge_defaults(data, defaults):
|
|
25
|
+
for key, value in defaults.items():
|
|
26
|
+
if key not in data:
|
|
27
|
+
data[key] = value
|
|
28
|
+
elif isinstance(value, dict) and isinstance(data.get(key), dict):
|
|
29
|
+
_merge_defaults(data[key], value)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _load_or_create(path, template_content):
|
|
33
|
+
try:
|
|
34
|
+
with open(path, "rb") as f:
|
|
35
|
+
data = tomlkit.load(f)
|
|
36
|
+
except FileNotFoundError:
|
|
37
|
+
_ensure_file(path, template_content)
|
|
38
|
+
with open(path, "rb") as f:
|
|
39
|
+
data = tomlkit.load(f)
|
|
40
|
+
|
|
41
|
+
defaults = tomlkit.loads(template_content)
|
|
42
|
+
_merge_defaults(data, defaults)
|
|
43
|
+
|
|
44
|
+
if data != defaults:
|
|
45
|
+
with open(path, "w") as f:
|
|
46
|
+
tomlkit.dump(data, f)
|
|
47
|
+
|
|
48
|
+
return data
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
ai_str = templates.ai
|
|
52
|
+
|
|
53
|
+
error_messages: Dict[str, str] = _load_or_create(
|
|
54
|
+
_get_data_path("error-messages.toml"), templates.error_messages
|
|
55
|
+
)
|
|
56
|
+
success_messages: Dict[str, str] = _load_or_create(
|
|
57
|
+
_get_data_path("success_messages.toml"), templates.success_messages
|
|
58
|
+
)
|
|
59
|
+
config: Dict[str, Any] = _load_or_create(
|
|
60
|
+
_get_data_path("config.toml"), templates.config
|
|
61
|
+
)
|
|
62
|
+
keywords: Dict[str, Dict[str, List[str]]] = _load_or_create(
|
|
63
|
+
_get_data_path("keywords.toml"), templates.keywords
|
|
64
|
+
)
|
|
65
|
+
ai: Dict[str, Any] = _load_or_create(_get_data_path("ai.toml"), ai_str)
|
|
66
|
+
system_prompt_text = ai["system_prompt"]
|
|
67
|
+
money: Dict[str, Dict[str, int]] = _load_or_create(
|
|
68
|
+
_get_data_path("money.toml"), r"""balances = {}"""
|
|
69
|
+
)
|
|
70
|
+
active: Dict[str, bool] = _load_or_create(
|
|
71
|
+
_get_data_path("active.toml"), templates.active
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
_ensure_file(_get_data_path(".env"), templates.env_template)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def save_toml(data, path):
|
|
78
|
+
with open(path, "w") as f:
|
|
79
|
+
tomlkit.dump(data, f)
|
Comprobot/functions.py
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
from typing import Any, Dict, List, cast
|
|
4
|
+
|
|
5
|
+
import appdirs
|
|
6
|
+
import discord
|
|
7
|
+
import groq
|
|
8
|
+
import ollama
|
|
9
|
+
from google import genai
|
|
10
|
+
from google.genai.errors import ClientError
|
|
11
|
+
|
|
12
|
+
from bot import client
|
|
13
|
+
from data import ai, system_prompt_text
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def para(count=1):
|
|
17
|
+
for i in range(count):
|
|
18
|
+
print()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def clear():
|
|
22
|
+
if os.name == "nt":
|
|
23
|
+
os.system("cls")
|
|
24
|
+
else:
|
|
25
|
+
os.system("clear")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
async def direct_msg(message, author_message):
|
|
29
|
+
user = await client.fetch_user(author_message.author.id)
|
|
30
|
+
dm_channel = user.dm_channel
|
|
31
|
+
if dm_channel is None:
|
|
32
|
+
dm_channel = await user.create_dm()
|
|
33
|
+
try:
|
|
34
|
+
await dm_channel.send(message)
|
|
35
|
+
except (discord.Forbidden, discord.HTTPException):
|
|
36
|
+
print(f"Couldn't DM {author_message.author.name}.")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def demoji(text):
|
|
40
|
+
emoji_pattern = re.compile(
|
|
41
|
+
"["
|
|
42
|
+
"\U0001f600-\U0001f64f" # emoticons
|
|
43
|
+
"\U0001f300-\U0001f5ff" # symbols & pictographs
|
|
44
|
+
"\U0001f680-\U0001f6ff" # transport & map symbols
|
|
45
|
+
"\U0001f1e0-\U0001f1ff" # flags (iOS)
|
|
46
|
+
"\U00002702-\U000027b0"
|
|
47
|
+
"\U000024c2-\U0001f251"
|
|
48
|
+
"\U0001f926-\U0001f937"
|
|
49
|
+
"\U00010000-\U0010ffff"
|
|
50
|
+
"\u200d"
|
|
51
|
+
"\u2640-\u2642"
|
|
52
|
+
"\u2600-\u2b55"
|
|
53
|
+
"\u23cf"
|
|
54
|
+
"\u23e9"
|
|
55
|
+
"\u231a"
|
|
56
|
+
"\ufe0f" # variation selectors
|
|
57
|
+
"\u3030"
|
|
58
|
+
"]+",
|
|
59
|
+
flags=re.UNICODE,
|
|
60
|
+
)
|
|
61
|
+
return emoji_pattern.sub("", text)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def chat(message):
|
|
65
|
+
messages: List[Dict[str, Any]] = []
|
|
66
|
+
user_id = client.user.id if client.user else ""
|
|
67
|
+
|
|
68
|
+
if ai["provider"].lower() in ("ollama", "groq"):
|
|
69
|
+
messages.append(
|
|
70
|
+
{
|
|
71
|
+
"role": "user",
|
|
72
|
+
"content": message.content.replace(f"<@{user_id}>", ""),
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
elif ai["provider"].lower() == "gemini":
|
|
76
|
+
messages.append(
|
|
77
|
+
{
|
|
78
|
+
"role": "user",
|
|
79
|
+
"parts": [{"text": message.content.replace(f"<@{user_id}>", "")}],
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
else:
|
|
83
|
+
raise ValueError(f"Unknown provider: {ai['provider']}")
|
|
84
|
+
|
|
85
|
+
if ai["provider"].lower() == "ollama":
|
|
86
|
+
messages.insert(
|
|
87
|
+
0,
|
|
88
|
+
{
|
|
89
|
+
"role": "system",
|
|
90
|
+
"content": system_prompt_text,
|
|
91
|
+
},
|
|
92
|
+
)
|
|
93
|
+
response = ollama.chat(model=cast(str, ai["model"]), messages=messages)
|
|
94
|
+
content: str = response.message.content or ""
|
|
95
|
+
elif ai["provider"].lower() == "gemini":
|
|
96
|
+
gemini_client = genai.Client(api_key=os.getenv("GEMINI"))
|
|
97
|
+
system_instruction = None
|
|
98
|
+
formatted_messages = []
|
|
99
|
+
for m in messages:
|
|
100
|
+
if m["role"] == "system":
|
|
101
|
+
system_instruction = m["content"]
|
|
102
|
+
else:
|
|
103
|
+
formatted_messages.append(
|
|
104
|
+
{
|
|
105
|
+
"role": m["role"],
|
|
106
|
+
"parts": [
|
|
107
|
+
{"text": m["content"] if "content" in m else m["parts"][0]}
|
|
108
|
+
],
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
config = None
|
|
112
|
+
if system_instruction:
|
|
113
|
+
config = genai.types.GenerateContentConfig(
|
|
114
|
+
system_instruction=system_instruction
|
|
115
|
+
)
|
|
116
|
+
try:
|
|
117
|
+
response = gemini_client.models.generate_content(
|
|
118
|
+
model=ai["model"], contents=formatted_messages, config=config
|
|
119
|
+
)
|
|
120
|
+
content = response.text or ""
|
|
121
|
+
except ClientError as e:
|
|
122
|
+
if "NOT_FOUND" in str(e) or "404" in str(e):
|
|
123
|
+
available = gemini_client.models.list()
|
|
124
|
+
print(f"Available models: {[m.name for m in available]}")
|
|
125
|
+
raise
|
|
126
|
+
elif ai["provider"].lower() == "groq":
|
|
127
|
+
groq_client = groq.Groq(api_key=os.getenv("GROQ"))
|
|
128
|
+
formatted_messages = [
|
|
129
|
+
{"role": "system", "content": system_prompt_text},
|
|
130
|
+
messages[0],
|
|
131
|
+
]
|
|
132
|
+
response = groq_client.chat.completions.create(
|
|
133
|
+
model=ai["model"], messages=formatted_messages
|
|
134
|
+
)
|
|
135
|
+
content = response.choices[0].message.content or ""
|
|
136
|
+
else:
|
|
137
|
+
raise ValueError(f"Unknown provider: {ai['provider']}")
|
|
138
|
+
|
|
139
|
+
if ai["provider"].lower() == "groq":
|
|
140
|
+
role = "assistant"
|
|
141
|
+
elif ai["provider"].lower() == "ollama":
|
|
142
|
+
role = "assistant"
|
|
143
|
+
elif ai["provider"].lower() == "gemini":
|
|
144
|
+
role = "model"
|
|
145
|
+
else:
|
|
146
|
+
raise ValueError(f"Unknown provider: {ai['provider']}")
|
|
147
|
+
|
|
148
|
+
messages.append(
|
|
149
|
+
{
|
|
150
|
+
"role": role,
|
|
151
|
+
"content": content,
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
max_total = 1 + cast(int, ai["max_messages_context"])
|
|
156
|
+
while len(messages) > max_total:
|
|
157
|
+
messages.pop(1)
|
|
158
|
+
|
|
159
|
+
if ai["remove_emojis"]:
|
|
160
|
+
content = demoji(content)
|
|
161
|
+
if ai["lower_response"]:
|
|
162
|
+
content = content.lower()
|
|
163
|
+
|
|
164
|
+
content = re.sub(r"<think>.*?</think>", "", content, flags=re.DOTALL).strip()
|
|
165
|
+
return content
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def create(path, content, is_dir=False):
|
|
169
|
+
base_dir = appdirs.user_data_dir(appname="Comprobot", appauthor=False)
|
|
170
|
+
|
|
171
|
+
if not os.path.isdir(base_dir):
|
|
172
|
+
os.makedirs(base_dir, exist_ok=True)
|
|
173
|
+
|
|
174
|
+
final_path = os.path.join(base_dir, path)
|
|
175
|
+
|
|
176
|
+
if is_dir:
|
|
177
|
+
os.makedirs(final_path, exist_ok=True)
|
|
178
|
+
else:
|
|
179
|
+
os.makedirs(os.path.dirname(final_path), exist_ok=True)
|
|
180
|
+
if not os.path.isfile(final_path):
|
|
181
|
+
with open(final_path, "w") as file:
|
|
182
|
+
file.write(content)
|
Comprobot/main.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import platform
|
|
2
|
+
import sys
|
|
3
|
+
from os import getenv as os_getenv
|
|
4
|
+
from os import path as os_path
|
|
5
|
+
from typing import cast
|
|
6
|
+
|
|
7
|
+
import appdirs
|
|
8
|
+
import discord
|
|
9
|
+
import dotenv
|
|
10
|
+
|
|
11
|
+
import process
|
|
12
|
+
from data import ai, config
|
|
13
|
+
from functions import chat, client, para
|
|
14
|
+
|
|
15
|
+
dotenv.load_dotenv(
|
|
16
|
+
dotenv.find_dotenv(
|
|
17
|
+
os_path.join(
|
|
18
|
+
appdirs.user_data_dir(appname="Comprobot", appauthor=False), ".env"
|
|
19
|
+
)
|
|
20
|
+
)
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
response = None
|
|
25
|
+
if sys.platform.startswith("win"):
|
|
26
|
+
print("Running on Windows (cmd)")
|
|
27
|
+
elif platform.system() in ["Linux", "Darwin"]:
|
|
28
|
+
pass
|
|
29
|
+
else:
|
|
30
|
+
print("Unknown OS")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@client.event
|
|
34
|
+
async def on_message(message):
|
|
35
|
+
|
|
36
|
+
print(
|
|
37
|
+
"\033[90m"
|
|
38
|
+
+ f"[{message.channel}] "
|
|
39
|
+
+ "\033[36m"
|
|
40
|
+
+ f"{message.author.name}: "
|
|
41
|
+
+ "\033[0m"
|
|
42
|
+
+ message.content
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
global response
|
|
46
|
+
|
|
47
|
+
if message.author == client.user:
|
|
48
|
+
return
|
|
49
|
+
response = None
|
|
50
|
+
|
|
51
|
+
if message.content.startswith(cast(str, config["command_prefix"])):
|
|
52
|
+
async with message.channel.typing():
|
|
53
|
+
response = await process.command(message)
|
|
54
|
+
elif message.content.startswith(cast(str, config["settings_prefix"])):
|
|
55
|
+
async with message.channel.typing():
|
|
56
|
+
response = await process.settings(message)
|
|
57
|
+
|
|
58
|
+
is_reply_to_bot = False
|
|
59
|
+
user_id = client.user.id if client.user else None
|
|
60
|
+
if message.reference and message.reference.message_id and user_id:
|
|
61
|
+
try:
|
|
62
|
+
ref_msg = await message.channel.fetch_message(message.reference.message_id)
|
|
63
|
+
is_reply_to_bot = ref_msg.author.id == user_id
|
|
64
|
+
except discord.NotFound:
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
if (f"<@{user_id}>" in message.content or is_reply_to_bot) and ai.get(
|
|
68
|
+
"activate_ai", False
|
|
69
|
+
):
|
|
70
|
+
async with message.channel.typing():
|
|
71
|
+
response = chat(message)
|
|
72
|
+
|
|
73
|
+
if response:
|
|
74
|
+
async with message.channel.typing():
|
|
75
|
+
content = str(response)
|
|
76
|
+
for chunk in [content[i : i + 2000] for i in range(0, len(content), 2000)]:
|
|
77
|
+
await message.channel.send(chunk)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@client.event
|
|
81
|
+
async def on_ready():
|
|
82
|
+
user_name = client.user.name if client.user else "Unknown"
|
|
83
|
+
print(f"Logged in as {user_name}")
|
|
84
|
+
para()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def main():
|
|
88
|
+
print(
|
|
89
|
+
f"Configuration directory: {appdirs.user_data_dir(appname='Comprobot', appauthor=False)}"
|
|
90
|
+
)
|
|
91
|
+
token = os_getenv("BOT_TOKEN")
|
|
92
|
+
if token:
|
|
93
|
+
client.run(token)
|
|
94
|
+
else:
|
|
95
|
+
print("Error: BOT_TOKEN not found in environment variables")
|
Comprobot/moderation.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import discord
|
|
2
|
+
from functions import direct_msg
|
|
3
|
+
|
|
4
|
+
async def ban(message):
|
|
5
|
+
member = message.guild.get_member(message.author.id)
|
|
6
|
+
if member is None:
|
|
7
|
+
try:
|
|
8
|
+
member = await message.guild.fetch_member(message.author.id)
|
|
9
|
+
except discord.NotFound:
|
|
10
|
+
print(f"Could not fetch member {message.author.name}.")
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
try:
|
|
14
|
+
await member.ban(reason=f"Sending banned text")
|
|
15
|
+
except discord.Forbidden:
|
|
16
|
+
print(f"Insufficient permissions to ban {message.author.name}.")
|
|
17
|
+
await direct_msg(
|
|
18
|
+
f"Your account has been banned because your message contains banned text",
|
|
19
|
+
message,
|
|
20
|
+
)
|
|
21
|
+
except (discord.Forbidden, discord.HTTPException):
|
|
22
|
+
print(f"Couldn't DM {message.author.name}")
|
|
23
|
+
|
|
24
|
+
async def kick(message):
|
|
25
|
+
member = message.guild.get_member(message.author.id)
|
|
26
|
+
if member is None:
|
|
27
|
+
try:
|
|
28
|
+
member = await message.guild.fetch_member(message.author.id)
|
|
29
|
+
except discord.NotFound:
|
|
30
|
+
print(f"Could not fetch member {message.author.name}.")
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
try:
|
|
34
|
+
await member.kick(reason=f"Sending banned text")
|
|
35
|
+
except (discord.Forbidden, discord.HTTPException):
|
|
36
|
+
print(f"Insufficient permissions to kick {message.author.name}")
|
|
37
|
+
await direct_msg(
|
|
38
|
+
f"Your account has been kicked because your message contains banned text",
|
|
39
|
+
message
|
|
40
|
+
)
|
|
41
|
+
except (discord.Forbidden, discord.HTTPException):
|
|
42
|
+
print(f"Couldn't DM {message.author.name}")
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import data
|
|
2
|
+
from appdirs import user_data_dir
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def add_money(username, amount):
|
|
6
|
+
data.money["members"][username] = data.money["members"].get(username, 0) + amount
|
|
7
|
+
data.save_toml(data.money, f"{user_data_dir('Comprobot')}/.dontchange/money.toml")
|
|
8
|
+
return f"{data.money['members'][username]}{data.config['money_symbol']} added to to {username}"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def remove_money(username, amount):
|
|
12
|
+
current = data.money["members"].get(username, 0)
|
|
13
|
+
if current < amount:
|
|
14
|
+
data.money["members"][username] = 0
|
|
15
|
+
data.save_toml(
|
|
16
|
+
data.money, f"{user_data_dir('Comprobot')}/.dontchange/money.toml"
|
|
17
|
+
)
|
|
18
|
+
return f"{username} doesn't have enough money. They now have 0{data.config['money_symbol']}."
|
|
19
|
+
else:
|
|
20
|
+
data.money["members"][username] -= amount
|
|
21
|
+
data.save_toml(
|
|
22
|
+
data.money, f"{user_data_dir('Comprobot')}/.dontchange/money.toml"
|
|
23
|
+
)
|
|
24
|
+
return f"{amount} subtracted from {username}. They now have {data.money['members'][username]}{data.config['money_symbol']}."
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def check_balance(username):
|
|
28
|
+
try:
|
|
29
|
+
return f"{data.money['members'][username]}{data.config['money_symbol']}"
|
|
30
|
+
except KeyError:
|
|
31
|
+
data.money["members"][username] = 0
|
|
32
|
+
data.save_toml(
|
|
33
|
+
data.money, f"{user_data_dir('Comprobot')}/.dontchange/money.toml"
|
|
34
|
+
)
|
|
35
|
+
return f"0{data.config['money_symbol']}"
|
Comprobot/process.py
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from appdirs import user_cache_dir, user_data_dir
|
|
5
|
+
|
|
6
|
+
import api
|
|
7
|
+
import commands
|
|
8
|
+
import data
|
|
9
|
+
import money_system
|
|
10
|
+
from bot import client
|
|
11
|
+
from data import active, config, error_messages, keywords, success_messages
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
async def command(ctx) -> str | None | Any:
|
|
15
|
+
|
|
16
|
+
command_parts = ctx.content[len(config["command_prefix"]) :].strip().split()
|
|
17
|
+
|
|
18
|
+
command = command_parts[0]
|
|
19
|
+
args = command_parts[1:]
|
|
20
|
+
|
|
21
|
+
if command in keywords["commands"]["quote"] and active["quote"]:
|
|
22
|
+
return api.quote()
|
|
23
|
+
elif command in keywords["commands"]["joke"] and active["joke"]:
|
|
24
|
+
return api.joke()
|
|
25
|
+
elif command in keywords["commands"]["meme"] and active["meme"]:
|
|
26
|
+
return api.meme()
|
|
27
|
+
elif command in keywords["commands"]["waifu"] and active["waifu"]:
|
|
28
|
+
return api.waifu()
|
|
29
|
+
elif command in keywords["commands"]["image"] and active["image"]:
|
|
30
|
+
if args[0] in keywords["commands"]["duck"] and active["duck"]:
|
|
31
|
+
return api.duck()
|
|
32
|
+
elif args[0] in keywords["commands"]["dog"] and active["dog"]:
|
|
33
|
+
return api.dog()
|
|
34
|
+
elif args[0] in keywords["commands"]["cat"] and active["cat"]:
|
|
35
|
+
return api.cat()
|
|
36
|
+
elif not args:
|
|
37
|
+
return error_messages["missing_argument"]
|
|
38
|
+
else:
|
|
39
|
+
return error_messages["unknown_argument"]
|
|
40
|
+
elif command in keywords["commands"]["chuck_norris"] and active["chuck_norris"]:
|
|
41
|
+
return api.chuck()
|
|
42
|
+
elif command in keywords["commands"]["fact"] and active["fact"]:
|
|
43
|
+
return api.fact()
|
|
44
|
+
elif command in keywords["commands"]["bible"] and active["bible"]:
|
|
45
|
+
if not args:
|
|
46
|
+
return api.bible(True)
|
|
47
|
+
if len(args) >= 3:
|
|
48
|
+
return api.bible(False, args[0], args[1], args[2])
|
|
49
|
+
return error_messages["passage_not_found"]
|
|
50
|
+
elif command in keywords["commands"]["truth"] and active["truth"]:
|
|
51
|
+
return api.tord(
|
|
52
|
+
"https://api.truthordarebot.xyz/v1/truth", args[0] if args else None
|
|
53
|
+
)
|
|
54
|
+
elif command in keywords["commands"]["dare"] and active["dare"]:
|
|
55
|
+
return api.tord(
|
|
56
|
+
"https://api.truthordarebot.xyz/api/dare", args[0] if args else None
|
|
57
|
+
)
|
|
58
|
+
elif command in keywords["commands"]["wyr"] and active["wyr"]:
|
|
59
|
+
return api.tord(
|
|
60
|
+
"https://api.truthordarebot.xyz/api/wyr", args[0] if args else None
|
|
61
|
+
)
|
|
62
|
+
elif (
|
|
63
|
+
command in keywords["commands"]["never_have_i_ever"]
|
|
64
|
+
and active["never_have_i_ever"]
|
|
65
|
+
):
|
|
66
|
+
return api.tord(
|
|
67
|
+
"https://api.truthordarebot.xyz/api/nhie", args[0] if args else None
|
|
68
|
+
)
|
|
69
|
+
elif command in keywords["commands"]["paranoia"] and active["paranoia"]:
|
|
70
|
+
return api.tord(
|
|
71
|
+
"https://api.truthordarebot.xyz/api/paranoia", args[0] if args else None
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
elif command in keywords["commands"]["qr_code"] and active["qr_code"]:
|
|
75
|
+
if args:
|
|
76
|
+
return commands.qr(args[0])
|
|
77
|
+
else:
|
|
78
|
+
return error_messages["missing_argument"]
|
|
79
|
+
|
|
80
|
+
elif command in keywords["commands"]["calculate"]:
|
|
81
|
+
if args:
|
|
82
|
+
return commands.calculate(args[0])
|
|
83
|
+
else:
|
|
84
|
+
return error_messages["missing_argument"]
|
|
85
|
+
|
|
86
|
+
elif command in keywords["commands"]["ascii_art"]:
|
|
87
|
+
return commands.ascii()
|
|
88
|
+
|
|
89
|
+
elif command in keywords["commands"]["currency"] and active["currency"]:
|
|
90
|
+
if not len(args) >= 3:
|
|
91
|
+
return error_messages["missing_argument"]
|
|
92
|
+
return api.currency(args[0], args[1], args[2])
|
|
93
|
+
|
|
94
|
+
elif command in keywords["money"]["check_balance"]:
|
|
95
|
+
if args:
|
|
96
|
+
return money_system.check_balance(args[0])
|
|
97
|
+
else:
|
|
98
|
+
return error_messages["missing_argument"]
|
|
99
|
+
elif command in keywords["money"]["add_money"] and (
|
|
100
|
+
ctx.author.guild_permissions.administrator or config["bot_admins"]
|
|
101
|
+
):
|
|
102
|
+
if len(args) >= 2:
|
|
103
|
+
try:
|
|
104
|
+
amount = int(args[1])
|
|
105
|
+
return money_system.add_money(args[0], amount)
|
|
106
|
+
except ValueError:
|
|
107
|
+
return f"Invalid amount: {args[1]}"
|
|
108
|
+
else:
|
|
109
|
+
return "No amount given."
|
|
110
|
+
elif command in keywords["money"]["remove_money"] and (
|
|
111
|
+
ctx.author.guild_permissions.administrator or config["bot_admins"]
|
|
112
|
+
):
|
|
113
|
+
if len(args) >= 2:
|
|
114
|
+
try:
|
|
115
|
+
amount = int(args[1])
|
|
116
|
+
return money_system.remove_money(args[0], amount)
|
|
117
|
+
except ValueError:
|
|
118
|
+
return f"Invalid amount: {args[1]}"
|
|
119
|
+
else:
|
|
120
|
+
return "No amount given."
|
|
121
|
+
|
|
122
|
+
elif command == "purge" and active["purge"]:
|
|
123
|
+
if ctx.author.guild_permissions.administrator:
|
|
124
|
+
await ctx.channel.purge()
|
|
125
|
+
return "All messages deleted."
|
|
126
|
+
|
|
127
|
+
else:
|
|
128
|
+
return None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
async def settings(ctx):
|
|
132
|
+
|
|
133
|
+
command_parts = ctx.content[len(config["settings_prefix"]) :].strip().split()
|
|
134
|
+
|
|
135
|
+
command = command_parts[0]
|
|
136
|
+
args = command_parts[1:]
|
|
137
|
+
|
|
138
|
+
cache_dir = user_cache_dir("Comprobot", appauthor=False)
|
|
139
|
+
os.makedirs(cache_dir, exist_ok=True)
|
|
140
|
+
|
|
141
|
+
if command in keywords["settings"]["profile_picture"]:
|
|
142
|
+
if not ctx.attachments:
|
|
143
|
+
return error_messages["no_attachments"]
|
|
144
|
+
if client is None or client.user is None:
|
|
145
|
+
return error_messages["bot_unavailable"]
|
|
146
|
+
new_pfp = ctx.attachments[0]
|
|
147
|
+
await new_pfp.save(f"{cache_dir}/pfp.png")
|
|
148
|
+
with open(f"{cache_dir}/pfp.png", "rb") as image_file:
|
|
149
|
+
image_data = image_file.read()
|
|
150
|
+
await client.user.edit(avatar=image_data)
|
|
151
|
+
return success_messages["profile_picture_applied"]
|
|
152
|
+
|
|
153
|
+
elif command in keywords["settings"]["banner"]:
|
|
154
|
+
if not ctx.attachments:
|
|
155
|
+
return error_messages["no_attachments"]
|
|
156
|
+
if client is None or client.user is None:
|
|
157
|
+
return error_messages["bot_unavailable"]
|
|
158
|
+
new_banner = ctx.attachments[0]
|
|
159
|
+
await new_banner.save(f"{cache_dir}/banner.png")
|
|
160
|
+
with open(f"{cache_dir}/banner.png", "rb") as image_file:
|
|
161
|
+
image_data = image_file.read()
|
|
162
|
+
await client.user.edit(banner=image_data)
|
|
163
|
+
return success_messages["banner_applied"]
|
|
164
|
+
|
|
165
|
+
elif command in keywords["settings"]["change_name"]:
|
|
166
|
+
if len(args) < 2:
|
|
167
|
+
return error_messages["missing_argument"]
|
|
168
|
+
if client is None or client.user is None:
|
|
169
|
+
return error_messages["bot_unavailable"]
|
|
170
|
+
await client.user.edit(username=args[1])
|
|
171
|
+
return success_messages["nickname_applied"]
|
|
172
|
+
|
|
173
|
+
elif command in keywords["settings"]["change_keywords"]:
|
|
174
|
+
if len(args) < 2:
|
|
175
|
+
return error_messages["missing_argument"]
|
|
176
|
+
|
|
177
|
+
target_category = None
|
|
178
|
+
for category in keywords:
|
|
179
|
+
if args[0] in keywords[category]:
|
|
180
|
+
target_category = category
|
|
181
|
+
break
|
|
182
|
+
|
|
183
|
+
if target_category is None:
|
|
184
|
+
return error_messages["unknown_argument"]
|
|
185
|
+
|
|
186
|
+
keywords[target_category][args[0]] = args[1:]
|
|
187
|
+
|
|
188
|
+
data.save_toml(keywords, f"{user_data_dir('Comprobot')}/keywords.toml")
|
|
189
|
+
|
|
190
|
+
return success_messages["keywords_applied"]
|
|
191
|
+
|
|
192
|
+
else:
|
|
193
|
+
return error_messages["unknown_command"]
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
async def games(ctx):
|
|
197
|
+
pass
|
Comprobot/templates.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
ai = r'''activate_ai = false
|
|
2
|
+
|
|
3
|
+
provider = "groq" # Available providers: "ollama", "gemini", "groq"
|
|
4
|
+
model = "qwen/qwen3-32b"
|
|
5
|
+
max_messages_context = 10
|
|
6
|
+
remove_emojis = true
|
|
7
|
+
lower_response = true
|
|
8
|
+
|
|
9
|
+
system_prompt = """
|
|
10
|
+
You are a helpful assistant that gives short, helpful answers.
|
|
11
|
+
Your answers can maximally be 1000 characters long.
|
|
12
|
+
"""'''
|
|
13
|
+
|
|
14
|
+
config = r"""
|
|
15
|
+
commmand_prefix = "!"
|
|
16
|
+
settings_prefix = "s!"
|
|
17
|
+
music_prefix = "m!"
|
|
18
|
+
|
|
19
|
+
money_symbol = "$"
|
|
20
|
+
bot_admins = []
|
|
21
|
+
ascii_art = []
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
error_messages = r'''quote = "Failed to get a quote."
|
|
25
|
+
joke = "Failed to get a joke."
|
|
26
|
+
meme = "Failed to get a meme."
|
|
27
|
+
waifu = "Failed to get a waifu image."
|
|
28
|
+
duck = "Failed to get a duck image."
|
|
29
|
+
dog = "Failed to get a dog image."
|
|
30
|
+
cat = "Failed to get a cat image."
|
|
31
|
+
chuck = "Failed to get a Chuck Norris joke."
|
|
32
|
+
fact = "Failed to get a fact."
|
|
33
|
+
bible = "Failed to get a bible verse."
|
|
34
|
+
passage_not_found = "Couldn't find bible passage: {{PASSAGE}}"
|
|
35
|
+
truth = "Failed to get a truth question."
|
|
36
|
+
dare = "Failed to get a dare question."
|
|
37
|
+
wyr = "Failed to get a Would You Rather question."
|
|
38
|
+
never-hie = "Failed to get a Never Have I Ever question."
|
|
39
|
+
paranoia = "Failed to get a paranoia question."
|
|
40
|
+
calculate = "Invalid calculation. Use +-*/"
|
|
41
|
+
bitcoin = "Failed to get the current bitcoin price."
|
|
42
|
+
currency = "Unknown currency."
|
|
43
|
+
unavailable = "API unavailable."
|
|
44
|
+
|
|
45
|
+
unknown_command = "Unknown command."
|
|
46
|
+
unknown_argument = "Unknown argument."
|
|
47
|
+
missing_argument = "Missing argument."
|
|
48
|
+
no_attachment = "No attachment given."
|
|
49
|
+
bot_unavailable = "Bot not available."'''
|
|
50
|
+
|
|
51
|
+
keywords = r"""[commands]
|
|
52
|
+
quote = ["quote"]
|
|
53
|
+
joke = ["joke"]
|
|
54
|
+
meme = ["meme"]
|
|
55
|
+
waifu = ["waifu"]
|
|
56
|
+
image = ["image", "picture"]
|
|
57
|
+
duck = ["duck"]
|
|
58
|
+
dog = ["dog"]
|
|
59
|
+
cat = ["cat"]
|
|
60
|
+
chuck_norris = ["chuck", "norris", "chucknorris"]
|
|
61
|
+
fact = ["fact"]
|
|
62
|
+
bible = ["bible"]
|
|
63
|
+
calculate = ["calculate", "calc"]
|
|
64
|
+
bitcoin = ["bitcoin", "btc"]
|
|
65
|
+
currency = ["currency", "convert", "conv"]
|
|
66
|
+
qr_code = ["qr_code", "qr"]
|
|
67
|
+
ascii_art = ["ascii", "art"]
|
|
68
|
+
|
|
69
|
+
truth = ["truth"]
|
|
70
|
+
dare = ["dare"]
|
|
71
|
+
wyr = ["wyr"]
|
|
72
|
+
never_have_i_ever = ["never-have-i-ever", "nhie"]
|
|
73
|
+
paranoia = ["paranoia"]
|
|
74
|
+
|
|
75
|
+
[settings]
|
|
76
|
+
settings = ["config", "set", "settings"]
|
|
77
|
+
profile_picture = ["pfp", "picture", "pic"]
|
|
78
|
+
banner = ["banner"]
|
|
79
|
+
change_name = ["name", "nickname"]
|
|
80
|
+
change_keywords = ["keywords", "key"]
|
|
81
|
+
|
|
82
|
+
[money]
|
|
83
|
+
add_money = ["add", "add_money"]
|
|
84
|
+
remove_money = ["remove", "rm", "remove_money"]
|
|
85
|
+
check_balance = ["check", "check_balance", "balance"]"""
|
|
86
|
+
|
|
87
|
+
moderation = r""""""
|
|
88
|
+
|
|
89
|
+
success_messages = r"""profile_picture_applied = "Profile picture applied successfully."
|
|
90
|
+
banner_applied = "Banner applied successfully."
|
|
91
|
+
nickname_applied = "Name applied successfully."
|
|
92
|
+
bio_applied = "Bio applied successfully."
|
|
93
|
+
keywords_applied = "Custom keywords applied successfully."
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
env_template = r"""BOT_TOKEN=
|
|
97
|
+
GEMINI=
|
|
98
|
+
GROQ=
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
create_commands = r"""create("config.toml", config)
|
|
102
|
+
create("error-messages.toml", error_messages)
|
|
103
|
+
create("success_messages.toml", success_messages)
|
|
104
|
+
create("keywords.toml", keywords)
|
|
105
|
+
create("ai.toml", ai)
|
|
106
|
+
create("moderation.toml", moderation)
|
|
107
|
+
create("data/.do_not_touch/money.toml", money)
|
|
108
|
+
create("data/.do_not_touch/conversation_history.toml", conversation_history)
|
|
109
|
+
create(".env", env_template)"""
|
|
110
|
+
|
|
111
|
+
active = r"""
|
|
112
|
+
quote = true
|
|
113
|
+
joke = true
|
|
114
|
+
meme = true
|
|
115
|
+
waifu = true
|
|
116
|
+
image = true
|
|
117
|
+
duck = true
|
|
118
|
+
dog = true
|
|
119
|
+
cat = true
|
|
120
|
+
chuck_norris = true
|
|
121
|
+
fact = true
|
|
122
|
+
bible = true
|
|
123
|
+
calculate = true
|
|
124
|
+
bitcoin = true
|
|
125
|
+
currency = true
|
|
126
|
+
qr_code = true
|
|
127
|
+
|
|
128
|
+
truth = true
|
|
129
|
+
dare = true
|
|
130
|
+
wyr = true
|
|
131
|
+
never_have_i_ever = true
|
|
132
|
+
paranoia = true
|
|
133
|
+
|
|
134
|
+
nsfw = false
|
|
135
|
+
|
|
136
|
+
purge = true
|
|
137
|
+
"""
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: comprobot
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A self-hostable Discord bot built for maximum customization.
|
|
5
|
+
Author: badluma
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/badluma/comprobot
|
|
8
|
+
Project-URL: Repository, https://github.com/badluma/comprobot
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: discord.py[voice]
|
|
15
|
+
Requires-Dist: python-dotenv
|
|
16
|
+
Requires-Dist: requests
|
|
17
|
+
Requires-Dist: tomlkit
|
|
18
|
+
Requires-Dist: appdirs
|
|
19
|
+
Requires-Dist: ollama
|
|
20
|
+
Requires-Dist: google-genai
|
|
21
|
+
Requires-Dist: groq
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: ruff; extra == "dev"
|
|
24
|
+
|
|
25
|
+
## Description
|
|
26
|
+
|
|
27
|
+
Comprobot is a highly-customizable, open-source Discord bot that you can run on your own server.
|
|
28
|
+
|
|
29
|
+
It’s built with Python, has a wide range of fun and useful commands, and is designed to be easy to extend. You can add new commands, customize outputs , or change the behaviour of existing ones. You can also easily edit the keywords of existing commands and customize their outputs.
|
|
30
|
+
|
|
31
|
+
The bot also comes with built-in AI capabilities when pinging the bot, with Ollama, Groq and Gemini as available providers.
|
|
32
|
+
|
|
33
|
+
## Documentation
|
|
34
|
+
|
|
35
|
+
You can find the whole documentation [here](https://badluma.github.io/Comprobot-Docs/).
|
|
36
|
+
|
|
37
|
+
## License
|
|
38
|
+
|
|
39
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Comprobot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
Comprobot/__main__.py,sha256=Vdhw8YA1K3wPMlbJQYL5WqvRzAKVeZ16mZQFO9VRmCo,62
|
|
3
|
+
Comprobot/api.py,sha256=VPpx8MPTRBmvqnJaZ1Sp_cwLqSi8_kVhe9LfJooz65k,6233
|
|
4
|
+
Comprobot/bot.py,sha256=MZAlsH85LeLfQ0tNXIUi0LnWW1kc8olDb01bp00-Pqo,328
|
|
5
|
+
Comprobot/commands.py,sha256=Drqz6zJSRQrhHaShtnCI9Aa7r-ILF9-BEPhB5UCHOU4,444
|
|
6
|
+
Comprobot/data.py,sha256=Vh01ePPwF9VaUUKFDvfjeecxFPz5hQONrq6mGdqv2Zw,2116
|
|
7
|
+
Comprobot/functions.py,sha256=ZrpXuGj-27y0bxfr4i8jIMekok12xvu5SDsVUhSVgx4,5391
|
|
8
|
+
Comprobot/main.py,sha256=A40QCmONS6G3R4JH455f2qz10WH44bN79X13g_hglSY,2482
|
|
9
|
+
Comprobot/moderation.py,sha256=Y4g9uIAK5MzaG6uj_9CtZDyzxVnCSmVDuXe9yZ7xkTs,1547
|
|
10
|
+
Comprobot/money_system.py,sha256=KxLry0fdfvbDKTeK1ogKPMlUrHOu__FmiyNymWYAZN8,1383
|
|
11
|
+
Comprobot/process.py,sha256=1QBrNpvF_dqmdNFox_7SmHurOe5zfqQLtsgdG5-4PLU,7153
|
|
12
|
+
Comprobot/templates.py,sha256=q9U_CFYqyhomP9Laka_XvoxLwr_6_8vpq9tsQUYGSCs,4312
|
|
13
|
+
comprobot-1.0.0.dist-info/METADATA,sha256=xDyruGc51JRNe2EAsi7tmiQY5EIrotsxTi88SVYD2sA,1391
|
|
14
|
+
comprobot-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
15
|
+
comprobot-1.0.0.dist-info/entry_points.txt,sha256=EJVO_FmI-sDLot5tDo5X3-JjO2WNWSopCzrCPCf1F1o,54
|
|
16
|
+
comprobot-1.0.0.dist-info/top_level.txt,sha256=JTdFBqXgm2Qndrp60n3lwY4UbOJR3Z0HJ7LTwiDHJdo,10
|
|
17
|
+
comprobot-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Comprobot
|