-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #139 from vintasoftware/feat/project-mgmt-example
Issue tracker example
- Loading branch information
Showing
11 changed files
with
226 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,7 @@ | |
"weather", | ||
"movies", | ||
"rag", | ||
"issue_tracker", | ||
] | ||
|
||
MIDDLEWARE = [ | ||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from django.contrib import admin | ||
|
||
from issue_tracker.models import Issue | ||
|
||
|
||
@admin.register(Issue) | ||
class IssueAdmin(admin.ModelAdmin): | ||
list_display = ( | ||
"id", | ||
"title", | ||
"assignee", | ||
"created_at", | ||
"updated_at", | ||
) | ||
search_fields = ("id", "title", "description", "assignee__username", "assignee__email") | ||
list_filter = ("assignee", "created_at", "updated_at") | ||
raw_id_fields = ("assignee",) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
from typing import Sequence | ||
|
||
from django.contrib.auth.models import User | ||
|
||
from django_ai_assistant import AIAssistant, method_tool | ||
from issue_tracker.models import Issue | ||
|
||
|
||
class IssueTrackerAIAssistant(AIAssistant): | ||
id = "issue_tracker_assistant" # noqa: A003 | ||
name = "Issue Tracker Assistant" | ||
instructions = ( | ||
"You are a issue tracker assistant. " | ||
"Help the user manage issues using the provided tools. " | ||
"Issue IDs are unique and auto-incremented, they are represented as #<id>. " | ||
"Make sure to include it in your responses, " | ||
"to know which issue you or the user are referring to. " | ||
) | ||
model = "gpt-4o" | ||
_user: User | ||
|
||
@method_tool | ||
def get_current_assignee_email(self) -> str: | ||
"""Get the current user's email""" | ||
return self._user.email | ||
|
||
def _format_issues(self, issues: Sequence[Issue]) -> str: | ||
if not issues: | ||
return "No issues found" | ||
return "\n\n".join( | ||
[f"- {issue.title} #{issue.id}\n{issue.description}" for issue in issues] | ||
) | ||
|
||
@method_tool | ||
def list_issues(self) -> str: | ||
"""List all issues""" | ||
return self._format_issues(list(Issue.objects.all())) | ||
|
||
@method_tool | ||
def list_user_assigned_issues(self, assignee_email: str) -> str: | ||
"""List the issues assigned to the provided user""" | ||
return self._format_issues(list(Issue.objects.filter(assignee__email=assignee_email))) | ||
|
||
@method_tool | ||
def assign_user_to_issue(self, issue_id: int, assignee_email: str = "") -> str: | ||
"""Assign a user to an issue. When assignee_email is empty, the issue assignment is removed.""" | ||
try: | ||
issue = Issue.objects.get(id=issue_id) | ||
if assignee_email: | ||
assignee = User.objects.get(email=assignee_email) | ||
else: | ||
assignee = None | ||
except Issue.DoesNotExist: | ||
return f"ERROR: Issue {issue_id} does not exist" | ||
except User.DoesNotExist: | ||
return f"ERROR: User {assignee_email} does not exist" | ||
issue.assignee = assignee | ||
issue.save() | ||
return f"Assigned {assignee_email} to issue {issue.title} #{issue.id}" | ||
|
||
@method_tool | ||
def create_issue(self, title: str, description: str = "", assignee_email: str = "") -> str: | ||
"""Create a new issue. Title is required. Description is optional. Assignee is optional.""" | ||
if assignee_email: | ||
try: | ||
assignee = User.objects.get(email=assignee_email) | ||
except User.DoesNotExist: | ||
return f"ERROR: User {assignee_email} does not exist" | ||
else: | ||
assignee = None | ||
issue = Issue.objects.create(title=title, description=description, assignee=assignee) | ||
return f"Created issue {issue.title} #{issue.id}" | ||
|
||
@method_tool | ||
def update_issue(self, issue_id: int, title: str, description: str = "") -> str: | ||
"""Update an issue""" | ||
try: | ||
issue = Issue.objects.get(id=issue_id) | ||
except Issue.DoesNotExist: | ||
return f"ERROR: Issue {issue_id} does not exist" | ||
issue.title = title | ||
issue.description = description | ||
issue.save() | ||
return f"Updated issue {issue.title} #{issue.id}" | ||
|
||
@method_tool | ||
def delete_issue(self, issue_id: int) -> str: | ||
"""Delete an issue""" | ||
try: | ||
issue = Issue.objects.get(id=issue_id) | ||
except Issue.DoesNotExist: | ||
return f"ERROR: Issue {issue_id} does not exist" | ||
issue.delete() | ||
return f"Deleted issue {issue.title} #{issue.id}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class IssueTrackerConfig(AppConfig): | ||
default_auto_field = "django.db.models.BigAutoField" | ||
name = "issue_tracker" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Generated by Django 5.0.6 on 2024-06-28 17:31 | ||
|
||
import django.db.models.deletion | ||
from django.conf import settings | ||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [ | ||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='Issue', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('title', models.CharField(max_length=255)), | ||
('description', models.TextField(blank=True)), | ||
('created_at', models.DateTimeField(auto_now_add=True)), | ||
('updated_at', models.DateTimeField(auto_now=True)), | ||
('assignee', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_issues', to=settings.AUTH_USER_MODEL)), | ||
], | ||
options={ | ||
'verbose_name': 'Issue', | ||
'verbose_name_plural': 'Issues', | ||
'ordering': ('assignee', 'created_at'), | ||
}, | ||
), | ||
] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
from django.conf import settings | ||
from django.db import models | ||
|
||
|
||
class Issue(models.Model): | ||
id: int # noqa: A003 | ||
title = models.CharField(max_length=255) | ||
description = models.TextField(blank=True) | ||
assignee = models.ForeignKey( | ||
settings.AUTH_USER_MODEL, | ||
null=True, | ||
blank=True, | ||
on_delete=models.SET_NULL, | ||
related_name="assigned_issues", | ||
) | ||
created_at = models.DateTimeField(auto_now_add=True) | ||
updated_at = models.DateTimeField(auto_now=True) | ||
|
||
class Meta: | ||
verbose_name = "Issue" | ||
verbose_name_plural = "Issues" | ||
ordering = ("assignee", "created_at") | ||
|
||
def __str__(self): | ||
return f"{self.title} - {self.assignee}" | ||
|
||
def __repr__(self) -> str: | ||
return f"<Issue {self.title} #{self.id} of {self.assignee}>" |