fengmiguoji commited on
Commit
1885161
·
verified ·
1 Parent(s): 8999c56

Upload 9 files

Browse files
.env.example ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ OPENAI_ENDPOINT=https://api.openai.com/v1
2
+ OPENAI_API_KEY=
3
+
4
+ ANTHROPIC_API_KEY=
5
+
6
+ GOOGLE_API_KEY=
7
+
8
+ AZURE_OPENAI_ENDPOINT=
9
+ AZURE_OPENAI_API_KEY=
10
+
11
+ DEEPSEEK_ENDPOINT=https://api.deepseek.com
12
+ DEEPSEEK_API_KEY=
13
+
14
+ # Set to false to disable anonymized telemetry
15
+ ANONYMIZED_TELEMETRY=true
16
+
17
+ # LogLevel: Set to debug to enable verbose logging, set to result to get results only. Available: result | debug | info
18
+ BROWSER_USE_LOGGING_LEVEL=info
19
+
20
+ # Chrome settings
21
+ CHROME_PATH=
22
+ CHROME_USER_DATA=
23
+ CHROME_DEBUGGING_PORT=9222
24
+ CHROME_DEBUGGING_HOST=localhost
25
+ CHROME_PERSISTENT_SESSION=false # Set to true to keep browser open between AI tasks
26
+
27
+ # Display settings
28
+ RESOLUTION=1920x1080x24 # Format: WIDTHxHEIGHTxDEPTH
29
+ RESOLUTION_WIDTH=1920 # Width in pixels
30
+ RESOLUTION_HEIGHT=1080 # Height in pixels
31
+
32
+ # VNC settings
33
+ VNC_PASSWORD=youvncpassword
.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
+ agent_history.gif filter=lfs diff=lfs merge=lfs -text
agent_history.gif ADDED

Git LFS Details

  • SHA256: ddbadb4286f9a2d1f063a309273f7f88267cce0718e42f165254d35a99f7a38e
  • Pointer size: 132 Bytes
  • Size of remote file: 1.31 MB
