Refactoring the v2 api code

This commit is contained in:
SwiftyOS
2024-11-07 18:30:17 +01:00
parent 40f38fcb46
commit deee943c3a
9 changed files with 200 additions and 59 deletions

View File

@@ -0,0 +1,73 @@
from typing import List
import pydantic
class Pagination(pydantic.BaseModel):
total_items: int = pydantic.Field(
description="Total number of items.", examples=[42]
)
total_pages: int = pydantic.Field(
description="Total number of pages.", examples=[97]
)
current_page: int = pydantic.Field(
description="Current_page page number.", examples=[1]
)
page_size: int = pydantic.Field(
description="Number of items per page.", examples=[25]
)
class StoreAgent(pydantic.BaseModel):
slug: str
agentName: str
agentImage: str
creator: str
creatorAvatar: str
subHeading: str
description: str
runs: int
stars: float
class StoreAgentsResponse(pydantic.BaseModel):
agents: list[StoreAgent]
pagination: Pagination
class StoreAgentDetails(pydantic.BaseModel):
slug: str
agentName: str
agentVideo: str
agentImage: list[str]
creator: str
creatorAvatar: str
subHeading: str
description: str
categoires: list[str]
runs: int
stars: float
verions: list[str]
class Creator(pydantic.BaseModel):
name: str
username: str
description: str
avatarUrl: str
numAgents: int
class CreatorsResponse(pydantic.BaseModel):
creators: List[Creator]
pagination: Pagination
class CreatorDetails(pydantic.BaseModel):
name: str
username: str
description: str
links: list[str]
avatarUrl: str
agentRating: float
agentRuns: int
topCategories: list[str]

View File

