mirror of
https://github.com/microsoft/autogen.git
synced 2025-12-24 13:39:24 +00:00
Add Deploy view in AGS (#4756)
* update version, fix component factory bug * add basic structure for deploy * minor fixes, deploy v1 * minor text updated * format fixes * formatting fixes .. webby test samples * update cli command, update views, * packakge.json and other fixes * format fixes
This commit is contained in:
parent
c21555290e
commit
4e3a70303d
@ -52,14 +52,14 @@ Have a local model server like Ollama, vLLM or LMStudio that provide an OpenAI c
|
||||
"component_type": "model",
|
||||
"model_capabilities": {
|
||||
"vision": false,
|
||||
"function_calling": false,
|
||||
"function_calling": true,
|
||||
"json_output": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```{caution}
|
||||
It is important that you add the `model_capabilities` field to the model client specification for custom models. This is used by the framework instantiate and use the model correctly.
|
||||
It is important that you add the `model_capabilities` field to the model client specification for custom models. This is used by the framework instantiate and use the model correctly. Also, the `AssistantAgent` and many other agents in AgentChat require the model to have the `function_calling` capability.
|
||||
```
|
||||
|
||||
## Q: The server starts but I can't access the UI
|
||||
|
||||
@ -29,8 +29,8 @@ from autogen_agentchat.messages import (
|
||||
MultiModalMessage,
|
||||
StopMessage,
|
||||
TextMessage,
|
||||
ToolCallRequestEvent,
|
||||
ToolCallExecutionEvent,
|
||||
ToolCallRequestEvent,
|
||||
)
|
||||
from autogen_core import CancellationToken, FunctionCall
|
||||
from autogen_core.models._types import FunctionExecutionResult
|
||||
|
||||
@ -54,7 +54,7 @@ def ui(
|
||||
|
||||
@app.command()
|
||||
def serve(
|
||||
workflow: str = "",
|
||||
team: str = "",
|
||||
host: str = "127.0.0.1",
|
||||
port: int = 8084,
|
||||
workers: int = 1,
|
||||
@ -64,9 +64,9 @@ def serve(
|
||||
Serve an API Endpoint based on an AutoGen Studio workflow json file.
|
||||
|
||||
Args:
|
||||
workflow (str): Path to the workflow json file.
|
||||
team (str): Path to the team json file.
|
||||
host (str, optional): Host to run the UI on. Defaults to 127.0.0.1 (localhost).
|
||||
port (int, optional): Port to run the UI on. Defaults to 8081.
|
||||
port (int, optional): Port to run the UI on. Defaults to 8084
|
||||
workers (int, optional): Number of workers to run the UI with. Defaults to 1.
|
||||
reload (bool, optional): Whether to reload the UI on code changes. Defaults to False.
|
||||
docs (bool, optional): Whether to generate API docs. Defaults to False.
|
||||
@ -74,7 +74,11 @@ def serve(
|
||||
"""
|
||||
|
||||
os.environ["AUTOGENSTUDIO_API_DOCS"] = str(docs)
|
||||
os.environ["AUTOGENSTUDIO_WORKFLOW_FILE"] = workflow
|
||||
os.environ["AUTOGENSTUDIO_TEAM_FILE"] = team
|
||||
|
||||
# validate the team file
|
||||
if not os.path.exists(team):
|
||||
raise ValueError(f"Team file not found: {team}")
|
||||
|
||||
uvicorn.run(
|
||||
"autogenstudio.web.serve:app",
|
||||
|
||||
@ -326,21 +326,19 @@ class ComponentFactory:
|
||||
async def load_agent(self, config: AgentConfig, input_func: Optional[Callable] = None) -> AgentComponent:
|
||||
"""Create agent instance from configuration."""
|
||||
|
||||
system_message = config.system_message if config.system_message else "You are a helpful assistant"
|
||||
model_client = None
|
||||
system_message = None
|
||||
tools = []
|
||||
if hasattr(config, "system_message") and config.system_message:
|
||||
system_message = config.system_message
|
||||
if hasattr(config, "model_client") and config.model_client:
|
||||
model_client = await self.load(config.model_client)
|
||||
if hasattr(config, "tools") and config.tools:
|
||||
for tool_config in config.tools:
|
||||
tool = await self.load(tool_config)
|
||||
tools.append(tool)
|
||||
|
||||
try:
|
||||
# Load model client if specified
|
||||
model_client = None
|
||||
if config.model_client:
|
||||
model_client = await self.load(config.model_client)
|
||||
|
||||
# Load tools if specified
|
||||
tools = []
|
||||
if config.tools:
|
||||
for tool_config in config.tools:
|
||||
tool = await self.load(tool_config)
|
||||
tools.append(tool)
|
||||
|
||||
if config.agent_type == AgentTypes.USERPROXY:
|
||||
return UserProxyAgent(
|
||||
name=config.name,
|
||||
|
||||
@ -12,8 +12,8 @@ from autogen_agentchat.messages import (
|
||||
MultiModalMessage,
|
||||
StopMessage,
|
||||
TextMessage,
|
||||
ToolCallRequestEvent,
|
||||
ToolCallExecutionEvent,
|
||||
ToolCallRequestEvent,
|
||||
)
|
||||
from autogen_core import CancellationToken
|
||||
from autogen_core import Image as AGImage
|
||||
|
||||
@ -6,23 +6,23 @@ import os
|
||||
from fastapi import FastAPI
|
||||
|
||||
from ..datamodel import Response
|
||||
from ..workflowmanager import WorkflowManager
|
||||
from ..teammanager import TeamManager
|
||||
|
||||
app = FastAPI()
|
||||
workflow_file_path = os.environ.get("AUTOGENSTUDIO_WORKFLOW_FILE", None)
|
||||
team_file_path = os.environ.get("AUTOGENSTUDIO_TEAM_FILE", None)
|
||||
|
||||
|
||||
if workflow_file_path:
|
||||
workflow_manager = WorkflowManager(workflow=workflow_file_path)
|
||||
if team_file_path:
|
||||
team_manager = TeamManager()
|
||||
else:
|
||||
raise ValueError("Workflow file must be specified")
|
||||
raise ValueError("Team file must be specified")
|
||||
|
||||
|
||||
@app.get("/predict/{task}")
|
||||
async def predict(task: str):
|
||||
response = Response(message="Task successfully completed", status=True, data=None)
|
||||
try:
|
||||
result_message = workflow_manager.run(message=task, clear_history=False)
|
||||
result_message = await team_manager.run(task=task, team_config=team_file_path)
|
||||
response.data = result_message
|
||||
except Exception as e:
|
||||
response.message = str(e)
|
||||
|
||||
@ -42,6 +42,7 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-syntax-highlighter": "^15.6.1",
|
||||
"tailwindcss": "^3.4.14",
|
||||
"yarn": "^1.22.22",
|
||||
"zustand": "^5.0.1"
|
||||
@ -51,7 +52,7 @@
|
||||
"@types/node": "^22.9.0",
|
||||
"@types/react": "^18.2.55",
|
||||
"@types/react-dom": "^18.2.19",
|
||||
"@types/react-syntax-highlighter": "^15.5.10",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
PanelLeftClose,
|
||||
PanelLeftOpen,
|
||||
GalleryHorizontalEnd,
|
||||
Rocket,
|
||||
} from "lucide-react";
|
||||
import Icon from "./icons";
|
||||
|
||||
@ -43,6 +44,12 @@ const navigation: INavItem[] = [
|
||||
icon: GalleryHorizontalEnd,
|
||||
breadcrumbs: [{ name: "Gallery", href: "/gallery", current: true }],
|
||||
},
|
||||
{
|
||||
name: "Deploy",
|
||||
href: "/deploy",
|
||||
icon: Rocket,
|
||||
breadcrumbs: [{ name: "Deploy", href: "/deploy", current: true }],
|
||||
},
|
||||
];
|
||||
|
||||
const classNames = (...classes: (string | undefined | boolean)[]) => {
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
import React from "react";
|
||||
import { Alert } from "antd";
|
||||
import { CodeSection, copyToClipboard } from "./guides";
|
||||
|
||||
const DockerGuide: React.FC = () => {
|
||||
return (
|
||||
<div className="max-w-4xl">
|
||||
<h1 className="tdext-2xl font-bold mb-6">Docker Container Setup</h1>
|
||||
|
||||
<Alert
|
||||
className="mb-6"
|
||||
message="Prerequisites"
|
||||
description={
|
||||
<ul className="list-disc pl-4 mt-2 space-y-1">
|
||||
<li>Docker installed on your system</li>
|
||||
</ul>
|
||||
}
|
||||
type="info"
|
||||
/>
|
||||
<CodeSection
|
||||
title="1. Dockerfile"
|
||||
description=<div>
|
||||
AutoGen Studio provides a
|
||||
<a
|
||||
href="https://github.com/microsoft/autogen/blob/main/python/packages/autogen-studio/Dockerfile"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-accent underline px-1"
|
||||
>
|
||||
Dockerfile
|
||||
</a>
|
||||
that you can use to build your Docker container.{" "}
|
||||
</div>
|
||||
code={`FROM mcr.microsoft.com/devcontainers/python:3.10
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
RUN pip install -U gunicorn autogenstudio
|
||||
|
||||
RUN useradd -m -u 1000 user
|
||||
USER user
|
||||
ENV HOME=/home/user
|
||||
PATH=/home/user/.local/bin:$PATH
|
||||
AUTOGENSTUDIO_APPDIR=/home/user/app
|
||||
|
||||
WORKDIR $HOME/app
|
||||
|
||||
COPY --chown=user . $HOME/app
|
||||
|
||||
CMD gunicorn -w $((2 * $(getconf _NPROCESSORS_ONLN) + 1)) --timeout 12600 -k uvicorn.workers.UvicornWorker autogenstudio.web.app:app --bind "0.0.0.0:8081"`}
|
||||
onCopy={copyToClipboard}
|
||||
/>
|
||||
|
||||
{/* Build and Run */}
|
||||
<CodeSection
|
||||
title="2. Build and Run"
|
||||
description="Build and run your Docker container:"
|
||||
code={`docker build -t autogenstudio .
|
||||
docker run -p 8000:8000 autogenstudio`}
|
||||
onCopy={copyToClipboard}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DockerGuide;
|
||||
@ -0,0 +1,78 @@
|
||||
import React from "react";
|
||||
import { Copy } from "lucide-react";
|
||||
import { Guide } from "../types";
|
||||
import PythonGuide from "./python";
|
||||
import DockerGuide from "./docker";
|
||||
import { PrismLight as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||
import js from "react-syntax-highlighter/dist/esm/languages/prism/javascript";
|
||||
import python from "react-syntax-highlighter/dist/esm/languages/prism/python";
|
||||
|
||||
import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism";
|
||||
|
||||
SyntaxHighlighter.registerLanguage("javascript", js);
|
||||
SyntaxHighlighter.registerLanguage("python", python);
|
||||
|
||||
interface GuideContentProps {
|
||||
guide: Guide;
|
||||
}
|
||||
|
||||
export const copyToClipboard = (text: string) => {
|
||||
navigator.clipboard.writeText(text);
|
||||
};
|
||||
export const GuideContent: React.FC<GuideContentProps> = ({ guide }) => {
|
||||
// Render different content based on guide type and id
|
||||
switch (guide.id) {
|
||||
case "python-setup":
|
||||
return <PythonGuide />;
|
||||
|
||||
case "docker-setup":
|
||||
return <DockerGuide />;
|
||||
|
||||
// Add more cases for other guides...
|
||||
|
||||
default:
|
||||
return (
|
||||
<div className="text-secondary">
|
||||
A Guide with the title <strong>{guide.title}</strong> is work in
|
||||
progress!
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
interface CodeSectionProps {
|
||||
title: string;
|
||||
description?: string | React.ReactNode;
|
||||
code?: string;
|
||||
onCopy: (text: string) => void;
|
||||
language?: string;
|
||||
}
|
||||
|
||||
export const CodeSection: React.FC<CodeSectionProps> = ({
|
||||
title,
|
||||
description,
|
||||
code,
|
||||
onCopy,
|
||||
language = "python",
|
||||
}) => (
|
||||
<section className="mt-6 bg-seco">
|
||||
<h2 className="text-md font-semibold mb-3">{title}</h2>
|
||||
{description && <p className=" mb-3">{description}</p>}
|
||||
{code && (
|
||||
<div className="relative bg-secondary text-sm p-4 rounded overflow-auto scroll">
|
||||
<button
|
||||
onClick={() => onCopy(code)}
|
||||
className="absolute right-2 top-2 p-2 bg-secondary hover:bg-primary rounded-md"
|
||||
>
|
||||
<Copy className="w-4 h-4 hover:text-accent transition duration-100" />
|
||||
</button>
|
||||
{/* overflow scroll custom style */}
|
||||
<SyntaxHighlighter language={language} wrapLines={true} style={oneDark}>
|
||||
{code}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
|
||||
export default GuideContent;
|
||||
@ -0,0 +1,68 @@
|
||||
import React from "react";
|
||||
import { Alert } from "antd";
|
||||
import { CodeSection, copyToClipboard } from "./guides";
|
||||
import { Download } from "lucide-react";
|
||||
|
||||
const PythonGuide: React.FC = () => {
|
||||
return (
|
||||
<div className="max-w-4xl">
|
||||
<h1 className="tdext-2xl font-bold mb-6">
|
||||
Using AutoGen Studio Teams in Python Code and REST API
|
||||
</h1>
|
||||
|
||||
<Alert
|
||||
className="mb-6"
|
||||
message="Prerequisites"
|
||||
description={
|
||||
<ul className="list-disc pl-4 mt-2 space-y-1">
|
||||
<li>AutoGen Studio installed</li>
|
||||
</ul>
|
||||
}
|
||||
type="info"
|
||||
/>
|
||||
|
||||
<div className="my-3 text-sm">
|
||||
{" "}
|
||||
You can reuse the declarative specifications of agent teams created in
|
||||
AutoGen studio in your python application by using the TeamManager
|
||||
class. . In TeamBuilder, select a team configuration and click download.{" "}
|
||||
<Download className="h-4 w-4 inline-block" />{" "}
|
||||
</div>
|
||||
|
||||
{/* Installation Steps */}
|
||||
<div className="space-y-6">
|
||||
{/* Basic Usage */}
|
||||
<CodeSection
|
||||
title="1. Run a Team in Python"
|
||||
description="Here's a simple example of using the TeamManager class from AutoGen Studio in your python code."
|
||||
code={`from autogenstudio.teammanager import TeamManager
|
||||
|
||||
# Initialize the TeamManager
|
||||
manager = TeamManager()
|
||||
|
||||
# Run a task with a specific team configuration
|
||||
result = await manager.run(
|
||||
task="What is the weather in New York?",
|
||||
team_config="team.json"
|
||||
)
|
||||
print(result)`}
|
||||
onCopy={copyToClipboard}
|
||||
/>
|
||||
|
||||
<CodeSection
|
||||
title="2. Serve a Team as a REST API"
|
||||
description=<div>
|
||||
AutoGen Studio offers a convenience CLI command to serve a team as a
|
||||
REST API endpoint.{" "}
|
||||
</div>
|
||||
code={`
|
||||
autogenstudio serve --team path/to/team.json --port 8084
|
||||
`}
|
||||
onCopy={copyToClipboard}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PythonGuide;
|
||||
@ -0,0 +1,86 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { ChevronRight, TriangleAlert } from "lucide-react";
|
||||
import { DeploySidebar } from "./sidebar";
|
||||
import { Guide, defaultGuides } from "./types";
|
||||
import { GuideContent } from "./guides/guides";
|
||||
|
||||
export const DeployManager: React.FC = () => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [guides, setGuides] = useState<Guide[]>(defaultGuides);
|
||||
const [currentGuide, setCurrentGuide] = useState<Guide | null>(null);
|
||||
const [isSidebarOpen, setIsSidebarOpen] = useState(() => {
|
||||
if (typeof window !== "undefined") {
|
||||
const stored = localStorage.getItem("deploySidebar");
|
||||
return stored !== null ? JSON.parse(stored) : true;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// Persist sidebar state
|
||||
useEffect(() => {
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.setItem("deploySidebar", JSON.stringify(isSidebarOpen));
|
||||
}
|
||||
}, [isSidebarOpen]);
|
||||
|
||||
// Set first guide as current if none selected
|
||||
useEffect(() => {
|
||||
if (!currentGuide && guides.length > 0) {
|
||||
setCurrentGuide(guides[0]);
|
||||
}
|
||||
}, [guides, currentGuide]);
|
||||
|
||||
return (
|
||||
<div className="relative flex h-full w-full">
|
||||
{/* Sidebar */}
|
||||
<div
|
||||
className={`absolute left-0 top-0 h-full transition-all duration-200 ease-in-out ${
|
||||
isSidebarOpen ? "w-64" : "w-12"
|
||||
}`}
|
||||
>
|
||||
<DeploySidebar
|
||||
isOpen={isSidebarOpen}
|
||||
guides={guides}
|
||||
currentGuide={currentGuide}
|
||||
onToggle={() => setIsSidebarOpen(!isSidebarOpen)}
|
||||
onSelectGuide={setCurrentGuide}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Main Content */}
|
||||
<div
|
||||
className={`flex-1 transition-all -mr-6 duration-200 ${
|
||||
isSidebarOpen ? "ml-64" : "ml-12"
|
||||
}`}
|
||||
>
|
||||
<div className="p-4 pt-2">
|
||||
{/* Breadcrumb */}
|
||||
<div className="flex items-center gap-2 mb-4 text-sm">
|
||||
<span className="text-primary font-medium">Deploy</span>
|
||||
{currentGuide && (
|
||||
<>
|
||||
<ChevronRight className="w-4 h-4 text-secondary" />
|
||||
<span className="text-secondary">{currentGuide.title}</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="rounded border border-secondary border-dashed p-2 text-sm mb-4">
|
||||
<TriangleAlert className="w-4 h-4 inline-block mr-2 -mt-1 text-secondary " />{" "}
|
||||
The deployment guide section is work in progress.
|
||||
</div>
|
||||
{/* Content Area */}
|
||||
{currentGuide ? (
|
||||
<GuideContent guide={currentGuide} />
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-[calc(100vh-190px)] text-secondary">
|
||||
Select a guide from the sidebar to get started
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeployManager;
|
||||
@ -0,0 +1,111 @@
|
||||
import React from "react";
|
||||
import { Button, Tooltip } from "antd";
|
||||
import {
|
||||
PanelLeftClose,
|
||||
PanelLeftOpen,
|
||||
Book,
|
||||
InfoIcon,
|
||||
RefreshCcw,
|
||||
} from "lucide-react";
|
||||
import type { Guide } from "./types";
|
||||
|
||||
interface DeploySidebarProps {
|
||||
isOpen: boolean;
|
||||
guides: Guide[];
|
||||
currentGuide: Guide | null;
|
||||
onToggle: () => void;
|
||||
onSelectGuide: (guide: Guide) => void;
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
export const DeploySidebar: React.FC<DeploySidebarProps> = ({
|
||||
isOpen,
|
||||
guides,
|
||||
currentGuide,
|
||||
onToggle,
|
||||
onSelectGuide,
|
||||
isLoading = false,
|
||||
}) => {
|
||||
// Render collapsed state
|
||||
if (!isOpen) {
|
||||
return (
|
||||
<div className="h-full border-r border-secondary">
|
||||
<div className="p-2 -ml-2">
|
||||
<Tooltip title="Documentation">
|
||||
<button
|
||||
onClick={onToggle}
|
||||
className="p-2 rounded-md hover:bg-secondary hover:text-accent text-secondary transition-colors focus:outline-none focus:ring-2 focus:ring-accent focus:ring-opacity-50"
|
||||
>
|
||||
<PanelLeftOpen strokeWidth={1.5} className="h-6 w-6" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full border-r border-secondary">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between pt-0 p-4 pl-2 pr-2 border-b border-secondary">
|
||||
<div className="flex items-center gap-2">
|
||||
{/* <Book className="w-4 h-4" /> */}
|
||||
<span className="text-primary font-medium">Guides</span>
|
||||
{/* <span className="px-2 py-0.5 text-xs bg-accent/10 text-accent rounded">
|
||||
{guides.length}
|
||||
</span> */}
|
||||
</div>
|
||||
<Tooltip title="Close Sidebar">
|
||||
<button
|
||||
onClick={onToggle}
|
||||
className="p-2 rounded-md hover:bg-secondary hover:text-accent text-secondary transition-colors focus:outline-none focus:ring-2 focus:ring-accent focus:ring-opacity-50"
|
||||
>
|
||||
<PanelLeftClose strokeWidth={1.5} className="h-6 w-6" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
{/* Loading State */}
|
||||
{isLoading && (
|
||||
<div className="p-4">
|
||||
<RefreshCcw className="w-4 h-4 inline-block animate-spin" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Empty State */}
|
||||
{!isLoading && guides.length === 0 && (
|
||||
<div className="p-2 m-2 text-center text-secondary text-sm border border-dashed rounded">
|
||||
<InfoIcon className="w-4 h-4 inline-block mr-1.5 -mt-0.5" />
|
||||
No deployment guide available
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Guides List */}
|
||||
<div className="overflow-y-auto h-[calc(100%-64px)] mt-4">
|
||||
{guides.map((guide) => (
|
||||
<div key={guide.id} className="relative">
|
||||
<div
|
||||
className={`absolute top-1 left-0.5 z-50 h-[calc(100%-8px)]
|
||||
w-1 bg-opacity-80 rounded ${
|
||||
currentGuide?.id === guide.id ? "bg-accent" : "bg-tertiary"
|
||||
}`}
|
||||
/>
|
||||
<div
|
||||
className={`group ml-1 flex flex-col p-2 rounded-l cursor-pointer hover:bg-secondary ${
|
||||
currentGuide?.id === guide.id
|
||||
? "border-accent bg-secondary"
|
||||
: "border-transparent"
|
||||
}`}
|
||||
onClick={() => onSelectGuide(guide)}
|
||||
>
|
||||
{/* Guide Title */}
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm truncate">{guide.title}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,23 @@
|
||||
export interface Guide {
|
||||
id: string;
|
||||
title: string;
|
||||
type: "python" | "docker" | "cloud";
|
||||
}
|
||||
|
||||
export const defaultGuides: Guide[] = [
|
||||
{
|
||||
id: "python-setup",
|
||||
title: "Python",
|
||||
type: "python",
|
||||
},
|
||||
{
|
||||
id: "docker-setup",
|
||||
title: "Docker",
|
||||
type: "docker",
|
||||
},
|
||||
// {
|
||||
// id: "cloud-deploy",
|
||||
// title: "Cloud",
|
||||
// type: "cloud",
|
||||
// },
|
||||
];
|
||||
@ -292,7 +292,7 @@ export const TeamBuilder: React.FC<TeamBuilderProps> = ({
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<Tooltip title="Download Team Configuration">
|
||||
<Tooltip title="Download Team">
|
||||
<Button
|
||||
type="text"
|
||||
icon={<Download size={18} />}
|
||||
|
||||
@ -116,11 +116,9 @@ export const TeamSidebar: React.FC<TeamSidebarProps> = ({
|
||||
</div>
|
||||
|
||||
{/* Section Label */}
|
||||
<div className="py-2 text-sm text-secondary">
|
||||
Recents
|
||||
{isLoading && (
|
||||
<RefreshCcw className="w-4 h-4 inline-block ml-2 animate-spin" />
|
||||
)}
|
||||
<div className="py-2 flex text-sm text-secondary">
|
||||
<div className="flex"> Recents</div>
|
||||
{isLoading && <RefreshCcw className="w-4 h-4 ml-2 animate-spin" />}
|
||||
</div>
|
||||
|
||||
{/* Teams List */}
|
||||
@ -137,9 +135,7 @@ export const TeamSidebar: React.FC<TeamSidebarProps> = ({
|
||||
{teams.length > 0 && (
|
||||
<div
|
||||
key={"teams_title"}
|
||||
className={` ${
|
||||
isLoading ? "opacity-50 pointer-events-none" : ""
|
||||
}`}
|
||||
className={` ${isLoading ? " pointer-events-none" : ""}`}
|
||||
>
|
||||
{" "}
|
||||
{teams.map((team) => (
|
||||
|
||||
28
python/packages/autogen-studio/frontend/src/pages/deploy.tsx
Normal file
28
python/packages/autogen-studio/frontend/src/pages/deploy.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import * as React from "react";
|
||||
import Layout from "../components/layout";
|
||||
import { graphql } from "gatsby";
|
||||
import DeployManager from "../components/views/deploy/manager";
|
||||
|
||||
// markup
|
||||
const DeployPage = ({ data }: any) => {
|
||||
return (
|
||||
<Layout meta={data.site.siteMetadata} title="Home" link={"/deploy"}>
|
||||
<main style={{ height: "100%" }} className=" h-full ">
|
||||
<DeployManager />
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export const query = graphql`
|
||||
query HomePageQuery {
|
||||
site {
|
||||
siteMetadata {
|
||||
description
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default DeployPage;
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user