aboutsummaryrefslogtreecommitdiffstats
path: root/cogs/assistant.py
diff options
context:
space:
mode:
Diffstat (limited to 'cogs/assistant.py')
-rw-r--r--cogs/assistant.py112
1 files changed, 20 insertions, 92 deletions
diff --git a/cogs/assistant.py b/cogs/assistant.py
index a91d027..fed7825 100644
--- a/cogs/assistant.py
+++ b/cogs/assistant.py
@@ -3,16 +3,11 @@
3# Copyright (C) 2026 Salmonik @ salmonik@tuta.io 3# Copyright (C) 2026 Salmonik @ salmonik@tuta.io
4# https://codeberg.org/salmonik/senator-sperma 4# https://codeberg.org/salmonik/senator-sperma
5 5
6import re
7import discord 6import discord
8from discord.ext import commands 7from discord.ext import commands
9import httpx 8import httpx
10import json
11import logging 9import logging
12import shutil
13import os 10import os
14from tempfile import NamedTemporaryFile
15from cogs.downloader import Downloader
16 11
17logger = logging.getLogger(__name__) 12logger = logging.getLogger(__name__)
18 13
@@ -46,15 +41,16 @@ class Jarvis(commands.Cog):
46 messages = Jarvis._build_messages(message, chain) 41 messages = Jarvis._build_messages(message, chain)
47 payload = Jarvis._build_payload(messages) 42 payload = Jarvis._build_payload(messages)
48 43
49 response_data = await Jarvis._make_api_request(payload, headers) 44 response_data = await Jarvis._safe_api_call(payload, headers)
50 response_message, action = Jarvis._parse_response(response_data) 45 if response_data is None:
46 await message.reply("Przepraszam, nie mogę teraz odpowiedzieć. Spróbuj ponownie później.")
47 return
48
49 response_message = Jarvis._parse_response(response_data)
51 50
52 channel = message.channel 51 channel = message.channel
53 await message.reply(response_message) 52 await message.reply(response_message)
54 53
55 if action == "download":
56 await Jarvis._handle_download_action(message, channel)
57
58 @staticmethod 54 @staticmethod
59 async def _build_message_chain(message): 55 async def _build_message_chain(message):
60 chain = [] 56 chain = []
@@ -80,10 +76,10 @@ class Jarvis(commands.Cog):
80 messages = [{ 76 messages = [{
81 "role": "system", 77 "role": "system",
82 "content": "Jesteś Senator Sperma Armostrong, także znany jako Jarvis." 78 "content": "Jesteś Senator Sperma Armostrong, także znany jako Jarvis."
83 "Twoim zadaniem, po za asystowaniem użytkownika, jest mówienie programowi nadrzędnemu jak sie zachować" 79 "Twoim zadaniem jest asystowanie użytkownika"
84 "pole 'message' może być tylko wypełnione w języku Polskim."
85 "zachowuj sie jak Jarvis, bądź osobistym asystentem użytkownika, nie używaj emotikon" 80 "zachowuj sie jak Jarvis, bądź osobistym asystentem użytkownika, nie używaj emotikon"
86 "nie pytaj sie użytkownika czy chcesz abyś coś zrobił, użytkownik ci sam powie abyś coś wykonał" 81 "nie pytaj sie użytkownika czy chce abyś coś zrobił, użytkownik ci sam powie abyś coś wykonał"
82 "Nie pozostawiaj wiadomości pustej oraz nie dawaj swojej wiadomości w pole myślenia"
87 }] 83 }]
88 84
89 if chain is None: 85 if chain is None:
@@ -92,7 +88,7 @@ class Jarvis(commands.Cog):
92 for msg in chain: 88 for msg in chain:
93 messages.append({ 89 messages.append({
94 "role": "user", 90 "role": "user",
95 "content": f"{msg.author.display_name}: {msg.content}" 91 "content": f"USER: {msg.author.display_name}\nMESSAGE: {msg.content}"
96 }) 92 })
97 93
98 return messages 94 return messages
@@ -102,38 +98,12 @@ class Jarvis(commands.Cog):
102 return { 98 return {
103 "model": os.getenv("OPENROUTER_MODEL"), 99 "model": os.getenv("OPENROUTER_MODEL"),
104 "messages": messages, 100 "messages": messages,
105 "response_format": Jarvis._get_response_schema(),
106 "plugins": [{"id": "response-healing"}] 101 "plugins": [{"id": "response-healing"}]
107 } 102 }
108 103
109 @staticmethod 104 @staticmethod
110 def _get_response_schema():
111 return {
112 "type": "json_schema",
113 "json_schema": {
114 "name": "response",
115 "strict": True,
116 "schema": {
117 "type": "object",
118 "properties": {
119 "message": {
120 "type": "string",
121 "description": "the message that user will receive",
122 },
123 "action": {
124 "type": "string",
125 "description": "the action to do, either download, compress or none"
126 }
127 },
128 "required": ["message", "action"],
129 "additionalProperties": False,
130 }
131 }
132 }
133
134 @staticmethod
135 async def _make_api_request(payload, headers): 105 async def _make_api_request(payload, headers):
136 async with httpx.AsyncClient() as client: 106 async with httpx.AsyncClient(timeout=30.0) as client:
137 url = "https://openrouter.ai/api/v1/chat/completions" 107 url = "https://openrouter.ai/api/v1/chat/completions"
138 response = await client.post(url=url, headers=headers, json=payload) 108 response = await client.post(url=url, headers=headers, json=payload)
139 response_data = response.json() 109 response_data = response.json()
@@ -141,62 +111,20 @@ class Jarvis(commands.Cog):
141 return response_data 111 return response_data
142 112
143 @staticmethod 113 @staticmethod
144 def _parse_response(response_data): 114 async def _safe_api_call(payload, headers):
145 content = response_data['choices'][0]['message']['content']
146 inner_json_str = content.strip('```json\n').strip('```').strip()
147 try: 115 try:
148 inner_data = json.loads(inner_json_str) 116 return await Jarvis._make_api_request(payload, headers)
149 response_message = inner_data['message'] 117 except httpx.HTTPError as e:
150 action = inner_data['action'] 118 logger.error(f"API request failed: {e}")
151 except (json.JSONDecodeError, KeyError): 119 return None
152 response_message = content
153 action = "none"
154
155 logger.info(response_message)
156 logger.info(action)
157
158 return response_message, action
159 120
160 @staticmethod 121 @staticmethod
161 async def _handle_download_action(message, channel): 122 def _parse_response(response_data):
162 url_match = Jarvis._extract_url(message.content) 123 content = response_data['choices'][0]['message']['content']
163 if not url_match:
164 await channel.send("Nie znaleziono poprawnego linku w odpowiedzi.")
165 return
166
167 response = await Downloader.download_standalone(url=url_match)
168 await Jarvis._process_download_response(response, channel)
169
170 @staticmethod
171 def _extract_url(content):
172 match = re.search(r'https://(?:[A-Za-z0-9-]+\.)*[A-Za-z0-9-]{1,63}\.[A-Za-z]{2,63}/\S*', content)
173 return match.group(0) if match else None
174
175 @staticmethod
176 async def _process_download_response(response, channel):
177 if not isinstance(response, dict):
178 return
179 124
180 if response["status"] == "success": 125 logger.info(content)
181 await Jarvis._handle_successful_download(response, channel)
182 else:
183 await Jarvis._handle_failed_download(response)
184 126
185 @staticmethod 127 return content
186 async def _handle_successful_download(response, channel):
187 if response["type"] == "url":
188 await channel.send(f"pobioron i wysyłon: {response['content']}")
189 elif response["type"] == "file":
190 file_data = response["content"]
191 await channel.send("wysyłon:", file=discord.File(file_data))
192 shutil.rmtree(response["temp_dir"])
193
194 @staticmethod
195 async def _handle_failed_download(response):
196 logger.error(f"Error: {response['content']}")
197 if 'details' in response:
198 logger.error(f"Details: {response['details']}")
199 shutil.rmtree(response["temp_dir"])
200 128
201def setup(bot): 129def setup(bot):
202 bot.add_cog(Jarvis(bot)) 130 bot.add_cog(Jarvis(bot))