add whois

This commit is contained in:
nexy7574 2023-12-05 21:12:33 +00:00
parent 0ca7e76c7d
commit 61fb6cb382
9 changed files with 177 additions and 261 deletions

View file

@ -20,9 +20,9 @@ import discord
import httpx import httpx
import pydantic import pydantic
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from config import guilds
from discord.ext import commands, pages, tasks from discord.ext import commands, pages, tasks
from config import guilds
from utils import Student, console, get_or_none from utils import Student, console, get_or_none
try: try:
@ -319,15 +319,16 @@ class Events(commands.Cog):
return return
if message.channel.name == "femboy-hole": if message.channel.name == "femboy-hole":
def generate_payload(_message: discord.Message) -> MessagePayload: def generate_payload(_message: discord.Message) -> MessagePayload:
_payload = MessagePayload( _payload = MessagePayload(
message_id=_message.id, message_id=_message.id,
author=_message.author.name, author=_message.author.name,
is_automated=_message.author.bot or _message.author.system, is_automated=_message.author.bot or _message.author.system,
avatar=_message.author.display_avatar.with_static_format("webp").with_size(512).url, avatar=_message.author.display_avatar.with_static_format("webp").with_size(512).url,
content=_message.content or '', content=_message.content or "",
clean_content=str(_message.clean_content or ''), clean_content=str(_message.clean_content or ""),
at=_message.created_at.timestamp() at=_message.created_at.timestamp(),
) )
for attachment in _message.attachments: for attachment in _message.attachments:
_payload.attachments.append( _payload.attachments.append(
@ -338,7 +339,7 @@ class Events(commands.Cog):
size=attachment.size, size=attachment.size,
width=attachment.width, width=attachment.width,
height=attachment.height, height=attachment.height,
content_type=attachment.content_type content_type=attachment.content_type,
) )
) )
if _message.reference is not None and _message.reference.cached_message: if _message.reference is not None and _message.reference.cached_message:
@ -346,11 +347,7 @@ class Events(commands.Cog):
_payload.reply_to = generate_payload(_message.reference.cached_message) _payload.reply_to = generate_payload(_message.reference.cached_message)
except RecursionError: except RecursionError:
_payload.reply_to = None _payload.reply_to = None
logging.warning( logging.warning("Failed to generate reply payload for message %s", _message.id, exc_info=True)
"Failed to generate reply payload for message %s",
_message.id,
exc_info=True
)
return _payload return _payload
payload = generate_payload(message) payload = generate_payload(message)
@ -449,7 +446,9 @@ class Events(commands.Cog):
r"bus((s)?es)?\W*$": {"file": discord.File(assets / "bus.m4a")}, r"bus((s)?es)?\W*$": {"file": discord.File(assets / "bus.m4a")},
r"^DoH$": {"content": "DoH: Domain Name Service over Hyper Text Transfer Protocol Secure"}, r"^DoH$": {"content": "DoH: Domain Name Service over Hyper Text Transfer Protocol Secure"},
r"^DoT$": {"content": "DoT: Domain Name Service over Transport Layer Security"}, r"^DoT$": {"content": "DoT: Domain Name Service over Transport Layer Security"},
r"^DoQ$": {"content": "DoQ: Domain Name Service over Quick User Datagram Protocol Internet Connections"}, r"^DoQ$": {
"content": "DoQ: Domain Name Service over Quick User Datagram Protocol Internet Connections"
},
r"^(Do)?DTLS$": {"content": "DoDTLS: Domain Name Service over Datagram Transport Layer Security"}, r"^(Do)?DTLS$": {"content": "DoDTLS: Domain Name Service over Datagram Transport Layer Security"},
} }
# Stop responding to any bots # Stop responding to any bots

View file

@ -162,9 +162,7 @@ class Extremism(commands.Cog):
size = 640 size = 640
size = min(640, max(160, size)) size = min(640, max(160, size))
decoration_url = urlparse(decoration_url)._replace( decoration_url = urlparse(decoration_url)._replace(query="?size={!s}&passthrough=true".format(size)).geturl()
query="?size={!s}&passthrough=true".format(size)
).geturl()
# Download the decoration # Download the decoration
try: try:
@ -199,9 +197,7 @@ class Extremism(commands.Cog):
# discord.File(decoration_bio, "decoration.png"), # discord.File(decoration_bio, "decoration.png"),
discord.File(img_bytes, filename="decorated." + ext) discord.File(img_bytes, filename="decorated." + ext)
] ]
await ctx.respond( await ctx.respond(files=files)
files=files
)
def setup(bot): def setup(bot):

View file

