development #1
@ -5,12 +5,25 @@ import asyncio
|
||||
import datetime
|
||||
import re
|
||||
import traceback
|
||||
import json
|
||||
from collections import Counter
|
||||
from redbot.core import Config, commands
|
||||
from openai import OpenAIError
|
||||
from .permissions import PermissionsMixin
|
||||
from .blacklist import BlacklistMixin
|
||||
from .memory import MemoryMixin
|
||||
from .weather import time_now, get_current_weather, get_weather_forecast
|
||||
from .tools_description import TOOLS
|
||||
|
||||
|
||||
CALLABLE_FUNCTIONS = {
|
||||
# Dictionary with functions to call.
|
||||
# You can use globals()[func_name](**args) instead, but that's too implicit.
|
||||
'time_now': time_now,
|
||||
'get_current_weather': get_current_weather,
|
||||
'get_weather_forecast': get_weather_forecast,
|
||||
}
|
||||
|
||||
|
||||
class ReginaldCog(PermissionsMixin, BlacklistMixin, MemoryMixin, commands.Cog):
|
||||
def __init__(self, bot):
|
||||
@ -170,14 +183,37 @@ class ReginaldCog(PermissionsMixin, BlacklistMixin, MemoryMixin, commands.Cog):
|
||||
model = await self.config.openai_model()
|
||||
try:
|
||||
client = openai.AsyncClient(api_key=api_key)
|
||||
response = await client.chat.completions.create(
|
||||
model=model,
|
||||
messages=messages,
|
||||
max_tokens=2048,
|
||||
temperature=0.7,
|
||||
presence_penalty=0.5,
|
||||
frequency_penalty=0.5
|
||||
)
|
||||
completion_args = {
|
||||
'model': model,
|
||||
'messages': messages,
|
||||
'max_tokens': 2048,
|
||||
'temperature': 0.7,
|
||||
'presence_penalty': 0.5,
|
||||
'frequency_penalty': 0.5,
|
||||
'tools': TOOLS,
|
||||
'tool_choice': 'auto',
|
||||
}
|
||||
response = await client.chat.completions.create(**completion_args)
|
||||
# Checking for function calls
|
||||
tool_calls = response.choices[0].message.tool_calls
|
||||
if tool_calls:
|
||||
for i_call in tool_calls:
|
||||
# Calling for necessary functions
|
||||
func_name = i_call.function.name
|
||||
func_args = json.loads(i_call.function.arguments)
|
||||
tool_call_id = i_call.id
|
||||
# Getting function result and putting it into messages
|
||||
func_result = CALLABLE_FUNCTIONS[func_name](**func_args)
|
||||
messages.append({
|
||||
'role': 'tool',
|
||||
'content': func_result,
|
||||
'tool_calls': tool_calls,
|
||||
'tool_call_id': tool_call_id,
|
||||
})
|
||||
# Second completion required if functions has been called to interpret the result into user-friendly
|
||||
# chat message.
|
||||
response = await client.chat.completions.create(**completion_args)
|
||||
|
||||
response_text = response.choices[0].message.content.strip()
|
||||
if response_text.startswith("Reginald:"):
|
||||
response_text = response_text[len("Reginald:"):].strip()
|
||||
|
||||
72
reginaldCog/tools_description.py
Normal file
72
reginaldCog/tools_description.py
Normal file
@ -0,0 +1,72 @@
|
||||
TOOLS = [
|
||||
{
|
||||
'type': 'function',
|
||||
'function': {
|
||||
'name': 'time_now',
|
||||
'description': 'Get current date and time in UTC timezone.',
|
||||
}
|
||||
},
|
||||
{
|
||||
'type': 'function',
|
||||
'function': {
|
||||
'name': 'get_current_weather',
|
||||
'description': '''
|
||||
Gets current weather for specified location.
|
||||
''',
|
||||
'parameters': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'location': {
|
||||
'type': 'string',
|
||||
'description': '''
|
||||
Location in human readable format.
|
||||
e.g: "Copenhagen", or "Copenhagen, Louisiana, US", if needed specifying.
|
||||
'''
|
||||
}
|
||||
},
|
||||
'required': [
|
||||
'location',
|
||||
],
|
||||
'additionalProperties': False
|
||||
},
|
||||
'strict': True
|
||||
}
|
||||
},
|
||||
{
|
||||
'type': 'function',
|
||||
'function': {
|
||||
'name': 'get_weather_forecast',
|
||||
'description': '''
|
||||
Forecast weather API method returns, depending upon your price plan level, upto next 14 day weather
|
||||
forecast and weather alert as json. The data is returned as a Forecast Object.
|
||||
Forecast object contains astronomy data, day weather forecast and hourly interval weather information
|
||||
for a given city.
|
||||
With a free weather API subscription, only up to three days of forecast can be requested.
|
||||
''',
|
||||
'parameters': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'location': {
|
||||
'type': 'string',
|
||||
'description': '''
|
||||
Location in human readable format.
|
||||
e.g: "Copenhagen", or "Copenhagen, Louisiana, US", if needed specifying.
|
||||
'''
|
||||
},
|
||||
'dt': {
|
||||
'type': 'string',
|
||||
'description': '''
|
||||
The date up until to request the forecast in YYYY-MM-DD format.
|
||||
Check the **time_now** function first if you unsure which date it is.
|
||||
'''
|
||||
},
|
||||
},
|
||||
'required': [
|
||||
'location', 'dt'
|
||||
],
|
||||
'additionalProperties': False
|
||||
},
|
||||
'strict': True
|
||||
}
|
||||
}
|
||||
]
|
||||
59
reginaldCog/weather.py
Normal file
59
reginaldCog/weather.py
Normal file
@ -0,0 +1,59 @@
|
||||
from datetime import datetime, timezone
|
||||
from os import environ
|
||||
import requests
|
||||
import json
|
||||
|
||||
WEATHER_API_KEY = environ.get('WEATHER_API_KEY')
|
||||
URL = 'http://api.weatherapi.com/v1'
|
||||
|
||||
|
||||
def time_now() -> datetime:
|
||||
return datetime.now(timezone.utc)
|
||||
|
||||
|
||||
def get_current_weather(location: str) -> str:
|
||||
weather = Weather(location=location)
|
||||
return json.dumps(weather.realtime())
|
||||
|
||||
|
||||
def get_weather_forecast(location: str, days: int = 14, dt: str = '2025-03-24') -> str:
|
||||
weather = Weather(location=location)
|
||||
return json.dumps(weather.forecast(days=days, dt=dt))
|
||||
|
||||
|
||||
class Weather:
|
||||
def __init__(self, location: str):
|
||||
self.__location = location
|
||||
|
||||
@property
|
||||
def location(self) -> str:
|
||||
return self.__location
|
||||
|
||||
@staticmethod
|
||||
def make_request(method: str, params: dict) -> dict:
|
||||
response = requests.get(url=f'{URL}{method}', params=params)
|
||||
return response.json()
|
||||
|
||||
def realtime(self):
|
||||
method = '/current.json'
|
||||
params = {
|
||||
'key': WEATHER_API_KEY,
|
||||
'q': self.location,
|
||||
}
|
||||
return self.make_request(method=method, params=params)
|
||||
|
||||
def forecast(self, days: int = 14, dt: str = '2025-03-24'):
|
||||
method = '/forecast.json'
|
||||
params = {
|
||||
'key': WEATHER_API_KEY,
|
||||
'q': self.location,
|
||||
'days': days,
|
||||
'dt': dt,
|
||||
}
|
||||
return self.make_request(method=method, params=params)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_weather = Weather('Aqtobe')
|
||||
result = json.dumps(test_weather.forecast(days=14, dt='2025-03-24'), indent=2)
|
||||
print(result)
|
||||
Loading…
x
Reference in New Issue
Block a user