From 96d668fa4b08724ed8b7d5c1f925e1c8bd542c44 Mon Sep 17 00:00:00 2001 From: Yannic Kilcher Date: Wed, 14 Dec 2022 23:08:08 +0100 Subject: [PATCH 1/2] Rough draft of story summarization interaction --- backend/app/api/v1/api.py | 3 +- backend/app/api/v1/tasks.py | 106 ++++++++++++++++++++++++++++++++ backend/app/schemas/protocol.py | 63 +++++++++++++++++++ 3 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 backend/app/api/v1/tasks.py create mode 100644 backend/app/schemas/protocol.py diff --git a/backend/app/api/v1/api.py b/backend/app/api/v1/api.py index 7c97c9cb..5a704c2d 100644 --- a/backend/app/api/v1/api.py +++ b/backend/app/api/v1/api.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- -from app.api.v1 import labelers, prompts +from app.api.v1 import labelers, prompts, tasks from fastapi import APIRouter api_router = APIRouter() api_router.include_router(labelers.router, prefix="/labelers", tags=["labelers"]) api_router.include_router(prompts.router, prefix="/prompts", tags=["prompts"]) +api_router.include_router(tasks.router, prefix="/tasks", tags=["tasks"]) diff --git a/backend/app/api/v1/tasks.py b/backend/app/api/v1/tasks.py new file mode 100644 index 00000000..494281d0 --- /dev/null +++ b/backend/app/api/v1/tasks.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- +from typing import Any, List +from uuid import UUID + +from app.api import deps +from app.schemas import protocol as protocol_schema +from fastapi import APIRouter, Depends, HTTPException +from fastapi.security.api_key import APIKey +from loguru import logger +from sqlmodel import Session +from starlette.status import HTTP_400_BAD_REQUEST + +router = APIRouter() + + +@router.post("/", response_model=List[protocol_schema.SummarizeStoryTask]) # work with Union once more types are added +def request_task( + *, + db: Session = Depends(deps.get_db), + api_key: APIKey = Depends(deps.get_api_key), + request: protocol_schema.GenericTaskRequest, # work with Union once more types are added +) -> Any: + """ + Create new task. + """ + deps.api_auth(api_key, db, create=True) + + # TODO: Create a task and store it in the database. + + match (request.type): + case "generic": + # here we create a task at random (and store it in the database) + logger.info("Frontend requested a generic task.") + task = protocol_schema.SummarizeStoryTask( + story="This is a story. A very long story. So long, it needs to be summarized.", + ) + + case _: + raise HTTPException( + status_code=HTTP_400_BAD_REQUEST, + detail="Invalid request type.", + ) + if request.user_id is not None: + task.addressed_users = [request.user_id] + + return [task] + + +@router.post("/{task_id}/ack") +def acknowledge_task( + *, + db: Session = Depends(deps.get_db), + api_key: APIKey = Depends(deps.get_api_key), + task_id: UUID, + response: protocol_schema.PostCreatedTaskResponse, +) -> Any: + """ + The frontend acknowledges a task. + """ + deps.api_auth(api_key, db, create=True) + + match (response.type): + case "post_created": + logger.info(f"Frontend acknowledged {task_id=} and created {response.post_id=}.") + # here we would store the post id in the database for the task + case _: + raise HTTPException( + status_code=HTTP_400_BAD_REQUEST, + detail="Invalid response type.", + ) + + return {} + + +@router.post("/interaction") +def post_interaction( + *, + db: Session = Depends(deps.get_db), + api_key: APIKey = Depends(deps.get_api_key), + interaction: protocol_schema.TextReplyToPost, +) -> Any: + """ + The frontend acknowledges a task. + """ + deps.api_auth(api_key, db, create=True) + + response = [] + match (interaction.type): + case "text_reply_to_post": + logger.info( + f"Frontend reports text reply to {interaction.post_id=} with {interaction.text=} by {interaction.user_id=}." + ) + # here we would store the text reply in the database + response.append( + protocol_schema.TaskDone( + reply_to_post_id=interaction.user_post_id, + addressed_users=[interaction.user_id], + ) + ) + case _: + raise HTTPException( + status_code=HTTP_400_BAD_REQUEST, + detail="Invalid response type.", + ) + + return response diff --git a/backend/app/schemas/protocol.py b/backend/app/schemas/protocol.py new file mode 100644 index 00000000..a63b9c11 --- /dev/null +++ b/backend/app/schemas/protocol.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +from typing import Literal, Optional +from uuid import UUID + +import pydantic +from pydantic import BaseModel + + +class TaskRequest(BaseModel): + """The frontend asks the backend for a task.""" + + type: Literal + user_id: Optional[str] = None + + +class GenericTaskRequest(TaskRequest): + type: Literal["generic"] = "generic" + + +class Task(BaseModel): + """A task is a unit of work that the backend gives to the frontend.""" + + id: UUID = pydantic.Field(default_factory=UUID) + type: Literal + addressed_users: Optional[list[str]] = None + + +class TaskResponse(BaseModel): + """A task response is a message from the frontend to acknowledge the given task.""" + + type: Literal + status: Literal["success", "failure"] + + +class PostCreatedTaskResponse(TaskResponse): + type: Literal["post_created"] = "post_created" + post_id: UUID + + +class SummarizeStoryTask(Task): + type: Literal["summarize_story"] = "summarize_story" + story: str + + +class TaskDone(Task): + type: Literal["task_done"] = "task_done" + reply_to_post_id: UUID + + +class Interaction(BaseModel): + """An interaction is a message from the frontend to the backend.""" + + type: Literal + user_id: str + + +class TextReplyToPost(Interaction): + """A user has replied to a post with text.""" + + type: Literal["text_reply_to_post"] = "text_reply_to_post" + post_id: UUID + user_post_id: UUID + text: str From 2b02ef2ddcab57c431035edd316051f2a15f87e6 Mon Sep 17 00:00:00 2001 From: Yannic Kilcher Date: Wed, 14 Dec 2022 23:51:42 +0100 Subject: [PATCH 2/2] docstring fix --- backend/app/api/v1/tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/app/api/v1/tasks.py b/backend/app/api/v1/tasks.py index 494281d0..2a5397e5 100644 --- a/backend/app/api/v1/tasks.py +++ b/backend/app/api/v1/tasks.py @@ -80,7 +80,7 @@ def post_interaction( interaction: protocol_schema.TextReplyToPost, ) -> Any: """ - The frontend acknowledges a task. + The frontend reports an interaction. """ deps.api_auth(api_key, db, create=True)