@ -5,7 +5,6 @@ import re
import typing import typing
import aiosqlite import aiosqlite
import discord import discord
from discord.ext import commands from discord.ext import commands
@ -42,7 +41,7 @@ class McDataBase:
""" """
SELECT since, started FROM breaks WHERE user_id = ?; SELECT since, started FROM breaks WHERE user_id = ?;
""", """,
(user_id,) (user_id,),
) as cursor: ) as cursor:
return await cursor.fetchone() return await cursor.fetchone()
@ -54,7 +53,7 @@ class McDataBase:
INSERT INTO breaks (user_id, since, started) VALUES (?, ?, ?) INSERT INTO breaks (user_id, since, started) VALUES (?, ?, ?)
ON CONFLICT(user_id) DO UPDATE SET since = excluded.since, started = excluded.started ON CONFLICT(user_id) DO UPDATE SET since = excluded.since, started = excluded.started
""", """,
(user_id, since, started) (user_id, since, started),
) )
async def remove_break(self, user_id: int) -> None: async def remove_break(self, user_id: int) -> None:
@ -63,7 +62,7 @@ class McDataBase:
""" """
DELETE FROM breaks WHERE user_id = ?; DELETE FROM breaks WHERE user_id = ?;
""", """,
(user_id,) (user_id,),
) )
await self.set_cooldown(user_id, now) await self.set_cooldown(user_id, now)
@ -72,7 +71,7 @@ class McDataBase:
""" """
SELECT expires FROM cooldowns WHERE user_id = ?; SELECT expires FROM cooldowns WHERE user_id = ?;
""", """,
(user_id,) (user_id,),
) as cursor: ) as cursor:
return await cursor.fetchone() return await cursor.fetchone()
@ -82,7 +81,7 @@ class McDataBase:
INSERT INTO cooldowns (user_id, expires) VALUES (?, ?) INSERT INTO cooldowns (user_id, expires) VALUES (?, ?)
ON CONFLICT(user_id) DO UPDATE SET expires = excluded.expires; ON CONFLICT(user_id) DO UPDATE SET expires = excluded.expires;
""", """,
(user_id, expires) (user_id, expires),
) )
async def remove_cooldown(self, user_id: int) -> None: async def remove_cooldown(self, user_id: int) -> None:
@ -90,7 +89,7 @@ class McDataBase:
""" """
DELETE FROM cooldowns WHERE user_id = ?; DELETE FROM cooldowns WHERE user_id = ?;
""", """,
(user_id,) (user_id,),
) )
async def __aenter__(self) -> "McDataBase": async def __aenter__(self) -> "McDataBase":
@ -123,35 +122,27 @@ class McDonaldsCog(commands.Cog):
if (last_info := await db.get_break(author.id)) is not None: if (last_info := await db.get_break(author.id)) is not None:
if message.content.upper() != "MCDONALDS!": if message.content.upper() != "MCDONALDS!":
if (message.created_at.timestamp() - last_info[1]) > 300: if (message.created_at.timestamp() - last_info[1]) > 300:
self.log.debug( self.log.debug("Ad break expired for %s (%s).", author.name, author.id)
"Ad break expired for %s (%s).", author.name, author.id
)
await db.remove_break(author.id) await db.remove_break(author.id)
await message.reply( await message.reply(
f"Thank you for your patience during this commercial break. You may now resume your" f"Thank you for your patience during this commercial break. You may now resume your"
f" activity.", f" activity.",
delete_after=120 delete_after=120,
) )
elif (message.created_at.timestamp() - last_info[0]) > 10: elif (message.created_at.timestamp() - last_info[0]) > 10:
self.log.info( self.log.info(
"Deleting message %r by %r as they need to skip the ad first.", "Deleting message %r by %r as they need to skip the ad first.", message, author
message,
author
) )
await message.delete(delay=0) await message.delete(delay=0)
await message.channel.send( await message.channel.send(
f"{message.author.mention} Please say `MCDONALDS!` to end commercial.", f"{message.author.mention} Please say `MCDONALDS!` to end commercial.", delete_after=30
delete_after=30
) )
await db.set_break(author.id, message.created_at.timestamp()) await db.set_break(author.id, message.created_at.timestamp())
elif message.author.bot is False: elif message.author.bot is False:
self.log.info("%r skipped the ad break.", author) self.log.info("%r skipped the ad break.", author)
await db.remove_break(author.id) await db.remove_break(author.id)
await message.reply( await message.reply("Thank you. You may now resume your activity.", delete_after=120)
"Thank you. You may now resume your activity.",
delete_after=120
)
@commands.user_command(name="Commercial Break") @commands.user_command(name="Commercial Break")
@commands.cooldown(2, 60, commands.BucketType.member) @commands.cooldown(2, 60, commands.BucketType.member)
@ -184,7 +175,7 @@ class McDonaldsCog(commands.Cog):
f"{member.mention} Commercial break! Please say `MCDONALDS!` to end commercial.\n" f"{member.mention} Commercial break! Please say `MCDONALDS!` to end commercial.\n"
f"*This commercial break is sponsored by {ctx.user.mention}.*", f"*This commercial break is sponsored by {ctx.user.mention}.*",
delete_after=300, delete_after=300,
allowed_mentions=discord.AllowedMentions(users=True, roles=False, everyone=False) allowed_mentions=discord.AllowedMentions(users=True, roles=False, everyone=False),
) )
await ctx.respond("Commercial break started.", ephemeral=True) await ctx.respond("Commercial break started.", ephemeral=True)
await ctx.delete(delay=120) await ctx.delete(delay=120)
@ -199,7 +190,7 @@ class McDonaldsCog(commands.Cog):
f"{member.mention} Commercial break! Please say `MCDONALDS!` to end commercial.\n" f"{member.mention} Commercial break! Please say `MCDONALDS!` to end commercial.\n"
f"*This commercial break is sponsored by {ctx.author.mention}.*", f"*This commercial break is sponsored by {ctx.author.mention}.*",
delete_after=300, delete_after=300,
allowed_mentions=discord.AllowedMentions(users=True, roles=False, everyone=False) allowed_mentions=discord.AllowedMentions(users=True, roles=False, everyone=False),
) )
await ctx.message.delete(delay=120) await ctx.message.delete(delay=120)

View file

