aboutsummaryrefslogtreecommitdiffstats
path: root/cogs/assistant.py
diff options
context:
space:
mode:
authorsalmonik <raisersoft@proton.me>2026-05-21 16:38:01 +0200
committersalmonik <raisersoft@proton.me>2026-05-21 16:38:01 +0200
commite498df0647caa0360513da80fded4f5e5ea8cf2e (patch)
tree1f29420bced9db36d0b653406ed3a9290e03ee1f /cogs/assistant.py
parentrequirements shenanigans (diff)
downloadsenator-sperma-e498df0647caa0360513da80fded4f5e5ea8cf2e.tar.gz
senator-sperma-e498df0647caa0360513da80fded4f5e5ea8cf2e.zip
make the assistant simpler
Signed-off-by: salmonik <raisersoft@proton.me>
Diffstat (limited to 'cogs/assistant.py')
-rw-r--r--cogs/assistant.py111
1 files changed, 21 insertions, 90 deletions
diff --git a/cogs/assistant.py b/cogs/assistant.py
index 9926361..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,59 +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'] 115 try:
146 inner_json_str = content.strip('```json\n').strip('```').strip() 116 return await Jarvis._make_api_request(payload, headers)
147 inner_data = json.loads(inner_json_str) 117 except httpx.HTTPError as e:
148 118 logger.error(f"API request failed: {e}")
149 response_message = inner_data['message'] 119 return None
150 action = inner_data['action']
151
152 logger.info(response_message)
153 logger.info(action)
154
155 return response_message, action
156
157 @staticmethod
158 async def _handle_download_action(message, channel):
159 url_match = Jarvis._extract_url(message.content)
160 if not url_match:
161 await channel.send("Nie znaleziono poprawnego linku w odpowiedzi.")
162 return
163
164 response = await Downloader.download_standalone(url=url_match)
165 await Jarvis._process_download_response(response, channel)
166
167 @staticmethod
168 def _extract_url(content):
169 match = re.search(r'https://(?:[A-Za-z0-9-]+\.)*[A-Za-z0-9-]{1,63}\.[A-Za-z]{2,63}/\S*', content)
170 return match.group(0) if match else None
171 120
172 @staticmethod 121 @staticmethod
173 async def _process_download_response(response, channel): 122 def _parse_response(response_data):
174 if not isinstance(response, dict): 123 content = response_data['choices'][0]['message']['content']
175 return
176
177 if response["status"] == "success":
178 await Jarvis._handle_successful_download(response, channel)
179 else:
180 await Jarvis._handle_failed_download(response)
181 124
182 @staticmethod 125 logger.info(content)
183 async def _handle_successful_download(response, channel):
184 if response["type"] == "url":
185 await channel.send(f"pobioron i wysyłon: {response['content']}")
186 elif response["type"] == "file":
187 file_data = response["content"]
188 await channel.send("wysyłon:", file=discord.File(file_data))
189 shutil.rmtree(response["temp_dir"])
190 126
191 @staticmethod 127 return content
192 async def _handle_failed_download(response):
193 logger.error(f"Error: {response['content']}")
194 if 'details' in response:
195 logger.error(f"Details: {response['details']}")
196 shutil.rmtree(response["temp_dir"])
197 128
198def setup(bot): 129def setup(bot):
199 bot.add_cog(Jarvis(bot)) 130 bot.add_cog(Jarvis(bot))