From 7b23483795fc102f1faeab00b9661cf782d4fda2 Mon Sep 17 00:00:00 2001 From: Cesar E Garza Date: Mon, 28 Oct 2024 21:37:30 -0500 Subject: [PATCH 1/2] new feedback endpoint --- src/fast_api_app/routes/infer.py | 41 +++++++++++++++++++++++++++++++- src/shared_lib/models.py | 29 ++++++++++++++++++++-- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/fast_api_app/routes/infer.py b/src/fast_api_app/routes/infer.py index 281b0c7..a80da80 100644 --- a/src/fast_api_app/routes/infer.py +++ b/src/fast_api_app/routes/infer.py @@ -1,6 +1,7 @@ import logging import os import time +import traceback import uuid from contextlib import asynccontextmanager @@ -8,6 +9,7 @@ from fastapi import APIRouter, HTTPException, Request from fastapi.responses import HTMLResponse from pydantic import BaseModel +from sqlalchemy.dialects.postgresql import insert as pg_insert from fast_api_app.connections import ( async_session, @@ -21,7 +23,7 @@ MAIN_ONLY_ABILITIES, STANDARD_ABILITIES, ) -from shared_lib.models import ModelInferenceLog +from shared_lib.models import FeedbackLog, ModelInferenceLog router = APIRouter() @@ -54,6 +56,12 @@ class InferenceResponse(BaseModel): metadata: MetaData +class FeedbackRequest(BaseModel): + request_id: str + user_agent: str + feedback: bool + + # Create a persistent client persistent_client = httpx.AsyncClient() @@ -405,3 +413,34 @@ async def infer(inference_request: InferenceRequest, request: Request): "processing_time_ms": processing_time, }, ) + + +@router.post("/api/feedback") +async def feedback(feedback_request: FeedbackRequest): + try: + async with async_session() as session: + stmt = ( + pg_insert(FeedbackLog) + .values( + request_id=feedback_request.request_id, + user_agent=feedback_request.user_agent, + feedback=feedback_request.feedback, + ) + .on_conflict_do_update( + index_elements=["request_id"], + set_={"feedback": feedback_request.feedback}, + ) + ) + result = await session.execute(stmt) + await session.commit() + + status_message = ( + "Feedback updated" + if result.rowcount > 0 + else "New feedback inserted" + ) + return {"status": f"{status_message} successfully"} + + except Exception as e: + logger.error(f"Error logging feedback: {e}") + raise HTTPException(status_code=500, detail="Error logging feedback") diff --git a/src/shared_lib/models.py b/src/shared_lib/models.py index 48424f8..4435b07 100644 --- a/src/shared_lib/models.py +++ b/src/shared_lib/models.py @@ -7,6 +7,7 @@ Column, DateTime, Float, + ForeignKeyConstraint, Index, Integer, SmallInteger, @@ -242,10 +243,15 @@ class WeaponLeaderboard(Base): class ModelInferenceLog(Base): __tablename__ = "model_inference_logs" - __table_args__ = {"schema": "splatgpt"} + __table_args__ = ( + UniqueConstraint( + "request_id", name="uq_model_inference_logs_request_id" + ), + {"schema": "splatgpt"}, + ) id = Column(BigInteger, primary_key=True) - request_id = Column(UUID(as_uuid=True), default=uuid.uuid4) + request_id = Column(UUID(as_uuid=True), default=uuid.uuid4, unique=True) timestamp = Column( DateTime(timezone=True), server_default=text("CURRENT_TIMESTAMP") ) @@ -261,3 +267,22 @@ class ModelInferenceLog(Base): status_code = Column(SmallInteger) output_data = Column(JSONB) error_message = Column(Text) + + +class FeedbackLog(Base): + __tablename__ = "feedback_logs" + __table_args__ = ( + ForeignKeyConstraint( + ["request_id"], + ["splatgpt.model_inference_logs.request_id"], + name="fk_request_id", + ondelete="CASCADE", + ), + UniqueConstraint("request_id", name="uq_feedback_logs_request_id"), + {"schema": "splatgpt"}, + ) + + id = Column(BigInteger, primary_key=True) + request_id = Column(UUID(as_uuid=True), nullable=False) + user_agent = Column(Text) + feedback = Column(Boolean) From a4861ff2a41f026d071328467892f11b8db6ab61 Mon Sep 17 00:00:00 2001 From: Cesar E Garza Date: Mon, 28 Oct 2024 21:57:14 -0500 Subject: [PATCH 2/2] updated GET documentation --- src/fast_api_app/routes/infer.py | 197 +++++++++++++++++++------------ 1 file changed, 120 insertions(+), 77 deletions(-) diff --git a/src/fast_api_app/routes/infer.py b/src/fast_api_app/routes/infer.py index a80da80..b670134 100644 --- a/src/fast_api_app/routes/infer.py +++ b/src/fast_api_app/routes/infer.py @@ -75,7 +75,7 @@ async def infer_instructions(): - SplatGPT Inference API Instructions + SplatGPT API Documentation -

