Skip to content

Commit

Permalink
feat: add assignment-agent (autogen + canvas) in py examples (#948)
Browse files Browse the repository at this point in the history
  • Loading branch information
abhishekpatil4 authored Dec 5, 2024
1 parent 7425eec commit 29e6cc4
Show file tree
Hide file tree
Showing 5 changed files with 281 additions and 0 deletions.
2 changes: 2 additions & 0 deletions python/examples/advanced_agents/assignment-agent/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
OPENAI_API_KEY=
COMPOSIO_API_KEY=
4 changes: 4 additions & 0 deletions python/examples/advanced_agents/assignment-agent/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
autogen
.env
__pycache__
.cache
41 changes: 41 additions & 0 deletions python/examples/advanced_agents/assignment-agent/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# AI Assignment Agent

This project implements a single AI agent built using Autogen and Composio Tools that can either create or review assignments based on user selection.

## Features
- Create new assignments on Canvas
- Review and grade submitted assignments on Canvas

## Prerequisites

- A connected Canvas account on Composio
- OpenAI API key
- Composio API key

## Installation

1. **Install dependencies**:
```bash
pip install -r requirements.txt
```

2. **Set up environment variables**:
Create a `.env` file with:
```
OPENAI_API_KEY=your_openai_key
COMPOSIO_API_KEY=your_composio_key
```

## Usage

Run the main script and select your desired operation:

```bash
python assignment_agent.py
```

You'll be prompted to:
1. Choose an operation:
- Option 1: Create a new assignment
- Option 2: Review existing assignments
2. Provide necessary details based on your selection
167 changes: 167 additions & 0 deletions python/examples/advanced_agents/assignment-agent/assignment_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
from autogen import AssistantAgent, UserProxyAgent
from composio_autogen import ComposioToolSet, Action
from composio import AppType
import os
from dotenv import load_dotenv

load_dotenv()

toolset = ComposioToolSet(
api_key=os.getenv("COMPOSIO_API_KEY"),
entity_id="karthik",
)
llm_config = {
"config_list": [
{
"model": "gpt-4o",
"api_key": os.getenv("OPENAI_API_KEY"),
}
]
}

chatbot = AssistantAgent(
"chatbot",
system_message="You're a helpful assistant that creates assignments for a course & reviews them. You will be given the details of the assigment to create and review, after creating or reviewing you need to TERMINATE.",
llm_config=llm_config,
)

user_proxy = UserProxyAgent(
name="User",
is_termination_msg=lambda x: x.get("content", "")
and "TERMINATE" in x.get("content", ""),
human_input_mode="NEVER",
code_execution_config={"use_docker": False},
)

toolset.register_tools(
actions=[
Action.CANVAS_CREATE_ASSIGNMENT,
Action.CANVAS_GET_ASSIGNMENT,
Action.CANVAS_LIST_ASSIGNMENT_SUBMISSIONS,
Action.CANVAS_GRADE_COMMENT_SUBMISSION,
],
caller=chatbot,
executor=user_proxy,
)

def get_courses():
courses = toolset.execute_action(
action=Action.CANVAS_LIST_COURSES,
entity_id="karthik",
params={}
)
return courses

def get_assignments(course_id):
assignments = toolset.execute_action(
action=Action.CANVAS_GET_ALL_ASSIGNMENTS,
entity_id="karthik",
params={"course_id": course_id}
)
return assignments

def get_course_id_by_name():
courses_response = get_courses()
if not courses_response.get('successfull'):
print("Failed to fetch courses")
return None

courses_data = courses_response['data']['response_data']
available_courses = {course['name'].strip(): course['id'] for course in courses_data}

print("\nAvailable courses:")
for course_name in available_courses.keys():
print(f"- {course_name}")

while True:
course_name = input("\nEnter course name: ").strip()
if course_name in available_courses:
return available_courses[course_name]
print(f"Course '{course_name}' not found. Please try again.")

def get_create_assignment_task():
course_id = get_course_id_by_name()
if not course_id:
return None

name = input("\nEnter assignment name: ").strip()
description = input("Enter assignment description: ")

return f"""
Create a new assignment for the course with id {course_id}.
Assignment details:
- Name: {name}
- Description: {description}
- Published: True
- Assignment Group: everyone
- Submission Types: Online (Text Entry)
- Display grade as: Points (10 is total points)
"""

def get_assignment_id_by_name(course_id):
assignments_response = get_assignments(course_id)
if not assignments_response.get('successfull'):
print("Failed to fetch assignments")
return None

assignments_data = assignments_response['data']['response_data']
available_assignments = {assignment['name'].strip(): assignment['id'] for assignment in assignments_data}

if not available_assignments:
print("No assignments found in this course")
return None

print("\nAvailable assignments:")
for assignment_name in available_assignments.keys():
print(f"- {assignment_name}")

while True:
assignment_name = input("\nEnter assignment name: ").strip()
if assignment_name in available_assignments:
return available_assignments[assignment_name]
print(f"Assignment '{assignment_name}' not found. Please try again.")

def get_review_assignment_task():
course_id = get_course_id_by_name()
if not course_id:
return None

assignment_id = get_assignment_id_by_name(course_id)
if not assignment_id:
return None

return f"""
You need to review the submissions for an assignment:
1. First get the assignent details using: CANVAS_GET_ASSIGNMENT
2. Then get the submissions for the assignment using: CANVAS_LIST_ASSIGNMENT_SUBMISSIONS
3. Based on the assignment details, review the submissions, check if they are correct
a. If all answers are correct, give full points (10)
b. If one or more answers are incorrect, give partial points (5)
c. If all answers are incorrect, give 0 points
and grade the submissions using: CANVAS_GRADE_COMMENT_SUBMISSION
Below are the details of the assignment:
- Course ID: {course_id}
- Assignment ID: {assignment_id}
"""

def main():
print("What would you like to do?")
print("1. Create new assignment")
print("2. Review an assignment")

choice = input("Enter your choice (1 or 2): ")

if choice == "1":
task = get_create_assignment_task()
elif choice == "2":
task = get_review_assignment_task()
else:
print("Invalid choice. Please select 1 or 2.")
return

if task:
response = user_proxy.initiate_chat(chatbot, message=task)
print(response.chat_history)

if __name__ == "__main__":
main()
67 changes: 67 additions & 0 deletions python/examples/advanced_agents/assignment-agent/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
aiohappyeyeballs==2.4.4
aiohttp==3.11.9
aiosignal==1.3.1
annotated-types==0.7.0
anyio==4.6.2.post1
async-timeout==5.0.1
attrs==24.2.0
bcrypt==4.2.1
certifi==2024.8.30
cffi==1.17.1
charset-normalizer==3.4.0
click==8.1.7
composio_autogen==0.5.50
composio_core==0.5.50
cryptography==44.0.0
diskcache==5.6.3
distro==1.9.0
docker==7.1.0
exceptiongroup==1.2.2
fastapi==0.115.6
FLAML==2.2.0
frozenlist==1.5.0
h11==0.14.0
httpcore==1.0.7
httpx==0.28.0
idna==3.10
importlib_metadata==8.5.0
inflection==0.5.1
jiter==0.8.0
jsonref==1.1.0
jsonschema==4.23.0
jsonschema-specifications==2024.10.1
markdown-it-py==3.0.0
mdurl==0.1.2
multidict==6.1.0
numpy==1.26.4
openai==1.56.1
packaging==24.2
paramiko==3.5.0
propcache==0.2.1
pyautogen==0.4.1
pycparser==2.22
pydantic==2.9.2
pydantic_core==2.23.4
Pygments==2.18.0
PyNaCl==1.5.0
pyperclip==1.9.0
Pysher==1.0.8
python-dotenv==1.0.1
referencing==0.35.1
regex==2024.11.6
requests==2.32.3
rich==13.9.4
rpds-py==0.22.1
semver==3.0.2
sentry-sdk==2.19.0
sniffio==1.3.1
starlette==0.41.3
termcolor==2.5.0
tiktoken==0.8.0
tqdm==4.67.1
typing_extensions==4.12.2
urllib3==2.2.3
uvicorn==0.32.1
websocket-client==1.8.0
yarl==1.18.3
zipp==3.21.0

0 comments on commit 29e6cc4

Please sign in to comment.