@@ -1,7 +1,10 @@
from re import _FlagsType
import fastapi
import fastapi.responses
import pydantic
import backend.server.v2.store.model
router = fastapi.APIRouter()
##############################################
@@ -12,7 +15,7 @@ router = fastapi.APIRouter()
@router.get("agents", tags=["store"])
def get_agents(
featured: bool, top: bool, categories: str, page: int = 1, page_size: int = 20
):
) -> backend.server.v2.store.model.StoreAgentsResponse:
"""
This is needed for:
- Home Page Featured Agents
@@ -36,6 +39,7 @@ def get_agents(
"""
class StoreAgent(pydantic.BaseModel):
slug: str
agentName: str
agentImage: str
creator: str
@@ -70,7 +74,9 @@ def get_agents(
@router.get("agents/{username}/{agent_name}")
def get_agent(username: str, agent_name: int):
def get_agent(
username: str, agent_name: int
) -> backend.server.v2.store.model.StoreAgentDetails:
"""
This is only used on the AgentDetails Page
@@ -78,6 +84,7 @@ def get_agent(username: str, agent_name: int):
"""
class StoreAgentDetails(pydantic.BaseModel):
slug: str
agentName: str
agentVideo: str
agentImage: list[str]
@@ -99,11 +106,46 @@ def get_agent(username: str, agent_name: int):
@router.get("creators", tags=["store"])
def get_creators(page: int = 1, page_size: int = 20):
"""Get a list of creators"""
def get_creators(
featured: bool, search: str, sortedBy: str, page: int = 1, page_size: int = 20
) -> backend.server.v2.store.model.CreatorsResponse:
"""
This is needed for:
- Home Page Featured Creators
- Search Results Page
---
To support this functionality we need:
- featured: bool - to limit the list to just featured agents
- search: str - vector search based on the creators profile description.
- sortedBy: [agentRating, agentRuns] -
"""
class Creator(pydantic.BaseModel):
name: str
username: str
description: str
avatarUrl: str
numAgents: int
pass
@router.get("creator/{username}", tags=["store"])
def get_ceator(username: string):
"""Get the details of a creator"""
def get_ceator(username: str) -> backend.server.v2.store.model.CreatorDetails:
"""
Get the details of a creator
- Creator Details Page
"""
class CreatorDetails(pydantic.BaseModel):
name: str
username: str
description: str
links: list[str]
avatarUrl: str
agentRating: float
agentRuns: int
topCategories: list[str]

View File

@@ -0,0 +1,79 @@
import fastapi
import fastapi.testclient
import backend.server.routers.v2.store
app = fastapi.FastAPI()
app.include_router(backend.server.routers.v2.store.router)
client = fastapi.testclient.TestClient(app)
def test_get_agents_featured():
response = client.get(
"/agents?featured=true&top=false&categories=&page=1&page_size=20"
)
assert response.status_code == 200
assert all(agent["featured"] for agent in response.json())
def test_get_agents_top():
response = client.get(
"/agents?featured=false&top=true&categories=&page=1&page_size=20"
)
assert response.status_code == 200
assert response.json() # Ensure there are agents returned
def test_get_agents_categories():
response = client.get(
"/agents?featured=false&top=false&categories=SEO&page=1&page_size=20"
)
assert response.status_code == 200
assert all("SEO" in agent["description"] for agent in response.json())
def test_get_agents_pagination():
response = client.get(
"/agents?featured=false&top=false&categories=&page=2&page_size=1"
)
assert response.status_code == 200
assert len(response.json()) == 1
def test_get_agents_no_agents():
response = client.get(
"/agents?featured=false&top=false&categories=NonExistentCategory&page=1&page_size=20"
)
assert response.status_code == 200
assert response.json() == []
def test_get_agents_invalid_request():
response = client.get(
"/agents?featured=invalid&top=false&categories=&page=1&page_size=20"
)
assert response.status_code == 422 # Unprocessable Entity
def test_get_agent_details():
response = client.get("/agents/AI%20Labs/Super%20SEO%20Optimizer")
assert response.status_code == 200
assert response.json()["agentName"] == "Super SEO Optimizer"
def test_get_creators():
response = client.get("/creators?page=1&page_size=20")
assert response.status_code == 200
assert response.json() # Ensure there are creators returned
def test_get_creator_details():
response = client.get("/creator/AI%20Labs")
assert response.status_code == 200
assert response.json()["username"] == "AI Labs"
def test_get_creator_invalid():
response = client.get("/creator/NonExistentUser")
assert response.status_code == 404 # Not Found

View File

@@ -31,7 +31,6 @@ model User {
AgentPreset AgentPreset[]
UserAgent UserAgent[]
UserGroupMemberships UserGroupMembership[]
Profile Profile[]
StoreListing StoreListing[]
StoreListingReview StoreListingReview[]
@@ -41,46 +40,6 @@ model User {
@@index([email])
}
model UserGroup {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt
name String
description String
groupIconUrl String?
UserGroupMemberships UserGroupMembership[]
Agents AgentGraph[]
Profile Profile[]
StoreListing StoreListing[]
@@index([name])
}
enum UserGroupRole {
MEMBER
OWNER
}
model UserGroupMembership {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt
userId String
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
userGroupId String
UserGroup UserGroup @relation(fields: [userGroupId], references: [id], onDelete: Cascade)
Role UserGroupRole @default(MEMBER)
@@unique([userId, userGroupId])
@@index([userId])
@@index([userGroupId])
}
// This model describes the Agent Graph/Flow (Multi Agent System).
model AgentGraph {
id String @default(uuid())
@@ -99,11 +58,6 @@ model AgentGraph {
// This allows us to delete user data with deleting the agent which maybe in use by other users
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
groupId String?
// Do not cascade delete the agent when the group is deleted
// This allows us to delete user group data with deleting the agent which maybe in use by other users
Group UserGroup? @relation(fields: [groupId], references: [id], onDelete: SetNull)
AgentNodes AgentNode[]
AgentGraphExecution AgentGraphExecution[]
AgentGraphExecutionSchedule AgentGraphExecutionSchedule[]
@@ -444,10 +398,6 @@ model Profile {
userId String?
User User? @relation(fields: [userId], references: [id], onDelete: Cascade)
// The group this profile belongs to, if any.
groupId String?
Group UserGroup? @relation(fields: [groupId], references: [id])
username String @unique
description String
@@ -475,9 +425,6 @@ model StoreListing {
owningUserId String
OwningUser User @relation(fields: [owningUserId], references: [id])
owningGroupId String?
OwningGroup UserGroup? @relation(fields: [owningGroupId], references: [id])
StoreListingVersions StoreListingVersion[]
StoreListingSubmission StoreListingSubmission[]