SplatGPT Inference API Instructions

- -

This endpoint provides detailed instructions on how to use the inference API for Splatoon 3 gear ability predictions.

+

SplatGPT API Documentation

-
-

Endpoint Details

+
+

Core API Endpoints

+ +

1. Inference Endpoint

+
+

Endpoint Details

+
    +
  • Method: POST
  • +
  • Endpoint: /api/infer
  • +
  • Header: A custom User-Agent is required
  • +
+
+ +

Request Headers

+

A custom User-Agent header is required for all requests to this endpoint. Requests without a custom User-Agent will be rejected.

+ +

Request Body

+
abilities
+

A dictionary of ability names and their corresponding Ability Point (AP) values. Each ability is represented by an integer AP value, where:

    -
  • Method: POST
  • -
  • Endpoint: /api/infer
  • -
  • Header: A custom User-Agent is required
  • +
  • A main slot ability has a weight of 10 AP
  • +
  • A sub slot ability has a weight of 3 AP
  • +
  • Main-Slot-Only abilities should always be represented as 10 AP
-
-

Request Headers

-

A custom User-Agent header is required for all requests to this endpoint. Requests without a custom User-Agent will be rejected.

+
weapon_id
+

An integer representing the unique identifier for a specific weapon in Splatoon 3. The internal ID, where 50 is the ID for 52 gal.

-

Request Body

- -

abilities

-

A dictionary of ability names and their corresponding Ability Point (AP) values. Each ability is represented by an integer AP value, where:

-
    -
  • A main slot ability has a weight of 10 AP
  • -
  • A sub slot ability has a weight of 3 AP
  • -
  • Main-Slot-Only abilities should always be represented as 10 AP
  • -
-

The total AP for an ability is the sum of its main and sub slot values. For example, one main (10 AP) and three subs (3 AP each) of Swim Speed Up would be represented as 19 AP.

- -

weapon_id

-

An integer representing the unique identifier for a specific weapon in Splatoon 3. The internal ID, where 50 is the ID for 52 gal.

- -

Example Request

-
{
+        

Example Inference Request

+
{
     "abilities": {
         "swim_speed_up": 19,
         "ninja_squid": 10,
@@ -183,68 +197,97 @@ async def infer_instructions():
     "weapon_id": 50
 }
-

Response

-

The response contains two main parts:

-
    -
  1. predictions: A list of tuples, each containing: +

    Inference Response

    +

    The response contains two main parts:

    +
      +
    1. predictions: A list of tuples, each containing: +
        +
      • An ability token (string)
      • +
      • The predicted value for that token (float)
      • +
      +
    2. +
    3. metadata: Additional information about the request and response, including: +
        +
      • request_id: A unique identifier for the request
      • +
      • api_version: The version of the API used
      • +
      • splatgpt_version: The version of the model used for prediction
      • +
      • cache_status: Whether the result was retrieved from cache ("hit") or newly computed ("miss")
      • +
      • processing_time_ms: The time taken to process the request, in milliseconds
      • +
      +
    4. +
    + +
    +

    The inference endpoint is rate-limited to 10 requests per minute to ensure fair usage and system stability.

    +
    + +

    2. Feedback Endpoint

    +
    +

    Endpoint Details

      -
    • An ability token (string)
    • -
    • The predicted value for that token (float)
    • +
    • Method: POST
    • +
    • Endpoint: /api/feedback
    -
  2. -
  3. metadata: Additional information about the request and response, including: -
      -
    • request_id: A unique identifier for the request
    • -
    • api_version: The version of the API used
    • -
    • splatgpt_version: The version of the model used for prediction
    • -
    • cache_status: Whether the result was retrieved from cache ("hit") or newly computed ("miss")
    • -
    • processing_time_ms: The time taken to process the request, in milliseconds
    • -
    -
  4. -
- -

Ability tokens are formatted as follows:

-
    -
  • For main-slot-only abilities: the ability name (e.g., ninja_squid)
  • -
  • For standard abilities: the ability name followed by a number representing the AP breakpoint (e.g., swim_speed_up_3, swim_speed_up_6, etc.)
  • -
-

The number in the token represents the minimum AP value for that prediction. For instance, swim_speed_up_3 represents the effect of Swim Speed Up with at least 3 AP.

- -
-

Note

-

This endpoint is rate-limited to 10 requests per minute to ensure fair usage and system stability.

+
+ +

The feedback endpoint allows users to provide feedback on inference predictions.

+ +

Feedback Request Body

+
{
+    "request_id": "string",  // The request_id from the inference response
+    "user_agent": "string",  // The User-Agent used in the request
+    "feedback": boolean      // true for positive feedback, false for negative
+}
+ +

Feedback Response

+

Upon successful submission, the endpoint returns a status message indicating whether the feedback was inserted or updated:

+
{
+    "status": "Feedback updated successfully" // or "New feedback inserted successfully"
+}
-

Ability Lists

-

Main-Only Abilities

- -

Standard Abilities

- + """