diff --git a/backend/app/api/deps.py b/backend/app/api/deps.py index deed0a3d..cecb5860 100644 --- a/backend/app/api/deps.py +++ b/backend/app/api/deps.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from typing import Generator +from app.config import settings from app.database import engine from app.models import ServiceClient from fastapi import HTTPException, Security @@ -37,6 +38,10 @@ def api_auth( delete: bool = False, ) -> ServiceClient: if api_key is not None: + if settings.ALLOW_ANY_API_KEY: + return ServiceClient( + api_key=api_key, name=api_key, can_append=True, can_read=True, can_write=True, can_delete=True + ) api_client = db.query(ServiceClient).filter(ServiceClient.api_key == api_key).first() if api_client is not None: if ( diff --git a/backend/app/api/v1/tasks.py b/backend/app/api/v1/tasks.py index 2a5397e5..07d0f9d1 100644 --- a/backend/app/api/v1/tasks.py +++ b/backend/app/api/v1/tasks.py @@ -31,9 +31,12 @@ def request_task( 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.", - ) + 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( diff --git a/backend/app/config.py b/backend/app/config.py index f0218bee..0780caf9 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -14,6 +14,8 @@ class Settings(BaseSettings): POSTGRES_DB: str = "postgres" DATABASE_URI: Optional[PostgresDsn] = None + ALLOW_ANY_API_KEY: bool = False + @validator("DATABASE_URI", pre=True) def assemble_db_connection(cls, v: Optional[str], values: Dict[str, Any]) -> Any: if isinstance(v, str): diff --git a/backend/app/schemas/protocol.py b/backend/app/schemas/protocol.py index 554c49e1..c1976bf7 100644 --- a/backend/app/schemas/protocol.py +++ b/backend/app/schemas/protocol.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from typing import Literal, Optional -from uuid import UUID +from uuid import UUID, uuid4 import pydantic from pydantic import BaseModel @@ -20,7 +20,7 @@ class GenericTaskRequest(TaskRequest): class Task(BaseModel): """A task is a unit of work that the backend gives to the frontend.""" - id: UUID = pydantic.Field(default_factory=UUID) + id: UUID = pydantic.Field(default_factory=uuid4) type: str addressed_users: Optional[list[str]] = None @@ -29,12 +29,12 @@ class TaskResponse(BaseModel): """A task response is a message from the frontend to acknowledge the given task.""" type: str - status: Literal["success", "failure"] + status: Literal["success", "failure"] = "success" class PostCreatedTaskResponse(TaskResponse): type: Literal["post_created"] = "post_created" - post_id: UUID + post_id: str class SummarizeStoryTask(Task): @@ -44,7 +44,7 @@ class SummarizeStoryTask(Task): class TaskDone(Task): type: Literal["task_done"] = "task_done" - reply_to_post_id: UUID + reply_to_post_id: str class Interaction(BaseModel): @@ -58,6 +58,6 @@ 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 + post_id: str + user_post_id: str text: str diff --git a/backend/scripts/run-local.sh b/backend/scripts/run-local.sh index d8bd86c6..bf45e870 100755 --- a/backend/scripts/run-local.sh +++ b/backend/scripts/run-local.sh @@ -1,3 +1,5 @@ #!/usr/bin/env bash +export ALLOW_ANY_API_KEY=True + uvicorn app.main:app --reload diff --git a/text-frontend/__main__.py b/text-frontend/__main__.py new file mode 100644 index 00000000..dab0c745 --- /dev/null +++ b/text-frontend/__main__.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +"""Simple REPL frontend.""" + +import requests +import typer + +app = typer.Typer() + + +@app.command() +def main(backend_url: str, api_key: str): + """Simple REPL frontend.""" + + def _post(path: str, json: dict) -> dict: + response = requests.post(f"{backend_url}{path}", json=json, headers={"X-API-Key": api_key}) + response.raise_for_status() + return response.json() + + typer.echo("Requesting work...") + tasks = _post("/api/v1/tasks/", {"type": "generic"}) + while tasks: + task = tasks.pop(0) + match (task["type"]): + case "summarize_story": + typer.echo("Summarize the following story:") + typer.echo(task["story"]) + + # acknowledge task + _post(f"/api/v1/tasks/{task['id']}/ack", {"type": "post_created", "post_id": "1234"}) + + summary = typer.prompt("Enter your summary") + + # send interaction + new_tasks = _post( + "/api/v1/tasks/interaction", + { + "type": "text_reply_to_post", + "post_id": "1234", + "user_post_id": "5678", + "text": summary, + "user_id": "1234", + }, + ) + tasks.extend(new_tasks) + case "task_done": + typer.echo("Task done!") + case _: + typer.echo(f"Unknown task type {task['type']}") + + +if __name__ == "__main__": + app() diff --git a/text-frontend/requirements.txt b/text-frontend/requirements.txt new file mode 100644 index 00000000..f48a93ad --- /dev/null +++ b/text-frontend/requirements.txt @@ -0,0 +1,2 @@ +requests==2.18.1 +typer==0.7.0