botrun-flow-lang 5.12.263__py3-none-any.whl → 6.2.21__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 (89) 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 +816 -811
  7. botrun_flow_lang/api/langgraph_constants.py +11 -0
  8. botrun_flow_lang/api/line_bot_api.py +1484 -1484
  9. botrun_flow_lang/api/model_api.py +300 -300
  10. botrun_flow_lang/api/rate_limit_api.py +32 -32
  11. botrun_flow_lang/api/routes.py +79 -79
  12. botrun_flow_lang/api/search_api.py +53 -53
  13. botrun_flow_lang/api/storage_api.py +395 -395
  14. botrun_flow_lang/api/subsidy_api.py +290 -290
  15. botrun_flow_lang/api/subsidy_api_system_prompt.txt +109 -109
  16. botrun_flow_lang/api/user_setting_api.py +70 -70
  17. botrun_flow_lang/api/version_api.py +31 -31
  18. botrun_flow_lang/api/youtube_api.py +26 -26
  19. botrun_flow_lang/constants.py +13 -13
  20. botrun_flow_lang/langgraph_agents/agents/agent_runner.py +178 -178
  21. botrun_flow_lang/langgraph_agents/agents/agent_tools/step_planner.py +77 -77
  22. botrun_flow_lang/langgraph_agents/agents/checkpointer/firestore_checkpointer.py +666 -666
  23. botrun_flow_lang/langgraph_agents/agents/gov_researcher/GOV_RESEARCHER_PRD.md +192 -192
  24. botrun_flow_lang/langgraph_agents/agents/gov_researcher/gemini_subsidy_graph.py +460 -460
  25. botrun_flow_lang/langgraph_agents/agents/gov_researcher/gov_researcher_2_graph.py +1002 -1002
  26. botrun_flow_lang/langgraph_agents/agents/gov_researcher/gov_researcher_graph.py +822 -822
  27. botrun_flow_lang/langgraph_agents/agents/langgraph_react_agent.py +730 -723
  28. botrun_flow_lang/langgraph_agents/agents/search_agent_graph.py +864 -864
  29. botrun_flow_lang/langgraph_agents/agents/tools/__init__.py +4 -4
  30. botrun_flow_lang/langgraph_agents/agents/tools/gemini_code_execution.py +376 -376
  31. botrun_flow_lang/langgraph_agents/agents/util/gemini_grounding.py +66 -66
  32. botrun_flow_lang/langgraph_agents/agents/util/html_util.py +316 -316
  33. botrun_flow_lang/langgraph_agents/agents/util/img_util.py +336 -294
  34. botrun_flow_lang/langgraph_agents/agents/util/local_files.py +419 -419
  35. botrun_flow_lang/langgraph_agents/agents/util/mermaid_util.py +86 -86
  36. botrun_flow_lang/langgraph_agents/agents/util/model_utils.py +143 -143
  37. botrun_flow_lang/langgraph_agents/agents/util/pdf_analyzer.py +562 -486
  38. botrun_flow_lang/langgraph_agents/agents/util/pdf_cache.py +250 -250
  39. botrun_flow_lang/langgraph_agents/agents/util/pdf_processor.py +204 -204
  40. botrun_flow_lang/langgraph_agents/agents/util/perplexity_search.py +464 -464
  41. botrun_flow_lang/langgraph_agents/agents/util/plotly_util.py +59 -59
  42. botrun_flow_lang/langgraph_agents/agents/util/tavily_search.py +199 -199
  43. botrun_flow_lang/langgraph_agents/agents/util/usage_metadata.py +34 -0
  44. botrun_flow_lang/langgraph_agents/agents/util/youtube_util.py +90 -90
  45. botrun_flow_lang/langgraph_agents/cache/langgraph_botrun_cache.py +197 -197
  46. botrun_flow_lang/llm_agent/llm_agent.py +19 -19
  47. botrun_flow_lang/llm_agent/llm_agent_util.py +83 -83
  48. botrun_flow_lang/log/.gitignore +2 -2
  49. botrun_flow_lang/main.py +61 -61
  50. botrun_flow_lang/main_fast.py +51 -51
  51. botrun_flow_lang/mcp_server/__init__.py +10 -10
  52. botrun_flow_lang/mcp_server/default_mcp.py +854 -744
  53. botrun_flow_lang/models/nodes/utils.py +205 -205
  54. botrun_flow_lang/models/token_usage.py +34 -34
  55. botrun_flow_lang/requirements.txt +21 -21
  56. botrun_flow_lang/services/base/firestore_base.py +30 -30
  57. botrun_flow_lang/services/hatch/hatch_factory.py +11 -11
  58. botrun_flow_lang/services/hatch/hatch_fs_store.py +419 -419
  59. botrun_flow_lang/services/storage/storage_cs_store.py +206 -206
  60. botrun_flow_lang/services/storage/storage_factory.py +12 -12
  61. botrun_flow_lang/services/storage/storage_store.py +65 -65
  62. botrun_flow_lang/services/user_setting/user_setting_factory.py +9 -9
  63. botrun_flow_lang/services/user_setting/user_setting_fs_store.py +66 -66
  64. botrun_flow_lang/static/docs/tools/index.html +926 -926
  65. botrun_flow_lang/tests/api_functional_tests.py +1525 -1525
  66. botrun_flow_lang/tests/api_stress_test.py +357 -357
  67. botrun_flow_lang/tests/shared_hatch_tests.py +333 -333
  68. botrun_flow_lang/tests/test_botrun_app.py +46 -46
  69. botrun_flow_lang/tests/test_html_util.py +31 -31
  70. botrun_flow_lang/tests/test_img_analyzer.py +190 -190
  71. botrun_flow_lang/tests/test_img_util.py +39 -39
  72. botrun_flow_lang/tests/test_local_files.py +114 -114
  73. botrun_flow_lang/tests/test_mermaid_util.py +103 -103
  74. botrun_flow_lang/tests/test_pdf_analyzer.py +104 -104
  75. botrun_flow_lang/tests/test_plotly_util.py +151 -151
  76. botrun_flow_lang/tests/test_run_workflow_engine.py +65 -65
  77. botrun_flow_lang/tools/generate_docs.py +133 -133
  78. botrun_flow_lang/tools/templates/tools.html +153 -153
  79. botrun_flow_lang/utils/__init__.py +7 -7
  80. botrun_flow_lang/utils/botrun_logger.py +344 -344
  81. botrun_flow_lang/utils/clients/rate_limit_client.py +209 -209
  82. botrun_flow_lang/utils/clients/token_verify_client.py +153 -153
  83. botrun_flow_lang/utils/google_drive_utils.py +654 -654
  84. botrun_flow_lang/utils/langchain_utils.py +324 -324
  85. botrun_flow_lang/utils/yaml_utils.py +9 -9
  86. {botrun_flow_lang-5.12.263.dist-info → botrun_flow_lang-6.2.21.dist-info}/METADATA +6 -6
  87. botrun_flow_lang-6.2.21.dist-info/RECORD +104 -0
  88. botrun_flow_lang-5.12.263.dist-info/RECORD +0 -102
  89. {botrun_flow_lang-5.12.263.dist-info → botrun_flow_lang-6.2.21.dist-info}/WHEEL +0 -0
