Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions backend/src/apps/common/open_ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@
from __future__ import annotations

import logging
from typing import TYPE_CHECKING, TypeVar

import openai
from django.conf import settings

if TYPE_CHECKING:
from pydantic import BaseModel

logger: logging.Logger = logging.getLogger(__name__)

T = TypeVar("T", bound="BaseModel")


class OpenAi:
"""Open AI communication class."""
Expand Down Expand Up @@ -75,6 +81,50 @@ def set_prompt(self, content: str) -> OpenAi:

return self

def parse(self, schema: type[T]) -> T | None:
"""Get a structured response validated against a pydantic schema.

Args:
schema (type[T]): A pydantic model class.

Returns:
T | None: A validated instance of the schema, or None on error.

"""
try:
Comment thread
rudransh-shrivastava marked this conversation as resolved.
response = self.client.beta.chat.completions.parse(
max_tokens=self.max_tokens,
messages=[
{"role": "system", "content": self.prompt},
{"role": "user", "content": self.input},
],
model=self.model,
response_format=schema,
temperature=self.temperature,
)
return response.choices[0].message.parsed
except openai.AuthenticationError:
logger.exception("OpenAI authentication failed: invalid or missing API key. ")
except openai.RateLimitError as e:
logger.warning(
"OpenAI rate limit exceeded: %s. Request may be retried with backoff.",
e,
)
except openai.BadRequestError:
logger.exception(
"OpenAI invalid request. Check model name, message format, and input size."
)
except openai.APIConnectionError:
logger.exception(
"OpenAI connection failed. Check network connectivity and firewall/proxy settings."
)
except Exception as e:
logger.exception(
"Unexpected OpenAI API error: %s",
type(e).__name__,
)
return None

def complete(self) -> str | None:
"""Get API response.

Expand Down
6 changes: 6 additions & 0 deletions backend/src/apps/owasp/admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@

from apps.owasp.models.project_health_requirements import ProjectHealthRequirements

from .board_discussion import BoardDiscussionAdmin
from .board_meeting import BoardMeetingAdmin
from .board_meeting_action import BoardMeetingActionAdmin
from .board_motion import BoardMotionAdmin
from .board_of_directors import BoardOfDirectorsAdmin
from .board_outcome import BoardOutcomeAdmin
from .board_vote import BoardVoteAdmin
from .chapter import ChapterAdmin
from .committee import CommitteeAdmin
from .entity_channel import EntityChannelAdmin
Expand Down
16 changes: 16 additions & 0 deletions backend/src/apps/owasp/admin/board_discussion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Board discussion admin configuration."""

from django.contrib import admin

from apps.owasp.models.board_discussion import BoardDiscussion


class BoardDiscussionAdmin(admin.ModelAdmin):
"""Admin for BoardDiscussion model."""

autocomplete_fields = ("participants",)
list_display = ("topic",)
search_fields = ("topic", "description")


admin.site.register(BoardDiscussion, BoardDiscussionAdmin)
18 changes: 18 additions & 0 deletions backend/src/apps/owasp/admin/board_meeting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Board meeting admin configuration."""

from django.contrib import admin

from apps.owasp.models.board_meeting import BoardMeeting


class BoardMeetingAdmin(admin.ModelAdmin):
"""Admin for BoardMeeting model."""

autocomplete_fields = ("board", "attendees", "absentees")
list_display = ("title", "date", "board", "type", "quorum_present")
list_filter = ("type", "quorum_present", "board__year")
ordering = ("-date",)
search_fields = ("title", "location", "source_path")


admin.site.register(BoardMeeting, BoardMeetingAdmin)
23 changes: 23 additions & 0 deletions backend/src/apps/owasp/admin/board_meeting_action.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""Board meeting action admin configuration."""

from django.contrib import admin

from apps.owasp.models.board_meeting_action import BoardMeetingAction


class BoardMeetingActionAdmin(admin.ModelAdmin):
"""Admin for BoardMeetingAction model."""

list_display = ("meeting", "order", "discussion", "motion", "outcome")
list_filter = ("meeting__type",)
ordering = ("meeting", "order")
raw_id_fields = ("meeting", "discussion", "motion", "outcome")
search_fields = (
"meeting__title",
"discussion__topic",
"motion__title",
"outcome__description",
)


admin.site.register(BoardMeetingAction, BoardMeetingActionAdmin)
16 changes: 16 additions & 0 deletions backend/src/apps/owasp/admin/board_motion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Board motion admin configuration."""

from django.contrib import admin

from apps.owasp.models.board_motion import BoardMotion


class BoardMotionAdmin(admin.ModelAdmin):
"""Admin for BoardMotion model."""

list_display = ("title", "sponsor", "second")
raw_id_fields = ("sponsor", "second", "amends_motion")
search_fields = ("title", "description", "background")


admin.site.register(BoardMotion, BoardMotionAdmin)
18 changes: 18 additions & 0 deletions backend/src/apps/owasp/admin/board_outcome.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Board outcome admin configuration."""

from django.contrib import admin

from apps.owasp.models.board_outcome import BoardOutcome


class BoardOutcomeAdmin(admin.ModelAdmin):
"""Admin for BoardOutcome model."""

autocomplete_fields = ("assignees",)
list_display = ("description", "status", "due_date")
list_filter = ("status",)
ordering = ("-due_date",)
search_fields = ("description",)


admin.site.register(BoardOutcome, BoardOutcomeAdmin)
18 changes: 18 additions & 0 deletions backend/src/apps/owasp/admin/board_vote.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Board vote admin configuration."""

from django.contrib import admin

from apps.owasp.models.board_vote import BoardVote


class BoardVoteAdmin(admin.ModelAdmin):
"""Admin for BoardVote model."""

autocomplete_fields = ("in_favor", "against", "abstain", "recused")
list_display = ("motion", "result", "type", "tally")
list_filter = ("result", "type")
raw_id_fields = ("motion",)
search_fields = ("motion__title", "tally")


admin.site.register(BoardVote, BoardVoteAdmin)
Loading
Loading