Skip to content

Commit

Permalink
Add Deploy view in AGS (microsoft#4756)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
victordibia authored Dec 19, 2024
1 parent c215552 commit 4e3a703
Show file tree
Hide file tree
Showing 18 changed files with 1,328 additions and 628 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
MultiModalMessage,
StopMessage,
TextMessage,
ToolCallRequestEvent,
ToolCallExecutionEvent,
ToolCallRequestEvent,
)
from autogen_core import CancellationToken, FunctionCall
from autogen_core.models._types import FunctionExecutionResult
Expand Down
12 changes: 8 additions & 4 deletions python/packages/autogen-studio/autogenstudio/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -64,17 +64,21 @@ 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.
"""

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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,21 +326,19 @@ async def load_team(self, config: TeamConfig, input_func: Optional[Callable] = N
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
MultiModalMessage,
StopMessage,
TextMessage,
ToolCallRequestEvent,
ToolCallExecutionEvent,
ToolCallRequestEvent,
)
from autogen_core import CancellationToken
from autogen_core import Image as AGImage
Expand Down
12 changes: 6 additions & 6 deletions python/packages/autogen-studio/autogenstudio/web/serve.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@
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)
Expand Down
3 changes: 2 additions & 1 deletion python/packages/autogen-studio/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
PanelLeftClose,
PanelLeftOpen,
GalleryHorizontalEnd,
Rocket,
} from "lucide-react";
import Icon from "./icons";

Expand Down Expand Up @@ -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)[]) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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;
Loading

0 comments on commit 4e3a703

Please sign in to comment.