@ -2,19 +2,16 @@ import asyncio
import fnmatch import fnmatch
import functools import functools
import glob import glob
import hashlib
import io import io
import logging
import pathlib
import openai
import pydub
import json import json
import logging
import math import math
import os import os
import pathlib
import random import random
import re import re
import shutil import shutil
import hashlib
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
@ -33,7 +30,9 @@ import aiohttp
import discord import discord
import dns.resolver import dns.resolver
import httpx import httpx
import openai
import psutil import psutil
import pydub
import pytesseract import pytesseract
import pyttsx3 import pyttsx3
from discord import Interaction from discord import Interaction
@ -75,9 +74,7 @@ except Exception as _pyttsx3_err:
VOICES = [] VOICES = []
async def ollama_stream_reader(response: httpx.Response) -> typing.AsyncGenerator[ async def ollama_stream_reader(response: httpx.Response) -> typing.AsyncGenerator[dict[str, str | int | bool], None]:
dict[str, str | int | bool], None
]:
async for chunk in response.aiter_lines(): async for chunk in response.aiter_lines():
# Each line is a JSON string # Each line is a JSON string
try: try:
@ -936,15 +933,12 @@ class OtherCog(commands.Cog):
"merge_output_format": "webm/mp4/mov/flv/avi/ogg/m4a/wav/mp3/opus/mka/mkv", "merge_output_format": "webm/mp4/mov/flv/avi/ogg/m4a/wav/mp3/opus/mka/mkv",
"source_address": "0.0.0.0", "source_address": "0.0.0.0",
"cookiefile": str(real_cookies_txt.resolve().absolute()), "cookiefile": str(real_cookies_txt.resolve().absolute()),
"concurrent_fragment_downloads": 4 "concurrent_fragment_downloads": 4,
} }
description = "" description = ""
proxy_url = "socks5://localhost:1090" proxy_url = "socks5://localhost:1090"
try: try:
proxy_down = await asyncio.wait_for( proxy_down = await asyncio.wait_for(self.check_proxy("socks5://localhost:1090"), timeout=10)
self.check_proxy("socks5://localhost:1090"),
timeout=10
)
if proxy_down > 0: if proxy_down > 0:
if proxy_down == 1: if proxy_down == 1:
description += ":warning: (SHRoNK) Proxy check leaked IP - trying backup proxy.\n" description += ":warning: (SHRoNK) Proxy check leaked IP - trying backup proxy.\n"
@ -953,10 +947,7 @@ class OtherCog(commands.Cog):
else: else:
description += ":warning: (SHRoNK) Unknown proxy error - trying backup proxy.\n" description += ":warning: (SHRoNK) Unknown proxy error - trying backup proxy.\n"
proxy_down = await asyncio.wait_for( proxy_down = await asyncio.wait_for(self.check_proxy("socks5://localhost:1080"), timeout=10)
self.check_proxy("socks5://localhost:1080"),
timeout=10
)
if proxy_down > 0: if proxy_down > 0:
if proxy_down == 1: if proxy_down == 1:
description += ":warning: (NexBox) Proxy check leaked IP..\n" description += ":warning: (NexBox) Proxy check leaked IP..\n"
@ -1011,20 +1002,14 @@ class OtherCog(commands.Cog):
"* Chosen format: `%s` (`%s`)" % (chosen_format, chosen_format_id), "* Chosen format: `%s` (`%s`)" % (chosen_format, chosen_format_id),
) )
if format_note: if format_note:
lines.append( lines.append("* Format note: %r" % format_note)
"* Format note: %r" % format_note
)
if final_extension: if final_extension:
lines.append( lines.append("* File extension: " + final_extension)
"* File extension: " + final_extension
)
if resolution: if resolution:
_s = resolution _s = resolution
if fps: if fps:
_s += " @ %s FPS" % fps _s += " @ %s FPS" % fps
lines.append( lines.append("* Resolution: " + _s)
"* Resolution: " + _s
)
if vcodec or acodec: if vcodec or acodec:
lines.append("%s+%s" % (vcodec or "N/A", acodec or "N/A")) lines.append("%s+%s" % (vcodec or "N/A", acodec or "N/A"))
@ -1766,12 +1751,13 @@ class OtherCog(commands.Cog):
model: str = "orca-mini", model: str = "orca-mini",
query: str = None, query: str = None,
context: str = None, context: str = None,
server: str = "auto" server: str = "auto",
): ):
""":3""" """:3"""
with open("./assets/ollama-prompt.txt") as file: with open("./assets/ollama-prompt.txt") as file:
system_prompt = file.read().replace("\n", " ").strip() system_prompt = file.read().replace("\n", " ").strip()
if query is None: if query is None:
class InputPrompt(discord.ui.Modal): class InputPrompt(discord.ui.Modal):
def __init__(self, is_owner: bool): def __init__(self, is_owner: bool):
super().__init__( super().__init__(
@ -1783,7 +1769,7 @@ class OtherCog(commands.Cog):
style=discord.InputTextStyle.long, style=discord.InputTextStyle.long,
), ),
title="Enter prompt", title="Enter prompt",
timeout=120 timeout=120,
) )
if is_owner: if is_owner:
self.add_item( self.add_item(
@ -1846,7 +1832,7 @@ class OtherCog(commands.Cog):
"codellama:python", "codellama:python",
"codellama:instruct", "codellama:instruct",
], ],
"owner": 421698654189912064 "owner": 421698654189912064,
}, },
"ollama.shronk.net:11434": { "ollama.shronk.net:11434": {
"name": "Alibaba Cloud", "name": "Alibaba Cloud",
@ -1861,26 +1847,19 @@ class OtherCog(commands.Cog):
"orca-mini:3b", "orca-mini:3b",
"orca-mini:7b", "orca-mini:7b",
], ],
"owner": 421698654189912064 "owner": 421698654189912064,
}, },
} }
H_DEFAULT = { H_DEFAULT = {"name": "Other", "allow": ["*"], "owner": 1019217990111199243}
"name": "Other",
"allow": ["*"],
"owner": 1019217990111199243
}
def model_is_allowed(model_name: str, _srv: dict[str, str | list[str] | int]) -> bool: def model_is_allowed(model_name: str, _srv: dict[str, str | list[str] | int]) -> bool:
if _srv["owner"] == ctx.user.id: if _srv["owner"] == ctx.user.id:
return True return True
for pat in _srv.get("allow", ['*']): for pat in _srv.get("allow", ["*"]):
if not fnmatch.fnmatch(model_name.lower(), pat.lower()): if not fnmatch.fnmatch(model_name.lower(), pat.lower()):
self.log.debug( self.log.debug(
"Server %r does not support %r (only %r.)" % ( "Server %r does not support %r (only %r.)"
_srv['name'], % (_srv["name"], model_name, ", ".join(_srv["allow"]))
model_name,
', '.join(_srv['allow'])
)
) )
else: else:
break break
@ -1890,9 +1869,7 @@ class OtherCog(commands.Cog):
class ServerSelector(discord.ui.View): class ServerSelector(discord.ui.View):
def __init__(self): def __init__(self):
super().__init__( super().__init__(disable_on_timeout=True)
disable_on_timeout=True
)
self.chosen_server = None self.chosen_server = None
async def interaction_check(self, interaction: Interaction) -> bool: async def interaction_check(self, interaction: Interaction) -> bool:
@ -1902,21 +1879,15 @@ class OtherCog(commands.Cog):
placeholder="Choose a server.", placeholder="Choose a server.",
custom_id="select", custom_id="select",
options=[ options=[
discord.SelectOption( discord.SelectOption(label="%s (%s)" % (y["name"], x), value=x)
label="%s (%s)" % (y['name'], x),
value=x
)
for x, y in servers.items() for x, y in servers.items()
if model_is_allowed(model, y) if model_is_allowed(model, y)
] + [
discord.SelectOption(
label="Custom",
value="custom"
)
] ]
+ [discord.SelectOption(label="Custom", value="custom")],
) )
async def select_callback(self, item: discord.ui.Select, interaction: discord.Interaction): async def select_callback(self, item: discord.ui.Select, interaction: discord.Interaction):
if item.values[0] == "custom": if item.values[0] == "custom":
class ServerSelectionModal(discord.ui.Modal): class ServerSelectionModal(discord.ui.Modal):
def __init__(self): def __init__(self):
super().__init__( super().__init__(
@ -1933,10 +1904,10 @@ class OtherCog(commands.Cog):
min_length=2, min_length=2,
max_length=5, max_length=5,
style=discord.InputTextStyle.short, style=discord.InputTextStyle.short,
value="11434" value="11434",
), ),
title="Enter server details", title="Enter server details",
timeout=120 timeout=120,
) )
self.hostname = None self.hostname = None
self.port = None self.port = None
@ -1955,8 +1926,7 @@ class OtherCog(commands.Cog):
self.chosen_server = item.values[0] self.chosen_server = item.values[0]
await interaction.response.defer(ephemeral=True) await interaction.response.defer(ephemeral=True)
await interaction.followup.send( await interaction.followup.send(
f"\N{white heavy check mark} Selected server {self.chosen_server}/", f"\N{white heavy check mark} Selected server {self.chosen_server}/", ephemeral=True
ephemeral=True
) )
self.stop() self.stop()
@ -1974,29 +1944,18 @@ class OtherCog(commands.Cog):
if not model_is_allowed(model, srv): if not model_is_allowed(model, srv):
return await ctx.respond( return await ctx.respond(
":x: <@{!s}> does not allow you to run that model on the server {!r}. You can, however, use" ":x: <@{!s}> does not allow you to run that model on the server {!r}. You can, however, use"
" any of the following: {}".format( " any of the following: {}".format(srv["owner"], srv["name"], ", ".join(srv.get("allow", ["*"])))
srv["owner"],
srv["name"],
", ".join(srv.get("allow", ["*"]))
)
) )
content = None content = None
embed = discord.Embed( embed = discord.Embed(colour=discord.Colour.greyple())
colour=discord.Colour.greyple()
)
embed.set_author( embed.set_author(
name=f"Loading {model}", name=f"Loading {model}",
url=f"http://{host}", url=f"http://{host}",
icon_url="https://cdn.discordapp.com/emojis/1101463077586735174.gif" icon_url="https://cdn.discordapp.com/emojis/1101463077586735174.gif",
)
FOOTER_TEXT = "Powered by Ollama • Using server {} ({})".format(
host,
servers.get(host, H_DEFAULT)['name']
)
embed.set_footer(
text=FOOTER_TEXT
) )
FOOTER_TEXT = "Powered by Ollama • Using server {} ({})".format(host, servers.get(host, H_DEFAULT)["name"])
embed.set_footer(text=FOOTER_TEXT)
msg = await ctx.respond(embed=embed, ephemeral=False) msg = await ctx.respond(embed=embed, ephemeral=False)
async with httpx.AsyncClient(follow_redirects=True) as client: async with httpx.AsyncClient(follow_redirects=True) as client:
@ -2013,19 +1972,15 @@ class OtherCog(commands.Cog):
error = "GET {0.url} HTTP {0.status_code}: {0.text}".format(e.response) error = "GET {0.url} HTTP {0.status_code}: {0.text}".format(e.response)
return await msg.edit( return await msg.edit(
embed=discord.Embed( embed=discord.Embed(
title="Failed to GET /tags. Offline?", title="Failed to GET /tags. Offline?", description=error, colour=discord.Colour.red()
description=error,
colour=discord.Colour.red()
).set_footer(text=FOOTER_TEXT) ).set_footer(text=FOOTER_TEXT)
) )
except httpx.TransportError as e: except httpx.TransportError as e:
return await msg.edit( return await msg.edit(
embed=discord.Embed( embed=discord.Embed(
title=f"Failed to connect to {host!r}", title=f"Failed to connect to {host!r}",
description="Transport error sending request to {}: {}".format( description="Transport error sending request to {}: {}".format(host, str(e)),
host, str(e) colour=discord.Colour.red(),
),
colour=discord.Colour.red()
).set_footer(text=FOOTER_TEXT) ).set_footer(text=FOOTER_TEXT)
) )
# get models # get models
@ -2033,9 +1988,7 @@ class OtherCog(commands.Cog):
response = await client.post("/show", json={"name": model}) response = await client.post("/show", json={"name": model})
except httpx.TransportError as e: except httpx.TransportError as e:
embed = discord.Embed( embed = discord.Embed(
title="Failed to connect to Ollama.", title="Failed to connect to Ollama.", description=str(e), colour=discord.Colour.red()
description=str(e),
colour=discord.Colour.red()
) )
embed.set_footer(text=FOOTER_TEXT) embed.set_footer(text=FOOTER_TEXT)
return await msg.edit(embed=embed) return await msg.edit(embed=embed)
@ -2044,10 +1997,7 @@ class OtherCog(commands.Cog):
await msg.edit(embed=embed) await msg.edit(embed=embed)
async with ctx.channel.typing(): async with ctx.channel.typing():
async with client.stream( async with client.stream(
"POST", "POST", "/pull", json={"name": model, "stream": True}, timeout=None
"/pull",
json={"name": model, "stream": True},
timeout=None
) as response: ) as response:
if response.status_code != 200: if response.status_code != 200:
error = await response.aread() error = await response.aread()
@ -2055,7 +2005,7 @@ class OtherCog(commands.Cog):
title=f"Failed to download model {model}:", title=f"Failed to download model {model}:",
description=f"HTTP {response.status_code}:\n```{error or '<no body>'}\n```", description=f"HTTP {response.status_code}:\n```{error or '<no body>'}\n```",
colour=discord.Colour.red(), colour=discord.Colour.red(),
url=str(response.url) url=str(response.url),
) )
embed.set_footer(text=FOOTER_TEXT) embed.set_footer(text=FOOTER_TEXT)
return await msg.edit(embed=embed) return await msg.edit(embed=embed)
@ -2070,8 +2020,9 @@ class OtherCog(commands.Cog):
percent = round(completed / total * 100, 2) percent = round(completed / total * 100, 2)
total_gigabytes = total / 1024 / 1024 / 1024 total_gigabytes = total / 1024 / 1024 / 1024
completed_gigabytes = completed / 1024 / 1024 / 1024 completed_gigabytes = completed / 1024 / 1024 / 1024
lines[chunk["status"]] = (f"{percent}% " lines[chunk["status"]] = (
f"({completed_gigabytes:.2f}GB/{total_gigabytes:.2f}GB)") f"{percent}% " f"({completed_gigabytes:.2f}GB/{total_gigabytes:.2f}GB)"
)
else: else:
status = chunk.get("status", chunk.get("error", os.urandom(3).hex())) status = chunk.get("status", chunk.get("error", os.urandom(3).hex()))
lines[status] = status lines[status] = status
@ -2090,7 +2041,7 @@ class OtherCog(commands.Cog):
title=f"Failed to download model {model}:", title=f"Failed to download model {model}:",
description=f"HTTP {response.status_code}:\n```{error or '<no body>'}\n```", description=f"HTTP {response.status_code}:\n```{error or '<no body>'}\n```",
colour=discord.Colour.red(), colour=discord.Colour.red(),
url=str(response.url) url=str(response.url),
) )
embed.set_footer(text=FOOTER_TEXT) embed.set_footer(text=FOOTER_TEXT)
return await msg.edit(embed=embed) return await msg.edit(embed=embed)
@ -2099,32 +2050,21 @@ class OtherCog(commands.Cog):
title=f"{model} says:", title=f"{model} says:",
description="", description="",
colour=discord.Colour.blurple(), colour=discord.Colour.blurple(),
timestamp=discord.utils.utcnow() timestamp=discord.utils.utcnow(),
) )
embed.set_footer(text=FOOTER_TEXT) embed.set_footer(text=FOOTER_TEXT)
await msg.edit(embed=embed) await msg.edit(embed=embed)
async with ctx.channel.typing(): async with ctx.channel.typing():
payload = { payload = {"model": model, "prompt": query, "format": "json", "system": system_prompt, "stream": True}
"model": model,
"prompt": query,
"format": "json",
"system": system_prompt,
"stream": True
}
if context: if context:
payload["context"] = context payload["context"] = context
async with client.stream( async with client.stream("POST", "/generate", json=payload, timeout=None) as response:
"POST",
"/generate",
json=payload,
timeout=None
) as response:
if response.status_code != 200: if response.status_code != 200:
error = await response.aread() error = await response.aread()
embed = discord.Embed( embed = discord.Embed(
title=f"Failed to generate response from {model}:", title=f"Failed to generate response from {model}:",
description=f"HTTP {response.status_code}:\n```{error or '<no body>'}\n```", description=f"HTTP {response.status_code}:\n```{error or '<no body>'}\n```",
colour=discord.Colour.red() colour=discord.Colour.red(),
) )
embed.set_footer(text=FOOTER_TEXT) embed.set_footer(text=FOOTER_TEXT)
return await msg.edit(embed=embed) return await msg.edit(embed=embed)
@ -2143,7 +2083,7 @@ class OtherCog(commands.Cog):
embed.set_author( embed.set_author(
name=f"Generating response with {model}", name=f"Generating response with {model}",
url=f"http://{host}", url=f"http://{host}",
icon_url="https://cdn.discordapp.com/emojis/1101463077586735174.gif" icon_url="https://cdn.discordapp.com/emojis/1101463077586735174.gif",
) )
embed.description += chunk["response"] embed.description += chunk["response"]
if (time() - last_edit) >= 5 or chunk["done"] is True: if (time() - last_edit) >= 5 or chunk["done"] is True:
@ -2154,10 +2094,7 @@ class OtherCog(commands.Cog):
embed.colour = discord.Colour.red() embed.colour = discord.Colour.red()
return await msg.edit(embed=embed, view=None) return await msg.edit(embed=embed, view=None)
if len(embed.description) >= 4000: if len(embed.description) >= 4000:
embed.add_field( embed.add_field(name="Aborting early", value="Output exceeded 4000 characters.")
name="Aborting early",
value="Output exceeded 4000 characters."
)
embed.title = embed.title[:-1] + " (Aborted)" embed.title = embed.title[:-1] + " (Aborted)"
embed.colour = discord.Colour.red() embed.colour = discord.Colour.red()
embed.description = embed.description[:4096] embed.description = embed.description[:4096]
@ -2207,28 +2144,22 @@ class OtherCog(commands.Cog):
self.context_cache[key] = context self.context_cache[key] = context
else: else:
context = key = None context = key = None
value = ("* Total: {}\n" value = (
"* Total: {}\n"
"* Model load: {}\n" "* Model load: {}\n"
"* Sample generation: {}\n" "* Sample generation: {}\n"
"* Prompt eval: {}\n" "* Prompt eval: {}\n"
"* Response generation: {}\n").format( "* Response generation: {}\n"
).format(
total_time_spent, total_time_spent,
load_time_spent, load_time_spent,
sample_time_sent, sample_time_sent,
prompt_eval_time_spent, prompt_eval_time_spent,
eval_time_spent, eval_time_spent,
) )
embed.add_field( embed.add_field(name="Timings", value=value, inline=False)
name="Timings",
value=value,
inline=False
)
if context: if context:
embed.add_field( embed.add_field(name="Context Key", value=key, inline=True)
name="Context Key",
value=key,
inline=True
)
embed.set_footer(text=FOOTER_TEXT) embed.set_footer(text=FOOTER_TEXT)
await msg.edit(content=None, embed=embed, view=None) await msg.edit(content=None, embed=embed, view=None)
self.ollama_locks.pop(msg, None) self.ollama_locks.pop(msg, None)
@ -2239,41 +2170,28 @@ class OtherCog(commands.Cog):
self, self,
ctx: discord.ApplicationContext, ctx: discord.ApplicationContext,
run_speed_test: bool = False, run_speed_test: bool = False,
proxy_name: discord.Option( proxy_name: discord.Option(str, choices=["SHRoNK", "NexBox", "first-working"]) = "first-working",
str, test_time: float = 30,
choices=[
"SHRoNK",
"NexBox",
"first-working"
]
) = "first-working",
test_time: float = 30
): ):
"""Tests proxies.""" """Tests proxies."""
test_time = max(5.0, test_time) test_time = max(5.0, test_time)
await ctx.defer() await ctx.defer()
SPEED_REGIONS = [ SPEED_REGIONS = ["fsn1", "nbg1", "hel1", "ash", "hil"]
"fsn1",
"nbg1",
"hel1",
"ash",
"hil"
]
results = { results = {
"localhost:1090": { "localhost:1090": {
"name": "SHRoNK", "name": "SHRoNK",
"failure": None, "failure": None,
"download_speed": 0.0, "download_speed": 0.0,
"tested": False, "tested": False,
"speedtest": "https://{hetzner_region}-speed.hetzner.com/100M.bin" "speedtest": "https://{hetzner_region}-speed.hetzner.com/100M.bin",
}, },
"localhost:1080": { "localhost:1080": {
"name": "NexBox", "name": "NexBox",
"failure": None, "failure": None,
"download_speed": 0.0, "download_speed": 0.0,
"tested": False, "tested": False,
"speedtest": "http://192.168.0.90:82/100M.bin" "speedtest": "http://192.168.0.90:82/100M.bin",
} },
} }
if proxy_name != "first-working": if proxy_name != "first-working":
for key, value in results.copy().items(): for key, value in results.copy().items():
@ -2281,18 +2199,13 @@ class OtherCog(commands.Cog):
continue continue
else: else:
results.pop(key) results.pop(key)
embed = discord.Embed( embed = discord.Embed(title="\N{white heavy check mark} Proxy available.")
title="\N{white heavy check mark} Proxy available."
)
FAILED = False FAILED = False
proxy_uri = None proxy_uri = None
for proxy_uri in results.keys(): for proxy_uri in results.keys():
name = results[proxy_uri]["name"] name = results[proxy_uri]["name"]
try: try:
proxy_down = await asyncio.wait_for( proxy_down = await asyncio.wait_for(self.check_proxy("socks5://" + proxy_uri), timeout=10)
self.check_proxy("socks5://" + proxy_uri),
timeout=10
)
results[proxy_uri]["tested"] = True results[proxy_uri]["tested"] = True
if proxy_down > 0: if proxy_down > 0:
embed.colour = discord.Colour.red() embed.colour = discord.Colour.red()
@ -2314,19 +2227,12 @@ class OtherCog(commands.Cog):
results[proxy_uri]["failure"] = f"Failed to check {name} proxy (`{e}`)." results[proxy_uri]["failure"] = f"Failed to check {name} proxy (`{e}`)."
results[proxy_uri]["tested"] = True results[proxy_uri]["tested"] = True
else: else:
embed = discord.Embed( embed = discord.Embed(title="\N{cross mark} All proxies failed.", colour=discord.Colour.red())
title="\N{cross mark} All proxies failed.",
colour=discord.Colour.red()
)
FAILED = True FAILED = True
for uri, value in results.items(): for uri, value in results.items():
if value["tested"]: if value["tested"]:
embed.add_field( embed.add_field(name=value["name"], value=value["failure"] or "Proxy is working.", inline=True)
name=value["name"],
value=value["failure"] or "Proxy is working.",
inline=True
)
embed.set_footer(text="No speed test will be run.") embed.set_footer(text="No speed test will be run.")
await ctx.respond(embed=embed) await ctx.respond(embed=embed)
if run_speed_test and FAILED is False: if run_speed_test and FAILED is False:
@ -2337,9 +2243,7 @@ class OtherCog(commands.Cog):
async with httpx.AsyncClient( async with httpx.AsyncClient(
http2=True, http2=True,
proxies=chosen_proxy, proxies=chosen_proxy,
headers={ headers={"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0"},
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0"
}
) as client: ) as client:
bytes_received = 0 bytes_received = 0
for region in SPEED_REGIONS: for region in SPEED_REGIONS:
@ -2357,9 +2261,7 @@ class OtherCog(commands.Cog):
response.raise_for_status() response.raise_for_status()
end = time() end = time()
now = discord.utils.utcnow() now = discord.utils.utcnow()
embed.set_footer( embed.set_footer(text=embed.footer.text + " | Finished at: " + now.strftime("%X"))
text=embed.footer.text + " | Finished at: " + now.strftime("%X")
)
break break
except Exception as e: except Exception as e:
results[proxy_uri]["failure"] = f"Failed to test {region} speed (`{e}`)." results[proxy_uri]["failure"] = f"Failed to test {region} speed (`{e}`)."
@ -2373,7 +2275,7 @@ class OtherCog(commands.Cog):
title=f"\U000023f2\U0000fe0f Speed test results (for {proxy_uri})", title=f"\U000023f2\U0000fe0f Speed test results (for {proxy_uri})",
description=f"Downloaded {megabytes:,.1f}MB in {elapsed:,.0f} seconds " description=f"Downloaded {megabytes:,.1f}MB in {elapsed:,.0f} seconds "
f"({megabits_per_second:,.0f}Mbps).\n`{latency:,.0f}ms` latency.", f"({megabits_per_second:,.0f}Mbps).\n`{latency:,.0f}ms` latency.",
colour=discord.Colour.green() if megabits_per_second >= 50 else discord.Colour.red() colour=discord.Colour.green() if megabits_per_second >= 50 else discord.Colour.red(),
) )
embed2.add_field(name="Source", value=used) embed2.add_field(name="Source", value=used)
await ctx.edit(embeds=[embed, embed2]) await ctx.edit(embeds=[embed, embed2])
@ -2407,15 +2309,11 @@ class OtherCog(commands.Cog):
f2.seek(0) f2.seek(0)
seg: pydub.AudioSegment = await asyncio.to_thread(pydub.AudioSegment.from_file, file=f2, format=_ft) seg: pydub.AudioSegment = await asyncio.to_thread(pydub.AudioSegment.from_file, file=f2, format=_ft)
seg = seg.set_channels(1) seg = seg.set_channels(1)
await asyncio.to_thread( await asyncio.to_thread(seg.export, f.name, format="mp4")
seg.export, f.name, format="mp4"
)
f.seek(0) f.seek(0)
transcript = await asyncio.to_thread( transcript = await asyncio.to_thread(
client.audio.transcriptions.create, client.audio.transcriptions.create, file=pathlib.Path(f.name), model="whisper-1"
file=pathlib.Path(f.name),
model="whisper-1"
) )
text = transcript.text text = transcript.text
cache.write_text(text) cache.write_text(text)
@ -2431,12 +2329,48 @@ class OtherCog(commands.Cog):
if await self.bot.is_owner(ctx.user): if await self.bot.is_owner(ctx.user):
await ctx.respond( await ctx.respond(
("Cached response ({})" if cached else "Uncached response ({})").format( ("Cached response ({})" if cached else "Uncached response ({})").format(file_hash), ephemeral=True
file_hash
),
ephemeral=True
) )
@commands.slash_command()
async def whois(self, ctx: discord.ApplicationContext, domain: str):
"""Runs a WHOIS."""
await ctx.defer()
url = urlparse("http://" + domain)
if not url.hostname:
return await ctx.respond("Invalid domain.")
process = await asyncio.create_subprocess_exec(
"whois", "-H", url.hostname, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, text=True
)
stdout, stderr = await process.communicate()
await process.wait()
if process.returncode != 0:
return await ctx.respond(f"Error:\n```{stderr[:3900]}```")
paginator = commands.Paginator()
redacted = io.BytesIO()
for line in stdout.splitlines():
if line.startswith(">>> Last update"):
break
if "REDACTED" in line:
redacted.write(line.encode() + b"\n")
else:
paginator.add_line(line)
if redacted.tell() > 0:
redacted.seek(0)
file = discord.File(redacted, "redacted-fields.txt", description="Any discovered redacted fields.")
else:
file = None
if len(paginator.pages) > 1:
for page in paginator.pages:
await ctx.respond(page)
if file:
await ctx.respond(file=file)
else:
await ctx.respond(paginator.pages[0], file=file)
def setup(bot): def setup(bot):
bot.add_cog(OtherCog(bot)) bot.add_cog(OtherCog(bot))