docker-compose.yml ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ services:
2
+ browser-use-webui:
3
+ build:
4
+ context: .
5
+ dockerfile: Dockerfile
6
+ ports:
7
+ - "7788:7788" # Gradio default port
8
+ - "6080:6080" # noVNC web interface
9
+ - "5900:5900" # VNC port
10
+ - "9222:9222" # Chrome remote debugging port
11
+ environment:
12
+ - OPENAI_ENDPOINT=${OPENAI_ENDPOINT:-https://api.openai.com/v1}
13
+ - OPENAI_API_KEY=${OPENAI_API_KEY:-}
14
+ - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
15
+ - GOOGLE_API_KEY=${GOOGLE_API_KEY:-}
16
+ - AZURE_OPENAI_ENDPOINT=${AZURE_OPENAI_ENDPOINT:-}
17
+ - AZURE_OPENAI_API_KEY=${AZURE_OPENAI_API_KEY:-}
18
+ - DEEPSEEK_ENDPOINT=${DEEPSEEK_ENDPOINT:-https://api.deepseek.com}
19
+ - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY:-}
20
+ - BROWSER_USE_LOGGING_LEVEL=${BROWSER_USE_LOGGING_LEVEL:-info}
21
+ - ANONYMIZED_TELEMETRY=false
22
+ - CHROME_PATH=/usr/bin/google-chrome
23
+ - CHROME_USER_DATA=/app/data/chrome_data
24
+ - CHROME_PERSISTENT_SESSION=${CHROME_PERSISTENT_SESSION:-false}
25
+ - DISPLAY=:99
26
+ - PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
27
+ - RESOLUTION=${RESOLUTION:-1920x1080x24}
28
+ - RESOLUTION_WIDTH=${RESOLUTION_WIDTH:-1920}
29
+ - RESOLUTION_HEIGHT=${RESOLUTION_HEIGHT:-1080}
30
+ - VNC_PASSWORD=${VNC_PASSWORD:-vncpassword}
31
+ - PERSISTENT_BROWSER_PORT=9222
32
+ - PERSISTENT_BROWSER_HOST=localhost
33
+ - CHROME_DEBUGGING_PORT=9222
34
+ - CHROME_DEBUGGING_HOST=localhost
35
+ volumes:
36
+ - ./data:/app/data
37
+ - ./data/chrome_data:/app/data/chrome_data
38
+ - /tmp/.X11-unix:/tmp/.X11-unix
39
+ restart: unless-stopped
40
+ shm_size: '2gb'
41
+ cap_add:
42
+ - SYS_ADMIN
43
+ security_opt:
44
+ - seccomp=unconfined
45
+ tmpfs:
46
+ - /tmp
47
+ healthcheck:
48
+ test: ["CMD", "nc", "-z", "localhost", "5900"]
49
+ interval: 10s
50
+ timeout: 5s
51
+ retries: 3
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ browser-use==0.1.19
2
+ langchain-google-genai==2.0.8
3
+ pyperclip==1.9.0
4
+ gradio==5.9.1
5
+ langchain-ollama==0.2.2
6
+ langchain-openai==0.2.14
supervisord.conf ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [supervisord]
2
+ nodaemon=true
3
+ logfile=/dev/stdout
4
+ logfile_maxbytes=0
5
+ loglevel=debug
6
+
7
+ [program:xvfb]
8
+ command=Xvfb :99 -screen 0 %(ENV_RESOLUTION)s -ac +extension GLX +render -noreset
9
+ autorestart=true
10
+ stdout_logfile=/dev/stdout
11
+ stdout_logfile_maxbytes=0
12
+ stderr_logfile=/dev/stderr
13
+ stderr_logfile_maxbytes=0
14
+ priority=100
15
+ startsecs=3
16
+
17
+ [program:vnc_setup]
18
+ command=bash -c "mkdir -p ~/.vnc && echo '%(ENV_VNC_PASSWORD)s' | vncpasswd -f > ~/.vnc/passwd && chmod 600 ~/.vnc/passwd && ls -la ~/.vnc/passwd"
19
+ autorestart=false
20
+ startsecs=0
21
+ priority=150
22
+ stdout_logfile=/dev/stdout
23
+ stdout_logfile_maxbytes=0
24
+ stderr_logfile=/dev/stderr
25
+ stderr_logfile_maxbytes=0
26
+
27
+ [program:x11vnc]
28
+ command=bash -c "sleep 3 && DISPLAY=:99 x11vnc -display :99 -forever -shared -rfbauth /root/.vnc/passwd -rfbport 5900 -bg -o /var/log/x11vnc.log"
29
+ autorestart=true
30
+ stdout_logfile=/dev/stdout
31
+ stdout_logfile_maxbytes=0
32
+ stderr_logfile=/dev/stderr
33
+ stderr_logfile_maxbytes=0
34
+ priority=200
35
+ startretries=5
36
+ startsecs=5
37
+ depends_on=vnc_setup
38
+
39
+ [program:x11vnc_log]
40
+ command=tail -f /var/log/x11vnc.log
41
+ autorestart=true
42
+ stdout_logfile=/dev/stdout
43
+ stdout_logfile_maxbytes=0
44
+ stderr_logfile=/dev/stderr
45
+ stderr_logfile_maxbytes=0
46
+ priority=250
47
+
48
+ [program:novnc]
49
+ command=bash -c "sleep 5 && cd /opt/novnc && ./utils/novnc_proxy --vnc localhost:5900 --listen 0.0.0.0:6080 --web /opt/novnc"
50
+ autorestart=true
51
+ stdout_logfile=/dev/stdout
52
+ stdout_logfile_maxbytes=0
53
+ stderr_logfile=/dev/stderr
54
+ stderr_logfile_maxbytes=0
55
+ priority=300
56
+ startretries=5
57
+ startsecs=3
58
+ depends_on=x11vnc
59
+
60
+ [program:persistent_browser]
61
+ command=bash -c 'if [ "%(ENV_CHROME_PERSISTENT_SESSION)s" = "true" ]; then mkdir -p /app/data/chrome_data && sleep 8 && google-chrome --user-data-dir=/app/data/chrome_data --window-position=0,0 --window-size=%(ENV_RESOLUTION_WIDTH)s,%(ENV_RESOLUTION_HEIGHT)s --start-maximized --no-sandbox --disable-dev-shm-usage --disable-gpu --disable-software-rasterizer --disable-setuid-sandbox --no-first-run --no-default-browser-check --no-experiments --ignore-certificate-errors --remote-debugging-port=9222 --remote-debugging-address=0.0.0.0 "data:text/html,<html><body style=\"background: \#f0f0f0; margin: 0; display: flex; justify-content: center; align-items: center; height: 100vh; font-family: Arial;\"><h1>Browser Ready for AI Interaction</h1></body></html>"; else echo "Persistent browser disabled"; fi'
62
+ autorestart=%(ENV_CHROME_PERSISTENT_SESSION)s
63
+ stdout_logfile=/dev/stdout
64
+ stdout_logfile_maxbytes=0
65
+ stderr_logfile=/dev/stderr
66
+ stderr_logfile_maxbytes=0
67
+ priority=350
68
+ startretries=3
69
+ startsecs=3
70
+ depends_on=novnc
71
+
72
+ [program:webui]
73
+ command=python webui.py --ip 0.0.0.0 --port 7788
74
+ directory=/app
75
+ autorestart=true
76
+ stdout_logfile=/dev/stdout
77
+ stdout_logfile_maxbytes=0
78
+ stderr_logfile=/dev/stderr
79
+ stderr_logfile_maxbytes=0
80
+ priority=400
81
+ startretries=3
82
+ startsecs=3
83
+ depends_on=persistent_browser
webui.py ADDED
@@ -0,0 +1,918 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ # @Time : 2025/1/1
3
+ # @Author : wenshao
4
+ # @Email : wenshaoguo1026@gmail.com
5
+ # @Project : browser-use-webui
6
+ # @FileName: webui.py
7
+
8
+ import pdb
9
+ import logging
10
+
11
+ from dotenv import load_dotenv
12
+
13
+ load_dotenv()
14
+ import os
15
+ import glob
16
+ import asyncio
17
+ import argparse
18
+ import os
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ import gradio as gr
23
+
24
+ from browser_use.agent.service import Agent
25
+ from playwright.async_api import async_playwright
26
+ from browser_use.browser.browser import Browser, BrowserConfig
27
+ from browser_use.browser.context import (
28
+ BrowserContextConfig,
29
+ BrowserContextWindowSize,
30
+ )
31
+ from playwright.async_api import async_playwright
32
+ from src.utils.agent_state import AgentState
33
+
34
+ from src.utils import utils
35
+ from src.agent.custom_agent import CustomAgent
36
+ from src.browser.custom_browser import CustomBrowser
37
+ from src.agent.custom_prompts import CustomSystemPrompt
38
+ from src.browser.config import BrowserPersistenceConfig
39
+ from src.browser.custom_context import BrowserContextConfig, CustomBrowserContext
40
+ from src.controller.custom_controller import CustomController
41
+ from gradio.themes import Citrus, Default, Glass, Monochrome, Ocean, Origin, Soft, Base
42
+ from src.utils.utils import update_model_dropdown, get_latest_files, capture_screenshot
43
+
44
+ from dotenv import load_dotenv
45
+ load_dotenv()
46
+
47
+ # Global variables for persistence
48
+ _global_browser = None
49
+ _global_browser_context = None
50
+
51
+ # Create the global agent state instance
52
+ _global_agent_state = AgentState()
53
+
54
+ async def stop_agent():
55
+ """Request the agent to stop and update UI with enhanced feedback"""
56
+ global _global_agent_state, _global_browser_context, _global_browser
57
+
58
+ try:
59
+ # Request stop
60
+ _global_agent_state.request_stop()
61
+
62
+ # Update UI immediately
63
+ message = "Stop requested - the agent will halt at the next safe point"
64
+ logger.info(f"🛑 {message}")
65
+
66
+ # Return UI updates
67
+ return (
68
+ message, # errors_output
69
+ gr.update(value="Stopping...", interactive=False), # stop_button
70
+ gr.update(interactive=False), # run_button
71
+ )
72
+ except Exception as e:
73
+ error_msg = f"Error during stop: {str(e)}"
74
+ logger.error(error_msg)
75
+ return (
76
+ error_msg,
77
+ gr.update(value="Stop", interactive=True),
78
+ gr.update(interactive=True)
79
+ )
80
+
81
+ async def run_browser_agent(
82
+ agent_type,
83
+ llm_provider,
84
+ llm_model_name,
85
+ llm_temperature,
86
+ llm_base_url,
87
+ llm_api_key,
88
+ use_own_browser,
89
+ keep_browser_open,
90
+ headless,
91
+ disable_security,
92
+ window_w,
93
+ window_h,
94
+ save_recording_path,
95
+ save_agent_history_path,
96
+ save_trace_path,
97
+ enable_recording,
98
+ task,
99
+ add_infos,
100
+ max_steps,
101
+ use_vision,
102
+ max_actions_per_step,
103
+ tool_call_in_content
104
+ ):
105
+ global _global_agent_state
106
+ _global_agent_state.clear_stop() # Clear any previous stop requests
107
+
108
+ try:
109
+ # Disable recording if the checkbox is unchecked
110
+ if not enable_recording:
111
+ save_recording_path = None
112
+
113
+ # Ensure the recording directory exists if recording is enabled
114
+ if save_recording_path:
115
+ os.makedirs(save_recording_path, exist_ok=True)
116
+
117
+ # Get the list of existing videos before the agent runs
118
+ existing_videos = set()
119
+ if save_recording_path:
120
+ existing_videos = set(
121
+ glob.glob(os.path.join(save_recording_path, "*.[mM][pP]4"))
122
+ + glob.glob(os.path.join(save_recording_path, "*.[wW][eE][bB][mM]"))
123
+ )
124
+
125
+ # Run the agent
126
+ llm = utils.get_llm_model(
127
+ provider=llm_provider,
128
+ model_name=llm_model_name,
129
+ temperature=llm_temperature,
130
+ base_url=llm_base_url,
131
+ api_key=llm_api_key,
132
+ )
133
+ if agent_type == "org":
134
+ final_result, errors, model_actions, model_thoughts, trace_file, history_file = await run_org_agent(
135
+ llm=llm,
136
+ use_own_browser=use_own_browser,
137
+ keep_browser_open=keep_browser_open,
138
+ headless=headless,
139
+ disable_security=disable_security,
140
+ window_w=window_w,
141
+ window_h=window_h,
142
+ save_recording_path=save_recording_path,
143
+ save_agent_history_path=save_agent_history_path,
144
+ save_trace_path=save_trace_path,
145
+ task=task,
146
+ max_steps=max_steps,
147
+ use_vision=use_vision,
148
+ max_actions_per_step=max_actions_per_step,
149
+ tool_call_in_content=tool_call_in_content
150
+ )
151
+ elif agent_type == "custom":
152
+ final_result, errors, model_actions, model_thoughts, trace_file, history_file = await run_custom_agent(
153
+ llm=llm,
154
+ use_own_browser=use_own_browser,
155
+ keep_browser_open=keep_browser_open,
156
+ headless=headless,
157
+ disable_security=disable_security,
158
+ window_w=window_w,
159
+ window_h=window_h,
160
+ save_recording_path=save_recording_path,
161
+ save_agent_history_path=save_agent_history_path,
162
+ save_trace_path=save_trace_path,
163
+ task=task,
164
+ add_infos=add_infos,
165
+ max_steps=max_steps,
166
+ use_vision=use_vision,
167
+ max_actions_per_step=max_actions_per_step,
168
+ tool_call_in_content=tool_call_in_content
169
+ )
170
+ else:
171
+ raise ValueError(f"Invalid agent type: {agent_type}")
172
+
173
+ # Get the list of videos after the agent runs (if recording is enabled)
174
+ latest_video = None
175
+ if save_recording_path:
176
+ new_videos = set(
177
+ glob.glob(os.path.join(save_recording_path, "*.[mM][pP]4"))
178
+ + glob.glob(os.path.join(save_recording_path, "*.[wW][eE][bB][mM]"))
179
+ )
180
+ if new_videos - existing_videos:
181
+ latest_video = list(new_videos - existing_videos)[0] # Get the first new video
182
+
183
+ return (
184
+ final_result,
185
+ errors,
186
+ model_actions,
187
+ model_thoughts,
188
+ latest_video,
189
+ trace_file,
190
+ history_file,
191
+ gr.update(value="Stop", interactive=True), # Re-enable stop button
192
+ gr.update(interactive=True) # Re-enable run button
193
+ )
194
+
195
+ except Exception as e:
196
+ import traceback
197
+ traceback.print_exc()
198
+ errors = str(e) + "\n" + traceback.format_exc()
199
+ return (
200
+ '', # final_result
201
+ errors, # errors
202
+ '', # model_actions
203
+ '', # model_thoughts
204
+ None, # latest_video
205
+ None, # history_file
206
+ None, # trace_file
207
+ gr.update(value="Stop", interactive=True), # Re-enable stop button
208
+ gr.update(interactive=True) # Re-enable run button
209
+ )
210
+
211
+
212
+ async def run_org_agent(
213
+ llm,
214
+ use_own_browser,
215
+ keep_browser_open,
216
+ headless,
217
+ disable_security,
218
+ window_w,
219
+ window_h,
220
+ save_recording_path,
221
+ save_agent_history_path,
222
+ save_trace_path,
223
+ task,
224
+ max_steps,
225
+ use_vision,
226
+ max_actions_per_step,
227
+ tool_call_in_content
228
+ ):
229
+ try:
230
+ global _global_browser, _global_browser_context, _global_agent_state
231
+
232
+ # Clear any previous stop request
233
+ _global_agent_state.clear_stop()
234
+
235
+ if use_own_browser:
236
+ chrome_path = os.getenv("CHROME_PATH", None)
237
+ if chrome_path == "":
238
+ chrome_path = None
239
+ else:
240
+ chrome_path = None
241
+
242
+ if _global_browser is None:
243
+ _global_browser = Browser(
244
+ config=BrowserConfig(
245
+ headless=headless,
246
+ disable_security=disable_security,
247
+ chrome_instance_path=chrome_path,
248
+ extra_chromium_args=[f"--window-size={window_w},{window_h}"],
249
+ )
250
+ )
251
+
252
+ if _global_browser_context is None:
253
+ _global_browser_context = await _global_browser.new_context(
254
+ config=BrowserContextConfig(
255
+ trace_path=save_trace_path if save_trace_path else None,
256
+ save_recording_path=save_recording_path if save_recording_path else None,
257
+ no_viewport=False,
258
+ browser_window_size=BrowserContextWindowSize(
259
+ width=window_w, height=window_h
260
+ ),
261
+ )
262
+ )
263
+
264
+ agent = Agent(
265
+ task=task,
266
+ llm=llm,
267
+ use_vision=use_vision,
268
+ browser=_global_browser,
269
+ browser_context=_global_browser_context,
270
+ max_actions_per_step=max_actions_per_step,
271
+ tool_call_in_content=tool_call_in_content
272
+ )
273
+ history = await agent.run(max_steps=max_steps)
274
+
275
+ history_file = os.path.join(save_agent_history_path, f"{agent.agent_id}.json")
276
+ agent.save_history(history_file)
277
+
278
+ final_result = history.final_result()
279
+ errors = history.errors()
280
+ model_actions = history.model_actions()
281
+ model_thoughts = history.model_thoughts()
282
+
283
+ trace_file = get_latest_files(save_trace_path)
284
+
285
+ return final_result, errors, model_actions, model_thoughts, trace_file.get('.zip'), history_file
286
+ except Exception as e:
287
+ import traceback
288
+ traceback.print_exc()
289
+ errors = str(e) + "\n" + traceback.format_exc()
290
+ return '', errors, '', '', None, None
291
+ finally:
292
+ # Handle cleanup based on persistence configuration
293
+ if not keep_browser_open:
294
+ if _global_browser_context:
295
+ await _global_browser_context.close()
296
+ _global_browser_context = None
297
+
298
+ if _global_browser:
299
+ await _global_browser.close()
300
+ _global_browser = None
301
+
302
+ async def run_custom_agent(
303
+ llm,
304
+ use_own_browser,
305
+ keep_browser_open,
306
+ headless,
307
+ disable_security,
308
+ window_w,
309
+ window_h,
310
+ save_recording_path,
311
+ save_agent_history_path,
312
+ save_trace_path,
313
+ task,
314
+ add_infos,
315
+ max_steps,
316
+ use_vision,
317
+ max_actions_per_step,
318
+ tool_call_in_content
319
+ ):
320
+ try:
321
+ global _global_browser, _global_browser_context, _global_agent_state
322
+
323
+ # Clear any previous stop request
324
+ _global_agent_state.clear_stop()
325
+
326
+ if use_own_browser:
327
+ chrome_path = os.getenv("CHROME_PATH", None)
328
+ if chrome_path == "":
329
+ chrome_path = None
330
+ else:
331
+ chrome_path = None
332
+
333
+ controller = CustomController()
334
+
335
+ # Initialize global browser if needed
336
+ if _global_browser is None:
337
+ _global_browser = CustomBrowser(
338
+ config=BrowserConfig(
339
+ headless=headless,
340
+ disable_security=disable_security,
341
+ chrome_instance_path=chrome_path,
342
+ extra_chromium_args=[f"--window-size={window_w},{window_h}"],
343
+ )
344
+ )
345
+
346
+ if _global_browser_context is None:
347
+ _global_browser_context = await _global_browser.new_context(
348
+ config=BrowserContextConfig(
349
+ trace_path=save_trace_path if save_trace_path else None,
350
+ save_recording_path=save_recording_path if save_recording_path else None,
351
+ no_viewport=False,
352
+ browser_window_size=BrowserContextWindowSize(
353
+ width=window_w, height=window_h
354
+ ),
355
+ )
356
+ )
357
+
358
+ # Create and run agent
359
+ agent = CustomAgent(
360
+ task=task,
361
+ add_infos=add_infos,
362
+ use_vision=use_vision,
363
+ llm=llm,
364
+ browser=_global_browser,
365
+ browser_context=_global_browser_context,
366
+ controller=controller,
367
+ system_prompt_class=CustomSystemPrompt,
368
+ max_actions_per_step=max_actions_per_step,
369
+ tool_call_in_content=tool_call_in_content,
370
+ agent_state=_global_agent_state
371
+ )
372
+ history = await agent.run(max_steps=max_steps)
373
+
374
+ history_file = os.path.join(save_agent_history_path, f"{agent.agent_id}.json")
375
+ agent.save_history(history_file)
376
+
377
+ final_result = history.final_result()
378
+ errors = history.errors()
379
+ model_actions = history.model_actions()
380
+ model_thoughts = history.model_thoughts()
381
+
382
+ trace_file = get_latest_files(save_trace_path)
383
+
384
+ return final_result, errors, model_actions, model_thoughts, trace_file.get('.zip'), history_file
385
+ except Exception as e:
386
+ import traceback
387
+ traceback.print_exc()
388
+ errors = str(e) + "\n" + traceback.format_exc()
389
+ return '', errors, '', '', None, None
390
+ finally:
391
+ # Handle cleanup based on persistence configuration
392
+ if not keep_browser_open:
393
+ if _global_browser_context:
394
+ await _global_browser_context.close()
395
+ _global_browser_context = None
396
+
397
+ if _global_browser:
398
+ await _global_browser.close()
399
+ _global_browser = None
400
+
401
+ async def run_with_stream(
402
+ agent_type,
403
+ llm_provider,
404
+ llm_model_name,
405
+ llm_temperature,
406
+ llm_base_url,
407
+ llm_api_key,
408
+ use_own_browser,
409
+ keep_browser_open,
410
+ headless,
411
+ disable_security,
412
+ window_w,
413
+ window_h,
414
+ save_recording_path,
415
+ save_agent_history_path,
416
+ save_trace_path,
417
+ enable_recording,
418
+ task,
419
+ add_infos,
420
+ max_steps,
421
+ use_vision,
422
+ max_actions_per_step,
423
+ tool_call_in_content
424
+ ):
425
+ global _global_agent_state
426
+ stream_vw = 80
427
+ stream_vh = int(80 * window_h // window_w)
428
+ if not headless:
429
+ result = await run_browser_agent(
430
+ agent_type=agent_type,
431
+ llm_provider=llm_provider,
432
+ llm_model_name=llm_model_name,
433
+ llm_temperature=llm_temperature,
434
+ llm_base_url=llm_base_url,
435
+ llm_api_key=llm_api_key,
436
+ use_own_browser=use_own_browser,
437
+ keep_browser_open=keep_browser_open,
438
+ headless=headless,
439
+ disable_security=disable_security,
440
+ window_w=window_w,
441
+ window_h=window_h,
442
+ save_recording_path=save_recording_path,
443
+ save_agent_history_path=save_agent_history_path,
444
+ save_trace_path=save_trace_path,
445
+ enable_recording=enable_recording,
446
+ task=task,
447
+ add_infos=add_infos,
448
+ max_steps=max_steps,
449
+ use_vision=use_vision,
450
+ max_actions_per_step=max_actions_per_step,
451
+ tool_call_in_content=tool_call_in_content
452
+ )
453
+ # Add HTML content at the start of the result array
454
+ html_content = f"<h1 style='width:{stream_vw}vw; height:{stream_vh}vh'>Using browser...</h1>"
455
+ yield [html_content] + list(result)
456
+ else:
457
+ try:
458
+ _global_agent_state.clear_stop()
459
+ # Run the browser agent in the background
460
+ agent_task = asyncio.create_task(
461
+ run_browser_agent(
462
+ agent_type=agent_type,
463
+ llm_provider=llm_provider,
464
+ llm_model_name=llm_model_name,
465
+ llm_temperature=llm_temperature,
466
+ llm_base_url=llm_base_url,
467
+ llm_api_key=llm_api_key,
468
+ use_own_browser=use_own_browser,
469
+ keep_browser_open=keep_browser_open,
470
+ headless=headless,
471
+ disable_security=disable_security,
472
+ window_w=window_w,
473
+ window_h=window_h,
474
+ save_recording_path=save_recording_path,
475
+ save_agent_history_path=save_agent_history_path,
476
+ save_trace_path=save_trace_path,
477
+ enable_recording=enable_recording,
478
+ task=task,
479
+ add_infos=add_infos,
480
+ max_steps=max_steps,
481
+ use_vision=use_vision,
482
+ max_actions_per_step=max_actions_per_step,
483
+ tool_call_in_content=tool_call_in_content
484
+ )
485
+ )
486
+
487
+ # Initialize values for streaming
488
+ html_content = f"<h1 style='width:{stream_vw}vw; height:{stream_vh}vh'>Using browser...</h1>"
489
+ final_result = errors = model_actions = model_thoughts = ""
490
+ latest_videos = trace = history_file = None
491
+
492
+
493
+ # Periodically update the stream while the agent task is running
494
+ while not agent_task.done():
495
+ try:
496
+ encoded_screenshot = await capture_screenshot(_global_browser_context)
497
+ if encoded_screenshot is not None:
498
+ html_content = f'<img src="data:image/jpeg;base64,{encoded_screenshot}" style="width:{stream_vw}vw; height:{stream_vh}vh ; border:1px solid #ccc;">'
499
+ else:
500
+ html_content = f"<h1 style='width:{stream_vw}vw; height:{stream_vh}vh'>Waiting for browser session...</h1>"
501
+ except Exception as e:
502
+ html_content = f"<h1 style='width:{stream_vw}vw; height:{stream_vh}vh'>Waiting for browser session...</h1>"
503
+
504
+ if _global_agent_state and _global_agent_state.is_stop_requested():
505
+ yield [
506
+ html_content,
507
+ final_result,
508
+ errors,
509
+ model_actions,
510
+ model_thoughts,
511
+ latest_videos,
512
+ trace,
513
+ history_file,
514
+ gr.update(value="Stopping...", interactive=False), # stop_button
515
+ gr.update(interactive=False), # run_button
516
+ ]
517
+ break
518
+ else:
519
+ yield [
520
+ html_content,
521
+ final_result,
522
+ errors,
523
+ model_actions,
524
+ model_thoughts,
525
+ latest_videos,
526
+ trace,
527
+ history_file,
528
+ gr.update(value="Stop", interactive=True), # Re-enable stop button
529
+ gr.update(interactive=True) # Re-enable run button
530
+ ]
531
+ await asyncio.sleep(0.05)
532
+
533
+ # Once the agent task completes, get the results
534
+ try:
535
+ result = await agent_task
536
+ final_result, errors, model_actions, model_thoughts, latest_videos, trace, history_file, stop_button, run_button = result
537
+ except Exception as e:
538
+ errors = f"Agent error: {str(e)}"
539
+
540
+ yield [
541
+ html_content,
542
+ final_result,
543
+ errors,
544
+ model_actions,
545
+ model_thoughts,
546
+ latest_videos,
547
+ trace,
548
+ history_file,
549
+ stop_button,
550
+ run_button
551
+ ]
552
+
553
+ except Exception as e:
554
+ import traceback
555
+ yield [
556
+ f"<h1 style='width:{stream_vw}vw; height:{stream_vh}vh'>Waiting for browser session...</h1>",
557
+ "",
558
+ f"Error: {str(e)}\n{traceback.format_exc()}",
559
+ "",
560
+ "",
561
+ None,
562
+ None,
563
+ None,
564
+ gr.update(value="Stop", interactive=True), # Re-enable stop button
565
+ gr.update(interactive=True) # Re-enable run button
566
+ ]
567
+
568
+ # Define the theme map globally
569
+ theme_map = {
570
+ "Default": Default(),
571
+ "Soft": Soft(),
572
+ "Monochrome": Monochrome(),
573
+ "Glass": Glass(),
574
+ "Origin": Origin(),
575
+ "Citrus": Citrus(),
576
+ "Ocean": Ocean(),
577
+ "Base": Base()
578
+ }
579
+
580
+ async def close_global_browser():
581
+ global _global_browser, _global_browser_context
582
+
583
+ if _global_browser_context:
584
+ await _global_browser_context.close()
585
+ _global_browser_context = None
586
+
587
+ if _global_browser:
588
+ await _global_browser.close()
589
+ _global_browser = None
590
+
591
+ def create_ui(theme_name="Ocean"):
592
+ css = """
593
+ .gradio-container {
594
+ max-width: 1200px !important;
595
+ margin: auto !important;
596
+ padding-top: 20px !important;
597
+ }
598
+ .header-text {
599
+ text-align: center;
600
+ margin-bottom: 30px;
601
+ }
602
+ .theme-section {
603
+ margin-bottom: 20px;
604
+ padding: 15px;
605
+ border-radius: 10px;
606
+ }
607
+ """
608
+
609
+ js = """
610
+ function refresh() {
611
+ const url = new URL(window.location);
612
+ if (url.searchParams.get('__theme') !== 'dark') {
613
+ url.searchParams.set('__theme', 'dark');
614
+ window.location.href = url.href;
615
+ }
616
+ }
617
+ """
618
+
619
+ with gr.Blocks(
620
+ title="Browser Use WebUI", theme=theme_map[theme_name], css=css, js=js
621
+ ) as demo:
622
+ with gr.Row():
623
+ gr.Markdown(
624
+ """
625
+ # 🌐 Browser Use WebUI
626
+ ### Control your browser with AI assistance
627
+ """,
628
+ elem_classes=["header-text"],
629
+ )
630
+
631
+ with gr.Tabs() as tabs:
632
+ with gr.TabItem("⚙️ Agent Settings", id=1):
633
+ with gr.Group():
634
+ agent_type = gr.Radio(
635
+ ["org", "custom"],
636
+ label="Agent Type",
637
+ value="custom",
638
+ info="Select the type of agent to use",
639
+ )
640
+ max_steps = gr.Slider(
641
+ minimum=1,
642
+ maximum=200,
643
+ value=100,
644
+ step=1,
645
+ label="Max Run Steps",
646
+ info="Maximum number of steps the agent will take",
647
+ )
648
+ max_actions_per_step = gr.Slider(
649
+ minimum=1,
650
+ maximum=20,
651
+ value=10,
652
+ step=1,
653
+ label="Max Actions per Step",
654
+ info="Maximum number of actions the agent will take per step",
655
+ )
656
+ use_vision = gr.Checkbox(
657
+ label="Use Vision",
658
+ value=True,
659
+ info="Enable visual processing capabilities",
660
+ )
661
+ tool_call_in_content = gr.Checkbox(
662
+ label="Use Tool Calls in Content",
663
+ value=True,
664
+ info="Enable Tool Calls in content",
665
+ )
666
+
667
+ with gr.TabItem("🔧 LLM Configuration", id=2):
668
+ with gr.Group():
669
+ llm_provider = gr.Dropdown(
670
+ choices=[provider for provider,model in utils.model_names.items()],
671
+ label="LLM Provider",
672
+ value="openai",
673
+ info="Select your preferred language model provider"
674
+ )
675
+ llm_model_name = gr.Dropdown(
676
+ label="Model Name",
677
+ choices=utils.model_names['openai'],
678
+ value="gpt-4o",
679
+ interactive=True,
680
+ allow_custom_value=True, # Allow users to input custom model names
681
+ info="Select a model from the dropdown or type a custom model name"
682
+ )
683
+ llm_temperature = gr.Slider(
684
+ minimum=0.0,
685
+ maximum=2.0,
686
+ value=1.0,
687
+ step=0.1,
688
+ label="Temperature",
689
+ info="Controls randomness in model outputs"
690
+ )
691
+ with gr.Row():
692
+ llm_base_url = gr.Textbox(
693
+ label="Base URL",
694
+ value='',
695
+ info="API endpoint URL (if required)"
696
+ )
697
+ llm_api_key = gr.Textbox(
698
+ label="API Key",
699
+ type="password",
700
+ value='',
701
+ info="Your API key (leave blank to use .env)"
702
+ )
703
+
704
+ with gr.TabItem("🌐 Browser Settings", id=3):
705
+ with gr.Group():
706
+ with gr.Row():
707
+ use_own_browser = gr.Checkbox(
708
+ label="Use Own Browser",
709
+ value=False,
710
+ info="Use your existing browser instance",
711
+ )
712
+ keep_browser_open = gr.Checkbox(
713
+ label="Keep Browser Open",
714
+ value=os.getenv("CHROME_PERSISTENT_SESSION", "False").lower() == "true",
715
+ info="Keep Browser Open between Tasks",
716
+ )
717
+ headless = gr.Checkbox(
718
+ label="Headless Mode",
719
+ value=False,
720
+ info="Run browser without GUI",
721
+ )
722
+ disable_security = gr.Checkbox(
723
+ label="Disable Security",
724
+ value=True,
725
+ info="Disable browser security features",
726
+ )
727
+ enable_recording = gr.Checkbox(
728
+ label="Enable Recording",
729
+ value=True,
730
+ info="Enable saving browser recordings",
731
+ )
732
+
733
+ with gr.Row():
734
+ window_w = gr.Number(
735
+ label="Window Width",
736
+ value=1280,
737
+ info="Browser window width",
738
+ )
739
+ window_h = gr.Number(
740
+ label="Window Height",
741
+ value=1100,
742
+ info="Browser window height",
743
+ )
744
+
745
+ save_recording_path = gr.Textbox(
746
+ label="Recording Path",
747
+ placeholder="e.g. ./tmp/record_videos",
748
+ value="./tmp/record_videos",
749
+ info="Path to save browser recordings",
750
+ interactive=True, # Allow editing only if recording is enabled
751
+ )
752
+
753
+ save_trace_path = gr.Textbox(
754
+ label="Trace Path",
755
+ placeholder="e.g. ./tmp/traces",
756
+ value="./tmp/traces",
757
+ info="Path to save Agent traces",
758
+ interactive=True,
759
+ )
760
+
761
+ save_agent_history_path = gr.Textbox(
762
+ label="Agent History Save Path",
763
+ placeholder="e.g., ./tmp/agent_history",
764
+ value="./tmp/agent_history",
765
+ info="Specify the directory where agent history should be saved.",
766
+ interactive=True,
767
+ )
768
+
769
+ with gr.TabItem("🤖 Run Agent", id=4):
770
+ task = gr.Textbox(
771
+ label="Task Description",
772
+ lines=4,
773
+ placeholder="Enter your task here...",
774
+ value="go to google.com and type 'OpenAI' click search and give me the first url",
775
+ info="Describe what you want the agent to do",
776
+ )
777
+ add_infos = gr.Textbox(
778
+ label="Additional Information",
779
+ lines=3,
780
+ placeholder="Add any helpful context or instructions...",
781
+ info="Optional hints to help the LLM complete the task",
782
+ )
783
+
784
+ with gr.Row():
785
+ run_button = gr.Button("▶️ Run Agent", variant="primary", scale=2)
786
+ stop_button = gr.Button("⏹️ Stop", variant="stop", scale=1)
787
+
788
+ with gr.Row():
789
+ browser_view = gr.HTML(
790
+ value="<h1 style='width:80vw; height:50vh'>Waiting for browser session...</h1>",
791
+ label="Live Browser View",
792
+ )
793
+
794
+ with gr.TabItem("📊 Results", id=5):
795
+ with gr.Group():
796
+
797
+ recording_display = gr.Video(label="Latest Recording")
798
+
799
+ gr.Markdown("### Results")
800
+ with gr.Row():
801
+ with gr.Column():
802
+ final_result_output = gr.Textbox(
803
+ label="Final Result", lines=3, show_label=True
804
+ )
805
+ with gr.Column():
806
+ errors_output = gr.Textbox(
807
+ label="Errors", lines=3, show_label=True
808
+ )
809
+ with gr.Row():
810
+ with gr.Column():
811
+ model_actions_output = gr.Textbox(
812
+ label="Model Actions", lines=3, show_label=True
813
+ )
814
+ with gr.Column():
815
+ model_thoughts_output = gr.Textbox(
816
+ label="Model Thoughts", lines=3, show_label=True
817
+ )
818
+
819
+ trace_file = gr.File(label="Trace File")
820
+
821
+ agent_history_file = gr.File(label="Agent History")
822
+
823
+ # Bind the stop button click event after errors_output is defined
824
+ stop_button.click(
825
+ fn=stop_agent,
826
+ inputs=[],
827
+ outputs=[errors_output, stop_button, run_button],
828
+ )
829
+
830
+ # Run button click handler
831
+ run_button.click(
832
+ fn=run_with_stream,
833
+ inputs=[
834
+ agent_type, llm_provider, llm_model_name, llm_temperature, llm_base_url, llm_api_key,
835
+ use_own_browser, keep_browser_open, headless, disable_security, window_w, window_h,
836
+ save_recording_path, save_agent_history_path, save_trace_path, # Include the new path
837
+ enable_recording, task, add_infos, max_steps, use_vision, max_actions_per_step, tool_call_in_content
838
+ ],
839
+ outputs=[
840
+ browser_view, # Browser view
841
+ final_result_output, # Final result
842
+ errors_output, # Errors
843
+ model_actions_output, # Model actions
844
+ model_thoughts_output, # Model thoughts
845
+ recording_display, # Latest recording
846
+ trace_file, # Trace file
847
+ agent_history_file, # Agent history file
848
+ stop_button, # Stop button
849
+ run_button # Run button
850
+ ],
851
+ )
852
+
853
+ with gr.TabItem("🎥 Recordings", id=6):
854
+ def list_recordings(save_recording_path):
855
+ if not os.path.exists(save_recording_path):
856
+ return []
857
+
858
+ # Get all video files
859
+ recordings = glob.glob(os.path.join(save_recording_path, "*.[mM][pP]4")) + glob.glob(os.path.join(save_recording_path, "*.[wW][eE][bB][mM]"))
860
+
861
+ # Sort recordings by creation time (oldest first)
862
+ recordings.sort(key=os.path.getctime)
863
+
864
+ # Add numbering to the recordings
865
+ numbered_recordings = []
866
+ for idx, recording in enumerate(recordings, start=1):
867
+ filename = os.path.basename(recording)
868
+ numbered_recordings.append((recording, f"{idx}. {filename}"))
869
+
870
+ return numbered_recordings
871
+
872
+ recordings_gallery = gr.Gallery(
873
+ label="Recordings",
874
+ value=list_recordings("./tmp/record_videos"),
875
+ columns=3,
876
+ height="auto",
877
+ object_fit="contain"
878
+ )
879
+
880
+ refresh_button = gr.Button("🔄 Refresh Recordings", variant="secondary")
881
+ refresh_button.click(
882
+ fn=list_recordings,
883
+ inputs=save_recording_path,
884
+ outputs=recordings_gallery
885
+ )
886
+
887
+ # Attach the callback to the LLM provider dropdown
888
+ llm_provider.change(
889
+ lambda provider, api_key, base_url: update_model_dropdown(provider, api_key, base_url),
890
+ inputs=[llm_provider, llm_api_key, llm_base_url],
891
+ outputs=llm_model_name
892
+ )
893
+
894
+ # Add this after defining the components
895
+ enable_recording.change(
896
+ lambda enabled: gr.update(interactive=enabled),
897
+ inputs=enable_recording,
898
+ outputs=save_recording_path
899
+ )
900
+
901
+ use_own_browser.change(fn=close_global_browser)
902
+ keep_browser_open.change(fn=close_global_browser)
903
+
904
+ return demo
905
+
906
+ def main():
907
+ parser = argparse.ArgumentParser(description="Gradio UI for Browser Agent")
908
+ parser.add_argument("--ip", type=str, default="127.0.0.1", help="IP address to bind to")
909
+ parser.add_argument("--port", type=int, default=7788, help="Port to listen on")
910
+ parser.add_argument("--theme", type=str, default="Ocean", choices=theme_map.keys(), help="Theme to use for the UI")
911
+ parser.add_argument("--dark-mode", action="store_true", help="Enable dark mode")
912
+ args = parser.parse_args()
913
+
914
+ demo = create_ui(theme_name=args.theme)
915
+ demo.launch(server_name=args.ip, server_port=args.port)
916
+
917
+ if __name__ == '__main__':
918
+ main()
启动.bat ADDED
@@ -0,0 +1 @@
 
 
1
+ python webui.py --ip 127.0.0.1 --port 7788
整理项目结构.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ def collect_code_files_to_txt(
4
+ repo_path: str,
5
+ output_file: str,
6
+ exclude_extensions=None,
7
+ encoding='utf-8'
8
+ ):
9
+ """
10
+ 将指定目录及其子目录下的所有文件内容整合到同一个文本文件中,
11
+ 但会排除某些不想处理的后缀(比如图片、音频等)。
12
+
13
+ :param repo_path: 项目根目录路径
14
+ :param output_file: 输出的txt文件路径
15
+ :param exclude_extensions: 需要排除的文件后缀列表(如 ['.svg','.png','.jpg']),
16
+ :param encoding: 打开文件使用的编码,默认为 utf-8。
17
+ """
18
+
19
+ with open(output_file, 'w', encoding=encoding) as out_f:
20
+ for root, dirs, files in os.walk(repo_path):
21
+ # 排除一些目录
22
+ if "__pycache__" in dirs:
23
+ dirs.remove("__pycache__")
24
+ if "node_modules" in dirs:
25
+ dirs.remove("node_modules")
26
+ if "models" in dirs:
27
+ dirs.remove("models")
28
+
29
+ for filename in files:
30
+ # 如果排除列表不为空,则检查是否需要跳过
31
+ if exclude_extensions is not None:
32
+ _, ext = os.path.splitext(filename)
33
+ if ext.lower() in exclude_extensions:
34
+ continue # 跳过这些扩展名
35
+
36
+ full_path = os.path.join(root, filename)
37
+
38
+ try:
39
+ with open(full_path, 'r', encoding=encoding) as code_f:
40
+ content = code_f.read()
41
+ except Exception as e:
42
+ print(f"无法读取文件: {full_path}, 原因: {e}")
43
+ continue
44
+
45
+ out_f.write(f"=== File Path: {full_path} ===\n")
46
+ out_f.write(content)
47
+ out_f.write("\n\n")
48
+
49
+ if __name__ == "__main__":
50
+ script_dir = os.path.dirname(os.path.abspath(__file__))
51
+ repo_dir = script_dir
52
+ output_txt = os.path.join(script_dir, "输出.txt")
53
+
54
+ # 这里我们专门排除 .svg, .png, .jpg
55
+ exclude_list = ['.svg', '.png', '.jpg', '.jpeg', '.gif']
56
+
57
+ collect_code_files_to_txt(
58
+ repo_path=repo_dir,
59
+ output_file=output_txt,
60
+ exclude_extensions=exclude_list,
61
+ encoding='utf-8'
62
+ )
63
+
64
+ print(f"文件收集完成,结果已保存到:{output_txt}")
输出.txt ADDED
The diff for this file is too large to render. See raw diff