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,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()