Spaces:
Sleeping
Sleeping
Upload 13 files
Browse files- .gitattributes +1 -0
- AWorld-main/aworlddistributed/.dockerignore +11 -0
- AWorld-main/aworlddistributed/.env_examples +28 -0
- AWorld-main/aworlddistributed/.gitignore +16 -0
- AWorld-main/aworlddistributed/Dockerfile +76 -0
- AWorld-main/aworlddistributed/README.md +158 -0
- AWorld-main/aworlddistributed/base.py +72 -0
- AWorld-main/aworlddistributed/config.py +30 -0
- AWorld-main/aworlddistributed/debug_run.py +7 -0
- AWorld-main/aworlddistributed/docker-compose.yaml +22 -0
- AWorld-main/aworlddistributed/img.png +3 -0
- AWorld-main/aworlddistributed/main.py +143 -0
- AWorld-main/aworlddistributed/requirements.txt +44 -0
- AWorld-main/aworlddistributed/start.sh +45 -0
.gitattributes
CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
AWorld-main/aworlddistributed/img.png filter=lfs diff=lfs merge=lfs -text
|
AWorld-main/aworlddistributed/.dockerignore
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.venv
|
2 |
+
.env
|
3 |
+
.git
|
4 |
+
.gitignore
|
5 |
+
.github
|
6 |
+
Dockerfile
|
7 |
+
examples
|
8 |
+
docs
|
9 |
+
*.md
|
10 |
+
dev.sh
|
11 |
+
dev-docker.sh
|
AWorld-main/aworlddistributed/.env_examples
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Development settings
|
2 |
+
LOG_FILE_PATH="aworldserver.log"
|
3 |
+
|
4 |
+
FILESYSTEM_SERVER_WORKDIR=""
|
5 |
+
|
6 |
+
## LLM
|
7 |
+
LLM_PROVIDER=""
|
8 |
+
LLM_BASE_URL=""
|
9 |
+
LLM_API_KEY=""
|
10 |
+
|
11 |
+
## TAVILY
|
12 |
+
TAVILY_API_KEY="xxx"
|
13 |
+
|
14 |
+
|
15 |
+
AUDIO_LLM_API_KEY=""
|
16 |
+
AUDIO_LLM_BASE_URL=""
|
17 |
+
AUDIO_LLM_MODEL_NAME=""
|
18 |
+
|
19 |
+
GOOGLE_API_KEY=""
|
20 |
+
GOOGLE_SEARCH_ENGINE_ID=""
|
21 |
+
GOOGLE_CSE_ID=""
|
22 |
+
|
23 |
+
E2B_API_KEY=""
|
24 |
+
|
25 |
+
APIFY_API_TOKEN=""
|
26 |
+
|
27 |
+
AMAP_API_KEY=""
|
28 |
+
START_TRACE_SERVER="true"
|
AWorld-main/aworlddistributed/.gitignore
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
__pycache__
|
2 |
+
.env
|
3 |
+
|
4 |
+
/litellm
|
5 |
+
|
6 |
+
pipelines/*
|
7 |
+
!pipelines/.gitignore
|
8 |
+
.DS_Store
|
9 |
+
datasets/gaia_dataset/**
|
10 |
+
task_logs/**/*
|
11 |
+
task_logs/result/**/*
|
12 |
+
|
13 |
+
aworldspace/agents/**/*.json
|
14 |
+
|
15 |
+
.venv
|
16 |
+
venv/
|
AWorld-main/aworlddistributed/Dockerfile
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.11-slim-bookworm AS base
|
2 |
+
|
3 |
+
|
4 |
+
## Basis ##
|
5 |
+
ENV ENV=prod \
|
6 |
+
PORT=9099
|
7 |
+
|
8 |
+
# Install GCC and build tools.
|
9 |
+
# These are kept in the final image to enable installing packages on the fly.
|
10 |
+
RUN apt-get update && \
|
11 |
+
apt-get install -y gcc build-essential curl git && \
|
12 |
+
apt-get clean && \
|
13 |
+
rm -rf /var/lib/apt/lists/*
|
14 |
+
|
15 |
+
RUN apt-get update && apt-get install -y wget unzip openssh-client procps nodejs npm
|
16 |
+
|
17 |
+
ARG PIP_OPTIONS='-i https://mirrors.aliyun.com/pypi/simple/'
|
18 |
+
ARG ENABLE_OSS_MOUNT=""
|
19 |
+
|
20 |
+
RUN pip install -U pip pysocks ${PIP_OPTIONS}
|
21 |
+
|
22 |
+
# Install Chrome Driver
|
23 |
+
RUN mkdir /app
|
24 |
+
|
25 |
+
RUN cd /app/ && \
|
26 |
+
wget https://storage.googleapis.com/chrome-for-testing-public/136.0.7103.92/linux64/chromedriver-linux64.zip && \
|
27 |
+
unzip chromedriver-linux64.zip && \
|
28 |
+
rm chromedriver-linux64.zip
|
29 |
+
ENV CHROME_DRIVER_PATH=/app/chromedriver-linux64/chromedriver
|
30 |
+
|
31 |
+
|
32 |
+
RUN if [ "$ENABLE_OSS_MOUNT" = "true" ]; then \
|
33 |
+
apt-get update && \
|
34 |
+
apt-get install -y gdebi-core mime-support && \
|
35 |
+
cd /tmp && \
|
36 |
+
wget https://gosspublic.alicdn.com/ossfs/ossfs_1.91.6_ubuntu22.04_amd64.deb && \
|
37 |
+
gdebi ossfs_1.91.6_ubuntu22.04_amd64.deb -n && \
|
38 |
+
rm ossfs_1.91.6_ubuntu22.04_amd64.deb && \
|
39 |
+
apt-get clean && \
|
40 |
+
rm -rf /var/lib/apt/lists/*; \
|
41 |
+
fi
|
42 |
+
|
43 |
+
FROM base as runner
|
44 |
+
|
45 |
+
WORKDIR /app
|
46 |
+
|
47 |
+
# Install Python dependencies
|
48 |
+
COPY ./requirements.txt .
|
49 |
+
RUN pip3 install uv ${PIP_OPTIONS}
|
50 |
+
RUN uv pip install --system -r requirements.txt --no-cache-dir ${PIP_OPTIONS}
|
51 |
+
|
52 |
+
# Copy the application code
|
53 |
+
RUN echo "start install aworld"
|
54 |
+
RUN mkdir -p /app/lib
|
55 |
+
RUN cd /app/lib && git clone https://github.com/inclusionAI/AWorld.git
|
56 |
+
RUN cd /app/lib/AWorld && git checkout framework_upgrade_aworldserver_gaia && pip install -r aworld/requirements.txt ${PIP_OPTIONS} && python setup.py install
|
57 |
+
|
58 |
+
RUN npx playwright install chrome --with-deps --no-shell
|
59 |
+
|
60 |
+
RUN cd /app
|
61 |
+
|
62 |
+
|
63 |
+
|
64 |
+
# Layer on for other components
|
65 |
+
FROM runner AS app
|
66 |
+
|
67 |
+
WORKDIR /app
|
68 |
+
|
69 |
+
COPY . .
|
70 |
+
|
71 |
+
# Expose the port
|
72 |
+
ENV HOST="0.0.0.0"
|
73 |
+
ENV PORT="9099"
|
74 |
+
|
75 |
+
# if we already installed the requirements on build, we can skip this step on run
|
76 |
+
ENTRYPOINT [ "bash", "start.sh" ]
|
AWorld-main/aworlddistributed/README.md
ADDED
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# AworldServer
|
2 |
+
|
3 |
+
AworldServer is an execution environment for the Aworld framework that integrates MCP LLM models. It supports distributed deployment and dynamic scaling.
|
4 |
+
|
5 |
+

|
6 |
+
|
7 |
+
The system features:
|
8 |
+
|
9 |
+
- Distributed Architecture: Supports multi-server deployment with load balancing
|
10 |
+
- Dynamic Scaling: Ability to adjust server capacity based on demand
|
11 |
+
- LLM Integration: Built-in MCP LLM model support
|
12 |
+
- Asynchronous Processing: Uses asynchronous programming patterns for improved performance
|
13 |
+
- Containerized Deployment: Docker containerization support for easy environment management
|
14 |
+
|
15 |
+
|
16 |
+
|
17 |
+
## 🚀 Quick Start
|
18 |
+
|
19 |
+
1. Start services using Docker Compose:
|
20 |
+
|
21 |
+
```sh
|
22 |
+
docker build --build-arg MINIMUM_BUILD=true -f Dockerfile --progress=plain -t aworldserver:main .
|
23 |
+
|
24 |
+
docker compose up -d
|
25 |
+
```
|
26 |
+
2. Configure the number of server instances:
|
27 |
+
|
28 |
+
You can modify the `docker-compose.yaml` file to adjust the number of server instances. The default configuration includes 3 instances:
|
29 |
+
|
30 |
+
3. Usage Methods:
|
31 |
+
|
32 |
+
a. OpenWebUI Integration:
|
33 |
+
- Configure external link in OpenWebUI settings
|
34 |
+
- Add AworldServer endpoints to the configuration
|
35 |
+
- Set up API key authentication
|
36 |
+
|
37 |
+
b. Python Client Usage:
|
38 |
+
```python
|
39 |
+
# Initialize AworldTaskClient with server endpoints
|
40 |
+
AWORLD_TASK_CLIENT = AworldTaskClient(
|
41 |
+
know_hosts=["localhost:9299", "localhost:9399", "localhost:9499"]
|
42 |
+
)
|
43 |
+
|
44 |
+
async def _run_gaia_task(gaia_question_id: str) -> None:
|
45 |
+
"""Run a single Gaia task with the given question ID.
|
46 |
+
|
47 |
+
Args:
|
48 |
+
gaia_question_id: The ID of the question to process
|
49 |
+
"""
|
50 |
+
global AWORLD_TASK_CLIENT
|
51 |
+
task_id = str(uuid.uuid4())
|
52 |
+
|
53 |
+
# Submit task to Aworld server
|
54 |
+
await AWORLD_TASK_CLIENT.submit_task(
|
55 |
+
AworldTask(
|
56 |
+
task_id=task_id,
|
57 |
+
agent_id="gaia_agent",
|
58 |
+
agent_input=gaia_question_id,
|
59 |
+
session_id="session_id",
|
60 |
+
user_id="SYSTEM"
|
61 |
+
)
|
62 |
+
)
|
63 |
+
|
64 |
+
# Get and print task result
|
65 |
+
task_result = await AWORLD_TASK_CLIENT.get_task_state(task_id=task_id)
|
66 |
+
print(task_result)
|
67 |
+
|
68 |
+
async def _batch_run_gaia_task(start_i: int, end_i: int) -> None:
|
69 |
+
"""Run multiple Gaia tasks in parallel.
|
70 |
+
|
71 |
+
Args:
|
72 |
+
start_i: Starting question ID
|
73 |
+
end_i: Ending question ID
|
74 |
+
"""
|
75 |
+
tasks = [
|
76 |
+
_run_gaia_task(str(i))
|
77 |
+
for i in range(start_i, end_i + 1)
|
78 |
+
]
|
79 |
+
await asyncio.gather(*tasks)
|
80 |
+
|
81 |
+
if __name__ == '__main__':
|
82 |
+
# Run batch processing for questions 1-5
|
83 |
+
asyncio.run(_batch_run_gaia_task(1, 5))
|
84 |
+
```
|
85 |
+
c. user curl
|
86 |
+
```shell
|
87 |
+
curl http://localhost:9299/v1/chat/completions \
|
88 |
+
-H "Content-Type: application/json" \
|
89 |
+
-H "Authorization: Bearer 0p3n-w3bu!" \
|
90 |
+
-d '{
|
91 |
+
"model": "gaia_agent",
|
92 |
+
"messages": [
|
93 |
+
{
|
94 |
+
"role": "user",
|
95 |
+
"content": [
|
96 |
+
{
|
97 |
+
"type": "text",
|
98 |
+
"text": "5"
|
99 |
+
}
|
100 |
+
]
|
101 |
+
}
|
102 |
+
]
|
103 |
+
}'
|
104 |
+
|
105 |
+
```
|
106 |
+
|
107 |
+
|
108 |
+
## 🔑 Key Features
|
109 |
+
|
110 |
+
- **Distributed Task Processing System**
|
111 |
+
- Multi-server load balancing
|
112 |
+
- Round-robin task distribution
|
113 |
+
- Asynchronous task processing
|
114 |
+
|
115 |
+
- **Docker Containerization**
|
116 |
+
- Multi-instance deployment
|
117 |
+
- Environment variable configuration
|
118 |
+
- Auto-restart mechanism
|
119 |
+
|
120 |
+
- **API Services**
|
121 |
+
- FastAPI framework support
|
122 |
+
- RESTful API design
|
123 |
+
- Asynchronous request handling
|
124 |
+
|
125 |
+
- **Development Tools**
|
126 |
+
- Debug mode support
|
127 |
+
- Batch task processing
|
128 |
+
- Task state tracking
|
129 |
+
|
130 |
+
- **Security Features**
|
131 |
+
- API key authentication
|
132 |
+
- Session management
|
133 |
+
- User authentication
|
134 |
+
|
135 |
+
|
136 |
+
|
137 |
+
## 📦 Installation and Setup
|
138 |
+
|
139 |
+
Get started with aworldserver in a few easy steps:
|
140 |
+
|
141 |
+
1. **Ensure Python 3.11 is installed.**
|
142 |
+
|
143 |
+
2. **Install the required dependencies:**
|
144 |
+
|
145 |
+
```sh
|
146 |
+
pip install -r requirements-minimux.txt
|
147 |
+
```
|
148 |
+
|
149 |
+
3. **Start the aworld server:**
|
150 |
+
|
151 |
+
```sh
|
152 |
+
sh ./start.sh
|
153 |
+
```
|
154 |
+
### Custom debug
|
155 |
+
|
156 |
+
please run `debug_run.py`
|
157 |
+
|
158 |
+
##
|
AWorld-main/aworlddistributed/base.py
ADDED
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import uuid
|
2 |
+
from typing import Any
|
3 |
+
from typing import List, Optional
|
4 |
+
from datetime import datetime
|
5 |
+
|
6 |
+
from pydantic import BaseModel, ConfigDict
|
7 |
+
from pydantic import Field
|
8 |
+
|
9 |
+
|
10 |
+
class AworldTask(BaseModel):
|
11 |
+
task_id: str = Field(default=None, description="task id")
|
12 |
+
agent_id: str = Field(default=None, description="agent id")
|
13 |
+
agent_input: str = Field(default=None, description="agent input")
|
14 |
+
session_id: Optional[str] = Field(default=None, description="session id")
|
15 |
+
user_id: Optional[str] = Field(default=None, description="user id")
|
16 |
+
llm_provider: Optional[str] = Field(default=None, description="llm provider")
|
17 |
+
llm_model_name: Optional[str] = Field(default=None, description="llm model name")
|
18 |
+
llm_api_key: Optional[str] = Field(default=None, description="llm api key")
|
19 |
+
llm_base_url: Optional[str] = Field(default=None, description="llm base url")
|
20 |
+
llm_custom_input: Optional[str] = Field(default=None, description="custom_input")
|
21 |
+
task_system_prompt: Optional[str] = Field(default=None, description="task_system_prompt")
|
22 |
+
mcp_servers: Optional[list[str]] = Field(default=None, description="mcp_servers")
|
23 |
+
node_id: Optional[str] = Field(default=None, description="execute task node_id")
|
24 |
+
client_id: Optional[str] = Field(default=None, description="submit client ip")
|
25 |
+
status: Optional[str] = Field(default="INIT", description="submitted/running/execute_failed/execute_success")
|
26 |
+
history_messages: Optional[int] = Field(default=100, description="history_message")
|
27 |
+
max_steps: Optional[int] = Field(default=100, description="max_steps")
|
28 |
+
max_retries: Optional[int] = Field(default=5, description="max_retries use Exponential backoff with jitter")
|
29 |
+
ext_info: Optional[dict] = Field(default_factory=dict, description="custom")
|
30 |
+
created_at: Optional[datetime] = Field(default=None, description="created time")
|
31 |
+
updated_at: Optional[datetime] = Field(default=None, description="updated time")
|
32 |
+
|
33 |
+
def mark_running(self):
|
34 |
+
self.status = 'RUNNING'
|
35 |
+
|
36 |
+
def mark_failed(self):
|
37 |
+
self.status = 'FAILED'
|
38 |
+
|
39 |
+
def mark_success(self):
|
40 |
+
self.status = 'SUCCESS'
|
41 |
+
|
42 |
+
class AworldTaskResult(BaseModel):
|
43 |
+
task: AworldTask = Field(default=None, description="task")
|
44 |
+
server_host: Optional[str] = Field(default=None, description="aworld server id")
|
45 |
+
data: Any = Field(default=None, description="result data")
|
46 |
+
|
47 |
+
class AworldTaskForm(BaseModel):
|
48 |
+
batch_id: str = Field(default=str(uuid.uuid4()), description="batch_id")
|
49 |
+
task: Optional[AworldTask] = Field(default=None, description="task")
|
50 |
+
user_id: Optional[str] = Field(default=None, description="user id")
|
51 |
+
client_id: Optional[str] = Field(default=None, description="submit client ip")
|
52 |
+
|
53 |
+
|
54 |
+
class OpenAIChatMessage(BaseModel):
|
55 |
+
role: str
|
56 |
+
content: str | List
|
57 |
+
|
58 |
+
model_config = ConfigDict(extra="allow")
|
59 |
+
|
60 |
+
|
61 |
+
class OpenAIChatCompletionForm(BaseModel):
|
62 |
+
stream: bool = True
|
63 |
+
model: str
|
64 |
+
messages: List[OpenAIChatMessage]
|
65 |
+
|
66 |
+
model_config = ConfigDict(extra="allow")
|
67 |
+
|
68 |
+
|
69 |
+
class FilterForm(BaseModel):
|
70 |
+
body: dict
|
71 |
+
user: Optional[dict] = None
|
72 |
+
model_config = ConfigDict(extra="allow")
|
AWorld-main/aworlddistributed/config.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import logging
|
3 |
+
from pathlib import Path
|
4 |
+
|
5 |
+
from aworld.utils.common import get_local_ip
|
6 |
+
|
7 |
+
####################################
|
8 |
+
# Load .env file
|
9 |
+
####################################
|
10 |
+
|
11 |
+
try:
|
12 |
+
from dotenv import load_dotenv, find_dotenv
|
13 |
+
|
14 |
+
load_dotenv(find_dotenv("./.env"))
|
15 |
+
except ImportError:
|
16 |
+
print("dotenv not installed, skipping...")
|
17 |
+
|
18 |
+
# Define log levels dictionary
|
19 |
+
LOG_LEVELS = {
|
20 |
+
'DEBUG': logging.DEBUG,
|
21 |
+
'INFO': logging.INFO,
|
22 |
+
'WARNING': logging.WARNING,
|
23 |
+
'ERROR': logging.ERROR,
|
24 |
+
'CRITICAL': logging.CRITICAL
|
25 |
+
}
|
26 |
+
ROOT_DIR = Path(__file__).parent # the path containing this file
|
27 |
+
AGENTS_DIR = os.getenv("AGENTS_DIR", "./aworldspace/agents")
|
28 |
+
ROOT_LOG = os.path.join(os.getenv("LOG_DIR_PATH", "logs") , get_local_ip())
|
29 |
+
WORKSPACE_TYPE = os.environ.get("WORKSPACE_TYPE", "local")
|
30 |
+
WORKSPACE_PATH = os.environ.get("WORKSPACE_PATH", "./data/workspaces")
|
AWorld-main/aworlddistributed/debug_run.py
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import uvicorn
|
2 |
+
from dotenv import load_dotenv
|
3 |
+
|
4 |
+
if __name__ == "__main__":
|
5 |
+
load_dotenv()
|
6 |
+
import main
|
7 |
+
uvicorn.run(main.app, host="0.0.0.0", port=9999)
|
AWorld-main/aworlddistributed/docker-compose.yaml
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
services:
|
2 |
+
aworldserver-1:
|
3 |
+
image: aworldserver:main
|
4 |
+
volumes:
|
5 |
+
- ./.env:/app/.env
|
6 |
+
ports:
|
7 |
+
- "9299:9099"
|
8 |
+
restart: always
|
9 |
+
aworldserver-2:
|
10 |
+
image: aworldserver:main
|
11 |
+
volumes:
|
12 |
+
- ./.env:/app/.env
|
13 |
+
ports:
|
14 |
+
- "9399:9099"
|
15 |
+
restart: always
|
16 |
+
aworldserver-3:
|
17 |
+
image: aworldserver:main
|
18 |
+
volumes:
|
19 |
+
- ./.env:/app/.env
|
20 |
+
ports:
|
21 |
+
- "9499:9099"
|
22 |
+
restart: always
|
AWorld-main/aworlddistributed/img.png
ADDED
![]() |
Git LFS Details
|
AWorld-main/aworlddistributed/main.py
ADDED
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import logging
|
2 |
+
import os
|
3 |
+
import time
|
4 |
+
from contextlib import asynccontextmanager
|
5 |
+
from logging.handlers import TimedRotatingFileHandler
|
6 |
+
import uvicorn
|
7 |
+
|
8 |
+
from fastapi import FastAPI, Request
|
9 |
+
from fastapi.middleware.cors import CORSMiddleware
|
10 |
+
|
11 |
+
from aworld.cmd.web.routers import workspaces
|
12 |
+
from aworldspace.routes import tasks
|
13 |
+
from aworldspace.utils.job import generate_openai_chat_completion
|
14 |
+
from aworldspace.utils.loader import load_modules_from_directory, PIPELINE_MODULES, PIPELINES
|
15 |
+
from base import OpenAIChatCompletionForm
|
16 |
+
from config import AGENTS_DIR, LOG_LEVELS, ROOT_LOG
|
17 |
+
|
18 |
+
if not os.path.exists(AGENTS_DIR):
|
19 |
+
os.makedirs(AGENTS_DIR)
|
20 |
+
|
21 |
+
# Add GLOBAL_LOG_LEVEL for Pipeplines
|
22 |
+
log_level = os.getenv("GLOBAL_LOG_LEVEL", "INFO").upper()
|
23 |
+
logging.basicConfig(level=LOG_LEVELS[log_level])
|
24 |
+
def setup_logging():
|
25 |
+
logger = logging.getLogger()
|
26 |
+
logger.setLevel(logging.INFO)
|
27 |
+
log_dir = ROOT_LOG
|
28 |
+
if not os.path.exists(log_dir):
|
29 |
+
os.makedirs(log_dir)
|
30 |
+
log_path = os.path.join(log_dir, "aworldserver.log")
|
31 |
+
file_handler = TimedRotatingFileHandler(log_path, when='H', interval=1, backupCount=24)
|
32 |
+
file_handler.setLevel(logging.INFO)
|
33 |
+
|
34 |
+
formatter = logging.Formatter(
|
35 |
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
36 |
+
)
|
37 |
+
file_handler.setFormatter(formatter)
|
38 |
+
|
39 |
+
error_log_path = os.path.join(log_dir, "aworldserver_error.log")
|
40 |
+
error_file_handler = TimedRotatingFileHandler(error_log_path, when='D', interval=1, backupCount=24)
|
41 |
+
error_file_handler.setLevel(logging.WARNING)
|
42 |
+
error_file_handler.setFormatter(formatter)
|
43 |
+
|
44 |
+
logger.addHandler(file_handler)
|
45 |
+
logger.addHandler(error_file_handler)
|
46 |
+
setup_logging()
|
47 |
+
|
48 |
+
|
49 |
+
async def on_startup():
|
50 |
+
await load_modules_from_directory(AGENTS_DIR)
|
51 |
+
await tasks.task_manager.start_task_executor()
|
52 |
+
|
53 |
+
for module in PIPELINE_MODULES.values():
|
54 |
+
if hasattr(module, "on_startup"):
|
55 |
+
await module.on_startup()
|
56 |
+
|
57 |
+
|
58 |
+
async def on_shutdown():
|
59 |
+
for module in PIPELINE_MODULES.values():
|
60 |
+
if hasattr(module, "on_shutdown"):
|
61 |
+
await module.on_shutdown()
|
62 |
+
|
63 |
+
|
64 |
+
async def reload():
|
65 |
+
await on_shutdown()
|
66 |
+
# Clear existing pipelines
|
67 |
+
PIPELINES.clear()
|
68 |
+
PIPELINE_MODULES.clear()
|
69 |
+
# Load pipelines afresh
|
70 |
+
await on_startup()
|
71 |
+
|
72 |
+
|
73 |
+
@asynccontextmanager
|
74 |
+
async def lifespan(app: FastAPI):
|
75 |
+
await on_startup()
|
76 |
+
yield
|
77 |
+
await on_shutdown()
|
78 |
+
|
79 |
+
|
80 |
+
app = FastAPI(docs_url="/docs", redoc_url=None, lifespan=lifespan)
|
81 |
+
|
82 |
+
|
83 |
+
origins = ["*"]
|
84 |
+
|
85 |
+
|
86 |
+
app.add_middleware(
|
87 |
+
CORSMiddleware,
|
88 |
+
allow_origins=origins,
|
89 |
+
allow_credentials=True,
|
90 |
+
allow_methods=["*"],
|
91 |
+
allow_headers=["*"],
|
92 |
+
)
|
93 |
+
app.include_router(tasks.router, prefix="/api/v1/tasks", tags=["tasks"])
|
94 |
+
app.include_router(workspaces.router, prefix="/api/v1/workspaces", tags=["workspace"])
|
95 |
+
|
96 |
+
|
97 |
+
@app.middleware("http")
|
98 |
+
async def check_url(request: Request, call_next):
|
99 |
+
start_time = int(time.time())
|
100 |
+
response = await call_next(request)
|
101 |
+
process_time = int(time.time()) - start_time
|
102 |
+
response.headers["X-Process-Time"] = str(process_time)
|
103 |
+
|
104 |
+
return response
|
105 |
+
|
106 |
+
@app.get("/v1")
|
107 |
+
@app.get("/")
|
108 |
+
async def get_status():
|
109 |
+
return {"status": True}
|
110 |
+
|
111 |
+
|
112 |
+
@app.post("/v1/chat/completions")
|
113 |
+
@app.post("/chat/completions")
|
114 |
+
async def chat_completion(form_data: OpenAIChatCompletionForm, request: Request
|
115 |
+
):
|
116 |
+
# Extract headers into a dict
|
117 |
+
headers = request.headers
|
118 |
+
if headers.get("x-aworld-session-id"):
|
119 |
+
metadata = {
|
120 |
+
"user_id": headers.get("x-aworld-user-id"),
|
121 |
+
"chat_id": headers.get("x-aworld-session-id"),
|
122 |
+
"message_id": headers.get("x-aworld-message-id")
|
123 |
+
}
|
124 |
+
|
125 |
+
# Add metadata to form_data
|
126 |
+
form_data.metadata = metadata
|
127 |
+
|
128 |
+
return await generate_openai_chat_completion(form_data)
|
129 |
+
|
130 |
+
@app.get("/health")
|
131 |
+
async def healthcheck():
|
132 |
+
return {
|
133 |
+
"status": True
|
134 |
+
}
|
135 |
+
|
136 |
+
|
137 |
+
if __name__ == "__main__":
|
138 |
+
uvicorn.run(
|
139 |
+
"aworlddistributed.main:app",
|
140 |
+
host="0.0.0.0",
|
141 |
+
port=8088,
|
142 |
+
reload=True,
|
143 |
+
)
|
AWorld-main/aworlddistributed/requirements.txt
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--index-url https://mirrors.aliyun.com/pypi/simple/
|
2 |
+
|
3 |
+
fastapi==0.111.0
|
4 |
+
uvicorn[standard]==0.23.1
|
5 |
+
pydantic==2.9.2
|
6 |
+
python-multipart==0.0.9
|
7 |
+
python-socketio
|
8 |
+
grpcio
|
9 |
+
|
10 |
+
passlib==1.7.4
|
11 |
+
passlib[bcrypt]
|
12 |
+
PyJWT[crypto]
|
13 |
+
|
14 |
+
requests==2.32.2
|
15 |
+
aiohttp==3.9.5
|
16 |
+
httpx
|
17 |
+
|
18 |
+
datasets==3.3.2
|
19 |
+
executing
|
20 |
+
flask
|
21 |
+
openpyxl
|
22 |
+
selenium==4.32.0
|
23 |
+
fitz==0.0.1.dev2
|
24 |
+
tabulate==0.9.0
|
25 |
+
frontend
|
26 |
+
tools
|
27 |
+
PyPDF2
|
28 |
+
html2text
|
29 |
+
xmltodict
|
30 |
+
docx2markdown
|
31 |
+
python-pptx
|
32 |
+
browser_use
|
33 |
+
|
34 |
+
oss2
|
35 |
+
prometheus_client~=0.21.1
|
36 |
+
opentelemetry-sdk~=1.32.1
|
37 |
+
opentelemetry-api~=1.32.1
|
38 |
+
opentelemetry-exporter-otlp~=1.32.1
|
39 |
+
opentelemetry-instrumentation-system-metrics~=0.53b1
|
40 |
+
e2b_code_interpreter
|
41 |
+
|
42 |
+
sqlalchemy~=2.0.40
|
43 |
+
psycopg2-binary==2.9.9
|
44 |
+
bcrypt==4.3.0
|
AWorld-main/aworlddistributed/start.sh
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env bash
|
2 |
+
PORT="${PORT:-9099}"
|
3 |
+
HOST="${HOST:-0.0.0.0}"
|
4 |
+
# Default value for PIPELINES_DIR
|
5 |
+
PIPELINES_DIR=${PIPELINES_DIR:-./aworldspace/agents}
|
6 |
+
|
7 |
+
UVICORN_LOOP="${UVICORN_LOOP:-auto}"
|
8 |
+
|
9 |
+
# OSS mount configuration - read from environment variables
|
10 |
+
if [ -n "$OSS_BUCKET" ] && [ -n "$OSS_AK_ID" ] && [ -n "$OSS_AK_SECRET" ]; then
|
11 |
+
echo "Configuring OSS mount..."
|
12 |
+
|
13 |
+
# Create OSS credentials file
|
14 |
+
echo "${OSS_BUCKET}:${OSS_AK_ID}:${OSS_AK_SECRET}" >> /etc/passwd-ossfs
|
15 |
+
chmod 640 /etc/passwd-ossfs
|
16 |
+
|
17 |
+
# Create mount point directories if they don't exist
|
18 |
+
mkdir -p /app/logs
|
19 |
+
mkdir -p /app/trace_data
|
20 |
+
mkdir -p /app/aworldspace/datasets
|
21 |
+
|
22 |
+
# Mount OSS directories
|
23 |
+
echo "Mounting OSS directories..."
|
24 |
+
if [ -n "$OSS_REGION_URL" ] && [ -n "$OSS_BUCKET_URL" ]; then
|
25 |
+
# Use custom region and URL
|
26 |
+
ossfs ${OSS_BUCKET}:/aworld/logs /app/logs -odirect_read -ononempty -oregion=${OSS_REGION_URL} -ourl=${OSS_BUCKET_URL} &
|
27 |
+
ossfs ${OSS_BUCKET}:/aworld/trace_data /app/trace_data -odirect_read -ononempty -oregion=${OSS_REGION_URL} -ourl=${OSS_BUCKET_URL} &
|
28 |
+
ossfs ${OSS_BUCKET}:/aworld/datasets /app/aworldspace/datasets -odirect_read -ononempty -oregion=${OSS_REGION_URL} -ourl=${OSS_BUCKET_URL} &
|
29 |
+
else
|
30 |
+
# Use default configuration
|
31 |
+
ossfs ${OSS_BUCKET}:/aworld/logs /app/logs -odirect_read -ononempty &
|
32 |
+
ossfs ${OSS_BUCKET}:/aworld/trace_data /app/trace_data -odirect_read -ononempty &
|
33 |
+
ossfs ${OSS_BUCKET}:/aworld/datasets /app/aworldspace/datasets -odirect_read -ononempty &
|
34 |
+
fi
|
35 |
+
|
36 |
+
# Wait for mount to complete
|
37 |
+
sleep 2
|
38 |
+
echo "OSS mount configuration completed"
|
39 |
+
else
|
40 |
+
echo "OSS configuration incomplete, skipping OSS mount"
|
41 |
+
fi
|
42 |
+
|
43 |
+
|
44 |
+
uvicorn main:app --host "$HOST" --port "$PORT" --forwarded-allow-ips '*' --loop "$UVICORN_LOOP"
|
45 |
+
|