Duibonduil commited on
Commit
64a1e64
·
verified ·
1 Parent(s): d7757a5

Upload 6 files

Browse files
aworld/cmd/web_legacy/chat.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import sys
3
+ import streamlit as st
4
+ from dotenv import load_dotenv
5
+ import logging
6
+ import os
7
+ import traceback
8
+ import importlib.util
9
+ import utils
10
+ import aworld.trace as trace
11
+ from trace_net import generate_trace_graph_full
12
+ from aworld.trace.base import get_tracer_provider
13
+
14
+ load_dotenv(os.path.join(os.getcwd(), ".env"))
15
+
16
+ logging.basicConfig(level=logging.INFO)
17
+ logger = logging.getLogger(__name__)
18
+
19
+ sys.path.insert(0, os.getcwd())
20
+
21
+
22
+ def agent_page():
23
+ st.set_page_config(
24
+ page_title="AWorld Agent",
25
+ page_icon=":robot_face:",
26
+ layout="wide",
27
+ )
28
+
29
+ st.markdown(
30
+ """\
31
+ <style>
32
+ .stAppHeader { display: none; }
33
+
34
+ div[data-testid="stMarkdownContainer"] pre {
35
+ max-height: 300px;
36
+ overflow-y: auto;
37
+ }
38
+ div[data-testid="stMarkdownContainer"] img {
39
+ max-height: 500px;
40
+ }
41
+ </style>""",
42
+ unsafe_allow_html=True,
43
+ )
44
+
45
+ query_params = st.query_params
46
+ selected_agent_from_url = query_params.get("agent", None)
47
+
48
+ if "selected_agent" not in st.session_state:
49
+ st.session_state.selected_agent = selected_agent_from_url
50
+ logger.info(f"Initialized selected_agent from URL: {selected_agent_from_url}")
51
+
52
+ if selected_agent_from_url != st.session_state.selected_agent:
53
+ st.session_state.selected_agent = selected_agent_from_url
54
+
55
+ with st.sidebar:
56
+ st.title("AWorld Agents List")
57
+ for agent in utils.list_agents():
58
+ if st.button(agent):
59
+ st.query_params["agent"] = agent
60
+ st.session_state.selected_agent = agent
61
+ logger.info(f"selected_agent={st.session_state.selected_agent}")
62
+
63
+ if st.session_state.selected_agent:
64
+ agent_name = st.session_state.selected_agent
65
+ st.title(f"AWorld Agent: {agent_name}")
66
+
67
+ if prompt := st.chat_input("Input message here~"):
68
+
69
+ with st.chat_message("user"):
70
+ st.markdown(prompt)
71
+
72
+ with st.chat_message("assistant"):
73
+ agent_name = st.session_state.selected_agent
74
+ agent_package_path = utils.get_agent_package_path(agent_name)
75
+ agent_module_file = os.path.join(agent_package_path, "agent.py")
76
+ try:
77
+ spec = importlib.util.spec_from_file_location(
78
+ agent_name, agent_module_file
79
+ )
80
+
81
+ if spec is None or spec.loader is None:
82
+ logger.error(
83
+ f"Could not load spec for agent {agent_name} from {agent_module_file}"
84
+ )
85
+ st.error(f"Error: Could not load agent! {agent_name}")
86
+ return
87
+
88
+ agent_module = importlib.util.module_from_spec(spec)
89
+ spec.loader.exec_module(agent_module)
90
+ except Exception as e:
91
+ logger.error(
92
+ f"Error loading agent {agent_name}, cwd:{os.getcwd()}, sys.path:{sys.path}: {traceback.format_exc()}"
93
+ )
94
+ st.error(f"Error: Could not load agent! {agent_name}")
95
+ return
96
+
97
+ agent = agent_module.AWorldAgent()
98
+
99
+ async def markdown_generator():
100
+ trace_id = None
101
+ async with trace.span("start") as span:
102
+ trace_id = span.get_trace_id()
103
+ async for line in agent.run(prompt):
104
+ st.write(line)
105
+ await asyncio.sleep(0.1)
106
+
107
+ get_tracer_provider().force_flush(5000)
108
+ file_name = f"graph.{trace_id}.html"
109
+ folder_name = "trace_data"
110
+ generate_trace_graph_full(
111
+ trace_id, folder_name=folder_name, file_name=file_name
112
+ )
113
+ view_page_url = f"/trace?trace_id={trace_id}"
114
+ st.write(f"\n---\n[View Trace]({view_page_url})\n")
115
+
116
+ asyncio.run(markdown_generator())
117
+ else:
118
+ st.title("AWorld Agent Chat Assistant")
119
+ st.info("Please select an Agent from the left sidebar to start")
120
+
121
+
122
+ try:
123
+ agent_page()
124
+ except Exception as e:
125
+ logger.error(f">>> Error: {traceback.format_exc()}")
126
+ st.error(f"Error: {str(e)}")
aworld/cmd/web_legacy/main.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from dotenv import load_dotenv
3
+ import logging
4
+ import os
5
+ import aworld.trace as trace
6
+
7
+ load_dotenv(os.path.join(os.getcwd(), ".env"))
8
+
9
+ logging.basicConfig(level=logging.INFO)
10
+ logger = logging.getLogger(__name__)
11
+
12
+ trace.configure()
13
+
14
+ chat = st.Page("chat.py", title="Chat", icon=":material/message:")
15
+ trace = st.Page("trace.py", title="Trace")
16
+
17
+ pg = st.navigation([chat, trace], position="hidden")
18
+ pg.run()
aworld/cmd/web_legacy/trace.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import traceback
3
+ import streamlit as st
4
+ import os
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ def view_page():
9
+ st.set_page_config(
10
+ page_title="HTML Viewer",
11
+ page_icon=":robot_face:",
12
+ layout="wide",
13
+ )
14
+
15
+ st.markdown(
16
+ "<style> .stAppHeader { display: none !important;} .stMainBlockContainer { padding: 5px 10px !important; } </style>",
17
+ unsafe_allow_html=True,
18
+ )
19
+
20
+ query_params = st.query_params
21
+ trace_id = query_params.get("trace_id", None)
22
+
23
+ side, main = st.columns([2, 8])
24
+
25
+ with side:
26
+ if st.button("Back To Chat"):
27
+ st.switch_page("chat.py")
28
+
29
+ with main:
30
+ if trace_id:
31
+ try:
32
+ st.header(f"Chat Trace Graph: {trace_id}")
33
+ folder_name = "trace_data"
34
+ file_name = f"graph.{trace_id}.html"
35
+ html_file_path = os.path.join(
36
+ os.getcwd(), folder_name, file_name
37
+ )
38
+ with open(html_file_path, "r") as file:
39
+ html_content = file.read()
40
+
41
+ st.components.v1.html(html_content, height=600, scrolling=True)
42
+ except Exception as e:
43
+ logger.error(f"Error: {traceback.format_exc()}")
44
+ st.write(f"Error: {traceback.format_exc()}")
45
+ else:
46
+ st.write("Parameter error!")
47
+
48
+
49
+ if __name__ == "__main__":
50
+ view_page()
aworld/cmd/web_legacy/trace_net.py ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+ import os
4
+ from pyvis.network import Network
5
+ from aworld.logs.util import logger
6
+ from aworld.trace.base import get_tracer_provider_silent
7
+
8
+ run_type_colors = {
9
+ "LLM": "#E6E6FA",
10
+ "TOOL": "#99FF99", # green
11
+ "MCP": "#99FF99",
12
+ "AGENT": "#9999FF", # blue
13
+ "OTHER": "#FFFF99" # yellow
14
+ }
15
+
16
+
17
+ def get_span_color(span):
18
+ run_type = span.get('run_type', 'OTHER')
19
+ return run_type_colors.get(run_type, run_type_colors['OTHER'])
20
+
21
+
22
+ def fetch_trace_data(trace_id=None):
23
+ try:
24
+ if trace_id:
25
+ response = requests.get(
26
+ f'http://localhost:7079/api/traces/{trace_id}')
27
+ response.raise_for_status()
28
+ return response.json() or {"root_span": []}
29
+ except requests.exceptions.RequestException as e:
30
+ logger.error(f"Error fetching trace data: {e}")
31
+ return {"root_span": []}
32
+
33
+
34
+ def flatten_spans(node, result=None):
35
+ if result is None:
36
+ result = []
37
+ result.append(node)
38
+ for child in node.get('children', []):
39
+ flatten_spans(child, result)
40
+ return result
41
+
42
+
43
+ def generate_trace_graph(trace_id=None):
44
+ tracer_provider = get_tracer_provider_silent()
45
+ if tracer_provider:
46
+ tracer_provider.force_flush(5000)
47
+ trace_data = fetch_trace_data(trace_id)
48
+ net = Network(height="200px", width="100%",
49
+ notebook=False, cdn_resources='in_line')
50
+
51
+ net.set_options("""
52
+ {
53
+ "nodes": {
54
+ "font": {"size": 8}
55
+ },
56
+ "physics": {
57
+ "enabled": true,
58
+ "hierarchicalRepulsion": {
59
+ "centralGravity": 0.5,
60
+ "springLength": 150,
61
+ "nodeDistance": 120
62
+ }
63
+ },
64
+ "layout": {
65
+ "hierarchical": {
66
+ "enabled": true,
67
+ "direction": "LR",
68
+ "sortMethod": "directed",
69
+ "nodeSpacing": 50,
70
+ "levelSeparation": 100,
71
+ "blockShifting": true,
72
+ "edgeMinimization": true
73
+ }
74
+ }
75
+ }
76
+ """)
77
+ root_spans = trace_data['root_span']
78
+ all_spans = []
79
+ for span in root_spans:
80
+ all_spans.extend(flatten_spans(span))
81
+
82
+ spans = {span['span_id']: span for span in all_spans}
83
+ for span_id, span in spans.items():
84
+ title = f"{span['name']}\n({span['run_type']})"
85
+ net.add_node(span_id, label=title, title=title,
86
+ shape='box', color=get_span_color(span))
87
+ if span.get('parent_id') and span['parent_id'] in spans:
88
+ net.add_edge(span['parent_id'], span_id, arrows='to')
89
+
90
+ net.show('trace_graph.html', notebook=False)
91
+ with open('trace_graph.html', 'a') as f:
92
+ f.write(f"""
93
+ <style>
94
+ #fullscreenBtn {{
95
+ position: absolute;
96
+ top: 10px;
97
+ right: 10px;
98
+ padding: 8px 12px;
99
+ background: #4CAF50;
100
+ color: white;
101
+ border: none;
102
+ border-radius: 4px;
103
+ cursor: pointer;
104
+ z-index: 1000;
105
+ }}
106
+ </style>
107
+ <div style="margin-top: 20px; padding: 20px; border-top: 1px solid #eee;">
108
+ <h3>Span Details</h3>
109
+ <pre id="spanDetails" style="max-height: 600px; overflow-y: auto;">Click on a node to view details</pre>
110
+ </div>
111
+ <script>
112
+ function moveNodesOnce() {{
113
+ var nodes = network.body.nodes;
114
+ var offsetX = 100;
115
+ var offsetY = 80;
116
+ for (var nodeId in nodes) {{
117
+ if (nodes.hasOwnProperty(nodeId)) {{
118
+ var node = nodes[nodeId];
119
+ network.moveNode(nodeId, node.x + offsetX, node.y + offsetY);
120
+ }}
121
+ }}
122
+ network.off("afterDrawing", moveNodesOnce);
123
+ }}
124
+ network.on("afterDrawing", moveNodesOnce);
125
+
126
+ network.on("click", function(params) {{
127
+ var nodeId = params.nodes[0];
128
+ var spanData = {json.dumps(spans)}[nodeId];
129
+ var displayData = {{}};
130
+ for (var key in spanData) {{
131
+ if (key !== 'children') {{
132
+ displayData[key] = spanData[key];
133
+ }}
134
+ }}
135
+ document.getElementById("spanDetails").innerHTML =
136
+ JSON.stringify(displayData, null, 2);
137
+ }});
138
+ </script>
139
+ """)
140
+
141
+
142
+ def generate_trace_graph_full(trace_id=None, folder_name="", file_name="trace_graph_full.html"):
143
+ trace_data = fetch_trace_data(trace_id)
144
+ net = Network(height="100%", width="100%",
145
+ notebook=False, cdn_resources='in_line')
146
+
147
+ net.set_options("""
148
+ {
149
+ "nodes": {
150
+ "font": {"size": 8}
151
+ },
152
+ "physics": {
153
+ "enabled": true,
154
+ "hierarchicalRepulsion": {
155
+ "centralGravity": 0.5,
156
+ "springLength": 150,
157
+ "nodeDistance": 120
158
+ }
159
+ },
160
+ "layout": {
161
+ "hierarchical": {
162
+ "enabled": true,
163
+ "direction": "LR",
164
+ "sortMethod": "directed",
165
+ "nodeSpacing": 50,
166
+ "levelSeparation": 100,
167
+ "blockShifting": true,
168
+ "edgeMinimization": true
169
+ }
170
+ }
171
+ }
172
+ """)
173
+
174
+ root_spans = trace_data['root_span']
175
+ all_spans = []
176
+ for span in root_spans:
177
+ all_spans.extend(flatten_spans(span))
178
+ spans = {span['span_id']: span for span in all_spans}
179
+ for span_id, span in spans.items():
180
+ title = f"{span['name']}\n({span['run_type']})"
181
+ net.add_node(span_id, label=title, title=title,
182
+ shape='box', color=get_span_color(span))
183
+ if span.get('parent_id') and span['parent_id'] in spans:
184
+ net.add_edge(span['parent_id'], span_id, arrows='to')
185
+
186
+ folder_path = os.path.join(os.getcwd(), folder_name)
187
+ os.makedirs(folder_path, exist_ok=True)
188
+ file_path = os.path.join(folder_path, file_name)
189
+ net.show(file_path, notebook=False)
190
+
191
+ with open(file_path, 'a') as f:
192
+ f.write(f"""
193
+ <style>
194
+ body {{ margin: 0; padding: 0; }}
195
+ #mynetwork {{
196
+ width: 100vw;
197
+ height: 100vh;
198
+ }}
199
+ #spanDetails {{
200
+ position: absolute;
201
+ right: 0;
202
+ top: 0;
203
+ width: 30%;
204
+ height: 100%;
205
+ padding: 20px;
206
+ background: white;
207
+ border-left: 1px solid #eee;
208
+ overflow-y: auto;
209
+ z-index: 1000;
210
+ }}
211
+ </style>
212
+ <div>
213
+ <h3>Span Details</h3>
214
+ <pre id="spanDetails" style="max-height: 100%; overflow-y: auto;">Click on a node to view details</pre>
215
+ </div>
216
+ <script>
217
+ function moveNodesOnce() {{
218
+ var nodes = network.body.nodes;
219
+ var offsetX = -250;
220
+ var offsetY = 0;
221
+ for (var nodeId in nodes) {{
222
+ if (nodes.hasOwnProperty(nodeId)) {{
223
+ var node = nodes[nodeId];
224
+ network.moveNode(nodeId, node.x + offsetX, node.y + offsetY);
225
+ }}
226
+ }}
227
+ network.off("afterDrawing", moveNodesOnce);
228
+ }}
229
+ network.on("afterDrawing", moveNodesOnce);
230
+ network.on("click", function(params) {{
231
+ var nodeId = params.nodes[0];
232
+ var spanData = {json.dumps(spans)}[nodeId];
233
+ var displayData = {{}};
234
+ for (var key in spanData) {{
235
+ if (key !== 'children') {{
236
+ displayData[key] = spanData[key];
237
+ }}
238
+ }}
239
+ document.getElementById("spanDetails").innerHTML =
240
+ JSON.stringify(displayData, null, 2);
241
+ }});
242
+ </script>
243
+ """)
aworld/cmd/web_legacy/utils.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+
4
+ def list_agents():
5
+ agents_dir = os.path.join(os.getcwd(), "agent_deploy")
6
+
7
+ if not os.path.exists(agents_dir):
8
+ return []
9
+
10
+ try:
11
+ # 列出agents_dir下的所有目录
12
+ agents = []
13
+ for item in os.listdir(agents_dir):
14
+ item_path = os.path.join(agents_dir, item)
15
+ if os.path.isdir(item_path):
16
+ # 检查是否包含agent.py文件
17
+ agent_file = os.path.join(item_path, "agent.py")
18
+ if os.path.exists(agent_file):
19
+ agents.append(item)
20
+ return agents
21
+ except OSError as e:
22
+ # 处理权限错误或其他文件系统错误
23
+ print(f"Error listing agents: {e}")
24
+ return []
25
+
26
+
27
+ def get_agent_package_path(agent_name):
28
+ return os.path.join(
29
+ os.getcwd(),
30
+ "agent_deploy",
31
+ agent_name,
32
+ )
aworld/cmd/web_legacy/web_server.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import streamlit.web.bootstrap as bootstrap
3
+
4
+
5
+ def run_web_server(port, args=None, **kwargs):
6
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "main.py")
7
+ kwargs = {**kwargs, "server.port": port}
8
+ bootstrap.load_config_options(flag_options=kwargs)
9
+ bootstrap.run(script, False, args, flag_options=kwargs)