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,151 +1,151 @@
1
- import unittest
2
- import requests
3
- from botrun_flow_lang.langgraph_agents.agents.util.plotly_util import (
4
- generate_plotly_files,
5
- )
6
-
7
-
8
- class TestPlotlyUtil(unittest.TestCase):
9
- def setUp(self):
10
- """Set up test fixtures"""
11
- self.botrun_flow_lang_url = (
12
- "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app"
13
- )
14
- self.user_id = "sebastian.hsu@gmail.com"
15
-
16
- def verify_plotly_content(self, html_url: str, expected_title: str):
17
- """Helper method to verify the plotly HTML content"""
18
- # Verify URL format
19
- self.assertTrue(html_url.endswith(".html"), "URL should end with .html")
20
-
21
- # Get the HTML content
22
- response = requests.get(html_url)
23
- self.assertEqual(response.status_code, 200, "Failed to fetch HTML content")
24
-
25
- html_content = response.text.lower()
26
-
27
- # Debug print
28
- print("\nHTML Content (first 500 chars):", html_content[:500])
29
- print("\nExpected title:", expected_title.lower())
30
-
31
- # Check if it's a plotly chart (case insensitive)
32
- self.assertTrue(
33
- "plotly" in html_content, "HTML content should contain 'plotly'"
34
- )
35
-
36
- # Check if it contains the expected title (case insensitive)
37
- # expected_title_lower = expected_title.lower()
38
- # self.assertTrue(
39
- # expected_title_lower in html_content,
40
- # f"HTML content should contain title '{expected_title}'",
41
- # )
42
-
43
- # Check if it contains the required plotly elements
44
- self.assertTrue(
45
- "<div" in html_content, "HTML content should contain div elements"
46
- )
47
- self.assertTrue(
48
- "<script" in html_content, "HTML content should contain script elements"
49
- )
50
-
51
- def test_generate_scatter_plot(self):
52
- """Test generating a scatter plot"""
53
- # Test data for scatter plot
54
- scatter_data = {
55
- "data": [
56
- {
57
- "type": "scatter",
58
- "x": [1, 2, 3, 4, 5],
59
- "y": [10, 11, 13, 8, 15],
60
- "mode": "markers+lines",
61
- "name": "樣本數據",
62
- }
63
- ],
64
- "layout": {
65
- "title": "散點圖範例",
66
- "xaxis": {"title": "X軸"},
67
- "yaxis": {"title": "Y軸"},
68
- },
69
- }
70
-
71
- # Execute test
72
- html_url = generate_plotly_files(
73
- figure_data=scatter_data,
74
- botrun_flow_lang_url=self.botrun_flow_lang_url,
75
- user_id=self.user_id,
76
- title="互動式散點圖",
77
- )
78
-
79
- # Verify results
80
- self.verify_plotly_content(html_url, "互動式散點圖")
81
-
82
- def test_generate_bar_chart(self):
83
- """Test generating a bar chart"""
84
- # Test data for bar chart
85
- bar_data = {
86
- "data": [
87
- {
88
- "type": "bar",
89
- "x": ["甲", "乙", "丙", "丁"],
90
- "y": [20, 14, 23, 25],
91
- "name": "長條圖數據",
92
- }
93
- ],
94
- "layout": {
95
- "title": "長條圖範例",
96
- "xaxis": {"title": "類別"},
97
- "yaxis": {"title": "數值"},
98
- },
99
- }
100
-
101
- # Execute test
102
- html_url = generate_plotly_files(
103
- figure_data=bar_data,
104
- botrun_flow_lang_url=self.botrun_flow_lang_url,
105
- user_id=self.user_id,
106
- title="互動式長條圖",
107
- )
108
-
109
- # Verify results
110
- self.verify_plotly_content(html_url, "互動式長條圖")
111
-
112
- def test_generate_pie_chart(self):
113
- """Test generating a pie chart"""
114
- # Test data for pie chart
115
- pie_data = {
116
- "data": [
117
- {
118
- "type": "pie",
119
- "values": [35, 25, 20, 20],
120
- "labels": ["甲部門", "乙部門", "丙部門", "丁部門"],
121
- "hole": 0.4,
122
- }
123
- ],
124
- "layout": {"title": "圓餅圖範例", "showlegend": True},
125
- }
126
-
127
- # Execute test
128
- html_url = generate_plotly_files(
129
- figure_data=pie_data,
130
- botrun_flow_lang_url=self.botrun_flow_lang_url,
131
- user_id=self.user_id,
132
- title="互動式圓餅圖",
133
- )
134
-
135
- # Verify results
136
- self.verify_plotly_content(html_url, "互動式圓餅圖")
137
-
138
- def test_generate_plotly_files_error(self):
139
- """Test error handling with invalid data"""
140
- result = generate_plotly_files(
141
- figure_data={
142
- "data": [{"type": "invalid_type"}]
143
- }, # Invalid plot type will cause an error
144
- botrun_flow_lang_url=self.botrun_flow_lang_url,
145
- user_id=self.user_id,
146
- )
147
- self.assertTrue(result.startswith("Error:"))
148
-
149
-
150
- if __name__ == "__main__":
151
- unittest.main()
1
+ import unittest
2
+ import requests
3
+ from botrun_flow_lang.langgraph_agents.agents.util.plotly_util import (
4
+ generate_plotly_files,
5
+ )
6
+
7
+
8
+ class TestPlotlyUtil(unittest.TestCase):
9
+ def setUp(self):
10
+ """Set up test fixtures"""
11
+ self.botrun_flow_lang_url = (
12
+ "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app"
13
+ )
14
+ self.user_id = "sebastian.hsu@gmail.com"
15
+
16
+ def verify_plotly_content(self, html_url: str, expected_title: str):
17
+ """Helper method to verify the plotly HTML content"""
18
+ # Verify URL format
19
+ self.assertTrue(html_url.endswith(".html"), "URL should end with .html")
20
+
21
+ # Get the HTML content
22
+ response = requests.get(html_url)
23
+ self.assertEqual(response.status_code, 200, "Failed to fetch HTML content")
24
+
25
+ html_content = response.text.lower()
26
+
27
+ # Debug print
28
+ print("\nHTML Content (first 500 chars):", html_content[:500])
29
+ print("\nExpected title:", expected_title.lower())
30
+
31
+ # Check if it's a plotly chart (case insensitive)
32
+ self.assertTrue(
33
+ "plotly" in html_content, "HTML content should contain 'plotly'"
34
+ )
35
+
36
+ # Check if it contains the expected title (case insensitive)
37
+ # expected_title_lower = expected_title.lower()
38
+ # self.assertTrue(
39
+ # expected_title_lower in html_content,
40
+ # f"HTML content should contain title '{expected_title}'",
41
+ # )
42
+
43
+ # Check if it contains the required plotly elements
44
+ self.assertTrue(
45
+ "<div" in html_content, "HTML content should contain div elements"
46
+ )
47
+ self.assertTrue(
48
+ "<script" in html_content, "HTML content should contain script elements"
49
+ )
50
+
51
+ def test_generate_scatter_plot(self):
52
+ """Test generating a scatter plot"""
53
+ # Test data for scatter plot
54
+ scatter_data = {
55
+ "data": [
56
+ {
57
+ "type": "scatter",
58
+ "x": [1, 2, 3, 4, 5],
59
+ "y": [10, 11, 13, 8, 15],
60
+ "mode": "markers+lines",
61
+ "name": "樣本數據",
62
+ }
63
+ ],
64
+ "layout": {
65
+ "title": "散點圖範例",
66
+ "xaxis": {"title": "X軸"},
67
+ "yaxis": {"title": "Y軸"},
68
+ },
69
+ }
70
+
71
+ # Execute test
72
+ html_url = generate_plotly_files(
73
+ figure_data=scatter_data,
74
+ botrun_flow_lang_url=self.botrun_flow_lang_url,
75
+ user_id=self.user_id,
76
+ title="互動式散點圖",
77
+ )
78
+
79
+ # Verify results
80
+ self.verify_plotly_content(html_url, "互動式散點圖")
81
+
82
+ def test_generate_bar_chart(self):
83
+ """Test generating a bar chart"""
84
+ # Test data for bar chart
85
+ bar_data = {
86
+ "data": [
87
+ {
88
+ "type": "bar",
89
+ "x": ["甲", "乙", "丙", "丁"],
90
+ "y": [20, 14, 23, 25],
91
+ "name": "長條圖數據",
92
+ }
93
+ ],
94
+ "layout": {
95
+ "title": "長條圖範例",
96
+ "xaxis": {"title": "類別"},
97
+ "yaxis": {"title": "數值"},
98
+ },
99
+ }
100
+
101
+ # Execute test
102
+ html_url = generate_plotly_files(
103
+ figure_data=bar_data,
104
+ botrun_flow_lang_url=self.botrun_flow_lang_url,
105
+ user_id=self.user_id,
106
+ title="互動式長條圖",
107
+ )
108
+
109
+ # Verify results
110
+ self.verify_plotly_content(html_url, "互動式長條圖")
111
+
112
+ def test_generate_pie_chart(self):
113
+ """Test generating a pie chart"""
114
+ # Test data for pie chart
115
+ pie_data = {
116
+ "data": [
117
+ {
118
+ "type": "pie",
119
+ "values": [35, 25, 20, 20],
120
+ "labels": ["甲部門", "乙部門", "丙部門", "丁部門"],
121
+ "hole": 0.4,
122
+ }
123
+ ],
124
+ "layout": {"title": "圓餅圖範例", "showlegend": True},
125
+ }
126
+
127
+ # Execute test
128
+ html_url = generate_plotly_files(
129
+ figure_data=pie_data,
130
+ botrun_flow_lang_url=self.botrun_flow_lang_url,
131
+ user_id=self.user_id,
132
+ title="互動式圓餅圖",
133
+ )
134
+
135
+ # Verify results
136
+ self.verify_plotly_content(html_url, "互動式圓餅圖")
137
+
138
+ def test_generate_plotly_files_error(self):
139
+ """Test error handling with invalid data"""
140
+ result = generate_plotly_files(
141
+ figure_data={
142
+ "data": [{"type": "invalid_type"}]
143
+ }, # Invalid plot type will cause an error
144
+ botrun_flow_lang_url=self.botrun_flow_lang_url,
145
+ user_id=self.user_id,
146
+ )
147
+ self.assertTrue(result.startswith("Error:"))
148
+
149
+
150
+ if __name__ == "__main__":
151
+ unittest.main()
@@ -1,65 +1,65 @@
1
- import asyncio
2
- from botrun_flow_lang.models.botrun_app import BotrunApp
3
- from botrun_flow_lang.models.workflow import WorkflowData
4
- from botrun_flow_lang.models.nodes.start_node import StartNode, StartNodeData
5
- from botrun_flow_lang.models.nodes.llm_node import LLMNode, LLMNodeData, LLMModelConfig
6
- from botrun_flow_lang.models.nodes.end_node import EndNode, EndNodeData
7
- from botrun_flow_lang.api.workflow.workflow_engine import run_workflow
8
-
9
-
10
- async def test_run_workflow():
11
- # 创建 BotrunApp
12
- botrun_app = BotrunApp(name="波文件問答", description="給波文件問答用的app")
13
-
14
- # 创建 StartNode
15
- start_node = StartNode(
16
- data=StartNodeData(title="Start", user_input="告訴我一個小紅帽的故事")
17
- )
18
-
19
- # 创建 LLMNode
20
- model_config = LLMModelConfig(
21
- completion_params={
22
- "max_tokens": 4096,
23
- "temperature": 0.7,
24
- },
25
- mode="chat",
26
- name="gpt-4o-2024-08-06",
27
- provider="openai",
28
- )
29
- llm_node = LLMNode(
30
- data=LLMNodeData(
31
- title="LLM",
32
- model=model_config,
33
- prompt_template=[
34
- {
35
- "role": "system",
36
- "text": "妳是臺灣人,回答要用臺灣繁體中文正式用語,需要的時候也可以用英文,可以親切、俏皮、幽默,但不能隨便輕浮。在使用者合理的要求下請盡量配合他的需求,不要隨便拒絕",
37
- },
38
- {
39
- "role": "user",
40
- "text": "{user_input}",
41
- },
42
- ],
43
- )
44
- )
45
-
46
- # 创建 EndNode
47
- end_node = EndNode(data=EndNodeData(title="End", output="故事結束:{llm_output}"))
48
-
49
- # 创建 Workflow
50
- workflow = WorkflowData(nodes=[start_node, llm_node, end_node])
51
-
52
- # 运行工作流
53
- result = await run_workflow(workflow, {})
54
-
55
- # 打印结果
56
- print(result["final_output"])
57
-
58
- # 添加一些断言来验证结果
59
- assert "final_output" in result
60
- assert result["final_output"].startswith("故事結束:")
61
- assert "小紅帽" in result["final_output"]
62
-
63
-
64
- if __name__ == "__main__":
65
- asyncio.run(test_run_workflow())
1
+ import asyncio
2
+ from botrun_flow_lang.models.botrun_app import BotrunApp
3
+ from botrun_flow_lang.models.workflow import WorkflowData
4
+ from botrun_flow_lang.models.nodes.start_node import StartNode, StartNodeData
5
+ from botrun_flow_lang.models.nodes.llm_node import LLMNode, LLMNodeData, LLMModelConfig
6
+ from botrun_flow_lang.models.nodes.end_node import EndNode, EndNodeData
7
+ from botrun_flow_lang.api.workflow.workflow_engine import run_workflow
8
+
9
+
10
+ async def test_run_workflow():
11
+ # 创建 BotrunApp
12
+ botrun_app = BotrunApp(name="波文件問答", description="給波文件問答用的app")
13
+
14
+ # 创建 StartNode
15
+ start_node = StartNode(
16
+ data=StartNodeData(title="Start", user_input="告訴我一個小紅帽的故事")
17
+ )
18
+
19
+ # 创建 LLMNode
20
+ model_config = LLMModelConfig(
21
+ completion_params={
22
+ "max_tokens": 4096,
23
+ "temperature": 0.7,
24
+ },
25
+ mode="chat",
26
+ name="gpt-4o-2024-08-06",
27
+ provider="openai",
28
+ )
29
+ llm_node = LLMNode(
30
+ data=LLMNodeData(
31
+ title="LLM",
32
+ model=model_config,
33
+ prompt_template=[
34
+ {
35
+ "role": "system",
36
+ "text": "妳是臺灣人,回答要用臺灣繁體中文正式用語,需要的時候也可以用英文,可以親切、俏皮、幽默,但不能隨便輕浮。在使用者合理的要求下請盡量配合他的需求,不要隨便拒絕",
37
+ },
38
+ {
39
+ "role": "user",
40
+ "text": "{user_input}",
41
+ },
42
+ ],
43
+ )
44
+ )
45
+
46
+ # 创建 EndNode
47
+ end_node = EndNode(data=EndNodeData(title="End", output="故事結束:{llm_output}"))
48
+
49
+ # 创建 Workflow
50
+ workflow = WorkflowData(nodes=[start_node, llm_node, end_node])
51
+
52
+ # 运行工作流
53
+ result = await run_workflow(workflow, {})
54
+
55
+ # 打印结果
56
+ print(result["final_output"])
57
+
58
+ # 添加一些断言来验证结果
59
+ assert "final_output" in result
60
+ assert result["final_output"].startswith("故事結束:")
61
+ assert "小紅帽" in result["final_output"]
62
+
63
+
64
+ if __name__ == "__main__":
65
+ asyncio.run(test_run_workflow())