mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
hooking up pages, added missing update at
This commit is contained in:
@@ -120,6 +120,7 @@ async def get_store_agent_details(
|
||||
runs=agent.runs,
|
||||
rating=agent.rating,
|
||||
versions=agent.versions,
|
||||
last_updated=agent.updated_at,
|
||||
)
|
||||
except backend.server.v2.store.exceptions.AgentNotFoundError:
|
||||
raise
|
||||
|
||||
@@ -38,6 +38,7 @@ async def test_get_store_agents(mocker):
|
||||
runs=10,
|
||||
rating=4.5,
|
||||
versions=["1.0"],
|
||||
updated_at=datetime.now(),
|
||||
)
|
||||
]
|
||||
|
||||
@@ -77,6 +78,7 @@ async def test_get_store_agent_details(mocker):
|
||||
runs=10,
|
||||
rating=4.5,
|
||||
versions=["1.0"],
|
||||
updated_at=datetime.now(),
|
||||
)
|
||||
|
||||
# Mock prisma call
|
||||
|
||||
@@ -50,6 +50,7 @@ class StoreAgentDetails(pydantic.BaseModel):
|
||||
runs: int
|
||||
rating: float
|
||||
versions: list[str]
|
||||
last_updated: datetime.datetime
|
||||
|
||||
|
||||
class Creator(pydantic.BaseModel):
|
||||
|
||||
@@ -70,6 +70,7 @@ def test_store_agent_details():
|
||||
runs=50,
|
||||
rating=4.5,
|
||||
versions=["1.0", "2.0"],
|
||||
last_updated=datetime.datetime.now(),
|
||||
)
|
||||
assert details.slug == "test-agent"
|
||||
assert len(details.agent_image) == 2
|
||||
|
||||
@@ -348,6 +348,7 @@ def test_get_agent_details(mocker: pytest_mock.MockFixture):
|
||||
runs=100,
|
||||
rating=4.5,
|
||||
versions=["1.0.0", "1.1.0"],
|
||||
last_updated=datetime.datetime.now(),
|
||||
)
|
||||
mock_db_call = mocker.patch("backend.server.v2.store.db.get_store_agent_details")
|
||||
mock_db_call.return_value = mocked_value
|
||||
|
||||
@@ -19,6 +19,7 @@ AgentRuns AS (
|
||||
)
|
||||
SELECT
|
||||
sl.id AS listing_id,
|
||||
slv."updatedAt" AS updated_at,
|
||||
slv.slug,
|
||||
a.name AS agent_name,
|
||||
slv."videoUrl" AS agent_video,
|
||||
|
||||
@@ -423,7 +423,8 @@ view Creator {
|
||||
}
|
||||
|
||||
view StoreAgent {
|
||||
listing_id String @id
|
||||
listing_id String @id
|
||||
updated_at DateTime
|
||||
|
||||
slug String
|
||||
agent_name String
|
||||
|
||||
@@ -1,8 +1,93 @@
|
||||
import AutoGPTServerAPI from "@/lib/autogpt-server-api";
|
||||
import { Navbar } from "@/components/agptui/Navbar";
|
||||
import { BreadCrumbs } from "@/components/agptui/BreadCrumbs";
|
||||
import { AgentInfo } from "@/components/agptui/AgentInfo";
|
||||
import { AgentImages } from "@/components/agptui/AgentImages";
|
||||
import { AgentsSection } from "@/components/agptui/composite/AgentsSection";
|
||||
import { BecomeACreator } from "@/components/agptui/BecomeACreator";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Metadata } from "next";
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: {
|
||||
params: { creator: string; slug: string };
|
||||
}): Promise<Metadata> {
|
||||
const api = new AutoGPTServerAPI();
|
||||
const agent = await api.getStoreAgent(params.creator, params.slug);
|
||||
|
||||
return {
|
||||
title: `${agent.agent_name} - AutoGPT Store`,
|
||||
description: agent.description,
|
||||
};
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const api = new AutoGPTServerAPI();
|
||||
const agents = await api.getStoreAgents({ featured: true });
|
||||
return agents.agents.map((agent) => ({
|
||||
creator: agent.creator,
|
||||
slug: agent.slug,
|
||||
lang: "en",
|
||||
}));
|
||||
}
|
||||
|
||||
export default async function Page({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ lang: string, creator: string, slug: string }>
|
||||
}) {
|
||||
const { lang, creator, slug } = await params
|
||||
return <div>My Post: {slug}</div>
|
||||
}
|
||||
params,
|
||||
}: {
|
||||
params: { lang: string; creator: string; slug: string };
|
||||
}) {
|
||||
const api = new AutoGPTServerAPI();
|
||||
const agent = await api.getStoreAgent(params.creator, params.slug);
|
||||
const otherAgents = await api.getStoreAgents({ creator: params.creator });
|
||||
const similarAgents = await api.getStoreAgents({
|
||||
search_query: agent.categories[0],
|
||||
});
|
||||
|
||||
const breadcrumbs = [
|
||||
{ name: "Store", link: "/store" },
|
||||
{ name: agent.creator, link: `/store/creator/${agent.creator}` },
|
||||
{ name: agent.agent_name, link: "#" },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-screen max-w-[1360px]">
|
||||
<main className="px-4 md:mt-4 lg:mt-8">
|
||||
<BreadCrumbs items={breadcrumbs} />
|
||||
|
||||
<div className="flex flex-col gap-5 lg:flex-row">
|
||||
<div>
|
||||
<AgentInfo
|
||||
name={agent.agent_name}
|
||||
creator={agent.creator}
|
||||
description={agent.description}
|
||||
rating={agent.rating}
|
||||
runs={agent.runs}
|
||||
categories={agent.categories}
|
||||
lastUpdated={agent.updated_at}
|
||||
version={agent.versions[agent.versions.length - 1]}
|
||||
/>
|
||||
</div>
|
||||
<AgentImages images={agent.agent_image} />
|
||||
</div>
|
||||
<Separator className="my-6" />
|
||||
<AgentsSection
|
||||
agents={otherAgents.agents}
|
||||
sectionTitle={`Other agents by ${agent.creator}`}
|
||||
/>
|
||||
<Separator className="my-6" />
|
||||
<AgentsSection
|
||||
agents={similarAgents.agents}
|
||||
sectionTitle="Similar agents"
|
||||
/>
|
||||
<Separator className="my-6" />
|
||||
<BecomeACreator
|
||||
title="Want to contribute?"
|
||||
heading="We're always looking for more Creators!"
|
||||
description="Join our ever-growing community of hackers and tinkerers"
|
||||
buttonText="Become a Creator"
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,33 @@
|
||||
import AutoGPTServerAPI from "@/lib/autogpt-server-api";
|
||||
import {
|
||||
CreatorDetails as Creator,
|
||||
StoreAgent,
|
||||
} from "@/lib/autogpt-server-api";
|
||||
import { CreatorDetails } from "@/components/agptui/composite/CreatorDetails";
|
||||
import { AgentsSection } from "@/components/agptui/composite/AgentsSection";
|
||||
import { BreadCrumbs } from "@/components/agptui/BreadCrumbs";
|
||||
import { Metadata } from "next";
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: {
|
||||
params: { creator: string };
|
||||
}): Promise<Metadata> {
|
||||
const api = new AutoGPTServerAPI();
|
||||
const creator = await api.getStoreCreator(params.creator);
|
||||
|
||||
return {
|
||||
title: `${creator.name} - AutoGPT Store`,
|
||||
description: creator.description,
|
||||
};
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const api = new AutoGPTServerAPI();
|
||||
const creators = await api.getStoreCreators({ featured: true });
|
||||
return creators.creators.map((creator) => ({
|
||||
creator: creator.username,
|
||||
lang: "en",
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -16,22 +36,40 @@ export default async function Page({
|
||||
}: {
|
||||
params: { lang: string; creator: string };
|
||||
}) {
|
||||
const { creator } = params;
|
||||
const api = new AutoGPTServerAPI();
|
||||
const creatorDetails = await api.getStoreCreator(creator);
|
||||
const creator = await api.getStoreCreator(params.creator);
|
||||
const creatorAgents = await api.getStoreAgents({ creator: params.creator });
|
||||
const agents = creatorAgents.agents;
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col items-center justify-center px-4">
|
||||
<CreatorDetails
|
||||
name={creatorDetails.name}
|
||||
username={creatorDetails.username}
|
||||
description={creatorDetails.description}
|
||||
avgRating={creatorDetails.agent_rating}
|
||||
agentCount={creatorDetails.agent_runs}
|
||||
topCategories={creatorDetails.top_categories}
|
||||
otherLinks={creatorDetails.links}
|
||||
avatarSrc={creatorDetails.avatar_url}
|
||||
/>
|
||||
</div>
|
||||
<>
|
||||
<div className="flex w-full flex-col items-center justify-center px-4">
|
||||
<div className="mt-8">
|
||||
<BreadCrumbs
|
||||
items={[
|
||||
{ name: "Store", link: "/store" },
|
||||
{ name: creator.name, link: "#" },
|
||||
]}
|
||||
/>
|
||||
<CreatorDetails
|
||||
avatarSrc={creator.avatar_url}
|
||||
name={creator.name}
|
||||
username={creator.username}
|
||||
description={creator.description}
|
||||
avgRating={creator.agent_rating}
|
||||
agentCount={creator.agent_runs}
|
||||
topCategories={creator.top_categories}
|
||||
otherLinks={creator.links}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-16">
|
||||
<AgentsSection
|
||||
agents={agents}
|
||||
hideAvatars={true}
|
||||
sectionTitle={`Agents by ${creator.name}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ async function getStoreData() {
|
||||
const [featuredAgents, topAgents, featuredCreators] = await Promise.all([
|
||||
api.getStoreAgents({ featured: true }),
|
||||
api.getStoreAgents({ sorted_by: "runs" }),
|
||||
api.getStoreCreators({ featured: true }),
|
||||
api.getStoreCreators({ featured: true, sorted_by: "num_agents" }),
|
||||
]);
|
||||
|
||||
return {
|
||||
@@ -38,13 +38,19 @@ export const metadata: Metadata = {
|
||||
description: "Find and use AI Agents created by our community",
|
||||
applicationName: "NextGen AutoGPT Store",
|
||||
authors: [{ name: "AutoGPT Team" }],
|
||||
keywords: ["AI agents", "automation", "artificial intelligence", "AutoGPT", "marketplace"],
|
||||
keywords: [
|
||||
"AI agents",
|
||||
"automation",
|
||||
"artificial intelligence",
|
||||
"AutoGPT",
|
||||
"marketplace",
|
||||
],
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
},
|
||||
openGraph: {
|
||||
title: "Agent Store - NextGen AutoGPT",
|
||||
title: "Agent Store - NextGen AutoGPT",
|
||||
description: "Find and use AI Agents created by our community",
|
||||
type: "website",
|
||||
siteName: "NextGen AutoGPT Store",
|
||||
@@ -53,24 +59,23 @@ export const metadata: Metadata = {
|
||||
url: "/images/store-og.png",
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: "NextGen AutoGPT Store"
|
||||
}
|
||||
]
|
||||
alt: "NextGen AutoGPT Store",
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: "Agent Store - NextGen AutoGPT",
|
||||
description: "Find and use AI Agents created by our community",
|
||||
images: ["/images/store-twitter.png"]
|
||||
images: ["/images/store-twitter.png"],
|
||||
},
|
||||
icons: {
|
||||
icon: "/favicon.ico",
|
||||
shortcut: "/favicon-16x16.png",
|
||||
apple: "/apple-touch-icon.png"
|
||||
}
|
||||
apple: "/apple-touch-icon.png",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
export default async function Page({
|
||||
params: { lang },
|
||||
}: {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export default async function Page({
|
||||
params,
|
||||
searchParams,
|
||||
}: {
|
||||
params: { lang: string },
|
||||
searchParams: { term?: string }
|
||||
}) {
|
||||
const searchTerm = searchParams.term || ''
|
||||
return <div>Search Results for: {searchTerm}</div>
|
||||
}
|
||||
params,
|
||||
searchParams,
|
||||
}: {
|
||||
params: { lang: string };
|
||||
searchParams: { term?: string };
|
||||
}) {
|
||||
const searchTerm = searchParams.term || "";
|
||||
return <div>Search Results for: {searchTerm}</div>;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { Button } from "./Button";
|
||||
import Link from "next/link";
|
||||
import { StarRatingIcons } from "@/components/ui/icons";
|
||||
interface AgentInfoProps {
|
||||
onRunAgent: () => void;
|
||||
name: string;
|
||||
creator: string;
|
||||
description: string;
|
||||
@@ -15,7 +16,6 @@ interface AgentInfoProps {
|
||||
}
|
||||
|
||||
export const AgentInfo: React.FC<AgentInfoProps> = ({
|
||||
onRunAgent,
|
||||
name,
|
||||
creator,
|
||||
description,
|
||||
@@ -25,6 +25,11 @@ export const AgentInfo: React.FC<AgentInfoProps> = ({
|
||||
lastUpdated,
|
||||
version,
|
||||
}) => {
|
||||
const onRunAgent = () => {
|
||||
// TODO: Implement run agent functionality
|
||||
console.log("Running agent:", name);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flow-root w-full lg:w-[27.5rem]">
|
||||
<div className="mb-2 font-neue text-3xl font-medium tracking-wide text-[#272727] md:mb-4 md:text-4xl lg:text-5xl">
|
||||
@@ -39,7 +44,7 @@ export const AgentInfo: React.FC<AgentInfoProps> = ({
|
||||
{creator}
|
||||
</Link>
|
||||
</div>
|
||||
<Button onClick={onRunAgent} className="mb-8" variant="outline">
|
||||
<Button onClick={onRunAgent} className="mb-8" variants="outline">
|
||||
Run agent
|
||||
</Button>
|
||||
<div className="font-['PP Neue Montreal TT'] mb-6 text-[1.1875rem] font-normal leading-relaxed tracking-tight text-[#282828]">
|
||||
|
||||
@@ -41,6 +41,14 @@ export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean;
|
||||
variant?:
|
||||
| "default"
|
||||
| "destructive"
|
||||
| "outline"
|
||||
| "secondary"
|
||||
| "ghost"
|
||||
| "link";
|
||||
size?: "default" | "sm" | "lg" | "primary" | "icon";
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
|
||||
@@ -43,16 +43,37 @@ export const AgentsSection: React.FC<AgentsSectionProps> = ({
|
||||
<div className="mb-6 font-neue text-[23px] font-bold leading-9 tracking-tight text-[#282828]">
|
||||
{sectionTitle}
|
||||
</div>
|
||||
<Carousel
|
||||
className="md:hidden"
|
||||
opts={{
|
||||
loop: true,
|
||||
}}
|
||||
>
|
||||
<CarouselContent>
|
||||
{topAgents.map((agent, index) => (
|
||||
<CarouselItem key={index} className="min-w-64 max-w-68">
|
||||
{!topAgents || topAgents.length === 0 ? (
|
||||
<div className="text-center text-gray-500">No agents found</div>
|
||||
) : (
|
||||
<>
|
||||
<Carousel
|
||||
className="md:hidden"
|
||||
opts={{
|
||||
loop: true,
|
||||
}}
|
||||
>
|
||||
<CarouselContent>
|
||||
{topAgents.map((agent, index) => (
|
||||
<CarouselItem key={index} className="min-w-64 max-w-68">
|
||||
<StoreCard
|
||||
agentName={agent.agent_name}
|
||||
agentImage={agent.agent_image}
|
||||
description={agent.description}
|
||||
runs={agent.runs}
|
||||
rating={agent.rating}
|
||||
avatarSrc={agent.creator_avatar}
|
||||
hideAvatar={hideAvatars}
|
||||
onClick={() => handleCardClick(agent.creator, agent.slug)}
|
||||
/>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
</Carousel>
|
||||
<div className="hidden grid-cols-1 place-items-center gap-3 md:grid md:grid-cols-2 lg:grid-cols-3">
|
||||
{topAgents.map((agent, index) => (
|
||||
<StoreCard
|
||||
key={index}
|
||||
agentName={agent.agent_name}
|
||||
agentImage={agent.agent_image}
|
||||
description={agent.description}
|
||||
@@ -62,25 +83,10 @@ export const AgentsSection: React.FC<AgentsSectionProps> = ({
|
||||
hideAvatar={hideAvatars}
|
||||
onClick={() => handleCardClick(agent.creator, agent.slug)}
|
||||
/>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
</Carousel>
|
||||
<div className="hidden grid-cols-1 place-items-center gap-3 md:grid md:grid-cols-2 lg:grid-cols-3">
|
||||
{topAgents.map((agent, index) => (
|
||||
<StoreCard
|
||||
key={index}
|
||||
agentName={agent.agent_name}
|
||||
agentImage={agent.agent_image}
|
||||
description={agent.description}
|
||||
runs={agent.runs}
|
||||
rating={agent.rating}
|
||||
avatarSrc={agent.creator_avatar}
|
||||
hideAvatar={hideAvatars}
|
||||
onClick={() => handleCardClick(agent.creator, agent.slug)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -9,7 +9,7 @@ interface CreatorDetailsProps {
|
||||
avgRating: number;
|
||||
agentCount: number;
|
||||
topCategories: string[];
|
||||
otherLinks: Record<string, string>;
|
||||
otherLinks: string[];
|
||||
avatarSrc: string;
|
||||
}
|
||||
|
||||
@@ -53,22 +53,20 @@ export const CreatorDetails: React.FC<CreatorDetailsProps> = React.memo(
|
||||
Other links
|
||||
</h2>
|
||||
<div className="flex flex-wrap gap-4">
|
||||
{Object.entries(otherLinks)
|
||||
.slice(0, 5)
|
||||
.map(([key, url]) => (
|
||||
<a
|
||||
key={key}
|
||||
href={url}
|
||||
className="flex items-center gap-2"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{getIconForSocial(url, { className: "h-6 w-6" })}
|
||||
<span className="font-neue text-lg font-normal tracking-tight text-[#282828]">
|
||||
{key}
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
{otherLinks.map((url, index) => (
|
||||
<a
|
||||
key={index}
|
||||
href={url}
|
||||
className="flex items-center gap-2"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{getIconForSocial(url, { className: "h-6 w-6" })}
|
||||
<span className="font-neue text-lg font-normal tracking-tight text-[#282828]">
|
||||
{new URL(url).hostname.replace("www.", "")}
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -100,7 +100,6 @@ export const AgentPage: React.FC<AgentPageProps> = ({
|
||||
<div className="flex flex-col gap-5 lg:flex-row">
|
||||
<div>
|
||||
<AgentInfo
|
||||
onRunAgent={handleRunAgent}
|
||||
name={agentInfo.name}
|
||||
creator={agentInfo.creator}
|
||||
description={agentInfo.description}
|
||||
|
||||
@@ -339,6 +339,7 @@ export type StoreAgentsResponse = {
|
||||
|
||||
export type StoreAgentDetails = {
|
||||
slug: string;
|
||||
updated_at: string;
|
||||
agent_name: string;
|
||||
agent_video: string;
|
||||
agent_image: string[];
|
||||
|
||||
Reference in New Issue
Block a user