View file

@ -5,10 +5,10 @@ from datetime import datetime, time, timedelta, timezone
from pathlib import Path from pathlib import Path
from typing import Dict, Optional, Union from typing import Dict, Optional, Union
import config
import discord import discord
from discord.ext import commands, tasks from discord.ext import commands, tasks
import config
from utils import TimeTableDaySwitcherView, console from utils import TimeTableDaySwitcherView, console

19
main.py
View file

@ -1,15 +1,15 @@
import logging
import os import os
import signal import signal
import sys import sys
import logging
import textwrap import textwrap
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
import discord
from discord.ext import commands
from rich.logging import RichHandler from rich.logging import RichHandler
import config import config
import discord
from discord.ext import commands
from utils import JimmyBanException, JimmyBans, console, get_or_none from utils import JimmyBanException, JimmyBans, console, get_or_none
from utils.client import bot from utils.client import bot
@ -25,13 +25,10 @@ logging.basicConfig(
markup=True, markup=True,
rich_tracebacks=True, rich_tracebacks=True,
show_path=False, show_path=False,
show_time=False show_time=False,
), ),
logging.FileHandler( logging.FileHandler("jimmy.log", "a"),
"jimmy.log", ],
"a"
)
]
) )
logging.getLogger("discord.gateway").setLevel(logging.WARNING) logging.getLogger("discord.gateway").setLevel(logging.WARNING)
for _ln in [ for _ln in [
@ -43,7 +40,7 @@ for _ln in [
"discord.bot", "discord.bot",
"httpcore.http11", "httpcore.http11",
"aiosqlite", "aiosqlite",
"httpx" "httpx",
]: ]:
logging.getLogger(_ln).setLevel(logging.INFO) logging.getLogger(_ln).setLevel(logging.INFO)

View file

@ -6,10 +6,11 @@ from datetime import datetime, timezone
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING, Dict, Optional, Union from typing import TYPE_CHECKING, Dict, Optional, Union
import config
import discord import discord
from discord.ext import commands from discord.ext import commands
import config
if TYPE_CHECKING: if TYPE_CHECKING:
from asyncio import Task from asyncio import Task
@ -57,6 +58,7 @@ class Bot(commands.Bot):
log.info(f"Loaded extension [green]{ext}") log.info(f"Loaded extension [green]{ext}")
if getattr(config, "CONNECT_MODE", None) == 2: if getattr(config, "CONNECT_MODE", None) == 2:
async def connect(self, *, reconnect: bool = True) -> None: async def connect(self, *, reconnect: bool = True) -> None:
self.log.critical("Exit target 2 reached, shutting down (not connecting to discord).") self.log.critical("Exit target 2 reached, shutting down (not connecting to discord).")
return return

View file

@ -8,13 +8,8 @@ import discord
import orm import orm
from discord.ui import View from discord.ui import View
from utils import ( from utils import BannedStudentID, Student, VerifyCode, console, get_or_none
BannedStudentID,
Student,
VerifyCode,
console,
get_or_none,
)
TOKEN_LENGTH = 16 TOKEN_LENGTH = 16
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:

View file

@ -3,6 +3,7 @@ import ipaddress
import logging import logging
import os import os
import textwrap import textwrap
from asyncio import Lock
from datetime import datetime, timezone from datetime import datetime, timezone
from hashlib import sha512 from hashlib import sha512
from http import HTTPStatus from http import HTTPStatus
@ -10,13 +11,13 @@ from pathlib import Path
import discord import discord
import httpx import httpx
from config import guilds from fastapi import FastAPI, Header, HTTPException, Request
from asyncio import Lock from fastapi import WebSocketException as _WSException
from fastapi import FastAPI, Header, HTTPException, Request, WebSocketException as _WSException
from websockets.exceptions import WebSocketException
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
from starlette.websockets import WebSocket, WebSocketDisconnect from starlette.websockets import WebSocket, WebSocketDisconnect
from websockets.exceptions import WebSocketException
from config import guilds
from utils import BannedStudentID, Student, VerifyCode, console, get_or_none from utils import BannedStudentID, Student, VerifyCode, console, get_or_none
from utils.db import AccessTokens from utils.db import AccessTokens
@ -112,7 +113,8 @@ async def authenticate(req: Request, code: str = None, state: str = None):
return RedirectResponse( return RedirectResponse(
discord.utils.oauth_url( discord.utils.oauth_url(
OAUTH_ID, redirect_uri=OAUTH_REDIRECT_URI, scopes=("identify", "connections", "guilds", "email") OAUTH_ID, redirect_uri=OAUTH_REDIRECT_URI, scopes=("identify", "connections", "guilds", "email")
) + f"&state={value}&prompt=none", )
+ f"&state={value}&prompt=none",
status_code=HTTPStatus.TEMPORARY_REDIRECT, status_code=HTTPStatus.TEMPORARY_REDIRECT,
headers={"Cache-Control": "no-store, no-cache"}, headers={"Cache-Control": "no-store, no-cache"},
) )