Skip to content

Commit

Permalink
Merge pull request #167 from MervinPraison/develop
Browse files Browse the repository at this point in the history
Custom Tools in PraisonAI Realtime
  • Loading branch information
MervinPraison authored Oct 8, 2024
2 parents 6c4f3da + 8b00279 commit fbf0bc9
Show file tree
Hide file tree
Showing 9 changed files with 278 additions and 8 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,7 @@ agentops.log
crewAI

# virtualenv
.venv
.venv

# Credentials
credentials.json
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install flask praisonai==0.1.1 gunicorn markdown
RUN pip install flask praisonai==0.1.2 gunicorn markdown
EXPOSE 8080
CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]
2 changes: 1 addition & 1 deletion docs/api/praisonai/deploy.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ <h2 id="raises">Raises</h2>
file.write(&#34;FROM python:3.11-slim\n&#34;)
file.write(&#34;WORKDIR /app\n&#34;)
file.write(&#34;COPY . .\n&#34;)
file.write(&#34;RUN pip install flask praisonai==0.1.1 gunicorn markdown\n&#34;)
file.write(&#34;RUN pip install flask praisonai==0.1.2 gunicorn markdown\n&#34;)
file.write(&#34;EXPOSE 8080\n&#34;)
file.write(&#39;CMD [&#34;gunicorn&#34;, &#34;-b&#34;, &#34;0.0.0.0:8080&#34;, &#34;api:app&#34;]\n&#39;)

Expand Down
2 changes: 1 addition & 1 deletion praisonai.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class Praisonai < Formula

desc "AI tools for various AI applications"
homepage "https://github.com/MervinPraison/PraisonAI"
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/0.1.1.tar.gz"
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/0.1.2.tar.gz"
sha256 "1828fb9227d10f991522c3f24f061943a254b667196b40b1a3e4a54a8d30ce32" # Replace with actual SHA256 checksum
license "MIT"

Expand Down
2 changes: 1 addition & 1 deletion praisonai/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def create_dockerfile(self):
file.write("FROM python:3.11-slim\n")
file.write("WORKDIR /app\n")
file.write("COPY . .\n")
file.write("RUN pip install flask praisonai==0.1.1 gunicorn markdown\n")
file.write("RUN pip install flask praisonai==0.1.2 gunicorn markdown\n")
file.write("EXPOSE 8080\n")
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')

Expand Down
48 changes: 47 additions & 1 deletion praisonai/ui/realtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,50 @@ def load_setting(key: str) -> str:

client = AsyncOpenAI()

# Add these new imports and code
import importlib.util
import logging
from importlib import import_module
from pathlib import Path

# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Try to import tools from the root directory
root_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
tools_path = os.path.join(root_dir, 'tools.py')
logger.info(f"Tools path: {tools_path}")

def import_tools_from_file(file_path):
spec = importlib.util.spec_from_file_location("custom_tools", file_path)
custom_tools_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(custom_tools_module)
logger.debug(f"Imported tools from {file_path}")
logger.debug(f"Tools: {custom_tools_module}")
return custom_tools_module

try:
if os.path.exists(tools_path):
# tools.py exists in the root directory, import from file
custom_tools_module = import_tools_from_file(tools_path)
logger.info("Successfully imported custom tools from root tools.py")
else:
logger.info("No custom tools.py file found in the root directory")
custom_tools_module = None

if custom_tools_module:
# Update the tools list with custom tools
if hasattr(custom_tools_module, 'tools') and isinstance(custom_tools_module.tools, list):
tools.extend(custom_tools_module.tools)
else:
for name, obj in custom_tools_module.__dict__.items():
if callable(obj) and not name.startswith("__"):
tools.append(({"type": "function", "function": obj}, obj))

except Exception as e:
logger.warning(f"Error importing custom tools: {str(e)}. Continuing without custom tools.")

@cl.on_chat_start
async def start():
initialize_db()
Expand Down Expand Up @@ -365,4 +409,6 @@ async def on_chat_resume(thread: ThreadDict):
cl.user_session.set("message_history", message_history)

# Reconnect to OpenAI realtime
await setup_openai_realtime()
await setup_openai_realtime()


1 change: 1 addition & 0 deletions praisonai/ui/realtimeclient/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@ async def update_session(self, **kwargs):
for key in self.tools
]
session = {**self.session_config, "tools": use_tools}
logger.debug(f"Updating session: {session}")
if self.realtime.is_connected():
await self.realtime.send("session.update", {"session": session})
return True
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "PraisonAI"
version = "0.1.1"
version = "0.1.2"
description = "PraisonAI application combines AutoGen and CrewAI or similar frameworks into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customization, and efficient human-agent collaboration."
authors = ["Mervin Praison"]
license = ""
Expand Down
222 changes: 221 additions & 1 deletion tools.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,227 @@
# # tools.py

# from google.oauth2.credentials import Credentials
# from googleapiclient.discovery import build
# from google.auth.transport.requests import Request
# from google_auth_oauthlib.flow import Flow
# from google_auth_oauthlib.flow import InstalledAppFlow
# import os
# import json
# import webbrowser
# from http.server import HTTPServer, BaseHTTPRequestHandler
# from urllib.parse import urlparse, parse_qs
# import threading
# from datetime import datetime, timedelta
# import logging

# # Set up logging
# log_level = os.getenv('LOGLEVEL', 'INFO').upper()
# logging.basicConfig(level=log_level)
# logger = logging.getLogger(__name__)
# logger.setLevel(log_level)

# # Set up Google Calendar API
# SCOPES = ['https://www.googleapis.com/auth/calendar']

# def get_calendar_service():
# logger.debug("Getting calendar service")
# creds = None
# token_dir = os.path.join(os.path.expanduser('~'), '.praison')
# token_path = os.path.join(token_dir, 'token.json')
# credentials_path = os.path.join(os.getcwd(), 'credentials.json')

# if os.path.exists(token_path):
# creds = Credentials.from_authorized_user_file(token_path, SCOPES)
# logger.debug(f"Credentials loaded from {token_path}")

# if not creds or not creds.valid:
# if creds and creds.expired and creds.refresh_token:
# logger.debug(f"Refreshing credentials")
# creds.refresh(Request())
# else:
# logger.debug(f"Starting new OAuth 2.0 flow")
# flow = InstalledAppFlow.from_client_secrets_file(credentials_path, SCOPES)
# logger.debug(f"Credentials path: {credentials_path}")
# creds = flow.run_local_server(port=8090)
# logger.debug(f"Setting up flow from {credentials_path}")
# # creds = flow.run_local_server(port=8090) # Use run_local_server from InstalledAppFlow

# # Ensure the ~/.praison directory exists
# os.makedirs(os.path.dirname(token_path), exist_ok=True)
# logger.debug(f"Saving credentials to {token_path}")
# with open(token_path, 'w') as token:
# token.write(creds.to_json())

# logger.debug("Building calendar service")
# return build('calendar', 'v3', credentials=creds)


# check_calendar_def = {
# "name": "check_calendar",
# "description": "Check Google Calendar for events within a specified time range",
# "parameters": {
# "type": "object",
# "properties": {
# "start_time": {"type": "string", "description": "Start time in ISO format (e.g., '2023-04-20T09:00:00-07:00')"},
# "end_time": {"type": "string", "description": "End time in ISO format (e.g., '2023-04-20T17:00:00-07:00')"}
# },
# "required": ["start_time", "end_time"]
# }
# }

# async def check_calendar_handler(start_time, end_time):
# try:
# service = get_calendar_service()
# events_result = service.events().list(calendarId='primary', timeMin=start_time,
# timeMax=end_time, singleEvents=True,
# orderBy='startTime').execute()
# events = events_result.get('items', [])
# logger.debug(f"Found {len(events)} events in the calendar")
# logger.debug(f"Events: {events}")
# return json.dumps(events)
# except Exception as e:
# return {"error": str(e)}

# check_calendar = (check_calendar_def, check_calendar_handler)

# add_calendar_event_def = {
# "name": "add_calendar_event",
# "description": "Add a new event to Google Calendar",
# "parameters": {
# "type": "object",
# "properties": {
# "summary": {"type": "string", "description": "Event title"},
# "start_time": {"type": "string", "description": "Start time in ISO format"},
# "end_time": {"type": "string", "description": "End time in ISO format"},
# "description": {"type": "string", "description": "Event description"}
# },
# "required": ["summary", "start_time", "end_time"]
# }
# }

# async def add_calendar_event_handler(summary, start_time, end_time, description=""):
# try:
# service = get_calendar_service()
# event = {
# 'summary': summary,
# 'description': description,
# 'start': {'dateTime': start_time, 'timeZone': 'UTC'},
# 'end': {'dateTime': end_time, 'timeZone': 'UTC'},
# }
# event = service.events().insert(calendarId='primary', body=event).execute()
# logger.debug(f"Event added: {event}")
# return {"status": "success", "event_id": event['id']}
# except Exception as e:
# return {"error": str(e)}

# add_calendar_event = (add_calendar_event_def, add_calendar_event_handler)

# list_calendar_events_def = {
# "name": "list_calendar_events",
# "description": "List Google Calendar events for a specific date",
# "parameters": {
# "type": "object",
# "properties": {
# "date": {"type": "string", "description": "Date in YYYY-MM-DD format"}
# },
# "required": ["date"]
# }
# }

# async def list_calendar_events_handler(date):
# try:
# service = get_calendar_service()
# start_of_day = f"{date}T00:00:00Z"
# end_of_day = f"{date}T23:59:59Z"
# events_result = service.events().list(calendarId='primary', timeMin=start_of_day,
# timeMax=end_of_day, singleEvents=True,
# orderBy='startTime').execute()
# events = events_result.get('items', [])
# logger.debug(f"Found {len(events)} events in the calendar for {date}")
# logger.debug(f"Events: {events}")
# return json.dumps(events)
# except Exception as e:
# return {"error": str(e)}

# list_calendar_events = (list_calendar_events_def, list_calendar_events_handler)

# update_calendar_event_def = {
# "name": "update_calendar_event",
# "description": "Update an existing Google Calendar event",
# "parameters": {
# "type": "object",
# "properties": {
# "event_id": {"type": "string", "description": "ID of the event to update"},
# "summary": {"type": "string", "description": "New event title"},
# "start_time": {"type": "string", "description": "New start time in ISO format"},
# "end_time": {"type": "string", "description": "New end time in ISO format"},
# "description": {"type": "string", "description": "New event description"}
# },
# "required": ["event_id"]
# }
# }

# async def update_calendar_event_handler(event_id, summary=None, start_time=None, end_time=None, description=None):
# try:
# service = get_calendar_service()
# event = service.events().get(calendarId='primary', eventId=event_id).execute()

# if summary:
# event['summary'] = summary
# if description:
# event['description'] = description
# if start_time:
# event['start'] = {'dateTime': start_time, 'timeZone': 'UTC'}
# if end_time:
# event['end'] = {'dateTime': end_time, 'timeZone': 'UTC'}

# updated_event = service.events().update(calendarId='primary', eventId=event_id, body=event).execute()
# logger.debug(f"Event updated: {updated_event}")
# return {"status": "success", "updated_event": updated_event}
# except Exception as e:
# return {"error": str(e)}

# update_calendar_event = (update_calendar_event_def, update_calendar_event_handler)

# delete_calendar_event_def = {
# "name": "delete_calendar_event",
# "description": "Delete a Google Calendar event",
# "parameters": {
# "type": "object",
# "properties": {
# "event_id": {"type": "string", "description": "ID of the event to delete"}
# },
# "required": ["event_id"]
# }
# }

# async def delete_calendar_event_handler(event_id):
# try:
# service = get_calendar_service()
# service.events().delete(calendarId='primary', eventId=event_id).execute()
# logger.debug(f"Event deleted: {event_id}")
# return {"status": "success", "message": f"Event with ID {event_id} has been deleted"}
# except Exception as e:
# return {"error": str(e)}

# delete_calendar_event = (delete_calendar_event_def, delete_calendar_event_handler)



# tools = [
# check_calendar,
# add_calendar_event,
# list_calendar_events,
# update_calendar_event,
# delete_calendar_event,
# ]





# from duckduckgo_search import DDGS
# from praisonai_tools import BaseTool

# class InternetSearchTool(BaseTool):
# name: str = "InternetSearchTool"
# description: str = "Search Internet for relevant information based on a query or latest news"
Expand Down

0 comments on commit fbf0bc9

Please sign in to comment.