@@ -1,114 +1,114 @@
1
- import unittest
2
- import asyncio
3
- import os
4
- from pathlib import Path
5
- from botrun_flow_lang.langgraph_agents.agents.util.local_files import (
6
- generate_tmp_text_file,
7
- read_tmp_text_file,
8
- )
9
-
10
-
11
- class TestLocalFiles(unittest.TestCase):
12
- def setUp(self):
13
- """Set up test fixtures"""
14
- # Test configuration
15
- self.test_text_content = (
16
- "This is a test text file content.\n\nLine 2\nLine 3\n測試中文內容"
17
- )
18
- self.user_id = "sebastian.hsu@gmail.com"
19
-
20
- def test_generate_tmp_text_file(self):
21
- """Test generate_tmp_text_file function"""
22
- # Run the async function
23
- result = asyncio.run(
24
- generate_tmp_text_file(self.test_text_content, self.user_id)
25
- )
26
-
27
- # Print the result for manual verification
28
- print("\nTest Result:")
29
- print(f"Generated storage path: {result}")
30
-
31
- # Basic validation
32
- if result.startswith("Error:"):
33
- print(f"Test failed with error: {result}")
34
- self.fail(f"Test failed with error: {result}")
35
- else:
36
- print("Test successful - storage path generated")
37
- # Validate storage path format
38
- expected_path_prefix = f"tmp/{self.user_id}/"
39
- self.assertTrue(
40
- result.startswith(expected_path_prefix),
41
- f"Expected storage path to start with '{expected_path_prefix}', got: {result}",
42
- )
43
-
44
- # Verify content by reading back the file
45
- read_content = asyncio.run(read_tmp_text_file(result))
46
- if read_content.startswith("Error:"):
47
- self.fail(f"Failed to read back content: {read_content}")
48
- else:
49
- self.assertEqual(
50
- read_content,
51
- self.test_text_content,
52
- "Read content doesn't match original content"
53
- )
54
- print("Content verification successful - read content matches original")
55
-
56
- def test_generate_tmp_text_file_with_unicode(self):
57
- """Test generate_tmp_text_file function with unicode content"""
58
- unicode_content = "Unicode test: 你好世界 🌍 ñáéíóú âêîôû àèìòù"
59
-
60
- result = asyncio.run(
61
- generate_tmp_text_file(unicode_content, self.user_id)
62
- )
63
-
64
- print(f"\nUnicode Test Result: {result}")
65
-
66
- if result.startswith("Error:"):
67
- print(f"Unicode test failed: {result}")
68
- self.fail(f"Unicode test failed: {result}")
69
- else:
70
- print("Unicode test successful - storage path generated")
71
-
72
- # Verify content by reading back the file
73
- read_content = asyncio.run(read_tmp_text_file(result))
74
- if read_content.startswith("Error:"):
75
- self.fail(f"Failed to read back unicode content: {read_content}")
76
- else:
77
- self.assertEqual(
78
- read_content,
79
- unicode_content,
80
- "Unicode read content doesn't match original content"
81
- )
82
- print("Unicode content verification successful - read content matches original")
83
-
84
- def test_generate_tmp_text_file_with_empty_content(self):
85
- """Test generate_tmp_text_file function with empty content"""
86
- empty_content = ""
87
-
88
- result = asyncio.run(
89
- generate_tmp_text_file(empty_content, self.user_id)
90
- )
91
-
92
- print(f"\nEmpty Content Test Result: {result}")
93
-
94
- if result.startswith("Error:"):
95
- print(f"Empty content test failed: {result}")
96
- self.fail(f"Empty content test failed: {result}")
97
- else:
98
- print("Empty content test successful - storage path generated")
99
-
100
- # Verify content by reading back the file
101
- read_content = asyncio.run(read_tmp_text_file(result))
102
- if read_content.startswith("Error:"):
103
- self.fail(f"Failed to read back empty content: {read_content}")
104
- else:
105
- self.assertEqual(
106
- read_content,
107
- empty_content,
108
- "Empty read content doesn't match original content"
109
- )
110
- print("Empty content verification successful - read content matches original")
111
-
112
-
113
- if __name__ == "__main__":
114
- unittest.main()
1
+ import unittest
2
+ import asyncio
3
+ import os
4
+ from pathlib import Path
5
+ from botrun_flow_lang.langgraph_agents.agents.util.local_files import (
6
+ generate_tmp_text_file,
7
+ read_tmp_text_file,
8
+ )
9
+
10
+
11
+ class TestLocalFiles(unittest.TestCase):
12
+ def setUp(self):
13
+ """Set up test fixtures"""
14
+ # Test configuration
15
+ self.test_text_content = (
16
+ "This is a test text file content.\n\nLine 2\nLine 3\n測試中文內容"
17
+ )
18
+ self.user_id = "sebastian.hsu@gmail.com"
19
+
20
+ def test_generate_tmp_text_file(self):
21
+ """Test generate_tmp_text_file function"""
22
+ # Run the async function
23
+ result = asyncio.run(
24
+ generate_tmp_text_file(self.test_text_content, self.user_id)
25
+ )
26
+
27
+ # Print the result for manual verification
28
+ print("\nTest Result:")
29
+ print(f"Generated storage path: {result}")
30
+
31
+ # Basic validation
32
+ if result.startswith("Error:"):
33
+ print(f"Test failed with error: {result}")
34
+ self.fail(f"Test failed with error: {result}")
35
+ else:
36
+ print("Test successful - storage path generated")
37
+ # Validate storage path format
38
+ expected_path_prefix = f"tmp/{self.user_id}/"
39
+ self.assertTrue(
40
+ result.startswith(expected_path_prefix),
41
+ f"Expected storage path to start with '{expected_path_prefix}', got: {result}",
42
+ )
43
+
44
+ # Verify content by reading back the file
45
+ read_content = asyncio.run(read_tmp_text_file(result))
46
+ if read_content.startswith("Error:"):
47
+ self.fail(f"Failed to read back content: {read_content}")
48
+ else:
49
+ self.assertEqual(
50
+ read_content,
51
+ self.test_text_content,
52
+ "Read content doesn't match original content"
53
+ )
54
+ print("Content verification successful - read content matches original")
55
+
56
+ def test_generate_tmp_text_file_with_unicode(self):
57
+ """Test generate_tmp_text_file function with unicode content"""
58
+ unicode_content = "Unicode test: 你好世界 🌍 ñáéíóú âêîôû àèìòù"
59
+
60
+ result = asyncio.run(
61
+ generate_tmp_text_file(unicode_content, self.user_id)
62
+ )
63
+
64
+ print(f"\nUnicode Test Result: {result}")
65
+
66
+ if result.startswith("Error:"):
67
+ print(f"Unicode test failed: {result}")
68
+ self.fail(f"Unicode test failed: {result}")
69
+ else:
70
+ print("Unicode test successful - storage path generated")
71
+
72
+ # Verify content by reading back the file
73
+ read_content = asyncio.run(read_tmp_text_file(result))
74
+ if read_content.startswith("Error:"):
75
+ self.fail(f"Failed to read back unicode content: {read_content}")
76
+ else:
77
+ self.assertEqual(
78
+ read_content,
79
+ unicode_content,
80
+ "Unicode read content doesn't match original content"
81
+ )
82
+ print("Unicode content verification successful - read content matches original")
83
+
84
+ def test_generate_tmp_text_file_with_empty_content(self):
85
+ """Test generate_tmp_text_file function with empty content"""
86
+ empty_content = ""
87
+
88
+ result = asyncio.run(
89
+ generate_tmp_text_file(empty_content, self.user_id)
90
+ )
91
+
92
+ print(f"\nEmpty Content Test Result: {result}")
93
+
94
+ if result.startswith("Error:"):
95
+ print(f"Empty content test failed: {result}")
96
+ self.fail(f"Empty content test failed: {result}")
97
+ else:
98
+ print("Empty content test successful - storage path generated")
99
+
100
+ # Verify content by reading back the file
101
+ read_content = asyncio.run(read_tmp_text_file(result))
102
+ if read_content.startswith("Error:"):
103
+ self.fail(f"Failed to read back empty content: {read_content}")
104
+ else:
105
+ self.assertEqual(
106
+ read_content,
107
+ empty_content,
108
+ "Empty read content doesn't match original content"
109
+ )
110
+ print("Empty content verification successful - read content matches original")
111
+
112
+
113
+ if __name__ == "__main__":
114
+ unittest.main()
@@ -1,103 +1,103 @@
1
- import unittest
2
- import requests
3
- from botrun_flow_lang.langgraph_agents.agents.util.mermaid_util import (
4
- generate_mermaid_files,
5
- )
6
-
7
-
8
- class TestMermaidUtil(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_mermaid_content(self, html_url: str):
17
- """Helper method to verify the mermaid 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
26
-
27
- # Check if it's a mermaid diagram
28
- self.assertTrue(
29
- "mermaid" in html_content, "HTML content should contain 'mermaid'"
30
- )
31
-
32
- # Check if it contains the required elements
33
- self.assertTrue(
34
- '<div class="mermaid"' in html_content,
35
- "HTML content should contain mermaid div",
36
- )
37
- self.assertTrue(
38
- "mermaid.min.js" in html_content,
39
- "HTML content should contain mermaid.js script",
40
- )
41
-
42
- def test_generate_flowchart(self):
43
- """Test generating a flowchart"""
44
- # Test data for flowchart
45
- flowchart_data = """
46
- graph TD
47
- A[開始] --> B{是否有資料?}
48
- B -->|是| C[處理資料]
49
- B -->|否| D[取得資料]
50
- C --> E[結束]
51
- D --> B
52
- """
53
-
54
- # Execute test
55
- html_url = generate_mermaid_files(
56
- mermaid_data=flowchart_data,
57
- botrun_flow_lang_url=self.botrun_flow_lang_url,
58
- user_id=self.user_id,
59
- title="互動式流程圖",
60
- )
61
-
62
- # Verify results
63
- self.verify_mermaid_content(html_url)
64
-
65
- def test_generate_sequence_diagram(self):
66
- """Test generating a sequence diagram"""
67
- # Test data for sequence diagram
68
- sequence_data = """
69
- sequenceDiagram
70
- participant 使用者
71
- participant 系統
72
- participant 資料庫
73
- 使用者->>系統: 請求資料
74
- 系統->>資料庫: 查詢資料
75
- 資料庫-->>系統: 返回結果
76
- 系統-->>使用者: 顯示資料
77
- """
78
-
79
- # Execute test
80
- html_url = generate_mermaid_files(
81
- mermaid_data=sequence_data,
82
- botrun_flow_lang_url=self.botrun_flow_lang_url,
83
- user_id=self.user_id,
84
- title="互動式序列圖",
85
- )
86
-
87
- # Verify results
88
- self.verify_mermaid_content(html_url)
89
-
90
- def test_generate_mermaid_files_error(self):
91
- """Test error handling with invalid data"""
92
- result = generate_mermaid_files(
93
- mermaid_data="invalid mermaid syntax",
94
- botrun_flow_lang_url=self.botrun_flow_lang_url,
95
- user_id=self.user_id,
96
- )
97
- self.assertFalse(
98
- result.startswith("Error:")
99
- ) # Mermaid will handle syntax errors client-side
100
-
101
-
102
- if __name__ == "__main__":
103
- unittest.main()
1
+ import unittest
2
+ import requests
3
+ from botrun_flow_lang.langgraph_agents.agents.util.mermaid_util import (
4
+ generate_mermaid_files,
5
+ )
6
+
7
+
8
+ class TestMermaidUtil(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_mermaid_content(self, html_url: str):
17
+ """Helper method to verify the mermaid 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
26
+
27
+ # Check if it's a mermaid diagram
28
+ self.assertTrue(
29
+ "mermaid" in html_content, "HTML content should contain 'mermaid'"
30
+ )
31
+
32
+ # Check if it contains the required elements
33
+ self.assertTrue(
34
+ '<div class="mermaid"' in html_content,
35
+ "HTML content should contain mermaid div",
36
+ )
37
+ self.assertTrue(
38
+ "mermaid.min.js" in html_content,
39
+ "HTML content should contain mermaid.js script",
40
+ )
41
+
42
+ def test_generate_flowchart(self):
43
+ """Test generating a flowchart"""
44
+ # Test data for flowchart
45
+ flowchart_data = """
46
+ graph TD
47
+ A[開始] --> B{是否有資料?}
48
+ B -->|是| C[處理資料]
49
+ B -->|否| D[取得資料]
50
+ C --> E[結束]
51
+ D --> B
52
+ """
53
+
54
+ # Execute test
55
+ html_url = generate_mermaid_files(
56
+ mermaid_data=flowchart_data,
57
+ botrun_flow_lang_url=self.botrun_flow_lang_url,
58
+ user_id=self.user_id,
59
+ title="互動式流程圖",
60
+ )
61
+
62
+ # Verify results
63
+ self.verify_mermaid_content(html_url)
64
+
65
+ def test_generate_sequence_diagram(self):
66
+ """Test generating a sequence diagram"""
67
+ # Test data for sequence diagram
68
+ sequence_data = """
69
+ sequenceDiagram
70
+ participant 使用者
71
+ participant 系統
72
+ participant 資料庫
73
+ 使用者->>系統: 請求資料
74
+ 系統->>資料庫: 查詢資料
75
+ 資料庫-->>系統: 返回結果
76
+ 系統-->>使用者: 顯示資料
77
+ """
78
+
79
+ # Execute test
80
+ html_url = generate_mermaid_files(
81
+ mermaid_data=sequence_data,
82
+ botrun_flow_lang_url=self.botrun_flow_lang_url,
83
+ user_id=self.user_id,
84
+ title="互動式序列圖",
85
+ )
86
+
87
+ # Verify results
88
+ self.verify_mermaid_content(html_url)
89
+
90
+ def test_generate_mermaid_files_error(self):
91
+ """Test error handling with invalid data"""
92
+ result = generate_mermaid_files(
93
+ mermaid_data="invalid mermaid syntax",
94
+ botrun_flow_lang_url=self.botrun_flow_lang_url,
95
+ user_id=self.user_id,
96
+ )
97
+ self.assertFalse(
98
+ result.startswith("Error:")
99
+ ) # Mermaid will handle syntax errors client-side
100
+
101
+
102
+ if __name__ == "__main__":
103
+ unittest.main()
@@ -1,104 +1,104 @@
1
- import unittest
2
- import os
3
- from pathlib import Path
4
- from botrun_flow_lang.langgraph_agents.agents.util.local_files import (
5
- upload_and_get_tmp_public_url,
6
- )
7
- from botrun_flow_lang.langgraph_agents.agents.util.pdf_analyzer import analyze_pdf
8
-
9
-
10
- class TestPDFAnalyzer(unittest.TestCase):
11
- def setUp(self):
12
- # Get the path to the test PDF file
13
- current_dir = Path(__file__).parent
14
- self.pdf_path = (
15
- current_dir
16
- / "test_files"
17
- / "1120701A海廣離岸風力發電計畫環境影響說明書-C04.PDF"
18
- )
19
-
20
- # Ensure the test file exists
21
- self.assertTrue(
22
- os.path.exists(self.pdf_path), f"Test file not found at {self.pdf_path}"
23
- )
24
-
25
- def test_pdf_exists(self):
26
- """Test if the PDF file exists"""
27
- self.assertEqual(True, os.path.exists(self.pdf_path))
28
-
29
- def test_pdf_readable(self):
30
- """Test if the PDF file is readable"""
31
- self.assertEqual(True, os.access(self.pdf_path, os.R_OK))
32
-
33
- def test_pdf_not_empty(self):
34
- """Test if the PDF file is not empty"""
35
- self.assertEqual(True, os.path.getsize(self.pdf_path) > 0)
36
-
37
- def test_pdf_extension(self):
38
- """Test if the file has a PDF extension"""
39
- self.assertEqual(True, self.pdf_path.suffix.lower() == ".pdf")
40
-
41
- def test_analyze_table_4_3_1(self):
42
- """Test analyzing table 4.3-1 from the PDF"""
43
- query = "請你幫我找出在報告書中的「表 4.3-1 環境敏感地區調查表-第一級環境敏感地區」表格中的所有項目的「查詢結果及限制內容」幫我列出是或否?請全部列出來,不要遺漏"
44
- pdf_url = upload_and_get_tmp_public_url(
45
- self.pdf_path,
46
- "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
47
- "sebastian.hsu@gmail.com",
48
- )
49
- result = analyze_pdf(pdf_url, query)
50
-
51
- # Print the result for inspection
52
- print("\nAnalyze PDF Result:")
53
- print("-" * 50)
54
- print(result)
55
- print("-" * 50)
56
-
57
- # 確保結果不為空
58
- self.assertIsNotNone(result)
59
- self.assertNotEqual("", result)
60
-
61
- # 檢查每個項目的結果
62
- self.assertTrue(
63
- "活動斷層兩側一定範圍: 否" in result
64
- or "活動斷層兩側一定範圍:否" in result,
65
- )
66
- self.assertTrue(
67
- "特定水土保持區: 否" in result or "特定水土保持區:否" in result
68
- )
69
- self.assertTrue("河川區域: 否" in result or "河川區域:否" in result)
70
- self.assertTrue(
71
- "洪氾區一級管制區及洪水平原一級管制區: 否" in result
72
- or "洪氾區一級管制區及洪水平原一級管制區:否" in result
73
- )
74
- self.assertTrue(
75
- "區域排水設施範圍: 是" in result or "區域排水設施範圍:是" in result
76
- )
77
- self.assertTrue(
78
- "國家公園區內之特別景觀區、生態保護區: 否" in result
79
- or "國家公園區內之特別景觀區、生態保護區:否" in result
80
- )
81
- self.assertTrue("自然保留區: 否" in result or "自然保留區:否" in result)
82
- self.assertTrue(
83
- "野生動物保護區: 否" in result or "野生動物保護區:否" in result
84
- )
85
- self.assertTrue(
86
- "野生動物重要棲息環境: 是" in result or "野生動物重要棲息環境:是" in result
87
- )
88
- self.assertTrue("自然保護區: 否" in result or "自然保護區:否" in result)
89
- self.assertTrue(
90
- "一級海岸保護區: 是" in result or "一級海岸保護區:是" in result
91
- )
92
- self.assertTrue(
93
- "國際級重要濕地、國家級重要濕地之核心保育區及生態復育區: 否" in result
94
- or "國際級重要濕地、國家級重要濕地之核心保育區及生態復育區:否" in result
95
- )
96
- self.assertTrue("古蹟保存區: 否" in result or "古蹟保存區:否" in result)
97
- self.assertTrue("考古遺址: 否" in result or "考古遺址:否" in result)
98
- self.assertTrue(
99
- "重要聚落建築群: 否" in result or "重要聚落建築群:否" in result
100
- )
101
-
102
-
103
- if __name__ == "__main__":
104
- unittest.main()
1
+ import unittest
2
+ import os
3
+ from pathlib import Path
4
+ from botrun_flow_lang.langgraph_agents.agents.util.local_files import (
5
+ upload_and_get_tmp_public_url,
6
+ )
7
+ from botrun_flow_lang.langgraph_agents.agents.util.pdf_analyzer import analyze_pdf
8
+
9
+
10
+ class TestPDFAnalyzer(unittest.TestCase):
11
+ def setUp(self):
12
+ # Get the path to the test PDF file
13
+ current_dir = Path(__file__).parent
14
+ self.pdf_path = (
15
+ current_dir
16
+ / "test_files"
17
+ / "1120701A海廣離岸風力發電計畫環境影響說明書-C04.PDF"
18
+ )
19
+
20
+ # Ensure the test file exists
21
+ self.assertTrue(
22
+ os.path.exists(self.pdf_path), f"Test file not found at {self.pdf_path}"
23
+ )
24
+
25
+ def test_pdf_exists(self):
26
+ """Test if the PDF file exists"""
27
+ self.assertEqual(True, os.path.exists(self.pdf_path))
28
+
29
+ def test_pdf_readable(self):
30
+ """Test if the PDF file is readable"""
31
+ self.assertEqual(True, os.access(self.pdf_path, os.R_OK))
32
+
33
+ def test_pdf_not_empty(self):
34
+ """Test if the PDF file is not empty"""
35
+ self.assertEqual(True, os.path.getsize(self.pdf_path) > 0)
36
+
37
+ def test_pdf_extension(self):
38
+ """Test if the file has a PDF extension"""
39
+ self.assertEqual(True, self.pdf_path.suffix.lower() == ".pdf")
40
+
41
+ def test_analyze_table_4_3_1(self):
42
+ """Test analyzing table 4.3-1 from the PDF"""
43
+ query = "請你幫我找出在報告書中的「表 4.3-1 環境敏感地區調查表-第一級環境敏感地區」表格中的所有項目的「查詢結果及限制內容」幫我列出是或否?請全部列出來,不要遺漏"
44
+ pdf_url = upload_and_get_tmp_public_url(
45
+ self.pdf_path,
46
+ "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
47
+ "sebastian.hsu@gmail.com",
48
+ )
49
+ result = analyze_pdf(pdf_url, query)
50
+
51
+ # Print the result for inspection
52
+ print("\nAnalyze PDF Result:")
53
+ print("-" * 50)
54
+ print(result)
55
+ print("-" * 50)
56
+
57
+ # 確保結果不為空
58
+ self.assertIsNotNone(result)
59
+ self.assertNotEqual("", result)
60
+
61
+ # 檢查每個項目的結果
62
+ self.assertTrue(
63
+ "活動斷層兩側一定範圍: 否" in result
64
+ or "活動斷層兩側一定範圍:否" in result,
65
+ )
66
+ self.assertTrue(
67
+ "特定水土保持區: 否" in result or "特定水土保持區:否" in result
68
+ )
69
+ self.assertTrue("河川區域: 否" in result or "河川區域:否" in result)
70
+ self.assertTrue(
71
+ "洪氾區一級管制區及洪水平原一級管制區: 否" in result
72
+ or "洪氾區一級管制區及洪水平原一級管制區:否" in result
73
+ )
74
+ self.assertTrue(
75
+ "區域排水設施範圍: 是" in result or "區域排水設施範圍:是" in result
76
+ )
77
+ self.assertTrue(
78
+ "國家公園區內之特別景觀區、生態保護區: 否" in result
79
+ or "國家公園區內之特別景觀區、生態保護區:否" in result
80
+ )
81
+ self.assertTrue("自然保留區: 否" in result or "自然保留區:否" in result)
82
+ self.assertTrue(
83
+ "野生動物保護區: 否" in result or "野生動物保護區:否" in result
84
+ )
85
+ self.assertTrue(
86
+ "野生動物重要棲息環境: 是" in result or "野生動物重要棲息環境:是" in result
87
+ )
88
+ self.assertTrue("自然保護區: 否" in result or "自然保護區:否" in result)
89
+ self.assertTrue(
90
+ "一級海岸保護區: 是" in result or "一級海岸保護區:是" in result
91
+ )
92
+ self.assertTrue(
93
+ "國際級重要濕地、國家級重要濕地之核心保育區及生態復育區: 否" in result
94
+ or "國際級重要濕地、國家級重要濕地之核心保育區及生態復育區:否" in result
95
+ )
96
+ self.assertTrue("古蹟保存區: 否" in result or "古蹟保存區:否" in result)
97
+ self.assertTrue("考古遺址: 否" in result or "考古遺址:否" in result)
98
+ self.assertTrue(
99
+ "重要聚落建築群: 否" in result or "重要聚落建築群:否" in result
100
+ )
101
+
102
+
103
+ if __name__ == "__main__":
104
+ unittest.main()