From 77883faaaa8343ca4df49627816be1ef779a039f Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 18 Jan 2026 13:30:04 +0100 Subject: jarvis --- cogs/downloader.py | 82 +++++++++++++++++++++++++++++++++--------- cogs/jarvis.py | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++ main.py | 1 + 3 files changed, 170 insertions(+), 16 deletions(-) create mode 100644 cogs/jarvis.py diff --git a/cogs/downloader.py b/cogs/downloader.py index 7925f2d..42acc1d 100644 --- a/cogs/downloader.py +++ b/cogs/downloader.py @@ -5,6 +5,7 @@ import requests import discord import re import yt_dlp +import json from discord.ext import commands from dotenv import load_dotenv @@ -49,6 +50,23 @@ class Downloader(commands.Cog): ): """Download and convert media from a URL to the specified format""" await ctx.defer() + # Call the function and get the response + response = await self.download_standalone(url=url, catbox=catbox, fformat=fformat, filename_user=filename_user) + if isinstance(response, dict): + if response["status"] == "success": + if response["type"] == "url": + await ctx.respond(f"pobioron i wysyłon: {response['content']}") + elif response["type"] == "file": + file_data = response["content"] + await ctx.respond(file=discord.File(file_data)) + else: + logger.error(f"Error: {response['content']}") + if 'details' in response: + logger.error(f"Details: {response['details']}") + + + @staticmethod + async def download_standalone(url: str, catbox: bool = False, fformat: str = "mp4", filename_user: str = None): try: logger.info(f"Downloading {url} as {fformat}") @@ -93,6 +111,7 @@ class Downloader(commands.Cog): filename = os.path.basename(actual_file) else: filename = filename_user + '.' + extension + actual_file = os.path.join(temp_dir, filename) if not os.path.exists(actual_file): raise Exception(f"Downloaded file not found: {actual_file}") @@ -128,32 +147,63 @@ class Downloader(commands.Cog): result = response.json() if 'fileurl' in result: dl_url = result['fileurl'] - await ctx.followup.send( - f"wysyłon\n" - f"{dl_url}\n" - ) + return { + "status": "success", + "type": "url", + "content": dl_url, + "format": fformat, + "filename": filename + } else: - await ctx.followup.send( - f"Odpowiedź serwera nie zawiera wymaganych danych: {result}") + return { + "status": "error", + "type": "error", + "content": "Invalid response from file server", + "details": str(result) + } except ValueError: - await ctx.followup.send(f"Nieprawidłowa odpowiedź z serwera: {response.text}") + return { + "status": "error", + "type": "error", + "content": "Failed to parse server response", + "details": response.text[:200] # First 200 chars of response + } else: error_msg = response.text if response.text else 'Unknown error' - await ctx.followup.send( - f"nie udało się wysłać pliku (HTTP {response.status_code}): {error_msg}") + return { + "status": "error", + "type": "error", + "content": f"Server returned {response.status_code}", + "details": error_msg + } except Exception as upload_error: - await ctx.followup.send(f"copyparty mnie nienawidzi :cccc\n {str(upload_error)}") - logger.error(f"copyparty upload error: {upload_error}", exc_info=True) + return { + "status": "error", + "type": "error", + "content": "Upload failed", + "details": str(upload_error) + } else: - await ctx.followup.send("wysyłon na discord\n", file=discord.File(filename)) - - logger.info(f"File processed: {actual_file}") + # If we have a file to return directly + return { + "status": "success", + "type": "file", + "content": actual_file, + "filename": filename + } except Exception as e: - await ctx.followup.send(f":(\n{str(e)}") - logger.error(f"Error in download command: {e}", exc_info=True) + error_msg = f"Error in download command: {e}" + logger.error(error_msg, exc_info=True) + return { + "status": "error", + "type": "error", + "content": "Download failed", + "details": str(e) + } + def setup(bot): diff --git a/cogs/jarvis.py b/cogs/jarvis.py new file mode 100644 index 0000000..0f4606b --- /dev/null +++ b/cogs/jarvis.py @@ -0,0 +1,103 @@ +import re +import discord +from discord.ext import commands +import requests +import json +import logging + +from cogs.compression import Compression +from cogs.downloader import Downloader + +logger = logging.getLogger(__name__) + + +class Jarvis(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @commands.Cog.listener() + async def on_message(self, message): + print(message.content) + if message.author == self.bot.user: + return + + if message.mentions: + if message.mentions[0].id == self.bot.user.id: + await self.jarvis(message) + + if "jarvis" in message.content.lower(): + await self.jarvis(message) + + @staticmethod + async def jarvis(message): + url = "https://openrouter.ai/api/v1/chat/completions" + headers = { + "Authorization": f"Bearer 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", + "Content-Type": "application/json" + } + payload = { + "model": "mistralai/devstral-2512:free", + "messages": [ + { + "role": "system", + "content": "respond in JSON format ONLY.\n" + "your task is to tell the program what to do and how to respond after receiving a message.\n" + "in the json, only fields need to be filled out, message and action\n" + "message is the response that the program will send the user, " + "and action is the action the program will do\n" + "action can either be: compress or download.\n" + "message field has to be filled out in polish.\n" + "act like jarvis, be a personal assistant to user, do not use emojis" + }, + { + "role": "user", + "content": f"{message.content}" + } + ] + } + + response = requests.post(url, headers=headers, json=payload) + # Parse the JSON response + response_data = response.json() + logger.info(response_data) + # Extract the content string + content = response_data['choices'][0]['message']['content'] + + # Remove the code block markers and parse the inner JSON + inner_json_str = content.strip('```json\n').strip('```').strip() + inner_data = json.loads(inner_json_str) + + # Now you can access the message and action + response_message = inner_data['message'] # "Proszę podać plik do kompresji lub link do pobrania." + action = inner_data['action'] # "none OR download OR compress" + channel = message.channel + logger.info(response_message) + logger.debug(action) + + await channel.send(response_message) + + if action == "download": + # Extract the URL from the message using regex + url_match = re.search(r'(https?://\S+)', message.content).group(0) + if not url_match: + await channel.send("Nie znaleziono poprawnego linku w odpowiedzi.") + return + + response = await Downloader.download_standalone(url=url_match) + if isinstance(response, dict): + if response["status"] == "success": + if response["type"] == "url": + await channel.send(f"pobioron i wysyłon: {response['content']}") + elif response["type"] == "file": + file_data = response["content"] + await channel.send("wysyłon:", file=discord.File(file_data)) + else: + logger.error(f"Error: {response['content']}") + if 'details' in response: + logger.error(f"Details: {response['details']}") + + elif action == "compress": + pass + +def setup(bot): + bot.add_cog(Jarvis(bot)) \ No newline at end of file diff --git a/main.py b/main.py index ea5d7c9..0fef6cb 100644 --- a/main.py +++ b/main.py @@ -63,6 +63,7 @@ if __name__ == "__main__": 'cogs.math', 'cogs.downloader', 'cogs.say', + 'cogs.jarvis', 'cogs.music.play', 'cogs.music.stop', 'cogs.music.join', -- cgit v1.2.3