Skip to content

Commit e64caa1

Browse files
committed
feat: 回退的妥协的tool_use呼叫,合并到系统提示词
1 parent ee2df63 commit e64caa1

File tree

6 files changed

+134
-22
lines changed

6 files changed

+134
-22
lines changed

src/api/request_processor.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,33 @@
1717
from .abort_detector import AbortSignalDetector, AbortSignalHandler
1818
from browser.page_controller import PageController
1919

20+
def _merge_tools_to_system_prompt(system_prompt: str, tools: Optional[list], logger, req_id: str) -> str:
21+
if not tools:
22+
return system_prompt
23+
function_declarations = []
24+
for tool in tools:
25+
if not isinstance(tool, dict):
26+
continue
27+
if tool.get('google_search_retrieval') is not None:
28+
continue
29+
if tool.get('function', {}).get('name') == 'googleSearch':
30+
continue
31+
if 'function' in tool:
32+
func = tool['function']
33+
declaration = {
34+
'name': func.get('name', ''),
35+
'description': func.get('description', ''),
36+
}
37+
if 'parameters' in func:
38+
declaration['parameters'] = func['parameters']
39+
function_declarations.append(declaration)
40+
if not function_declarations:
41+
return system_prompt
42+
tools_json = json.dumps(function_declarations, indent=2, ensure_ascii=False)
43+
logger.info(f"[{req_id}] 🔧 合并 {len(function_declarations)} 个函数到系统提示词")
44+
tools_section = f"<tools>\n{tools_json}\n</tools>\n\n"
45+
return tools_section + system_prompt
46+
2047
async def _initialize_request_context(req_id: str, request: ChatCompletionRequest) -> dict:
2148
from server import logger, page_instance, is_page_ready, parsed_model_list, current_ai_studio_model_id, model_switching_lock, page_params_cache, params_cache_lock
2249
request_manager.register_request(req_id, {'model': request.model, 'stream': request.stream, 'message_count': len(request.messages)})
@@ -670,7 +697,10 @@ async def _process_request_refactored(req_id: str, request: ChatCompletionReques
670697

671698
await _handle_parameter_cache(req_id, context)
672699
await page_controller.adjust_parameters(request.model_dump(exclude_none=True), context['page_params_cache'], context['params_cache_lock'], context['model_id_to_use'], context['parsed_model_list'], check_client_disconnected)
673-
await page_controller.set_system_instructions(system_prompt, check_client_disconnected)
700+
701+
# 合并tools到system prompt
702+
final_system_prompt = _merge_tools_to_system_prompt(system_prompt, request.tools, context['logger'], req_id)
703+
await page_controller.set_system_instructions(final_system_prompt, check_client_disconnected)
674704
check_client_disconnected('提交提示前最终检查')
675705
await page_controller.submit_prompt(prepared_prompt, image_list, check_client_disconnected)
676706
response_result = await _handle_response_processing(req_id, request, page, context, result_future, submit_button_locator, check_client_disconnected, disconnect_check_task)

src/browser/page_controller.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import re
66
import os
77
from playwright.async_api import Page as AsyncPage, expect as expect_async, TimeoutError, Locator
8+
import json as json_module
89
from config import TEMPERATURE_INPUT_SELECTOR, MAX_OUTPUT_TOKENS_SELECTOR, STOP_SEQUENCE_INPUT_SELECTOR, MAT_CHIP_REMOVE_BUTTON_SELECTOR, TOP_P_INPUT_SELECTOR, SUBMIT_BUTTON_SELECTOR, SUBMIT_BUTTON_SELECTORS, OVERLAY_SELECTOR, PROMPT_TEXTAREA_SELECTOR, PROMPT_TEXTAREA_SELECTORS, RESPONSE_CONTAINER_SELECTOR, RESPONSE_TEXT_SELECTOR, EDIT_MESSAGE_BUTTON_SELECTOR, USE_URL_CONTEXT_SELECTOR, UPLOAD_BUTTON_SELECTOR, UPLOAD_BUTTON_SELECTORS, INSERT_BUTTON_SELECTOR, INSERT_BUTTON_SELECTORS, HIDDEN_FILE_INPUT_SELECTORS, THINKING_MODE_TOGGLE_SELECTOR, SET_THINKING_BUDGET_TOGGLE_SELECTOR, THINKING_BUDGET_INPUT_SELECTOR, GROUNDING_WITH_GOOGLE_SEARCH_TOGGLE_SELECTOR, ZERO_STATE_SELECTOR, SYSTEM_INSTRUCTIONS_BUTTON_SELECTOR, SYSTEM_INSTRUCTIONS_TEXTAREA_SELECTOR, SKIP_PREFERENCE_VOTE_BUTTON_SELECTOR, CLICK_TIMEOUT_MS, WAIT_FOR_ELEMENT_TIMEOUT_MS, CLEAR_CHAT_VERIFY_TIMEOUT_MS, DEFAULT_TEMPERATURE, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_STOP_SEQUENCES, DEFAULT_TOP_P, ENABLE_URL_CONTEXT, ENABLE_THINKING_BUDGET, DEFAULT_THINKING_BUDGET, ENABLE_GOOGLE_SEARCH, THINKING_LEVEL_SELECT_SELECTOR, THINKING_LEVEL_OPTIONS, DEFAULT_THINKING_LEVEL, ADVANCED_SETTINGS_EXPANDER_SELECTOR
910
from config.timeouts import (
1011
MAX_RETRIES, SLEEP_RETRY, SLEEP_SHORT, SLEEP_MEDIUM, SLEEP_LONG, SLEEP_TICK,
@@ -71,6 +72,7 @@ async def handle_tools_panel():
7172
await self._open_url_content(check_client_disconnected)
7273
else:
7374
self.logger.info(f'[{self.req_id}] URL Context 功能已禁用,跳过调整。')
75+
# NOTE: Function Calling 改为合并到 system prompt,不再通过 UI 填写
7476

7577
tasks = [
7678
self._adjust_temperature(temp_to_set, page_params_cache, params_cache_lock, check_client_disconnected),
@@ -87,16 +89,20 @@ async def handle_tools_panel():
8789
async def set_system_instructions(self, system_prompt: str, check_client_disconnected: Callable):
8890
if not system_prompt:
8991
return
90-
self.logger.info(f'[{self.req_id}] 正在设置系统指令...')
92+
self.logger.info(f'[{self.req_id}] 正在设置系统指令 (长度: {len(system_prompt)} chars)...')
9193
await self._check_disconnect(check_client_disconnected, 'Start System Instructions')
9294
try:
9395
sys_prompt_button = self.page.locator(SYSTEM_INSTRUCTIONS_BUTTON_SELECTOR)
9496
sys_prompt_textarea = self.page.locator(SYSTEM_INSTRUCTIONS_TEXTAREA_SELECTOR)
9597
await self._click_and_verify(sys_prompt_button, sys_prompt_textarea, 'System Instructions Button', 'System Instructions Textarea')
96-
await expect_async(sys_prompt_textarea).to_be_editable(timeout=5000)
97-
await sys_prompt_textarea.fill(system_prompt, timeout=5000)
98-
await expect_async(sys_prompt_textarea).to_have_value(system_prompt, timeout=5000)
99-
self.logger.info(f'[{self.req_id}] 系统指令已成功填充并验证。')
98+
await expect_async(sys_prompt_textarea).to_be_editable(timeout=TIMEOUT_ELEMENT_VISIBLE)
99+
await sys_prompt_textarea.fill(system_prompt)
100+
await asyncio.sleep(DELAY_AFTER_FILL)
101+
filled_value = await sys_prompt_textarea.input_value(timeout=TIMEOUT_INPUT_VALUE)
102+
if len(filled_value) >= len(system_prompt) * 0.9:
103+
self.logger.info(f'[{self.req_id}] ✅ 系统指令已填充 (验证长度: {len(filled_value)} chars)')
104+
else:
105+
self.logger.warning(f'[{self.req_id}] ⚠️ 系统指令填充可能不完整 (期望: {len(system_prompt)}, 实际: {len(filled_value)})')
100106
for close_attempt in range(1, 4):
101107
try:
102108
await self.page.keyboard.press("Escape")
@@ -108,10 +114,14 @@ async def set_system_instructions(self, system_prompt: str, check_client_disconn
108114
except Exception:
109115
pass
110116
except Exception as e:
111-
self.logger.error(f'[{self.req_id}] 设置系统指令时出错: {e}')
117+
err_msg = str(e)
118+
if len(err_msg) > 200:
119+
err_msg = err_msg[:200] + '...[truncated]'
120+
self.logger.error(f'[{self.req_id}] 设置系统指令时出错: {err_msg}')
112121
if isinstance(e, ClientDisconnectedError):
113122
raise
114123

124+
115125
async def _control_thinking_mode_toggle(self, should_be_checked: bool, check_client_disconnected: Callable) -> bool:
116126
toggle_selector = THINKING_MODE_TOGGLE_SELECTOR
117127
action = '啟用' if should_be_checked else '停用'
@@ -385,6 +395,10 @@ async def _adjust_google_search(self, request_params: Dict[str, Any], check_clie
385395
self.logger.error(f"[{self.req_id}] ❌ Google Search 設定失敗,已重試 {max_retries} 次")
386396

387397

398+
# NOTE: _extract_function_declarations 和 _adjust_function_calling 已移除
399+
# Function Calling 改为将 tools 定义合并到 system prompt 中
400+
401+
388402
async def _ensure_advanced_settings_expanded(self, check_client_disconnected: Callable):
389403
max_retries = MAX_RETRIES
390404
expander_locator = self.page.locator(ADVANCED_SETTINGS_EXPANDER_SELECTOR)

src/config/constants.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,48 @@
1+
# 常量配置
12
import os
23
import json
34
from dotenv import load_dotenv
45
load_dotenv()
6+
7+
# 模型相关
58
MODEL_NAME = os.environ.get('MODEL_NAME', 'AI-Studio_Proxy_API')
69
CHAT_COMPLETION_ID_PREFIX = os.environ.get('CHAT_COMPLETION_ID_PREFIX', 'chatcmpl-')
710
DEFAULT_FALLBACK_MODEL_ID = os.environ.get('DEFAULT_FALLBACK_MODEL_ID', 'no model list')
11+
12+
# 默认参数
813
DEFAULT_TEMPERATURE = float(os.environ.get('DEFAULT_TEMPERATURE', '1.0'))
914
DEFAULT_MAX_OUTPUT_TOKENS = int(os.environ.get('DEFAULT_MAX_OUTPUT_TOKENS', '65536'))
1015
DEFAULT_TOP_P = float(os.environ.get('DEFAULT_TOP_P', '0.95'))
16+
17+
# 功能开关
1118
ENABLE_URL_CONTEXT = os.environ.get('ENABLE_URL_CONTEXT', 'false').lower() in ('true', '1', 'yes')
1219
ENABLE_THINKING_BUDGET = os.environ.get('ENABLE_THINKING_BUDGET', 'false').lower() in ('true', '1', 'yes')
1320
DEFAULT_THINKING_BUDGET = int(os.environ.get('DEFAULT_THINKING_BUDGET', '8192'))
1421
ENABLE_GOOGLE_SEARCH = os.environ.get('ENABLE_GOOGLE_SEARCH', 'false').lower() in ('true', '1', 'yes')
22+
23+
# 停止序列
1524
try:
1625
DEFAULT_STOP_SEQUENCES = json.loads(os.environ.get('DEFAULT_STOP_SEQUENCES', '["用户:"]'))
1726
except (json.JSONDecodeError, TypeError):
1827
DEFAULT_STOP_SEQUENCES = ['用户:']
28+
29+
# URL和端点
1930
AI_STUDIO_URL_PATTERN = os.environ.get('AI_STUDIO_URL_PATTERN', 'aistudio.google.com/')
2031
MODELS_ENDPOINT_URL_CONTAINS = os.environ.get('MODELS_ENDPOINT_URL_CONTAINS', 'MakerSuiteService/ListModels')
32+
33+
# 消息标记
2134
USER_INPUT_START_MARKER_SERVER = os.environ.get('USER_INPUT_START_MARKER_SERVER', '__USER_INPUT_START__')
2235
USER_INPUT_END_MARKER_SERVER = os.environ.get('USER_INPUT_END_MARKER_SERVER', '__USER_INPUT_END__')
36+
37+
# 模型过滤
2338
EXCLUDED_MODELS_FILENAME = os.environ.get('EXCLUDED_MODELS_FILENAME', 'excluded_models.txt')
24-
STREAM_TIMEOUT_LOG_STATE = {'consecutive_timeouts': 0, 'last_error_log_time': 0.0, 'suppress_until_time': 0.0, 'max_initial_errors': int(os.environ.get('STREAM_MAX_INITIAL_ERRORS', '3')), 'warning_interval_after_suppress': float(os.environ.get('STREAM_WARNING_INTERVAL_AFTER_SUPPRESS', '60.0')), 'suppress_duration_after_initial_burst': float(os.environ.get('STREAM_SUPPRESS_DURATION_AFTER_INITIAL_BURST', '400.0'))}
39+
40+
# 流式超时日志状态
41+
STREAM_TIMEOUT_LOG_STATE = {
42+
'consecutive_timeouts': 0,
43+
'last_error_log_time': 0.0,
44+
'suppress_until_time': 0.0,
45+
'max_initial_errors': int(os.environ.get('STREAM_MAX_INITIAL_ERRORS', '3')),
46+
'warning_interval_after_suppress': float(os.environ.get('STREAM_WARNING_INTERVAL_AFTER_SUPPRESS', '60.0')),
47+
'suppress_duration_after_initial_burst': float(os.environ.get('STREAM_SUPPRESS_DURATION_AFTER_INITIAL_BURST', '400.0'))
48+
}

src/config/selectors.py

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# 输入区域
12
PROMPT_TEXTAREA_SELECTORS = [
23
'ms-prompt-box textarea[aria-label="Enter a prompt"]',
34
'ms-prompt-box textarea[placeholder="Start typing a prompt"]',
@@ -9,13 +10,15 @@
910
INPUT_SELECTOR = PROMPT_TEXTAREA_SELECTOR
1011
INPUT_SELECTOR2 = PROMPT_TEXTAREA_SELECTOR
1112

13+
# 提交按钮
1214
SUBMIT_BUTTON_SELECTORS = [
1315
'button[aria-label="Run"].run-button',
1416
'ms-run-button button[aria-label="Run"]',
1517
'ms-prompt-box ms-run-button button',
1618
]
1719
SUBMIT_BUTTON_SELECTOR = SUBMIT_BUTTON_SELECTORS[0]
1820

21+
# 文件上传
1922
INSERT_BUTTON_SELECTORS = [
2023
'button[data-test-id="add-media-button"]',
2124
'button[aria-label="Insert images, videos, audio, or files"]',
@@ -40,39 +43,65 @@
4043
HIDDEN_FILE_INPUT_SELECTOR = HIDDEN_FILE_INPUT_SELECTORS[0]
4144

4245
UPLOADED_MEDIA_ITEM_SELECTOR = 'ms-prompt-box .multi-media-row ms-media-chip'
46+
47+
# 响应区域
4348
SKIP_PREFERENCE_VOTE_BUTTON_SELECTOR = 'button[data-test-id="skip-button"][aria-label="Skip preference vote"]'
4449
RESPONSE_CONTAINER_SELECTOR = 'ms-chat-turn .chat-turn-container.model'
4550
RESPONSE_TEXT_SELECTOR = 'ms-cmark-node.cmark-node'
4651

52+
# 加载状态
4753
LOADING_SPINNER_SELECTORS = [
4854
'button[aria-label="Run"].run-button svg .stoppable-spinner',
4955
'ms-run-button button svg .stoppable-spinner',
5056
'ms-prompt-box ms-run-button button svg .stoppable-spinner',
5157
]
5258
LOADING_SPINNER_SELECTOR = LOADING_SPINNER_SELECTORS[0]
5359

60+
# 对话框/遮罩层
5461
OVERLAY_SELECTOR = '.mat-mdc-dialog-inner-container'
5562
ZERO_STATE_SELECTOR = 'ms-zero-state'
5663
ERROR_TOAST_SELECTOR = 'div.toast.warning, div.toast.error'
64+
65+
# 消息编辑
5766
EDIT_MESSAGE_BUTTON_SELECTOR = 'button[aria-label="Edit"].toggle-edit-button:has(span:text-is("edit"))'
5867
MESSAGE_TEXTAREA_SELECTOR = 'ms-chat-turn:last-child ms-text-chunk ms-autosize-textarea'
5968
FINISH_EDIT_BUTTON_SELECTOR = 'button[aria-label="Stop editing"].toggle-edit-button'
6069
MORE_OPTIONS_BUTTON_SELECTOR = 'button[aria-label="Open options"]'
6170
COPY_MARKDOWN_BUTTON_SELECTOR = 'button[role="menuitem"]:has-text("Copy markdown")'
6271
COPY_MARKDOWN_BUTTON_SELECTOR_ALT = 'div[role="menu"] button:has-text("Copy Markdown")'
72+
73+
# 高级设置
6374
ADVANCED_SETTINGS_EXPANDER_SELECTOR = 'button[aria-label="Expand or collapse advanced settings"]'
6475
MAX_OUTPUT_TOKENS_SELECTOR = 'input[aria-label="Maximum output tokens"]'
6576
STOP_SEQUENCE_INPUT_SELECTOR = 'input[aria-label="Add stop token"]'
6677
MAT_CHIP_REMOVE_BUTTON_SELECTOR = 'mat-chip-set mat-chip-row button[aria-label*="Remove"]'
6778
TOP_P_INPUT_SELECTOR = '//div[contains(@class, "settings-item-column") and .//h3[normalize-space()="Top P"]]//input[@type="number"]'
6879
TEMPERATURE_INPUT_SELECTOR = '//div[contains(@class, "settings-item-column") and .//h3[normalize-space()="Temperature"]]//input[@type="number"]'
80+
81+
# 工具面板
6982
USE_URL_CONTEXT_SELECTOR = 'button[aria-label="Browse the url context"]'
83+
GROUNDING_WITH_GOOGLE_SEARCH_TOGGLE_SELECTOR = 'div[data-test-id="searchAsAToolTooltip"] mat-slide-toggle button'
84+
85+
# 思考模式
7086
THINKING_MODE_TOGGLE_SELECTOR = 'mat-slide-toggle[data-test-toggle="enable-thinking"]'
7187
SET_THINKING_BUDGET_TOGGLE_SELECTOR = 'mat-slide-toggle[data-test-toggle="manual-budget"]'
7288
THINKING_BUDGET_INPUT_SELECTOR = 'ms-slider[data-test-slider] input[type="number"]'
73-
GROUNDING_WITH_GOOGLE_SEARCH_TOGGLE_SELECTOR = 'div[data-test-id="searchAsAToolTooltip"] mat-slide-toggle button'
89+
THINKING_LEVEL_SELECT_SELECTOR = 'mat-select[aria-label="Thinking Level"], mat-select[aria-label="Thinking level"]'
90+
THINKING_LEVEL_OPTIONS = {
91+
'minimal': 'mat-option:has-text("Minimal")',
92+
'low': 'mat-option:has-text("Low")',
93+
'medium': 'mat-option:has-text("Medium")',
94+
'high': 'mat-option:has-text("High")',
95+
}
96+
THINKING_LEVEL_OPTION_HIGH_SELECTOR = THINKING_LEVEL_OPTIONS['high']
97+
THINKING_LEVEL_OPTION_LOW_SELECTOR = THINKING_LEVEL_OPTIONS['low']
98+
DEFAULT_THINKING_LEVEL = "high"
99+
100+
# 系统指令
74101
SYSTEM_INSTRUCTIONS_BUTTON_SELECTOR = 'button[aria-label="System instructions"]'
75102
SYSTEM_INSTRUCTIONS_TEXTAREA_SELECTOR = 'textarea[aria-label="System instructions"]'
103+
104+
# 模型选择器
76105
MODEL_SELECTOR_CARD_TITLE = '.model-selector-card .title'
77106
MODEL_SELECTOR_CARD_NAME = '[data-test-id="model-name"]'
78107
MODEL_SELECTOR_CARD_SUBTITLE = '.model-selector-card .subtitle'
@@ -83,18 +112,15 @@
83112
MODEL_OPTION_CONTENT_SPAN = '.model-option-content span'
84113
MODEL_SELECTORS_LIST = [MODEL_SELECTOR_CARD_TITLE, MODEL_SELECTOR_CARD_NAME, MODEL_SELECTOR_CARD_SUBTITLE, MODEL_SELECTOR_LEGACY_PRIMARY, MODEL_SELECTOR_LEGACY_FALLBACK, MODEL_SELECTOR_LEGACY_GENERIC, '.model-selector span', MODEL_SELECTOR_BUTTON_SPAN, MODEL_OPTION_CONTENT_SPAN]
85114

86-
THINKING_LEVEL_SELECT_SELECTOR = 'mat-select[aria-label="Thinking Level"], mat-select[aria-label="Thinking level"]'
87-
THINKING_LEVEL_OPTIONS = {
88-
'minimal': 'mat-option:has-text("Minimal")',
89-
'low': 'mat-option:has-text("Low")',
90-
'medium': 'mat-option:has-text("Medium")',
91-
'high': 'mat-option:has-text("High")',
92-
}
93-
THINKING_LEVEL_OPTION_HIGH_SELECTOR = THINKING_LEVEL_OPTIONS['high']
94-
THINKING_LEVEL_OPTION_LOW_SELECTOR = THINKING_LEVEL_OPTIONS['low']
95-
DEFAULT_THINKING_LEVEL = "high"
96-
115+
# 速率限制
97116
RATE_LIMIT_CALLOUT_SELECTOR = 'ms-callout.error-callout .message, ms-callout.warning-callout .message'
98117
RATE_LIMIT_KEYWORDS = ["exceeded quota", "out of free generations"]
99118

100-
119+
# Function Calling (尚未使用,改为合并到system prompt)
120+
FUNCTION_CALLING_TOGGLE_SELECTOR = 'div[data-test-id="functionCallingTooltip"] mat-slide-toggle'
121+
EDIT_FUNCTION_DECLARATIONS_BUTTON_SELECTOR = 'button.edit-function-declarations-button'
122+
FUNCTION_DECLARATIONS_DIALOG_SELECTOR = 'ms-edit-function-declarations-dialog'
123+
FUNCTION_DECLARATIONS_DIALOG_CLOSE_BUTTON_SELECTOR = 'ms-edit-function-declarations-dialog h2 button[aria-label="close"]'
124+
FUNCTION_DECLARATIONS_CODE_EDITOR_TAB_SELECTOR = 'ms-edit-function-declarations-dialog button[role="tab"]:has-text("Code Editor")'
125+
FUNCTION_DECLARATIONS_TEXTAREA_SELECTOR = 'ms-edit-function-declarations-dialog ms-text-editor textarea'
126+
FUNCTION_DECLARATIONS_SAVE_BUTTON_SELECTOR = 'ms-edit-function-declarations-dialog mat-dialog-actions button:has-text("Save")'

src/config/settings.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1+
# 应用设置
12
import os
23
from dotenv import load_dotenv
34
load_dotenv()
5+
6+
# 调试开关
47
DEBUG_LOGS_ENABLED = os.environ.get('DEBUG_LOGS_ENABLED', 'false').lower() in ('true', '1', 'yes')
58
TRACE_LOGS_ENABLED = os.environ.get('TRACE_LOGS_ENABLED', 'false').lower() in ('true', '1', 'yes')
9+
10+
# 认证相关
611
AUTO_SAVE_AUTH = os.environ.get('AUTO_SAVE_AUTH', '').lower() in ('1', 'true', 'yes')
712
AUTH_SAVE_TIMEOUT = int(os.environ.get('AUTH_SAVE_TIMEOUT', '30'))
813
AUTO_CONFIRM_LOGIN = os.environ.get('AUTO_CONFIRM_LOGIN', 'true').lower() in ('1', 'true', 'yes')
14+
15+
# 目录路径
916
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
1017
DATA_DIR = os.path.join(PROJECT_ROOT, 'data')
1118
AUTH_PROFILES_DIR = os.path.join(DATA_DIR, 'auth_profiles')
@@ -14,6 +21,7 @@
1421
LOG_DIR = os.path.join(PROJECT_ROOT, 'logs')
1522
APP_LOG_FILE_PATH = os.path.join(LOG_DIR, 'app.log')
1623

24+
# 工具函数
1725
def get_environment_variable(key: str, default: str='') -> str:
1826
return os.environ.get(key, default)
1927

@@ -29,6 +37,8 @@ def get_int_env(key: str, default: int=0) -> int:
2937
return int(os.environ.get(key, str(default)))
3038
except (ValueError, TypeError):
3139
return default
40+
41+
# 代理和脚本注入
3242
NO_PROXY_ENV = os.environ.get('NO_PROXY')
3343
ENABLE_SCRIPT_INJECTION = get_boolean_env('ENABLE_SCRIPT_INJECTION', True)
3444
USERSCRIPT_PATH = get_environment_variable('USERSCRIPT_PATH', 'browser/more_models.js')

0 commit comments

Comments
 (0)