Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to AutoGen Assistant #828

Merged
merged 25 commits into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
56e214e
improve template for files, integreate files in db
victordibia Nov 22, 2023
0f60c3a
ui update, improvements to file display grid
victordibia Nov 22, 2023
9d839f5
add new global skill for image generation
victordibia Nov 22, 2023
70dfb70
update readme to address #739
victordibia Nov 23, 2023
4e34360
utils.py refactor, separate db uitls for ease of development
victordibia Nov 28, 2023
8d47458
db utils
victordibia Nov 28, 2023
a88cb41
add support for sessions both in backend api and ui
victordibia Nov 28, 2023
479229e
improve implementation for session support
victordibia Nov 28, 2023
3569fc2
add early v1 support for a gallery and publishing to a gallery
victordibia Nov 29, 2023
9cf8d87
rewrite logic for file storage representation. Store only file refere…
victordibia Nov 30, 2023
793f102
update generate image logic
victordibia Nov 30, 2023
e0564d3
update ui layout
victordibia Nov 30, 2023
eb352db
fix light dark mode bug
victordibia Dec 1, 2023
ae92e98
v1 support for showing items added to gallery
victordibia Dec 1, 2023
b57d453
remove viewer as it is merged in gallery
victordibia Dec 1, 2023
c5bd1e8
formatting updates
victordibia Dec 1, 2023
81cac0f
Merge branch 'main' into autogenra
victordibia Dec 1, 2023
4c9d618
QOL refactoring
victordibia Dec 1, 2023
719fed1
readme and general updates
victordibia Dec 1, 2023
1699c8e
add example notebook on assistant api
victordibia Dec 1, 2023
f39508a
imporve naming conventions and formatting
victordibia Dec 1, 2023
49c72eb
readme update
victordibia Dec 1, 2023
e2346fa
Update samples/apps/autogen-assistant/pyproject.toml
victordibia Dec 2, 2023
bf32763
Update samples/apps/autogen-assistant/notebooks/tutorial.ipynb
victordibia Dec 2, 2023
ed739df
Merge branch 'main' into autogenra
victordibia Dec 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 47 additions & 48 deletions samples/apps/autogen-assistant/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,64 +19,57 @@ Project Structure:
- _autogenra/_ code for the backend classes and web api (FastAPI)
- _frontend/_ code for the webui, built with Gatsby and Tailwind

## Getting Started

