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