botrun-flow-lang 5.9.301__py3-none-any.whl → 5.10.82__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. botrun_flow_lang/api/auth_api.py +39 -39
  2. botrun_flow_lang/api/auth_utils.py +183 -183
  3. botrun_flow_lang/api/botrun_back_api.py +65 -65
  4. botrun_flow_lang/api/flow_api.py +3 -3
  5. botrun_flow_lang/api/hatch_api.py +481 -481
  6. botrun_flow_lang/api/langgraph_api.py +796 -796
  7. botrun_flow_lang/api/line_bot_api.py +1357 -1357
  8. botrun_flow_lang/api/model_api.py +300 -300
  9. botrun_flow_lang/api/rate_limit_api.py +32 -32
  10. botrun_flow_lang/api/routes.py +79 -79
  11. botrun_flow_lang/api/search_api.py +53 -53
  12. botrun_flow_lang/api/storage_api.py +316 -316
  13. botrun_flow_lang/api/subsidy_api.py +290 -290
  14. botrun_flow_lang/api/subsidy_api_system_prompt.txt +109 -109
  15. botrun_flow_lang/api/user_setting_api.py +70 -70
  16. botrun_flow_lang/api/version_api.py +31 -31
  17. botrun_flow_lang/api/youtube_api.py +26 -26
  18. botrun_flow_lang/constants.py +13 -13
  19. botrun_flow_lang/langgraph_agents/agents/agent_runner.py +174 -174
  20. botrun_flow_lang/langgraph_agents/agents/agent_tools/step_planner.py +77 -77
  21. botrun_flow_lang/langgraph_agents/agents/checkpointer/firestore_checkpointer.py +666 -666
  22. botrun_flow_lang/langgraph_agents/agents/gov_researcher/GOV_RESEARCHER_PRD.md +192 -192
  23. botrun_flow_lang/langgraph_agents/agents/gov_researcher/gov_researcher_2_graph.py +1002 -1002
  24. botrun_flow_lang/langgraph_agents/agents/gov_researcher/gov_researcher_graph.py +822 -822
  25. botrun_flow_lang/langgraph_agents/agents/langgraph_react_agent.py +548 -542
  26. botrun_flow_lang/langgraph_agents/agents/search_agent_graph.py +864 -864
  27. botrun_flow_lang/langgraph_agents/agents/tools/__init__.py +4 -4
  28. botrun_flow_lang/langgraph_agents/agents/tools/gemini_code_execution.py +376 -376
  29. botrun_flow_lang/langgraph_agents/agents/util/gemini_grounding.py +66 -66
  30. botrun_flow_lang/langgraph_agents/agents/util/html_util.py +316 -316
  31. botrun_flow_lang/langgraph_agents/agents/util/img_util.py +294 -294
  32. botrun_flow_lang/langgraph_agents/agents/util/local_files.py +345 -345
  33. botrun_flow_lang/langgraph_agents/agents/util/mermaid_util.py +86 -86
  34. botrun_flow_lang/langgraph_agents/agents/util/model_utils.py +143 -143
  35. botrun_flow_lang/langgraph_agents/agents/util/pdf_analyzer.py +160 -160
  36. botrun_flow_lang/langgraph_agents/agents/util/perplexity_search.py +464 -464
  37. botrun_flow_lang/langgraph_agents/agents/util/plotly_util.py +59 -59
  38. botrun_flow_lang/langgraph_agents/agents/util/tavily_search.py +199 -199
  39. botrun_flow_lang/langgraph_agents/agents/util/youtube_util.py +90 -90
  40. botrun_flow_lang/langgraph_agents/cache/langgraph_botrun_cache.py +197 -197
  41. botrun_flow_lang/llm_agent/llm_agent.py +19 -19
  42. botrun_flow_lang/llm_agent/llm_agent_util.py +83 -83
  43. botrun_flow_lang/log/.gitignore +2 -2
  44. botrun_flow_lang/main.py +61 -61
  45. botrun_flow_lang/main_fast.py +51 -51
  46. botrun_flow_lang/mcp_server/__init__.py +10 -10
  47. botrun_flow_lang/mcp_server/default_mcp.py +711 -711
  48. botrun_flow_lang/models/nodes/utils.py +205 -205
  49. botrun_flow_lang/models/token_usage.py +34 -34
  50. botrun_flow_lang/requirements.txt +21 -21
  51. botrun_flow_lang/services/base/firestore_base.py +30 -30
  52. botrun_flow_lang/services/hatch/hatch_factory.py +11 -11
  53. botrun_flow_lang/services/hatch/hatch_fs_store.py +372 -372
  54. botrun_flow_lang/services/storage/storage_cs_store.py +202 -202
  55. botrun_flow_lang/services/storage/storage_factory.py +12 -12
  56. botrun_flow_lang/services/storage/storage_store.py +65 -65
  57. botrun_flow_lang/services/user_setting/user_setting_factory.py +9 -9
  58. botrun_flow_lang/services/user_setting/user_setting_fs_store.py +66 -66
  59. botrun_flow_lang/static/docs/tools/index.html +926 -926
  60. botrun_flow_lang/tests/api_functional_tests.py +1525 -1525
  61. botrun_flow_lang/tests/api_stress_test.py +357 -357
  62. botrun_flow_lang/tests/shared_hatch_tests.py +333 -333
  63. botrun_flow_lang/tests/test_botrun_app.py +46 -46
  64. botrun_flow_lang/tests/test_html_util.py +31 -31
  65. botrun_flow_lang/tests/test_img_analyzer.py +190 -190
  66. botrun_flow_lang/tests/test_img_util.py +39 -39
  67. botrun_flow_lang/tests/test_local_files.py +114 -114
  68. botrun_flow_lang/tests/test_mermaid_util.py +103 -103
  69. botrun_flow_lang/tests/test_pdf_analyzer.py +104 -104
  70. botrun_flow_lang/tests/test_plotly_util.py +151 -151
  71. botrun_flow_lang/tests/test_run_workflow_engine.py +65 -65
  72. botrun_flow_lang/tools/generate_docs.py +133 -133
  73. botrun_flow_lang/tools/templates/tools.html +153 -153
  74. botrun_flow_lang/utils/__init__.py +7 -7
  75. botrun_flow_lang/utils/botrun_logger.py +344 -344
  76. botrun_flow_lang/utils/clients/rate_limit_client.py +209 -209
  77. botrun_flow_lang/utils/clients/token_verify_client.py +153 -153
  78. botrun_flow_lang/utils/google_drive_utils.py +654 -654
  79. botrun_flow_lang/utils/langchain_utils.py +324 -324
  80. botrun_flow_lang/utils/yaml_utils.py +9 -9
  81. {botrun_flow_lang-5.9.301.dist-info → botrun_flow_lang-5.10.82.dist-info}/METADATA +2 -2
  82. botrun_flow_lang-5.10.82.dist-info/RECORD +99 -0
  83. botrun_flow_lang-5.9.301.dist-info/RECORD +0 -99
  84. {botrun_flow_lang-5.9.301.dist-info → botrun_flow_lang-5.10.82.dist-info}/WHEEL +0 -0
@@ -1,133 +1,133 @@
1
- import inspect
2
- import os
3
- from pathlib import Path
4
- from jinja2 import Environment, FileSystemLoader
5
- from typing import get_type_hints, Any
6
- import sys
7
-
8
- # Add the project root to the Python path
9
- project_root = Path(__file__).parent.parent.parent
10
- sys.path.append(str(project_root))
11
-
12
- from botrun_flow_lang.langgraph_agents.agents.langgraph_react_agent import (
13
- chat_with_pdf,
14
- chat_with_imgs,
15
- current_date_time,
16
- scrape,
17
- web_search,
18
- # deep_research,
19
- create_mermaid_diagram,
20
- create_plotly_chart,
21
- generate_image,
22
- generate_tmp_public_url,
23
- create_html_page,
24
- )
25
-
26
- # List of tool functions to document
27
- TOOLS = sorted(
28
- [
29
- chat_with_imgs,
30
- chat_with_pdf,
31
- create_mermaid_diagram,
32
- create_plotly_chart,
33
- current_date_time,
34
- generate_image,
35
- generate_tmp_public_url,
36
- scrape,
37
- web_search,
38
- # deep_research,
39
- create_html_page,
40
- ],
41
- key=lambda x: x.name,
42
- )
43
-
44
-
45
- def get_tool_info(tool):
46
- """Extract documentation information from a tool function."""
47
- # 處理 LangChain 工具
48
- if hasattr(tool, "name"):
49
- func_name = tool.name
50
- else:
51
- func_name = tool.__name__
52
-
53
- # 獲取文檔字符串
54
- if hasattr(tool, "description"):
55
- doc = tool.description
56
- else:
57
- doc = inspect.getdoc(tool) or "No documentation available."
58
-
59
- # 獲取簽名
60
- if hasattr(tool, "func"):
61
- sig = inspect.signature(tool.func)
62
- else:
63
- sig = inspect.signature(tool)
64
-
65
- # Get parameters info
66
- parameters = []
67
- for name, param in sig.parameters.items():
68
- annotation = (
69
- str(param.annotation)
70
- if param.annotation != inspect.Parameter.empty
71
- else "Any"
72
- )
73
- if "Annotated" in annotation:
74
- # 簡化 Annotated 類型
75
- annotation = annotation.split("[")[1].split(",")[0]
76
- parameters.append(
77
- {
78
- "name": name,
79
- "annotation": annotation,
80
- "default": (
81
- None
82
- if param.default == inspect.Parameter.empty
83
- else str(param.default)
84
- ),
85
- }
86
- )
87
-
88
- # Get return annotation
89
- return_annotation = (
90
- str(sig.return_annotation)
91
- if sig.return_annotation != inspect.Signature.empty
92
- else "Any"
93
- )
94
- if "Annotated" in return_annotation:
95
- # 簡化 Annotated 類型
96
- return_annotation = return_annotation.split("[")[1].split(",")[0]
97
-
98
- return {
99
- "name": func_name,
100
- "doc": doc,
101
- "parameters": parameters,
102
- "return_annotation": return_annotation,
103
- }
104
-
105
-
106
- def generate_html_docs():
107
- """Generate HTML documentation for all tool functions."""
108
- # Setup Jinja2 environment
109
- env = Environment(
110
- loader=FileSystemLoader(os.path.join(os.path.dirname(__file__), "templates"))
111
- )
112
- template = env.get_template("tools.html")
113
-
114
- # Get documentation for all tools
115
- tools_info = [get_tool_info(tool) for tool in TOOLS]
116
-
117
- # Render the template
118
- html_content = template.render(tools=tools_info)
119
-
120
- # Ensure the output directory exists
121
- output_dir = Path(project_root) / "botrun_flow_lang" / "static" / "docs" / "tools"
122
- output_dir.mkdir(parents=True, exist_ok=True)
123
-
124
- # Write the HTML file
125
- output_file = output_dir / "index.html"
126
- with open(output_file, "w", encoding="utf-8") as f:
127
- f.write(html_content)
128
-
129
- print(f"Documentation generated at: {output_file}")
130
-
131
-
132
- if __name__ == "__main__":
133
- generate_html_docs()
1
+ import inspect
2
+ import os
3
+ from pathlib import Path
4
+ from jinja2 import Environment, FileSystemLoader
5
+ from typing import get_type_hints, Any
6
+ import sys
7
+
8
+ # Add the project root to the Python path
9
+ project_root = Path(__file__).parent.parent.parent
10
+ sys.path.append(str(project_root))
11
+
12
+ from botrun_flow_lang.langgraph_agents.agents.langgraph_react_agent import (
13
+ chat_with_pdf,
14
+ chat_with_imgs,
15
+ current_date_time,
16
+ scrape,
17
+ web_search,
18
+ # deep_research,
19
+ create_mermaid_diagram,
20
+ create_plotly_chart,
21
+ generate_image,
22
+ generate_tmp_public_url,
23
+ create_html_page,
24
+ )
25
+
26
+ # List of tool functions to document
27
+ TOOLS = sorted(
28
+ [
29
+ chat_with_imgs,
30
+ chat_with_pdf,
31
+ create_mermaid_diagram,
32
+ create_plotly_chart,
33
+ current_date_time,
34
+ generate_image,
35
+ generate_tmp_public_url,
36
+ scrape,
37
+ web_search,
38
+ # deep_research,
39
+ create_html_page,
40
+ ],
41
+ key=lambda x: x.name,
42
+ )
43
+
44
+
45
+ def get_tool_info(tool):
46
+ """Extract documentation information from a tool function."""
47
+ # 處理 LangChain 工具
48
+ if hasattr(tool, "name"):
49
+ func_name = tool.name
50
+ else:
51
+ func_name = tool.__name__
52
+
53
+ # 獲取文檔字符串
54
+ if hasattr(tool, "description"):
55
+ doc = tool.description
56
+ else:
57
+ doc = inspect.getdoc(tool) or "No documentation available."
58
+
59
+ # 獲取簽名
60
+ if hasattr(tool, "func"):
61
+ sig = inspect.signature(tool.func)
62
+ else:
63
+ sig = inspect.signature(tool)
64
+
65
+ # Get parameters info
66
+ parameters = []
67
+ for name, param in sig.parameters.items():
68
+ annotation = (
69
+ str(param.annotation)
70
+ if param.annotation != inspect.Parameter.empty
71
+ else "Any"
72
+ )
73
+ if "Annotated" in annotation:
74
+ # 簡化 Annotated 類型
75
+ annotation = annotation.split("[")[1].split(",")[0]
76
+ parameters.append(
77
+ {
78
+ "name": name,
79
+ "annotation": annotation,
80
+ "default": (
81
+ None
82
+ if param.default == inspect.Parameter.empty
83
+ else str(param.default)
84
+ ),
85
+ }
86
+ )
87
+
88
+ # Get return annotation
89
+ return_annotation = (
90
+ str(sig.return_annotation)
91
+ if sig.return_annotation != inspect.Signature.empty
92
+ else "Any"
93
+ )
94
+ if "Annotated" in return_annotation:
95
+ # 簡化 Annotated 類型
96
+ return_annotation = return_annotation.split("[")[1].split(",")[0]
97
+
98
+ return {
99
+ "name": func_name,
100
+ "doc": doc,
101
+ "parameters": parameters,
102
+ "return_annotation": return_annotation,
103
+ }
104
+
105
+
106
+ def generate_html_docs():
107
+ """Generate HTML documentation for all tool functions."""
108
+ # Setup Jinja2 environment
109
+ env = Environment(
110
+ loader=FileSystemLoader(os.path.join(os.path.dirname(__file__), "templates"))
111
+ )
112
+ template = env.get_template("tools.html")
113
+
114
+ # Get documentation for all tools
115
+ tools_info = [get_tool_info(tool) for tool in TOOLS]
116
+
117
+ # Render the template
118
+ html_content = template.render(tools=tools_info)
119
+
120
+ # Ensure the output directory exists
121
+ output_dir = Path(project_root) / "botrun_flow_lang" / "static" / "docs" / "tools"
122
+ output_dir.mkdir(parents=True, exist_ok=True)
123
+
124
+ # Write the HTML file
125
+ output_file = output_dir / "index.html"
126
+ with open(output_file, "w", encoding="utf-8") as f:
127
+ f.write(html_content)
128
+
129
+ print(f"Documentation generated at: {output_file}")
130
+
131
+
132
+ if __name__ == "__main__":
133
+ generate_html_docs()
@@ -1,154 +1,154 @@
1
- <!DOCTYPE html>
2
- <html lang="zh-TW">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>ReAct Agent Tools Documentation</title>
7
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
8
- <link href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css" rel="stylesheet">
9
- <style>
10
- .tool-section {
11
- margin-bottom: 2rem;
12
- padding: 1rem;
13
- border: 1px solid #dee2e6;
14
- border-radius: 0.25rem;
15
- }
16
- .tool-name {
17
- color: #0d6efd;
18
- margin-bottom: 1rem;
19
- padding-top: 60px; /* 為固定導航欄留出空間 */
20
- margin-top: -60px; /* 抵消 padding-top */
21
- }
22
- .param-table {
23
- margin-top: 1rem;
24
- }
25
- .doc-content {
26
- white-space: pre-wrap;
27
- font-family: monospace;
28
- background-color: #f8f9fa;
29
- padding: 1rem;
30
- border-radius: 0.25rem;
31
- }
32
- #sidebar {
33
- position: fixed;
34
- top: 0;
35
- left: 0;
36
- height: 100vh;
37
- width: 250px;
38
- background-color: #f8f9fa;
39
- padding: 20px;
40
- overflow-y: auto;
41
- border-right: 1px solid #dee2e6;
42
- }
43
- #main-content {
44
- margin-left: 250px;
45
- padding: 20px;
46
- }
47
- .nav-link {
48
- color: #0d6efd;
49
- padding: 5px 0;
50
- }
51
- .nav-link:hover {
52
- background-color: #e9ecef;
53
- }
54
- .nav-link.active {
55
- font-weight: bold;
56
- background-color: #e9ecef;
57
- }
58
- </style>
59
- </head>
60
- <body>
61
- <div id="sidebar">
62
- <h5 class="mb-3">Tools</h5>
63
- <nav class="nav flex-column">
64
- {% for tool in tools %}
65
- <a class="nav-link" href="#{{ tool.name }}">{{ tool.name }}</a>
66
- {% endfor %}
67
- </nav>
68
- </div>
69
-
70
- <div id="main-content">
71
- <h1 class="mb-4">ReAct Agent Tools Documentation</h1>
72
-
73
- <div class="row">
74
- <div class="col-12">
75
- {% for tool in tools %}
76
- <div class="tool-section" id="{{ tool.name }}">
77
- <h2 class="tool-name">@tool {{ tool.name }}</h2>
78
-
79
- <h4>Documentation:</h4>
80
- <div class="doc-content">{{ tool.doc }}</div>
81
-
82
- <h4 class="mt-3">Parameters:</h4>
83
- <table class="table param-table">
84
- <thead>
85
- <tr>
86
- <th>Name</th>
87
- <th>Type</th>
88
- <th>Default</th>
89
- </tr>
90
- </thead>
91
- <tbody>
92
- {% for param in tool.parameters %}
93
- <tr>
94
- <td>{{ param.name }}</td>
95
- <td><code>{{ param.annotation }}</code></td>
96
- <td>{% if param.default != None %}<code>{{ param.default }}</code>{% else %}-{% endif %}</td>
97
- </tr>
98
- {% endfor %}
99
- </tbody>
100
- </table>
101
-
102
- <h4 class="mt-3">Returns:</h4>
103
- <code>{{ tool.return_annotation }}</code>
104
- </div>
105
- {% endfor %}
106
- </div>
107
- </div>
108
- </div>
109
-
110
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
111
- <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"></script>
112
- <script>
113
- // 高亮當前選中的導航項
114
- document.addEventListener('DOMContentLoaded', function() {
115
- const navLinks = document.querySelectorAll('.nav-link');
116
-
117
- // 監聽滾動事件
118
- window.addEventListener('scroll', function() {
119
- let currentSection = '';
120
- const sections = document.querySelectorAll('.tool-section');
121
-
122
- sections.forEach(section => {
123
- const sectionTop = section.offsetTop;
124
- const sectionHeight = section.clientHeight;
125
- if (pageYOffset >= sectionTop - 100) {
126
- currentSection = section.getAttribute('id');
127
- }
128
- });
129
-
130
- // 更新導航項的激活狀態
131
- navLinks.forEach(link => {
132
- link.classList.remove('active');
133
- if (link.getAttribute('href').substring(1) === currentSection) {
134
- link.classList.add('active');
135
- }
136
- });
137
- });
138
-
139
- // 平滑滾動
140
- navLinks.forEach(link => {
141
- link.addEventListener('click', function(e) {
142
- e.preventDefault();
143
- const targetId = this.getAttribute('href').substring(1);
144
- const targetElement = document.getElementById(targetId);
145
- window.scrollTo({
146
- top: targetElement.offsetTop - 20,
147
- behavior: 'smooth'
148
- });
149
- });
150
- });
151
- });
152
- </script>
153
- </body>
1
+ <!DOCTYPE html>
2
+ <html lang="zh-TW">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>ReAct Agent Tools Documentation</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
8
+ <link href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css" rel="stylesheet">
9
+ <style>
10
+ .tool-section {
11
+ margin-bottom: 2rem;
12
+ padding: 1rem;
13
+ border: 1px solid #dee2e6;
14
+ border-radius: 0.25rem;
15
+ }
16
+ .tool-name {
17
+ color: #0d6efd;
18
+ margin-bottom: 1rem;
19
+ padding-top: 60px; /* 為固定導航欄留出空間 */
20
+ margin-top: -60px; /* 抵消 padding-top */
21
+ }
22
+ .param-table {
23
+ margin-top: 1rem;
24
+ }
25
+ .doc-content {
26
+ white-space: pre-wrap;
27
+ font-family: monospace;
28
+ background-color: #f8f9fa;
29
+ padding: 1rem;
30
+ border-radius: 0.25rem;
31
+ }
32
+ #sidebar {
33
+ position: fixed;
34
+ top: 0;
35
+ left: 0;
36
+ height: 100vh;
37
+ width: 250px;
38
+ background-color: #f8f9fa;
39
+ padding: 20px;
40
+ overflow-y: auto;
41
+ border-right: 1px solid #dee2e6;
42
+ }
43
+ #main-content {
44
+ margin-left: 250px;
45
+ padding: 20px;
46
+ }
47
+ .nav-link {
48
+ color: #0d6efd;
49
+ padding: 5px 0;
50
+ }
51
+ .nav-link:hover {
52
+ background-color: #e9ecef;
53
+ }
54
+ .nav-link.active {
55
+ font-weight: bold;
56
+ background-color: #e9ecef;
57
+ }
58
+ </style>
59
+ </head>
60
+ <body>
61
+ <div id="sidebar">
62
+ <h5 class="mb-3">Tools</h5>
63
+ <nav class="nav flex-column">
64
+ {% for tool in tools %}
65
+ <a class="nav-link" href="#{{ tool.name }}">{{ tool.name }}</a>
66
+ {% endfor %}
67
+ </nav>
68
+ </div>
69
+
70
+ <div id="main-content">
71
+ <h1 class="mb-4">ReAct Agent Tools Documentation</h1>
72
+
73
+ <div class="row">
74
+ <div class="col-12">
75
+ {% for tool in tools %}
76
+ <div class="tool-section" id="{{ tool.name }}">
77
+ <h2 class="tool-name">@tool {{ tool.name }}</h2>
78
+
79
+ <h4>Documentation:</h4>
80
+ <div class="doc-content">{{ tool.doc }}</div>
81
+
82
+ <h4 class="mt-3">Parameters:</h4>
83
+ <table class="table param-table">
84
+ <thead>
85
+ <tr>
86
+ <th>Name</th>
87
+ <th>Type</th>
88
+ <th>Default</th>
89
+ </tr>
90
+ </thead>
91
+ <tbody>
92
+ {% for param in tool.parameters %}
93
+ <tr>
94
+ <td>{{ param.name }}</td>
95
+ <td><code>{{ param.annotation }}</code></td>
96
+ <td>{% if param.default != None %}<code>{{ param.default }}</code>{% else %}-{% endif %}</td>
97
+ </tr>
98
+ {% endfor %}
99
+ </tbody>
100
+ </table>
101
+
102
+ <h4 class="mt-3">Returns:</h4>
103
+ <code>{{ tool.return_annotation }}</code>
104
+ </div>
105
+ {% endfor %}
106
+ </div>
107
+ </div>
108
+ </div>
109
+
110
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
111
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"></script>
112
+ <script>
113
+ // 高亮當前選中的導航項
114
+ document.addEventListener('DOMContentLoaded', function() {
115
+ const navLinks = document.querySelectorAll('.nav-link');
116
+
117
+ // 監聽滾動事件
118
+ window.addEventListener('scroll', function() {
119
+ let currentSection = '';
120
+ const sections = document.querySelectorAll('.tool-section');
121
+
122
+ sections.forEach(section => {
123
+ const sectionTop = section.offsetTop;
124
+ const sectionHeight = section.clientHeight;
125
+ if (pageYOffset >= sectionTop - 100) {
126
+ currentSection = section.getAttribute('id');
127
+ }
128
+ });
129
+
130
+ // 更新導航項的激活狀態
131
+ navLinks.forEach(link => {
132
+ link.classList.remove('active');
133
+ if (link.getAttribute('href').substring(1) === currentSection) {
134
+ link.classList.add('active');
135
+ }
136
+ });
137
+ });
138
+
139
+ // 平滑滾動
140
+ navLinks.forEach(link => {
141
+ link.addEventListener('click', function(e) {
142
+ e.preventDefault();
143
+ const targetId = this.getAttribute('href').substring(1);
144
+ const targetElement = document.getElementById(targetId);
145
+ window.scrollTo({
146
+ top: targetElement.offsetTop - 20,
147
+ behavior: 'smooth'
148
+ });
149
+ });
150
+ });
151
+ });
152
+ </script>
153
+ </body>
154
154
  </html>
@@ -1,7 +1,7 @@
1
- from botrun_flow_lang.utils.botrun_logger import (
2
- BotrunLogger,
3
- get_default_botrun_logger,
4
- get_session_botrun_logger,
5
- )
6
-
7
- __all__ = ["BotrunLogger", "get_default_botrun_logger", "get_session_botrun_logger"]
1
+ from botrun_flow_lang.utils.botrun_logger import (
2
+ BotrunLogger,
3
+ get_default_botrun_logger,
4
+ get_session_botrun_logger,
5
+ )
6
+
7
+ __all__ = ["BotrunLogger", "get_default_botrun_logger", "get_session_botrun_logger"]