botrun-flow-lang 5.12.263__py3-none-any.whl → 5.12.264__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 (87) 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 +508 -508
  6. botrun_flow_lang/api/langgraph_api.py +811 -811
  7. botrun_flow_lang/api/line_bot_api.py +1484 -1484
  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 +395 -395
  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 +178 -178
  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/gemini_subsidy_graph.py +460 -460
  24. botrun_flow_lang/langgraph_agents/agents/gov_researcher/gov_researcher_2_graph.py +1002 -1002
  25. botrun_flow_lang/langgraph_agents/agents/gov_researcher/gov_researcher_graph.py +822 -822
  26. botrun_flow_lang/langgraph_agents/agents/langgraph_react_agent.py +723 -723
  27. botrun_flow_lang/langgraph_agents/agents/search_agent_graph.py +864 -864
  28. botrun_flow_lang/langgraph_agents/agents/tools/__init__.py +4 -4
  29. botrun_flow_lang/langgraph_agents/agents/tools/gemini_code_execution.py +376 -376
  30. botrun_flow_lang/langgraph_agents/agents/util/gemini_grounding.py +66 -66
  31. botrun_flow_lang/langgraph_agents/agents/util/html_util.py +316 -316
  32. botrun_flow_lang/langgraph_agents/agents/util/img_util.py +294 -294
  33. botrun_flow_lang/langgraph_agents/agents/util/local_files.py +419 -419
  34. botrun_flow_lang/langgraph_agents/agents/util/mermaid_util.py +86 -86
  35. botrun_flow_lang/langgraph_agents/agents/util/model_utils.py +143 -143
  36. botrun_flow_lang/langgraph_agents/agents/util/pdf_analyzer.py +486 -486
  37. botrun_flow_lang/langgraph_agents/agents/util/pdf_cache.py +250 -250
  38. botrun_flow_lang/langgraph_agents/agents/util/pdf_processor.py +204 -204
  39. botrun_flow_lang/langgraph_agents/agents/util/perplexity_search.py +464 -464
  40. botrun_flow_lang/langgraph_agents/agents/util/plotly_util.py +59 -59
  41. botrun_flow_lang/langgraph_agents/agents/util/tavily_search.py +199 -199
  42. botrun_flow_lang/langgraph_agents/agents/util/youtube_util.py +90 -90
  43. botrun_flow_lang/langgraph_agents/cache/langgraph_botrun_cache.py +197 -197
  44. botrun_flow_lang/llm_agent/llm_agent.py +19 -19
  45. botrun_flow_lang/llm_agent/llm_agent_util.py +83 -83
  46. botrun_flow_lang/log/.gitignore +2 -2
  47. botrun_flow_lang/main.py +61 -61
  48. botrun_flow_lang/main_fast.py +51 -51
  49. botrun_flow_lang/mcp_server/__init__.py +10 -10
  50. botrun_flow_lang/mcp_server/default_mcp.py +744 -744
  51. botrun_flow_lang/models/nodes/utils.py +205 -205
  52. botrun_flow_lang/models/token_usage.py +34 -34
  53. botrun_flow_lang/requirements.txt +21 -21
  54. botrun_flow_lang/services/base/firestore_base.py +30 -30
  55. botrun_flow_lang/services/hatch/hatch_factory.py +11 -11
  56. botrun_flow_lang/services/hatch/hatch_fs_store.py +419 -419
  57. botrun_flow_lang/services/storage/storage_cs_store.py +206 -206
  58. botrun_flow_lang/services/storage/storage_factory.py +12 -12
  59. botrun_flow_lang/services/storage/storage_store.py +65 -65
  60. botrun_flow_lang/services/user_setting/user_setting_factory.py +9 -9
  61. botrun_flow_lang/services/user_setting/user_setting_fs_store.py +66 -66
  62. botrun_flow_lang/static/docs/tools/index.html +926 -926
  63. botrun_flow_lang/tests/api_functional_tests.py +1525 -1525
  64. botrun_flow_lang/tests/api_stress_test.py +357 -357
  65. botrun_flow_lang/tests/shared_hatch_tests.py +333 -333
  66. botrun_flow_lang/tests/test_botrun_app.py +46 -46
  67. botrun_flow_lang/tests/test_html_util.py +31 -31
  68. botrun_flow_lang/tests/test_img_analyzer.py +190 -190
  69. botrun_flow_lang/tests/test_img_util.py +39 -39
  70. botrun_flow_lang/tests/test_local_files.py +114 -114
  71. botrun_flow_lang/tests/test_mermaid_util.py +103 -103
  72. botrun_flow_lang/tests/test_pdf_analyzer.py +104 -104
  73. botrun_flow_lang/tests/test_plotly_util.py +151 -151
  74. botrun_flow_lang/tests/test_run_workflow_engine.py +65 -65
  75. botrun_flow_lang/tools/generate_docs.py +133 -133
  76. botrun_flow_lang/tools/templates/tools.html +153 -153
  77. botrun_flow_lang/utils/__init__.py +7 -7
  78. botrun_flow_lang/utils/botrun_logger.py +344 -344
  79. botrun_flow_lang/utils/clients/rate_limit_client.py +209 -209
  80. botrun_flow_lang/utils/clients/token_verify_client.py +153 -153
  81. botrun_flow_lang/utils/google_drive_utils.py +654 -654
  82. botrun_flow_lang/utils/langchain_utils.py +324 -324
  83. botrun_flow_lang/utils/yaml_utils.py +9 -9
  84. {botrun_flow_lang-5.12.263.dist-info → botrun_flow_lang-5.12.264.dist-info}/METADATA +1 -1
  85. botrun_flow_lang-5.12.264.dist-info/RECORD +102 -0
  86. botrun_flow_lang-5.12.263.dist-info/RECORD +0 -102
  87. {botrun_flow_lang-5.12.263.dist-info → botrun_flow_lang-5.12.264.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"]