AutoGen requires access to an LLM. Please see the [AutoGen docs](https://microsoft.github.io/autogen/docs/FAQ#set-your-api-endpoints) on how to configure access to your LLM provider. In this sample, We recommend setting up your `OPENAI_API_KEY` or `AZURE_OPENAI_API_KEY` environment variable and then specifying the exact model parameters to be used in the `llm_config` that is passed to each agent specification. See the `get_default_agent_config()` method in `utils.py` to see an example of setting up `llm_config`. The example below shows how to configure access to an Azure OPENAI LLM.

```python
llm_config = LLMConfig(
config_list=[{
"model": "gpt-4",
"api_key": "<azure_api_key>",
"api_base": "<azure api base>",
"api_type": "azure",
"api_version": "2023-06-01-preview"
}],
temperature=0,
)
```
### Installation

```bash
export OPENAI_API_KEY=<your_api_key>
```
1. **Install from PyPi**

### Install and Run
We recommend using a virtual environment (e.g., conda) to avoid conflicts with existing Python packages. With Python 3.10 or newer active in your virtual environment, use pip to install AutoGen Assistant:

To install a prebuilt version of the app from PyPi. We highly recommend using a virtual environment (e.g. miniconda) and **python 3.10+** to avoid dependency conflicts.
```bash
pip install autogenra
```

```bash
pip install autogenra
autogenra ui --port 8081 # run the web ui on port 8081
```
2. **Install from Source**

### Install from Source
> Note: This approach requires some familiarity with building interfaces in React.

To install the app from source, clone the repository and install the dependencies.
If you prefer to install from source, ensure you have Python 3.10+ and Node.js (version above 14.15.0) installed. Here's how you get started:

```bash
pip install -e .
```
- Clone the AutoGen Assistant repository and install its Python dependencies:

You will also need to build the app front end. Note that your Gatsby requires node > 14.15.0 . You may need to [upgrade your node](https://stackoverflow.com/questions/10075990/upgrading-node-js-to-latest-version) version as needed.
```bash
pip install -e .
```

```bash
npm install --global yarn
cd frontend
yarn install
yarn build
```
- Navigate to the `samples/apps/autogen-assistant/frontend` directory, install dependencies, and build the UI:

The command above will build the frontend ui and copy the build artifacts to the `autogenra` web ui folder. Note that you may have to run `npm install --force --legacy-peer-deps` to force resolve some peer dependencies.
```bash
npm install -g gatsby-cli
npm install --global yarn
cd frontend
yarn install
yarn build
```

Run the web ui:
For Windows users, to build the frontend, you may need alternative commands to build the frontend.

```bash

gatsby clean && rmdir /s /q ..\\autogenra\\web\\ui && (set \"PREFIX_PATH_VALUE=\" || ver>nul) && gatsby build --prefix-paths && xcopy /E /I /Y public ..\\autogenra\\web\\ui

````

### Running the Application

Once installed, run the web UI by entering the following in your terminal:

```bash
autogenra ui --port 8081 # run the web ui on port 8081
autogenra ui --port 8081
```

Navigate to <http://localhost:8081/> to view the web ui.
This will start the application on the specified port. Open your web browser and go to `http://localhost:8081/` to begin using AutoGen Assistant.

To update the web ui, navigate to the frontend directory, make changes and rebuild the ui.
Now that you have AutoGen Assistant installed and running, you are ready to explore its capabilities, including defining and modifying agent workflows, interacting with agents and sessions, and expanding agent skills.

## Capabilities

Expand Down Expand Up @@ -108,12 +101,18 @@ The agents responds by _writing and executing code_ to create a python program t

## FAQ

- How do I add more skills to the research assistant? This can be done by adding a new file with documented functions to `autogenra/web/skills/global` directory.
- How do I specify the agent configuration (e.g. temperature, model, agent system message, model etc). You can do either from the UI interface or by modifying the default agent configuration in `utils.py` (`get_default_agent_config()` method)
- How do I reset the conversation? You can reset the conversation by deleting the `database.sqlite` file. You can also delete user files by deleting the `autogenra/web/files/user/<user_id_md5hash>` folder.
- How do I view messages generated by agents? You can view the messages generated by the agents in the debug console. You can also view the messages in the `database.sqlite` file.
**Q: How can I add more skills to the AutoGen Assistant?**
A: You can extend the capabilities of your agents by adding new Python functions. The AutoGen Assistant interface also lets you directly paste functions that can be reused in the agent workflow.

**Q: Where can I adjust the agent configurations and settings?**
A: You can modify agent configurations directly from the UI or by editing the default configurations in the `utils.py` file under the `get_default_agent_config()` method (assuming you are building your own UI).

**Q: If I want to reset the conversation with an agent, how do I go about it?**
A: To reset your conversation history, you can delete the `database.sqlite` file. If you need to clear user-specific data, remove the relevant `autogenra/web/files/user/<user_id_md5hash>` folder.

**Q: Is it possible to view the output and messages generated by the agents during interactions?**
A: Yes, you can view the generated messages in the debug console of the web UI, providing insights into the agent interactions. Alternatively, you can inspect the `database.sqlite` file for a comprehensive record of messages.

## Acknowledgements

Based on the [AutoGen](https://microsoft.github.io/autogen) project.
Adapted in October 2023 from a research prototype (original credits: Gagan Bansal, Adam Fourney, Victor Dibia, Piali Choudhury, Saleema Amershi, Ahmed Awadallah, Chi Wang)
AutoGen assistant is Based on the [AutoGen](https://microsoft.github.io/autogen) project. It is adapted in October 2023 from a research prototype (original credits: Gagan Bansal, Adam Fourney, Victor Dibia, Piali Choudhury, Saleema Amershi, Ahmed Awadallah, Chi Wang)
3 changes: 3 additions & 0 deletions samples/apps/autogen-assistant/autogenra/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .autogenflow import *
from .autogenchat import *
from .datamodel import *
21 changes: 10 additions & 11 deletions samples/apps/autogen-assistant/autogenra/autogenchat.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import json
import time
from typing import List
from .datamodel import FlowConfig, Message
from .datamodel import AgentWorkFlowConfig, Message
from .utils import extract_successful_code_blocks, get_default_agent_config, get_modified_files
from .autogenflow import AutoGenFlow
from .autogenflow import AutoGenWorkFlowManager
import os


class ChatManager:
class AutoGenChatManager:
def __init__(self) -> None:
pass

def chat(self, message: Message, history: List, flow_config: FlowConfig = None, **kwargs) -> None:
def chat(self, message: Message, history: List, flow_config: AgentWorkFlowConfig = None, **kwargs) -> None:
work_dir = kwargs.get("work_dir", None)
scratch_dir = os.path.join(work_dir, "scratch")
skills_suffix = kwargs.get("skills_prompt", "")
Expand All @@ -21,7 +21,9 @@ def chat(self, message: Message, history: List, flow_config: FlowConfig = None,
flow_config = get_default_agent_config(scratch_dir, skills_suffix=skills_suffix)

# print("Flow config: ", flow_config)
flow = AutoGenFlow(config=flow_config, history=history, work_dir=scratch_dir, asst_prompt=skills_suffix)
flow = AutoGenWorkFlowManager(
config=flow_config, history=history, work_dir=scratch_dir, assistant_prompt=skills_suffix
)
message_text = message.content.strip()

output = ""
Expand All @@ -36,11 +38,7 @@ def chat(self, message: Message, history: List, flow_config: FlowConfig = None,
successful_code_blocks = extract_successful_code_blocks(agent_chat_messages)
successful_code_blocks = "\n\n".join(successful_code_blocks)
output = (
(
flow.sender.last_message()["content"]
+ "\n The following code snippets were used: \n"
+ successful_code_blocks
)
(flow.sender.last_message()["content"] + "\n" + successful_code_blocks)
if successful_code_blocks
else flow.sender.last_message()["content"]
)
Expand All @@ -51,14 +49,15 @@ def chat(self, message: Message, history: List, flow_config: FlowConfig = None,
modified_files = get_modified_files(start_time, end_time, scratch_dir, dest_dir=work_dir)
metadata["files"] = modified_files

print("Modified files: ", modified_files)
print("Modified files: ", len(modified_files))

output_message = Message(
user_id=message.user_id,
root_msg_id=message.root_msg_id,
role="assistant",
content=output,
metadata=json.dumps(metadata),
session_id=message.session_id,
)

return output_message
19 changes: 12 additions & 7 deletions samples/apps/autogen-assistant/autogenra/autogenflow.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
from typing import List, Optional
from dataclasses import asdict
import autogen
from .datamodel import AgentFlowSpec, FlowConfig, Message
from .datamodel import AgentFlowSpec, AgentWorkFlowConfig, Message


class AutoGenFlow:
class AutoGenWorkFlowManager:
"""
AutoGenFlow class to load agents from a provided configuration and run a chat between them
AutoGenWorkFlowManager class to load agents from a provided configuration and run a chat between them
"""

def __init__(
self, config: FlowConfig, history: Optional[List[Message]] = None, work_dir: str = None, asst_prompt: str = None
self,
config: AgentWorkFlowConfig,
history: Optional[List[Message]] = None,
work_dir: str = None,
assistant_prompt: str = None,
) -> None:
"""
Initializes the AutoGenFlow with agents specified in the config and optional
Expand All @@ -21,8 +25,8 @@ def __init__(
history: An optional list of previous messages to populate the agents' history.

"""
self.work_dir = work_dir
self.asst_prompt = asst_prompt
self.work_dir = work_dir or "work_dir"
self.assistant_prompt = assistant_prompt or ""
self.sender = self.load(config.sender)
self.receiver = self.load(config.receiver)

Expand Down Expand Up @@ -87,13 +91,14 @@ def sanitize_agent_spec(self, agent_spec: AgentFlowSpec) -> AgentFlowSpec:
code_execution_config = agent_spec.config.code_execution_config or {}
code_execution_config["work_dir"] = self.work_dir
agent_spec.config.code_execution_config = code_execution_config

if agent_spec.type == "assistant":
agent_spec.config.system_message = (
autogen.AssistantAgent.DEFAULT_SYSTEM_MESSAGE
+ "\n\n"
+ agent_spec.config.system_message
+ "\n\n"
+ self.asst_prompt
+ self.assistant_prompt
)

return agent_spec
Expand Down
81 changes: 62 additions & 19 deletions samples/apps/autogen-assistant/autogenra/datamodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from datetime import datetime
from typing import Any, Callable, Dict, List, Literal, Optional, Union
from pydantic.dataclasses import dataclass
from dataclasses import field
from dataclasses import asdict, field


@dataclass
Expand All @@ -17,6 +17,7 @@ class Message(object):
ra: Optional[str] = None
code: Optional[str] = None
metadata: Optional[Any] = None
session_id: Optional[str] = None

def __post_init__(self):
if self.msg_id is None:
Expand All @@ -25,18 +26,9 @@ def __post_init__(self):
self.timestamp = datetime.now()

def dict(self):
return {
"user_id": self.user_id,
"role": self.role,
"content": self.content,
"root_msg_id": self.root_msg_id,
"msg_id": self.msg_id,
"timestamp": self.timestamp,
"personalize": self.personalize,
"ra": self.ra,
"code": self.code,
"metadata": self.metadata,
}
result = asdict(self)
result["timestamp"] = result["timestamp"].isoformat()
return result


# web api data models
Expand Down Expand Up @@ -69,7 +61,7 @@ class AgentConfig:
"""Data model for Agent Config for Autogen"""

name: str
llm_config: Optional[LLMConfig] = None
llm_config: Optional[Union[LLMConfig, bool]] = False
human_input_mode: str = "NEVER"
max_consecutive_auto_reply: int = 10
system_message: Optional[str] = None
Expand All @@ -86,35 +78,86 @@ class AgentFlowSpec:


@dataclass
class FlowConfig:
class AgentWorkFlowConfig:
"""Data model for Flow Config for Autogen"""

name: str
sender: AgentFlowSpec
receiver: Union[AgentFlowSpec, List[AgentFlowSpec]]
type: Literal["default", "groupchat"] = "default"

def dict(self):
return asdict(self)


@dataclass
class Session(object):
"""Data model for AutoGen Chat Session"""

user_id: str
session_id: Optional[str] = None
timestamp: Optional[datetime] = None
flow_config: AgentWorkFlowConfig = None

def __post_init__(self):
if self.timestamp is None:
self.timestamp = datetime.now()
if self.session_id is None:
self.session_id = str(uuid.uuid4())

def dict(self):
result = asdict(self)
result["timestamp"] = self.timestamp.isoformat()
return result


@dataclass
class Gallery(object):
"""Data model for Gallery Item"""

session: Session
messages: List[Message]
tags: List[str]
id: Optional[str] = None
timestamp: Optional[datetime] = None

def __post_init__(self):
if self.timestamp is None:
self.timestamp = datetime.now()
if self.id is None:
self.id = str(uuid.uuid4())

def dict(self):
result = asdict(self)
result["timestamp"] = self.timestamp.isoformat()
return result


@dataclass
class ChatWebRequestModel(object):
"""Data model for Chat Web Request for Web End"""

message: Message
flow_config: FlowConfig
flow_config: AgentWorkFlowConfig


@dataclass
class DeleteMessageWebRequestModel(object):
user_id: str
msg_id: str
session_id: Optional[str] = None


@dataclass
class ClearDBWebRequestModel(object):
class CreateSkillWebRequestModel(object):
user_id: str
skills: Union[str, List[str]]


@dataclass
class CreateSkillWebRequestModel(object):
class DBWebRequestModel(object):
user_id: str
skills: Union[str, List[str]]
msg_id: Optional[str] = None
session: Optional[Session] = None
skills: Optional[Union[str, List[str]]] = None
tags: Optional[List[str]] = None
Loading
Loading