added rating workflow

This commit is contained in:
Yannic Kilcher
2022-12-16 00:03:06 +01:00
parent 7ccb55e756
commit bb1a0fe432
3 changed files with 144 additions and 48 deletions
+65 -39
View File
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from typing import Any, List
import random
from typing import Any
from uuid import UUID
from app.api import deps
@@ -13,40 +14,58 @@ 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 generate_task(request: protocol_schema.TaskRequest) -> protocol_schema.Task:
match (request.type):
case protocol_schema.TaskRequestType.generic:
logger.info("Frontend requested a generic task.")
while request.type == protocol_schema.TaskRequestType.generic:
request.type = random.choice(list(protocol_schema.TaskRequestType)).value
return generate_task(request)
case protocol_schema.TaskRequestType.summarize_story:
logger.info("Generating a SummarizeStoryTask.")
task = protocol_schema.SummarizeStoryTask(
story="This is a story. A very long story. So long, it needs to be summarized.",
)
case protocol_schema.TaskRequestType.rate_summary:
logger.info("Generating a RateSummaryTask.")
task = protocol_schema.RateSummaryTask(
full_text="This is a story. A very long story. So long, it needs to be summarized.",
summary="This is a summary.",
scale=protocol_schema.RatingScale(min=1, max=5),
)
case _:
raise HTTPException(
status_code=HTTP_400_BAD_REQUEST,
detail="Invalid request type.",
)
logger.info(f"Generated {task=}.")
if request.user_id is not None:
task.addressed_users = [request.user_id]
return task
@router.post("/", response_model=protocol_schema.AnyTask) # 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
request: protocol_schema.TaskRequest,
) -> 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.")
try:
task = protocol_schema.SummarizeStoryTask(
story="This is a story. A very long story. So long, it needs to be summarized.",
)
except Exception:
logger.exception("Failed to create task.")
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]
try:
task = generate_task(request)
# TODO: store task in database
except Exception:
logger.exception("Failed to generate task.")
raise HTTPException(
status_code=HTTP_400_BAD_REQUEST,
)
return task
@router.post("/{task_id}/ack")
@@ -55,17 +74,20 @@ def acknowledge_task(
db: Session = Depends(deps.get_db),
api_key: APIKey = Depends(deps.get_api_key),
task_id: UUID,
response: protocol_schema.PostCreatedTaskResponse,
response: protocol_schema.AnyTaskResponse,
) -> Any:
"""
The frontend acknowledges a task.
"""
deps.api_auth(api_key, db, create=True)
match (response.type):
case "post_created":
match (type(response)):
case protocol_schema.PostCreatedTaskResponse:
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 protocol_schema.RatingCreatedTaskResponse:
logger.info(f"Frontend acknowledged {task_id=} for {response.post_id=}.")
# here we would store the rating id in the database for the task
case _:
raise HTTPException(
status_code=HTTP_400_BAD_REQUEST,
@@ -80,30 +102,34 @@ def post_interaction(
*,
db: Session = Depends(deps.get_db),
api_key: APIKey = Depends(deps.get_api_key),
interaction: protocol_schema.TextReplyToPost,
interaction: protocol_schema.AnyInteraction,
) -> Any:
"""
The frontend reports an interaction.
"""
deps.api_auth(api_key, db, create=True)
response = []
match (interaction.type):
case "text_reply_to_post":
match (type(interaction)):
case protocol_schema.TextReplyToPost:
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],
)
return protocol_schema.TaskDone(
reply_to_post_id=interaction.user_post_id,
addressed_users=[interaction.user_id],
)
case protocol_schema.PostRating:
logger.info(
f"Frontend reports rating of {interaction.post_id=} with {interaction.rating=} by {interaction.user_id=}."
)
# here we would store the rating in the database
return protocol_schema.TaskDone(
reply_to_post_id=interaction.post_id,
addressed_users=[interaction.user_id],
)
case _:
raise HTTPException(
status_code=HTTP_400_BAD_REQUEST,
detail="Invalid response type.",
)
return response
+53 -6
View File
@@ -1,22 +1,25 @@
# -*- coding: utf-8 -*-
from typing import Literal, Optional
import enum
from typing import Literal, Optional, Union
from uuid import UUID, uuid4
import pydantic
from pydantic import BaseModel
class TaskRequestType(str, enum.Enum):
generic = "generic"
summarize_story = "summarize_story"
rate_summary = "rate_summary"
class TaskRequest(BaseModel):
"""The frontend asks the backend for a task."""
type: str
type: TaskRequestType = TaskRequestType.generic
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."""
@@ -37,16 +40,46 @@ class PostCreatedTaskResponse(TaskResponse):
post_id: str
class RatingCreatedTaskResponse(TaskResponse):
type: Literal["rating_created"] = "rating_created"
post_id: str
AnyTaskResponse = Union[
PostCreatedTaskResponse,
RatingCreatedTaskResponse,
]
class SummarizeStoryTask(Task):
type: Literal["summarize_story"] = "summarize_story"
story: str
class RatingScale(BaseModel):
min: int
max: int
class RateSummaryTask(Task):
type: Literal["rate_summary"] = "rate_summary"
full_text: str
summary: str
scale: RatingScale = RatingScale(min=1, max=5)
class TaskDone(Task):
type: Literal["task_done"] = "task_done"
reply_to_post_id: str
AnyTask = Union[
SummarizeStoryTask,
RateSummaryTask,
TaskDone,
]
class Interaction(BaseModel):
"""An interaction is a message from the frontend to the backend."""
@@ -61,3 +94,17 @@ class TextReplyToPost(Interaction):
post_id: str
user_post_id: str
text: str
class PostRating(Interaction):
"""A user has replied to a post with text."""
type: Literal["post_rating"] = "post_rating"
post_id: str
rating: int
AnyInteraction = Union[
TextReplyToPost,
PostRating,
]
+26 -3
View File
@@ -17,7 +17,8 @@ def main(backend_url: str, api_key: str):
return response.json()
typer.echo("Requesting work...")
tasks = _post("/api/v1/tasks/", {"type": "generic"})
# tasks = [_post("/api/v1/tasks/", {"type": "generic"})]
tasks = [_post("/api/v1/tasks/", {"type": "rate_summary"})]
while tasks:
task = tasks.pop(0)
match (task["type"]):
@@ -31,7 +32,7 @@ def main(backend_url: str, api_key: str):
summary = typer.prompt("Enter your summary")
# send interaction
new_tasks = _post(
new_task = _post(
"/api/v1/tasks/interaction",
{
"type": "text_reply_to_post",
@@ -41,7 +42,29 @@ def main(backend_url: str, api_key: str):
"user_id": "1234",
},
)
tasks.extend(new_tasks)
tasks.append(new_task)
case "rate_summary":
typer.echo("Rate the following summary:")
typer.echo(task["summary"])
typer.echo("Full text:")
typer.echo(task["full_text"])
typer.echo(f"Rating scale: {task['scale']['min']} - {task['scale']['max']}")
# acknowledge task
_post(f"/api/v1/tasks/{task['id']}/ack", {"type": "rating_created", "post_id": "1234"})
rating = typer.prompt("Enter your rating", type=int)
# send interaction
new_task = _post(
"/api/v1/tasks/interaction",
{
"type": "post_rating",
"post_id": "1234",
"rating": rating,
"user_id": "1234",
},
)
tasks.append(new_task)
case "task_done":
typer.echo("Task done!")
case _: