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,46 +1,46 @@
1
- import unittest
2
- from botrun_flow_lang.models.botrun_app import BotrunApp, BotrunAppMode
3
-
4
-
5
- class TestBotrunApp(unittest.TestCase):
6
- def test_to_yaml(self):
7
- app = BotrunApp(
8
- name="Test App",
9
- description="A test application",
10
- mode=BotrunAppMode.CHATBOT,
11
- )
12
- yaml_str = app.to_yaml()
13
- self.assertIn("name: Test App", yaml_str)
14
- self.assertIn("description: A test application", yaml_str)
15
- self.assertIn("mode: chatbot", yaml_str)
16
-
17
- def test_from_yaml(self):
18
- yaml_str = """
19
- name: Test App
20
- description: A test application
21
- mode: workflow
22
- """
23
- app = BotrunApp.from_yaml(yaml_str)
24
- self.assertEqual(app.name, "Test App")
25
- self.assertEqual(app.description, "A test application")
26
- self.assertEqual(app.mode, BotrunAppMode.WORKFLOW)
27
-
28
- def test_roundtrip(self):
29
- original_app = BotrunApp(
30
- name="Test App",
31
- description="A test application",
32
- mode=BotrunAppMode.CHATBOT,
33
- )
34
- yaml_str = original_app.to_yaml()
35
- reconstructed_app = BotrunApp.from_yaml(yaml_str)
36
- self.assertEqual(original_app, reconstructed_app)
37
-
38
- def test_invalid_mode(self):
39
- with self.assertRaises(ValueError):
40
- BotrunApp(
41
- name="Test App", description="A test application", mode="invalid_mode"
42
- )
43
-
44
-
45
- if __name__ == "__main__":
46
- unittest.main()
1
+ import unittest
2
+ from botrun_flow_lang.models.botrun_app import BotrunApp, BotrunAppMode
3
+
4
+
5
+ class TestBotrunApp(unittest.TestCase):
6
+ def test_to_yaml(self):
7
+ app = BotrunApp(
8
+ name="Test App",
9
+ description="A test application",
10
+ mode=BotrunAppMode.CHATBOT,
11
+ )
12
+ yaml_str = app.to_yaml()
13
+ self.assertIn("name: Test App", yaml_str)
14
+ self.assertIn("description: A test application", yaml_str)
15
+ self.assertIn("mode: chatbot", yaml_str)
16
+
17
+ def test_from_yaml(self):
18
+ yaml_str = """
19
+ name: Test App
20
+ description: A test application
21
+ mode: workflow
22
+ """
23
+ app = BotrunApp.from_yaml(yaml_str)
24
+ self.assertEqual(app.name, "Test App")
25
+ self.assertEqual(app.description, "A test application")
26
+ self.assertEqual(app.mode, BotrunAppMode.WORKFLOW)
27
+
28
+ def test_roundtrip(self):
29
+ original_app = BotrunApp(
30
+ name="Test App",
31
+ description="A test application",
32
+ mode=BotrunAppMode.CHATBOT,
33
+ )
34
+ yaml_str = original_app.to_yaml()
35
+ reconstructed_app = BotrunApp.from_yaml(yaml_str)
36
+ self.assertEqual(original_app, reconstructed_app)
37
+
38
+ def test_invalid_mode(self):
39
+ with self.assertRaises(ValueError):
40
+ BotrunApp(
41
+ name="Test App", description="A test application", mode="invalid_mode"
42
+ )
43
+
44
+
45
+ if __name__ == "__main__":
46
+ unittest.main()
@@ -1,31 +1,31 @@
1
- import unittest
2
- import asyncio
3
- from pathlib import Path
4
- import os
5
- from botrun_flow_lang.langgraph_agents.agents.util.html_util import modify_gcs_html
6
-
7
-
8
- class TestHtmlUtil(unittest.TestCase):
9
- def setUp(self):
10
- """Set up test fixtures"""
11
- self.gcs_url = "https://storage.googleapis.com/hatch-botrun-hatch-dev/html/sebastian.hsu%40gmail.com/tmp_euvrg5j.html"
12
- self.modification_instruction = (
13
- "Increase the number at the top of the page by 1"
14
- )
15
-
16
- def test_modify_gcs_html(self):
17
- """Test modify_gcs_html function with real parameters"""
18
- # Run the async function with real parameters
19
- result = asyncio.run(
20
- modify_gcs_html(self.gcs_url, self.modification_instruction)
21
- )
22
-
23
- # Print the result for manual verification
24
- print("\nTest Result:")
25
- print(f"Success: {result[0]}")
26
- print(f"URL: {result[1]}")
27
- print(f"Error (if any): {result[2]}")
28
-
29
-
30
- if __name__ == "__main__":
31
- unittest.main()
1
+ import unittest
2
+ import asyncio
3
+ from pathlib import Path
4
+ import os
5
+ from botrun_flow_lang.langgraph_agents.agents.util.html_util import modify_gcs_html
6
+
7
+
8
+ class TestHtmlUtil(unittest.TestCase):
9
+ def setUp(self):
10
+ """Set up test fixtures"""
11
+ self.gcs_url = "https://storage.googleapis.com/hatch-botrun-hatch-dev/html/sebastian.hsu%40gmail.com/tmp_euvrg5j.html"
12
+ self.modification_instruction = (
13
+ "Increase the number at the top of the page by 1"
14
+ )
15
+
16
+ def test_modify_gcs_html(self):
17
+ """Test modify_gcs_html function with real parameters"""
18
+ # Run the async function with real parameters
19
+ result = asyncio.run(
20
+ modify_gcs_html(self.gcs_url, self.modification_instruction)
21
+ )
22
+
23
+ # Print the result for manual verification
24
+ print("\nTest Result:")
25
+ print(f"Success: {result[0]}")
26
+ print(f"URL: {result[1]}")
27
+ print(f"Error (if any): {result[2]}")
28
+
29
+
30
+ if __name__ == "__main__":
31
+ unittest.main()
@@ -1,190 +1,190 @@
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.img_util import analyze_imgs
8
-
9
-
10
- class TestImgAnalyzer(unittest.TestCase):
11
- def setUp(self):
12
- # Get the path to the test image file
13
- self.current_dir = Path(__file__).parent
14
- self.img_path = self.current_dir / "test_files" / "d5712343.jpg"
15
-
16
- # Ensure the test file exists
17
- self.assertTrue(
18
- os.path.exists(self.img_path), f"Test file not found at {self.img_path}"
19
- )
20
-
21
- def test_img_exists(self):
22
- """Test if the image file exists"""
23
- self.assertEqual(True, os.path.exists(self.img_path))
24
-
25
- def test_img_readable(self):
26
- """Test if the image file is readable"""
27
- self.assertEqual(True, os.access(self.img_path, os.R_OK))
28
-
29
- def test_img_not_empty(self):
30
- """Test if the image file is not empty"""
31
- self.assertEqual(True, os.path.getsize(self.img_path) > 0)
32
-
33
- def test_img_extension(self):
34
- """Test if the file has a JPG extension"""
35
- self.assertEqual(True, self.img_path.suffix.lower() in [".jpg", ".jpeg"])
36
-
37
- def test_analyze_1_image_content(self):
38
- """Test analyzing the content of the image"""
39
- query = "請描述這張圖片的內容,並列出主要可見的物件或人物,請使用繁體中文,臺灣用語進行回答。"
40
- img_url = upload_and_get_tmp_public_url(
41
- self.img_path,
42
- "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
43
- "sebastian.hsu@gmail.com",
44
- )
45
- result = analyze_imgs([img_url], query) # Pass URL in a list
46
-
47
- # Print the result for inspection
48
- print("\ntest_analyze_1_image_content:")
49
- print("-" * 50)
50
- print(result)
51
- print("-" * 50)
52
-
53
- # 確保結果不為空
54
- self.assertIsNotNone(result)
55
- self.assertNotEqual("", result)
56
-
57
- # 確保結果不是錯誤訊息
58
- self.assertFalse(result.startswith("Error:"))
59
-
60
- # 確保回應內容包含描述性文字
61
- self.assertTrue(len(result) > 50) # 確保回應有足夠的長度
62
- self.assertIn("佛教", result, "找不到回應中包含佛教,回應內容:" + result)
63
-
64
- def test_analyze_2_images_content(self):
65
- """Test analyzing the content of the image"""
66
- img1_path = self.current_dir / "test_files" / "spot_difference_1.png"
67
- img2_path = self.current_dir / "test_files" / "spot_difference_2.png"
68
- query = "幫我分析這兩張圖片裡的時鐘時間是否一樣?一樣回答「一樣」,不一樣回答「不一樣」"
69
- img_url1 = upload_and_get_tmp_public_url(
70
- img1_path,
71
- "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
72
- "sebastian.hsu@gmail.com",
73
- )
74
- img_url2 = upload_and_get_tmp_public_url(
75
- img2_path,
76
- "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
77
- "sebastian.hsu@gmail.com",
78
- )
79
- result = analyze_imgs([img_url1, img_url2], query) # Pass URL in a list
80
-
81
- # Print the result for inspection
82
- print("\ntest_analyze_2_images_content_case_1:")
83
- print("-" * 50)
84
- print(result)
85
- print("-" * 50)
86
-
87
- # 確保結果不為空
88
- self.assertIsNotNone(result)
89
- self.assertNotEqual("", result)
90
-
91
- # 確保結果不是錯誤訊息
92
- self.assertFalse(result.startswith("Error:"))
93
-
94
- # 確保回應內容包含描述性文字
95
- self.assertIn("不一樣", result)
96
-
97
- img1_path = self.current_dir / "test_files" / "spot_difference_1.png"
98
- img2_path = self.current_dir / "test_files" / "spot_difference_1.png"
99
- query = "幫我分析這兩張圖片裡的時鐘時間是否一樣?一樣回答「一樣」,不一樣回答「不一樣」"
100
- img_url1 = upload_and_get_tmp_public_url(
101
- img1_path,
102
- "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
103
- "sebastian.hsu@gmail.com",
104
- )
105
- img_url2 = upload_and_get_tmp_public_url(
106
- img2_path,
107
- "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
108
- "sebastian.hsu@gmail.com",
109
- )
110
- result = analyze_imgs([img_url1, img_url2], query) # Pass URL in a list
111
-
112
- # Print the result for inspection
113
- print("\ntest_analyze_2_images_content_case_2:")
114
- print("-" * 50)
115
- print(result)
116
- print("-" * 50)
117
-
118
- # 確保結果不為空
119
- self.assertIsNotNone(result)
120
- self.assertNotEqual("", result)
121
-
122
- # 確保結果不是錯誤訊息
123
- self.assertFalse(result.startswith("Error:"))
124
-
125
- # 確保回應內容包含描述性文字
126
- self.assertIn("一樣", result)
127
-
128
- def test_analyze_images_media_type_jpeg(self):
129
- """Test analyzing the content of the image"""
130
- img1_path = (
131
- self.current_dir / "test_files" / "ImportedPhoto.760363950.029251.jpeg"
132
- )
133
- img2_path = (
134
- self.current_dir / "test_files" / "ImportedPhoto.760363950.030446.jpeg"
135
- )
136
- img3_path = (
137
- self.current_dir / "test_files" / "ImportedPhoto.760363950.031127.jpeg"
138
- )
139
- query = "我該去哪個月台,為什麼?回答時要包含列車車號以及月台號。"
140
- img_url1 = upload_and_get_tmp_public_url(
141
- img1_path,
142
- "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
143
- "sebastian.hsu@gmail.com",
144
- )
145
- img_url2 = upload_and_get_tmp_public_url(
146
- img2_path,
147
- "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
148
- "sebastian.hsu@gmail.com",
149
- )
150
- img_url3 = upload_and_get_tmp_public_url(
151
- img3_path,
152
- "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
153
- "sebastian.hsu@gmail.com",
154
- )
155
- result = analyze_imgs(
156
- [img_url1, img_url2, img_url3], query
157
- ) # Pass URL in a list
158
-
159
- # Print the result for inspection
160
- print("\ntest_analyze_images_media_type_jpeg:")
161
- print("-" * 50)
162
- print(result)
163
- print("-" * 50)
164
-
165
- # 確保結果不為空
166
- self.assertIsNotNone(result)
167
- self.assertNotEqual("", result)
168
-
169
- # 確保結果不是錯誤訊息
170
- self.assertFalse(result.startswith("Error:"))
171
-
172
- # 確保回應內容包含描述性文字
173
- self.assertTrue(
174
- any(
175
- platform in result
176
- for platform in [
177
- "5 A-C",
178
- "5 D-F",
179
- "5-A-C",
180
- "5-A/C",
181
- "5-D-F",
182
- "5-D/F",
183
- ]
184
- ),
185
- "Result should contain either '5 A-C' or '5 D-F'",
186
- )
187
-
188
-
189
- if __name__ == "__main__":
190
- 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.img_util import analyze_imgs
8
+
9
+
10
+ class TestImgAnalyzer(unittest.TestCase):
11
+ def setUp(self):
12
+ # Get the path to the test image file
13
+ self.current_dir = Path(__file__).parent
14
+ self.img_path = self.current_dir / "test_files" / "d5712343.jpg"
15
+
16
+ # Ensure the test file exists
17
+ self.assertTrue(
18
+ os.path.exists(self.img_path), f"Test file not found at {self.img_path}"
19
+ )
20
+
21
+ def test_img_exists(self):
22
+ """Test if the image file exists"""
23
+ self.assertEqual(True, os.path.exists(self.img_path))
24
+
25
+ def test_img_readable(self):
26
+ """Test if the image file is readable"""
27
+ self.assertEqual(True, os.access(self.img_path, os.R_OK))
28
+
29
+ def test_img_not_empty(self):
30
+ """Test if the image file is not empty"""
31
+ self.assertEqual(True, os.path.getsize(self.img_path) > 0)
32
+
33
+ def test_img_extension(self):
34
+ """Test if the file has a JPG extension"""
35
+ self.assertEqual(True, self.img_path.suffix.lower() in [".jpg", ".jpeg"])
36
+
37
+ def test_analyze_1_image_content(self):
38
+ """Test analyzing the content of the image"""
39
+ query = "請描述這張圖片的內容,並列出主要可見的物件或人物,請使用繁體中文,臺灣用語進行回答。"
40
+ img_url = upload_and_get_tmp_public_url(
41
+ self.img_path,
42
+ "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
43
+ "sebastian.hsu@gmail.com",
44
+ )
45
+ result = analyze_imgs([img_url], query) # Pass URL in a list
46
+
47
+ # Print the result for inspection
48
+ print("\ntest_analyze_1_image_content:")
49
+ print("-" * 50)
50
+ print(result)
51
+ print("-" * 50)
52
+
53
+ # 確保結果不為空
54
+ self.assertIsNotNone(result)
55
+ self.assertNotEqual("", result)
56
+
57
+ # 確保結果不是錯誤訊息
58
+ self.assertFalse(result.startswith("Error:"))
59
+
60
+ # 確保回應內容包含描述性文字
61
+ self.assertTrue(len(result) > 50) # 確保回應有足夠的長度
62
+ self.assertIn("佛教", result, "找不到回應中包含佛教,回應內容:" + result)
63
+
64
+ def test_analyze_2_images_content(self):
65
+ """Test analyzing the content of the image"""
66
+ img1_path = self.current_dir / "test_files" / "spot_difference_1.png"
67
+ img2_path = self.current_dir / "test_files" / "spot_difference_2.png"
68
+ query = "幫我分析這兩張圖片裡的時鐘時間是否一樣?一樣回答「一樣」,不一樣回答「不一樣」"
69
+ img_url1 = upload_and_get_tmp_public_url(
70
+ img1_path,
71
+ "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
72
+ "sebastian.hsu@gmail.com",
73
+ )
74
+ img_url2 = upload_and_get_tmp_public_url(
75
+ img2_path,
76
+ "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
77
+ "sebastian.hsu@gmail.com",
78
+ )
79
+ result = analyze_imgs([img_url1, img_url2], query) # Pass URL in a list
80
+
81
+ # Print the result for inspection
82
+ print("\ntest_analyze_2_images_content_case_1:")
83
+ print("-" * 50)
84
+ print(result)
85
+ print("-" * 50)
86
+
87
+ # 確保結果不為空
88
+ self.assertIsNotNone(result)
89
+ self.assertNotEqual("", result)
90
+
91
+ # 確保結果不是錯誤訊息
92
+ self.assertFalse(result.startswith("Error:"))
93
+
94
+ # 確保回應內容包含描述性文字
95
+ self.assertIn("不一樣", result)
96
+
97
+ img1_path = self.current_dir / "test_files" / "spot_difference_1.png"
98
+ img2_path = self.current_dir / "test_files" / "spot_difference_1.png"
99
+ query = "幫我分析這兩張圖片裡的時鐘時間是否一樣?一樣回答「一樣」,不一樣回答「不一樣」"
100
+ img_url1 = upload_and_get_tmp_public_url(
101
+ img1_path,
102
+ "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
103
+ "sebastian.hsu@gmail.com",
104
+ )
105
+ img_url2 = upload_and_get_tmp_public_url(
106
+ img2_path,
107
+ "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
108
+ "sebastian.hsu@gmail.com",
109
+ )
110
+ result = analyze_imgs([img_url1, img_url2], query) # Pass URL in a list
111
+
112
+ # Print the result for inspection
113
+ print("\ntest_analyze_2_images_content_case_2:")
114
+ print("-" * 50)
115
+ print(result)
116
+ print("-" * 50)
117
+
118
+ # 確保結果不為空
119
+ self.assertIsNotNone(result)
120
+ self.assertNotEqual("", result)
121
+
122
+ # 確保結果不是錯誤訊息
123
+ self.assertFalse(result.startswith("Error:"))
124
+
125
+ # 確保回應內容包含描述性文字
126
+ self.assertIn("一樣", result)
127
+
128
+ def test_analyze_images_media_type_jpeg(self):
129
+ """Test analyzing the content of the image"""
130
+ img1_path = (
131
+ self.current_dir / "test_files" / "ImportedPhoto.760363950.029251.jpeg"
132
+ )
133
+ img2_path = (
134
+ self.current_dir / "test_files" / "ImportedPhoto.760363950.030446.jpeg"
135
+ )
136
+ img3_path = (
137
+ self.current_dir / "test_files" / "ImportedPhoto.760363950.031127.jpeg"
138
+ )
139
+ query = "我該去哪個月台,為什麼?回答時要包含列車車號以及月台號。"
140
+ img_url1 = upload_and_get_tmp_public_url(
141
+ img1_path,
142
+ "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
143
+ "sebastian.hsu@gmail.com",
144
+ )
145
+ img_url2 = upload_and_get_tmp_public_url(
146
+ img2_path,
147
+ "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
148
+ "sebastian.hsu@gmail.com",
149
+ )
150
+ img_url3 = upload_and_get_tmp_public_url(
151
+ img3_path,
152
+ "https://botrun-flow-lang-fastapi-dev-36186877499.asia-east1.run.app",
153
+ "sebastian.hsu@gmail.com",
154
+ )
155
+ result = analyze_imgs(
156
+ [img_url1, img_url2, img_url3], query
157
+ ) # Pass URL in a list
158
+
159
+ # Print the result for inspection
160
+ print("\ntest_analyze_images_media_type_jpeg:")
161
+ print("-" * 50)
162
+ print(result)
163
+ print("-" * 50)
164
+
165
+ # 確保結果不為空
166
+ self.assertIsNotNone(result)
167
+ self.assertNotEqual("", result)
168
+
169
+ # 確保結果不是錯誤訊息
170
+ self.assertFalse(result.startswith("Error:"))
171
+
172
+ # 確保回應內容包含描述性文字
173
+ self.assertTrue(
174
+ any(
175
+ platform in result
176
+ for platform in [
177
+ "5 A-C",
178
+ "5 D-F",
179
+ "5-A-C",
180
+ "5-A/C",
181
+ "5-D-F",
182
+ "5-D/F",
183
+ ]
184
+ ),
185
+ "Result should contain either '5 A-C' or '5 D-F'",
186
+ )
187
+
188
+
189
+ if __name__ == "__main__":
190
+ unittest.main()
@@ -1,39 +1,39 @@
1
- import unittest
2
- from pathlib import Path
3
- import os
4
- from botrun_flow_lang.langgraph_agents.agents.util.img_util import get_img_content_type
5
-
6
-
7
- class TestImgUtil(unittest.TestCase):
8
- def setUp(self):
9
- """Set up test fixtures"""
10
- self.current_dir = Path(__file__).parent
11
- self.test_files_dir = self.current_dir / "test_files"
12
-
13
- def test_get_content_type_png_1(self):
14
- """Test get_content_type with PNG file"""
15
- img_path = self.test_files_dir / "ImportedPhoto.760363950.029251.jpeg"
16
- content_type = get_img_content_type(img_path)
17
- self.assertEqual(content_type, "image/png")
18
-
19
- def test_get_content_type_png_2(self):
20
- """Test get_content_type with PNG file"""
21
- img_path = self.test_files_dir / "spot_difference_1.png"
22
- content_type = get_img_content_type(img_path)
23
- self.assertEqual(content_type, "image/png")
24
-
25
- def test_get_content_type_jpeg_1(self):
26
- """Test get_content_type with PNG file"""
27
- img_path = self.test_files_dir / "ImportedPhoto.760363950.030446.jpeg"
28
- content_type = get_img_content_type(img_path)
29
- self.assertEqual(content_type, "image/jpeg")
30
-
31
- def test_get_content_type_jpeg_2(self):
32
- """Test get_content_type with PNG file"""
33
- img_path = self.test_files_dir / "d5712343.jpg"
34
- content_type = get_img_content_type(img_path)
35
- self.assertEqual(content_type, "image/jpeg")
36
-
37
-
38
- if __name__ == "__main__":
39
- unittest.main()
1
+ import unittest
2
+ from pathlib import Path
3
+ import os
4
+ from botrun_flow_lang.langgraph_agents.agents.util.img_util import get_img_content_type
5
+
6
+
7
+ class TestImgUtil(unittest.TestCase):
8
+ def setUp(self):
9
+ """Set up test fixtures"""
10
+ self.current_dir = Path(__file__).parent
11
+ self.test_files_dir = self.current_dir / "test_files"
12
+
13
+ def test_get_content_type_png_1(self):
14
+ """Test get_content_type with PNG file"""
15
+ img_path = self.test_files_dir / "ImportedPhoto.760363950.029251.jpeg"
16
+ content_type = get_img_content_type(img_path)
17
+ self.assertEqual(content_type, "image/png")
18
+
19
+ def test_get_content_type_png_2(self):
20
+ """Test get_content_type with PNG file"""
21
+ img_path = self.test_files_dir / "spot_difference_1.png"
22
+ content_type = get_img_content_type(img_path)
23
+ self.assertEqual(content_type, "image/png")
24
+
25
+ def test_get_content_type_jpeg_1(self):
26
+ """Test get_content_type with PNG file"""
27
+ img_path = self.test_files_dir / "ImportedPhoto.760363950.030446.jpeg"
28
+ content_type = get_img_content_type(img_path)
29
+ self.assertEqual(content_type, "image/jpeg")
30
+
31
+ def test_get_content_type_jpeg_2(self):
32
+ """Test get_content_type with PNG file"""
33
+ img_path = self.test_files_dir / "d5712343.jpg"
34
+ content_type = get_img_content_type(img_path)
35
+ self.assertEqual(content_type, "image/jpeg")
36
+
37
+
38
+ if __name__ == "__main__":
39
+ unittest.main()