diff options
Diffstat (limited to '')
| -rw-r--r-- | cogs/downloader.py | 82 | ||||
| -rw-r--r-- | cogs/jarvis.py | 103 | ||||
| -rw-r--r-- | main.py | 1 |
3 files changed, 170 insertions, 16 deletions
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 | |||
| 5 | import discord | 5 | import discord |
| 6 | import re | 6 | import re |
| 7 | import yt_dlp | 7 | import yt_dlp |
| 8 | import json | ||
| 8 | from discord.ext import commands | 9 | from discord.ext import commands |
| 9 | from dotenv import load_dotenv | 10 | from dotenv import load_dotenv |
| 10 | 11 | ||
| @@ -49,6 +50,23 @@ class Downloader(commands.Cog): | |||
| 49 | ): | 50 | ): |
| 50 | """Download and convert media from a URL to the specified format""" | 51 | """Download and convert media from a URL to the specified format""" |
| 51 | await ctx.defer() | 52 | await ctx.defer() |
| 53 | # Call the function and get the response | ||
| 54 | response = await self.download_standalone(url=url, catbox=catbox, fformat=fformat, filename_user=filename_user) | ||
| 55 | if isinstance(response, dict): | ||
| 56 | if response["status"] == "success": | ||
| 57 | if response["type"] == "url": | ||
| 58 | await ctx.respond(f"pobioron i wysyłon: {response['content']}") | ||
| 59 | elif response["type"] == "file": | ||
| 60 | file_data = response["content"] | ||
| 61 | await ctx.respond(file=discord.File(file_data)) | ||
| 62 | else: | ||
| 63 | logger.error(f"Error: {response['content']}") | ||
| 64 | if 'details' in response: | ||
| 65 | logger.error(f"Details: {response['details']}") | ||
| 66 | |||
| 67 | |||
| 68 | @staticmethod | ||
| 69 | async def download_standalone(url: str, catbox: bool = False, fformat: str = "mp4", filename_user: str = None): | ||
| 52 | try: | 70 | try: |
| 53 | logger.info(f"Downloading {url} as {fformat}") | 71 | logger.info(f"Downloading {url} as {fformat}") |
| 54 | 72 | ||
| @@ -93,6 +111,7 @@ class Downloader(commands.Cog): | |||
| 93 | filename = os.path.basename(actual_file) | 111 | filename = os.path.basename(actual_file) |
| 94 | else: | 112 | else: |
| 95 | filename = filename_user + '.' + extension | 113 | filename = filename_user + '.' + extension |
| 114 | actual_file = os.path.join(temp_dir, filename) | ||
| 96 | 115 | ||
| 97 | if not os.path.exists(actual_file): | 116 | if not os.path.exists(actual_file): |
| 98 | raise Exception(f"Downloaded file not found: {actual_file}") | 117 | raise Exception(f"Downloaded file not found: {actual_file}") |
| @@ -128,32 +147,63 @@ class Downloader(commands.Cog): | |||
| 128 | result = response.json() | 147 | result = response.json() |
| 129 | if 'fileurl' in result: | 148 | if 'fileurl' in result: |
| 130 | dl_url = result['fileurl'] | 149 | dl_url = result['fileurl'] |
| 131 | await ctx.followup.send( | 150 | return { |
| 132 | f"wysyłon\n" | 151 | "status": "success", |
| 133 | f"{dl_url}\n" | 152 | "type": "url", |
| 134 | ) | 153 | "content": dl_url, |
| 154 | "format": fformat, | ||
| 155 | "filename": filename | ||
| 156 | } | ||
| 135 | else: | 157 | else: |
| 136 | await ctx.followup.send( | 158 | return { |
| 137 | f"Odpowiedź serwera nie zawiera wymaganych danych: {result}") | 159 | "status": "error", |
| 160 | "type": "error", | ||
| 161 | "content": "Invalid response from file server", | ||
| 162 | "details": str(result) | ||
| 163 | } | ||
| 138 | except ValueError: | 164 | except ValueError: |
| 139 | await ctx.followup.send(f"Nieprawidłowa odpowiedź z serwera: {response.text}") | 165 | return { |
| 166 | "status": "error", | ||
| 167 | "type": "error", | ||
| 168 | "content": "Failed to parse server response", | ||
| 169 | "details": response.text[:200] # First 200 chars of response | ||
| 170 | } | ||
| 140 | else: | 171 | else: |
| 141 | error_msg = response.text if response.text else 'Unknown error' | 172 | error_msg = response.text if response.text else 'Unknown error' |
| 142 | await ctx.followup.send( | 173 | return { |
| 143 | f"nie udało się wysłać pliku (HTTP {response.status_code}): {error_msg}") | 174 | "status": "error", |
| 175 | "type": "error", | ||
| 176 | "content": f"Server returned {response.status_code}", | ||
| 177 | "details": error_msg | ||
| 178 | } | ||
| 144 | 179 | ||
| 145 | except Exception as upload_error: | 180 | except Exception as upload_error: |
| 146 | await ctx.followup.send(f"copyparty mnie nienawidzi :cccc\n {str(upload_error)}") | 181 | return { |
| 147 | logger.error(f"copyparty upload error: {upload_error}", exc_info=True) | 182 | "status": "error", |
| 183 | "type": "error", | ||
| 184 | "content": "Upload failed", | ||
| 185 | "details": str(upload_error) | ||
| 186 | } | ||
| 148 | 187 | ||
| 149 | else: | 188 | else: |
| 150 | await ctx.followup.send("wysyłon na discord\n", file=discord.File(filename)) | 189 | # If we have a file to return directly |
| 151 | 190 | return { | |
| 152 | logger.info(f"File processed: {actual_file}") | 191 | "status": "success", |
| 192 | "type": "file", | ||
| 193 | "content": actual_file, | ||
| 194 | "filename": filename | ||
| 195 | } | ||
| 153 | 196 | ||
| 154 | except Exception as e: | 197 | except Exception as e: |
| 155 | await ctx.followup.send(f":(\n{str(e)}") | 198 | error_msg = f"Error in download command: {e}" |
| 156 | logger.error(f"Error in download command: {e}", exc_info=True) | 199 | logger.error(error_msg, exc_info=True) |
| 200 | return { | ||
| 201 | "status": "error", | ||
| 202 | "type": "error", | ||
| 203 | "content": "Download failed", | ||
| 204 | "details": str(e) | ||
| 205 | } | ||
| 206 | |||
| 157 | 207 | ||
| 158 | 208 | ||
| 159 | def setup(bot): | 209 | 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 @@ | |||
| 1 | import re | ||
| 2 | import discord | ||
| 3 | from discord.ext import commands | ||
| 4 | import requests | ||
| 5 | import json | ||
| 6 | import logging | ||
| 7 | |||
| 8 | from cogs.compression import Compression | ||
| 9 | from cogs.downloader import Downloader | ||
| 10 | |||
| 11 | logger = logging.getLogger(__name__) | ||
| 12 | |||
| 13 | |||
| 14 | class Jarvis(commands.Cog): | ||
| 15 | def __init__(self, bot): | ||
| 16 | self.bot = bot | ||
| 17 | |||
| 18 | @commands.Cog.listener() | ||
| 19 | async def on_message(self, message): | ||
| 20 | print(message.content) | ||
| 21 | if message.author == self.bot.user: | ||
| 22 | return | ||
| 23 | |||
| 24 | if message.mentions: | ||
| 25 | if message.mentions[0].id == self.bot.user.id: | ||
| 26 | await self.jarvis(message) | ||
| 27 | |||
| 28 | if "jarvis" in message.content.lower(): | ||
| 29 | await self.jarvis(message) | ||
| 30 | |||
| 31 | @staticmethod | ||
| 32 | async def jarvis(message): | ||
| 33 | url = "https://openrouter.ai/api/v1/chat/completions" | ||
| 34 | headers = { | ||
| 35 | "Authorization": f"Bearer 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", | ||
| 36 | "Content-Type": "application/json" | ||
| 37 | } | ||
| 38 | payload = { | ||
| 39 | "model": "mistralai/devstral-2512:free", | ||
| 40 | "messages": [ | ||
| 41 | { | ||
| 42 | "role": "system", | ||
| 43 | "content": "respond in JSON format ONLY.\n" | ||
| 44 | "your task is to tell the program what to do and how to respond after receiving a message.\n" | ||
| 45 | "in the json, only fields need to be filled out, message and action\n" | ||
| 46 | "message is the response that the program will send the user, " | ||
| 47 | "and action is the action the program will do\n" | ||
| 48 | "action can either be: compress or download.\n" | ||
| 49 | "message field has to be filled out in polish.\n" | ||
| 50 | "act like jarvis, be a personal assistant to user, do not use emojis" | ||
| 51 | }, | ||
| 52 | { | ||
| 53 | "role": "user", | ||
| 54 | "content": f"{message.content}" | ||
| 55 | } | ||
| 56 | ] | ||
| 57 | } | ||
| 58 | |||
| 59 | response = requests.post(url, headers=headers, json=payload) | ||
| 60 | # Parse the JSON response | ||
| 61 | response_data = response.json() | ||
| 62 | logger.info(response_data) | ||
| 63 | # Extract the content string | ||
| 64 | content = response_data['choices'][0]['message']['content'] | ||
| 65 | |||
| 66 | # Remove the code block markers and parse the inner JSON | ||
| 67 | inner_json_str = content.strip('```json\n').strip('```').strip() | ||
| 68 | inner_data = json.loads(inner_json_str) | ||
| 69 | |||
| 70 | # Now you can access the message and action | ||
| 71 | response_message = inner_data['message'] # "Proszę podać plik do kompresji lub link do pobrania." | ||
| 72 | action = inner_data['action'] # "none OR download OR compress" | ||
| 73 | channel = message.channel | ||
| 74 | logger.info(response_message) | ||
| 75 | logger.debug(action) | ||
| 76 | |||
| 77 | await channel.send(response_message) | ||
| 78 | |||
| 79 | if action == "download": | ||
| 80 | # Extract the URL from the message using regex | ||
| 81 | url_match = re.search(r'(https?://\S+)', message.content).group(0) | ||
| 82 | if not url_match: | ||
| 83 | await channel.send("Nie znaleziono poprawnego linku w odpowiedzi.") | ||
| 84 | return | ||
| 85 | |||
| 86 | response = await Downloader.download_standalone(url=url_match) | ||
| 87 | if isinstance(response, dict): | ||
| 88 | if response["status"] == "success": | ||
| 89 | if response["type"] == "url": | ||
| 90 | await channel.send(f"pobioron i wysyłon: {response['content']}") | ||
| 91 | elif response["type"] == "file": | ||
| 92 | file_data = response["content"] | ||
| 93 | await channel.send("wysyłon:", file=discord.File(file_data)) | ||
| 94 | else: | ||
| 95 | logger.error(f"Error: {response['content']}") | ||
| 96 | if 'details' in response: | ||
| 97 | logger.error(f"Details: {response['details']}") | ||
| 98 | |||
| 99 | elif action == "compress": | ||
| 100 | pass | ||
| 101 | |||
| 102 | def setup(bot): | ||
| 103 | bot.add_cog(Jarvis(bot)) \ No newline at end of file | ||
| @@ -63,6 +63,7 @@ if __name__ == "__main__": | |||
| 63 | 'cogs.math', | 63 | 'cogs.math', |
| 64 | 'cogs.downloader', | 64 | 'cogs.downloader', |
| 65 | 'cogs.say', | 65 | 'cogs.say', |
| 66 | 'cogs.jarvis', | ||
| 66 | 'cogs.music.play', | 67 | 'cogs.music.play', |
| 67 | 'cogs.music.stop', | 68 | 'cogs.music.stop', |
| 68 | 'cogs.music.join', | 69 | 'cogs.music.join', |
