Intermediate commits (oldest → newest):
- Create python-app.yml
- Create python-package.yml
- Various fixes
- Playlist based on chat history
- Additional logging
- Improvements
- ASync search and moving to fully asynchronous work + responses to config command
- Various fixes
- Test chat gpt4
This commit is contained in:
2025-10-30 16:58:52 +01:00
parent 87f06d6269
commit 75032b67d0
10 changed files with 502 additions and 75 deletions
+202 -26
View File
@@ -24,7 +24,7 @@ from logging import handlers
from pathlib import Path, PurePath
from platform import uname
from sys import platform
from typing import List, TypedDict, Optional
from typing import List, Optional, TypedDict
# *==============Imported libraries
import discord
@@ -53,10 +53,12 @@ Music_Config = TypedDict(
)
# *=========================================== Predefines
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s")
MASTER_TIMEOUT = datetime.now()
INITIAL_TIME_WAIT = 5
MUZYKA: Music_Config = {"playing": False, "ctx": None, "queue": [], "requestor": []}
MUZYKA: Music_Config = {"playing": False,
"ctx": None, "queue": [], "requestor": []}
LOGFILE = ""
NETRC_FILE = ""
@@ -66,6 +68,11 @@ MEMORY_FIVE_MUZYKA = ""
SETTINGS_FILE = ""
ENCODING = ""
GRAPHICS_PATH = ""
MUZYKA_MOJEGO_LUDU_HISTORIA = 1500
MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE = 15
MUZYKA_MOJEGO_LUDU_PLAJLISTA = 30
# *=========================================== Platform Specific Predefines
if platform in ("linux", "linux2"):
@@ -185,7 +192,6 @@ async def on_ready():
logger.debug("%s has connected to Discord!", client.user)
await client.change_presence(activity=discord.Game(name="Axe Throwing Darts"))
await client.tree.sync()
# await tree.sync(guild=discord.Object(id=Your guild id))
await check()
@@ -363,7 +369,6 @@ async def disconnect(ctx):
# trunk-ignore(pylint/R0915)
# trunk-ignore(pylint/R0914)
# trunk-ignore(pylint/R0912)
async def play(ctx, zamawial=None, arg=None):
"""
@@ -449,7 +454,6 @@ async def check():
"""Funkcja sprawdzająca czy grać następny kawałek."""
while True:
# TODO: Tu dołożyć skanowanie rozmiaru pliku logowania oraz plików pamięci i przenoszenie ich na większy dysk.
# TODO: Dodać typing i dać znać że wykonuje operacje porządkowania Baru (zamiata, układa szklanki itp.)
# trunk-ignore(codespell/misspelled)
# TODO: dlaczego sie tu wypierdala
if client.voice_clients:
@@ -564,10 +568,18 @@ async def handle_response(prompt, vykidailo, bartender, history, username, music
# * extend bo 20 ostatnich
if music:
history.append(message_table_muzyka[0])
history.extend(message_table_muzyka[-20:])
history.extend(message_table_muzyka[-15:])
response = await openai.ChatCompletion.acreate(
model="gpt-4-32k", messages=history
)
else:
history.append(MESSAGE_TABLE[0])
history.extend(MESSAGE_TABLE[-20:])
history.extend(MESSAGE_TABLE[-15:])
response = await openai.ChatCompletion.acreate(
model="gpt-3.5-turbo-16k", messages=history
)
logger.info("Historia wysłana:")
logger.debug(history)
response = await openai.ChatCompletion.acreate(
@@ -631,7 +643,8 @@ async def get_file(ctx, source, link):
item_type, item_id = spotify.parse_spotify_url(link)
if item_id:
file_list = spotify.fetch_tracks(spotify_ctrl, item_type, link)
directory_name = spotify.get_item_name(spotify_ctrl, item_type, item_id)
directory_name = spotify.get_item_name(
spotify_ctrl, item_type, item_id)
url_data = {"urls": []}
url_dict = {}
url_dict["save_path"] = Path(
@@ -755,10 +768,42 @@ async def async_iterator_generator(range_of_iterable):
"""
async def get_stats(ctx, history_limit):
"""
The `get_stats` function retrieves the message history of a specific channel and counts the
frequency of each word in the messages.
:param ctx: The `ctx` parameter is an object that represents the context of the command being
executed. It contains information such as the message, the author, the server, and other relevant
details
:param history_limit: The `history_limit` parameter is the maximum number of messages to retrieve
from the channel history. It determines how far back in time the statistics will be calculated
:return: The function `get_stats` returns a dictionary `stats` that contains the frequency count of
words found in the messages from the specified channel.
"""
channel_id = 1062047367337095268
async with ctx.typing():
stats = {}
channel = client.get_channel(channel_id)
messages = [message async for message in channel.history(limit=history_limit)]
# traverse the iterable of awaitables
for message in messages:
# await and get the result from the awaitable
result = message.content
words = result.split()
for word in words:
if word in stats:
stats[word] += 1
else:
stats[word] = 1
for name, how_many in stats.items():
yield name, how_many
# trunk-ignore(pylint/R0914)
# trunk-ignore(pylint/R0915)
# trunk-ignore(pylint/R0912)
async def wyszukaj(ctx, how_many=0):
async def wyszukaj(ctx, how_many=0, slowa_kluczowe=None):
"""
Take in a context object and an optional integer parameter "how_many" and perform search
operation on music library.
@@ -772,7 +817,10 @@ async def wyszukaj(ctx, how_many=0):
"""
# TODO: Potem dorobić wyszukiwania po kawałkach słów
# i sieć neuronową z możliwością wyrażenia opinii o dopasowaniu.
word_list = ctx.message.content.split()
if slowa_kluczowe:
word_list = slowa_kluczowe
else:
word_list = ctx.message.content.split()
logger.info("Wyszukuje")
search_weight = []
for _ in range(len(music_file_list)):
@@ -783,15 +831,13 @@ async def wyszukaj(ctx, how_many=0):
skip_start = 2
else:
skip_start = 1
for word in word_list[skip_start:]:
async for word in async_iterator_generator(word_list[skip_start:]):
token_weight = len(word)
logger.info("Słowo kluczowe: %s", word)
itr = 0
for file in music_file_list:
if platform == "win32":
file = file.split("\\")
else:
file = file.split("/")
async for file in async_iterator_generator(music_file_list):
file = file.split(SEPARATOR_FILE_PATH)
char_remove = [
".",
"^",
@@ -804,6 +850,7 @@ async def wyszukaj(ctx, how_many=0):
"[",
"]",
"\\",
"/",
"|",
"(",
")",
@@ -814,9 +861,9 @@ async def wyszukaj(ctx, how_many=0):
"mp3",
]
all_words = []
for f_iter in file:
for char in char_remove:
f_iter = f_iter.replace(char, "")
async for f_iter in async_iterator_generator(file):
async for char in async_iterator_generator(char_remove):
f_iter = await remove_characters(f_iter, char)
tmp = f_iter.split()
all_words.extend(tmp)
pingu = 1
@@ -826,19 +873,21 @@ async def wyszukaj(ctx, how_many=0):
else:
skip = 4
matched_times = 1
for itm in all_words[skip:]:
async for itm in async_iterator_generator(all_words[skip:]):
pingu += 1
pattern = ".*" + word + ".*"
if re.match(pattern, itm, re.IGNORECASE):
temp_weight = (
search_weight[itr][0]
+ (token_weight + (pingu**1.5) / pattern_len) / matched_times
+ (token_weight + (pingu**1.5) /
pattern_len) / matched_times
)
search_weight[itr] = temp_weight, music_file_list[itr]
matched_times += 1
itr += 1
logger.info("Stworzylem tablice wag zajęło mi to %s", datetime.now() - time_start)
logger.info("Stworzylem tablice wag zajęło mi to %s",
datetime.now() - time_start)
time_start = datetime.now()
item_to_search = await max_weight(search_weight)
itr = 0
@@ -860,6 +909,18 @@ async def wyszukaj(ctx, how_many=0):
return return_list
async def remove_characters(string, character):
"""
The `remove_characters` function removes all occurrences of a specified character from a given
string.
:param string: The string parameter is the input string from which characters will be removed
:param character: The character parameter is the character that you want to remove from the string
:return: a new string where all occurrences of the specified character have been removed.
"""
return string.replace(character, "")
async def max_weight(lista):
"""
Take a list of weights and return the maximum weight.
@@ -1317,7 +1378,7 @@ async def zrob_mi_plejliste(ctx):
if metadata.tag.title:
reply += " z prywatnej kolekcji Hammera i na Twoją specjalną rpośbę.\n"
else:
reply += f"{index}. {plik[1]} z prywatnej kolekcji Hammera."
reply += f"{index}. {plik[1]} z prywatnej kolekcji Hammera.\n"
index += 1
if len(reply) > 1800:
@@ -1487,7 +1548,14 @@ async def get_image_stable_diffusion(ctx):
pass
# @client.hybrid_command()
# trunk-ignore(mypy/arg-type)
@client.hybrid_command(
name="zagraj_muzyke_mego_ludu",
description="Gra muzyke wyszukana na bazie tematow konwersacji na kanale NZ",
guild=discord.Object(id=664789470779932693),
)
# trunk-ignore(pylint/R0912)
# trunk-ignore(pylint/R0915)
async def zagraj_muzyke_mego_ludu(ctx):
"""
Play completeley random playlist based on messaging history.
@@ -1497,9 +1565,117 @@ async def zagraj_muzyke_mego_ludu(ctx):
channel, the author, and other relevant details. In this case, it is being passed as a parameter to
the `get_image
"""
stats = {}
if ctx:
logger.info("Zagraj muzyke mego ludu: wywolane")
stat_iter = get_stats(ctx, MUZYKA_MOJEGO_LUDU_HISTORIA)
async for name, how_many in stat_iter:
if len(name) > 3:
stats[name] = how_many
sorted_stats = sorted(stats.items(), key=lambda x: x[1])
logger.info("Zagraj muzyke mego ludu:zebrano statystyki")
key_words = []
for stat in sorted_stats:
key_words.append(stat[0])
logger.info(sorted_stats[:MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE])
logger.info(key_words[:MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE])
logger.info(sorted_stats[-MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE:])
logger.info(key_words[-MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE:])
final_key_words = key_words[:MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE]
final_key_words.extend(key_words[-MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE:])
reply = "Wygenerowana plejlista:\n"
async with ctx.typing():
logger.info("Zaczynam szukać timestamp %s", datetime.now())
search_time_glob = datetime.now()
file = await wyszukaj(ctx=ctx, how_many=MUZYKA_MOJEGO_LUDU_PLAJLISTA, slowa_kluczowe=final_key_words)
logger.info("Zagraj muzyke mego ludu:wygenerowano plejliste")
logger.info(file)
logger.info(
"Koniec szukania(timestamp %s zajęło %s",
datetime.now(),
datetime.now() - search_time_glob,
)
index = 1
if file:
for plik in file:
global MUZYKA # pylint: disable=global-variable-not-assigned
MUZYKA["queue"].insert(0, plik[1])
MUZYKA["requestor"].insert(0, ctx.author)
metadata = eyed3.load(plik[1])
if metadata and metadata.tag:
if metadata.tag.title:
reply += f"{index} {metadata.tag.title}"
else:
reply += f"{index}. {plik[1]} z prywatnej kolekcji Hammera."
if metadata.tag.artist:
reply += f" wykonawcy {metadata.tag.artist}"
if metadata.tag.album:
reply += f" z albumu {metadata.tag.album}"
if metadata.tag.title:
reply += " z prywatnej kolekcji Hammera i na Twoją specjalną rpośbę.\n"
else:
reply += f"{index}. {plik[1]} z prywatnej kolekcji Hammera.\n"
index += 1
if len(reply) > 1800:
await ctx.send(reply)
reply = ""
else:
await ctx.send(
"Obawiam się że nie mogę nic znaleźć u siebie. Spróbuj komendy '$dej_co_ze_spotifaja' jeśli masz link"
)
await ctx.send(reply)
logger.info("Plejlista zrobiona")
# trunk-ignore(mypy/arg-type)
@client.hybrid_command(
name="parametry_muzyki_mego_ludu",
description="Konfiguruje komende zagraj muzyke mojego ludu",
guild=discord.Object(id=664789470779932693),
)
async def parametry_muzyki_mego_ludu(ctx, ile_historii=1500, ile_slow_kluczowych=15, jak_dluga_plejlista=30):
"""
The function `parametry_muzyki_mego_ludu` sets global variables for the number of history entries,
number of keywords, and length of playlist for a music application.
:param ctx: The `ctx` parameter is typically used in Discord.py, a Python library for creating
Discord bots. It represents the context of the command being executed, including information about
the message, the server, and the user who invoked the command
:param ile_historii: The parameter "ile_historii" represents the number of history items for the
music playlist, defaults to 1500 (optional)
:param ile_slow_kluczowych: The parameter "ile_slow_kluczowych" represents the number of keywords or
key phrases related to music that you want to include in your analysis or search, defaults to 30
(optional)
:param jak_dluga_plejlista: The parameter "jak_dluga_plejlista" determines the length of the
playlist. It specifies how many songs should be included in the playlist, defaults to 30 (optional)
"""
if ctx:
pass
async with ctx.typing():
# if ':' in ile_historii:
# _, _, ile_historii = ile_historii.partition(':')
# if ':' in ile_slow_kluczowych:
# _, _, ile_slow_kluczowych = ile_slow_kluczowych.partition(':')
# if ':' in jak_dluga_plejlista:
# _, _, jak_dluga_plejlista = jak_dluga_plejlista.partition(':')
try:
global MUZYKA_MOJEGO_LUDU_HISTORIA # pylint: disable=global-statement
global MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE # pylint: disable=global-statement
global MUZYKA_MOJEGO_LUDU_PLAJLISTA # pylint: disable=global-statement
logger.info("Długość historii wyszukiwania: %s\n Ilość słów kluczowych: %s\n Długość plejlisty do wygenerowanie: %s", MUZYKA_MOJEGO_LUDU_HISTORIA, MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE, MUZYKA_MOJEGO_LUDU_PLAJLISTA)
ctx.send(f"Dotychczasowe wartośći:\n Długość historii wyszukiwania: {MUZYKA_MOJEGO_LUDU_HISTORIA}\n Ilość słów kluczowych: {MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE}\n Długość plejlisty do wygenerowanie:{MUZYKA_MOJEGO_LUDU_PLAJLISTA}")
MUZYKA_MOJEGO_LUDU_HISTORIA = ile_historii
MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE = ile_slow_kluczowych
MUZYKA_MOJEGO_LUDU_PLAJLISTA = jak_dluga_plejlista
logger.info("Długość historii wyszukiwania: %s\n Ilość słów kluczowych: %s\n Długość plejlisty do wygenerowanie: %s", MUZYKA_MOJEGO_LUDU_HISTORIA, MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE, MUZYKA_MOJEGO_LUDU_PLAJLISTA)
ctx.send(f"Zmienione wartośći:\n Długość historii wyszukiwania: {MUZYKA_MOJEGO_LUDU_HISTORIA}\n Ilość słów kluczowych: {MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE}\n Długość plejlisty do wygenerowanie:{MUZYKA_MOJEGO_LUDU_PLAJLISTA}")
except discord.ext.commands.errors.BadArgument as exce:
ctx.send("Spierdalaj")
logger.info(exce)
# *================================== Run