botrun-flow-lang 5.11.11__py3-none-any.whl → 5.12.261__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.
@@ -0,0 +1,204 @@
1
+ """
2
+ PDF 處理工具模組
3
+
4
+ 提供 PDF 切割等功能,用於處理大型 PDF 檔案。
5
+ 使用 pypdf(純 Python)實作,避免 C++ 庫的 segfault 問題。
6
+ """
7
+
8
+ import io
9
+ from typing import List, Tuple
10
+
11
+ from pypdf import PdfReader, PdfWriter
12
+
13
+
14
+ def get_pdf_size(pdf_content: bytes) -> int:
15
+ """
16
+ 取得 PDF 檔案大小(bytes)
17
+
18
+ Args:
19
+ pdf_content: PDF 檔案的二進位內容
20
+
21
+ Returns:
22
+ int: 檔案大小(bytes)
23
+ """
24
+ return len(pdf_content)
25
+
26
+
27
+ def get_pdf_size_mb(pdf_content: bytes) -> float:
28
+ """
29
+ 取得 PDF 檔案大小(MB)
30
+
31
+ Args:
32
+ pdf_content: PDF 檔案的二進位內容
33
+
34
+ Returns:
35
+ float: 檔案大小(MB)
36
+ """
37
+ return len(pdf_content) / (1024 * 1024)
38
+
39
+
40
+ def get_pdf_page_count(pdf_content: bytes) -> int:
41
+ """
42
+ 取得 PDF 總頁數
43
+
44
+ Args:
45
+ pdf_content: PDF 檔案的二進位內容
46
+
47
+ Returns:
48
+ int: 總頁數
49
+ """
50
+ try:
51
+ reader = PdfReader(io.BytesIO(pdf_content))
52
+ return len(reader.pages)
53
+ except Exception as e:
54
+ print(f"[get_pdf_page_count] 無法讀取 PDF 頁數: {e}")
55
+ return 0
56
+
57
+
58
+ def split_pdf_by_pages(
59
+ pdf_content: bytes, pages_per_chunk: int = 15
60
+ ) -> List[Tuple[bytes, str]]:
61
+ """
62
+ 按頁數切割 PDF
63
+
64
+ Args:
65
+ pdf_content: PDF 檔案的二進位內容
66
+ pages_per_chunk: 每個切片的頁數(預設 15 頁)
67
+
68
+ Returns:
69
+ List[Tuple[bytes, str]]: 切片清單,每個元素為 (切片內容, 頁碼範圍字串)
70
+ 例如: [(chunk_bytes, "page-001-015"), (chunk_bytes, "page-016-030"), ...]
71
+ """
72
+ chunks = []
73
+
74
+ try:
75
+ reader = PdfReader(io.BytesIO(pdf_content))
76
+ total_pages = len(reader.pages)
77
+
78
+ for start_idx in range(0, total_pages, pages_per_chunk):
79
+ end_idx = min(start_idx + pages_per_chunk, total_pages)
80
+
81
+ # 建立新的 PDF 並複製頁面
82
+ writer = PdfWriter()
83
+ for page_idx in range(start_idx, end_idx):
84
+ writer.add_page(reader.pages[page_idx])
85
+
86
+ # 輸出切片
87
+ output = io.BytesIO()
88
+ writer.write(output)
89
+ chunk_bytes = output.getvalue()
90
+
91
+ # 產生頁碼範圍字串(1-indexed)
92
+ page_range = f"page-{start_idx + 1:03d}-{end_idx:03d}"
93
+
94
+ chunks.append((chunk_bytes, page_range))
95
+
96
+ except Exception as e:
97
+ print(f"[split_pdf_by_pages] 切割 PDF 時發生錯誤: {e}")
98
+ # 如果切割失敗,回傳整個 PDF 作為單一切片
99
+ if pdf_content:
100
+ chunks.append((pdf_content, "page-001-all"))
101
+
102
+ return chunks
103
+
104
+
105
+ def calculate_optimal_chunk_size(
106
+ pdf_content: bytes,
107
+ target_size_mb: float = 4.0,
108
+ min_pages: int = 5,
109
+ max_pages: int = 30,
110
+ ) -> int:
111
+ """
112
+ 計算最佳切割頁數,確保每個切片小於目標大小
113
+
114
+ 策略:
115
+ 1. 先估算每頁平均大小
116
+ 2. 計算達到目標大小需要的頁數
117
+ 3. 限制在 min_pages 和 max_pages 之間
118
+
119
+ Args:
120
+ pdf_content: PDF 檔案的二進位內容
121
+ target_size_mb: 目標切片大小(MB),預設 4MB
122
+ min_pages: 最小頁數,預設 5 頁
123
+ max_pages: 最大頁數,預設 30 頁
124
+
125
+ Returns:
126
+ int: 建議的每個切片頁數
127
+ """
128
+ total_size_mb = get_pdf_size_mb(pdf_content)
129
+ total_pages = get_pdf_page_count(pdf_content)
130
+
131
+ if total_pages == 0:
132
+ return min_pages
133
+
134
+ # 估算每頁平均大小
135
+ avg_page_size_mb = total_size_mb / total_pages
136
+
137
+ # 計算達到目標大小需要的頁數
138
+ if avg_page_size_mb > 0:
139
+ optimal_pages = int(target_size_mb / avg_page_size_mb)
140
+ else:
141
+ optimal_pages = max_pages
142
+
143
+ # 限制在範圍內
144
+ optimal_pages = max(min_pages, min(optimal_pages, max_pages))
145
+
146
+ return optimal_pages
147
+
148
+
149
+ def split_pdf_smart(
150
+ pdf_content: bytes, target_size_mb: float = 4.0
151
+ ) -> List[Tuple[bytes, str]]:
152
+ """
153
+ 智慧切割 PDF
154
+
155
+ 先計算最佳切割頁數,然後進行切割。
156
+ 如果切割後某個切片仍超過目標大小,會進一步分割。
157
+
158
+ Args:
159
+ pdf_content: PDF 檔案的二進位內容
160
+ target_size_mb: 目標切片大小(MB),預設 4MB
161
+
162
+ Returns:
163
+ List[Tuple[bytes, str]]: 切片清單,每個元素為 (切片內容, 頁碼範圍字串)
164
+ """
165
+ # 計算最佳切割頁數
166
+ pages_per_chunk = calculate_optimal_chunk_size(pdf_content, target_size_mb)
167
+ print(f"[split_pdf_smart] 計算最佳切割頁數: {pages_per_chunk} 頁/切片")
168
+
169
+ # 進行初步切割
170
+ chunks = split_pdf_by_pages(pdf_content, pages_per_chunk)
171
+
172
+ # 檢查是否有切片超過目標大小,如果有則進一步分割
173
+ final_chunks = []
174
+ for chunk_bytes, page_range in chunks:
175
+ chunk_size_mb = get_pdf_size_mb(chunk_bytes)
176
+
177
+ if chunk_size_mb > target_size_mb and pages_per_chunk > 5:
178
+ # 這個切片太大,需要進一步分割
179
+ print(
180
+ f"[split_pdf_smart] 切片 {page_range} 大小 {chunk_size_mb:.2f}MB "
181
+ f"超過目標 {target_size_mb}MB,進一步分割"
182
+ )
183
+
184
+ # 取得這個切片的頁碼範圍
185
+ parts = page_range.replace("page-", "").split("-")
186
+ start_page = int(parts[0])
187
+
188
+ # 用更小的頁數重新切割
189
+ smaller_chunks = split_pdf_by_pages(chunk_bytes, pages_per_chunk // 2)
190
+
191
+ # 更新頁碼範圍
192
+ chunk_page_count = get_pdf_page_count(chunk_bytes)
193
+ for i, (sub_chunk, _) in enumerate(smaller_chunks):
194
+ sub_start = start_page + i * (pages_per_chunk // 2)
195
+ sub_end = min(
196
+ sub_start + (pages_per_chunk // 2) - 1,
197
+ start_page + chunk_page_count - 1,
198
+ )
199
+ sub_range = f"page-{sub_start:03d}-{sub_end:03d}"
200
+ final_chunks.append((sub_chunk, sub_range))
201
+ else:
202
+ final_chunks.append((chunk_bytes, page_range))
203
+
204
+ return final_chunks
@@ -15,7 +15,9 @@ from langchain_core.runnables import RunnableConfig
15
15
 
16
16
  # Import necessary dependencies
17
17
  from botrun_flow_lang.models.nodes.utils import scrape_single_url
18
- from botrun_flow_lang.langgraph_agents.agents.util.pdf_analyzer import analyze_pdf
18
+ from botrun_flow_lang.langgraph_agents.agents.util.pdf_analyzer import (
19
+ analyze_pdf_async,
20
+ )
19
21
  from botrun_flow_lang.langgraph_agents.agents.util.img_util import analyze_imgs
20
22
  from botrun_flow_lang.langgraph_agents.agents.util.local_files import (
21
23
  upload_and_get_tmp_public_url,
@@ -76,6 +78,10 @@ async def chat_with_pdf(
76
78
  """
77
79
  Analyze a PDF file and answer questions about its content.
78
80
 
81
+ Supports intelligent processing based on file size:
82
+ - Small files (< 5MB): Direct multimodal analysis
83
+ - Large files (>= 5MB): Compress -> Split -> Parallel multimodal Q&A -> Merge results
84
+
79
85
  Args:
80
86
  pdf_url: The URL to the PDF file (can be generated using generate_tmp_public_url for local files)
81
87
  user_input: The user's question or instruction about the PDF content
@@ -91,7 +97,7 @@ async def chat_with_pdf(
91
97
  if not pdf_url.startswith("http"):
92
98
  pdf_url = upload_and_get_tmp_public_url(pdf_url, botrun_flow_lang_url, user_id)
93
99
 
94
- return analyze_pdf(pdf_url, user_input)
100
+ return await analyze_pdf_async(pdf_url, user_input)
95
101
 
96
102
 
97
103
  @mcp.tool()
@@ -175,10 +181,10 @@ async def generate_image(
175
181
  # 驗證必要參數
176
182
  if not user_id:
177
183
  logger.error("User ID not available")
178
- raise Exception("User ID not available")
184
+ return "User ID not available"
179
185
  if not botrun_flow_lang_url:
180
186
  logger.error("botrun_flow_lang_url not available")
181
- raise Exception("botrun_flow_lang_url not available")
187
+ return "botrun_flow_lang_url not available"
182
188
 
183
189
  # Check rate limit before generating image
184
190
  rate_limit_client = RateLimitClient()
@@ -195,10 +201,12 @@ async def generate_image(
195
201
  f"User {user_id} has reached daily limit of {daily_limit} image generations. "
196
202
  f"Current usage: {current_usage}. Please try again tomorrow."
197
203
  )
198
- raise BotrunRateLimitException(
199
- f"You have reached your daily limit of {daily_limit} image generations. "
204
+ return f"[Please tell user error] You have reached your daily limit of {daily_limit} image generations. " \
200
205
  f"Current usage: {current_usage}. Please try again tomorrow."
201
- )
206
+ # raise BotrunRateLimitException(
207
+ # f"You have reached your daily limit of {daily_limit} image generations. "
208
+ # f"Current usage: {current_usage}. Please try again tomorrow."
209
+ # )
202
210
 
203
211
  # 2. 使用 DALL-E 生成圖片
204
212
  dalle_wrapper = DallEAPIWrapper(
@@ -267,7 +275,8 @@ async def generate_tmp_public_url(
267
275
  logger.info(f"generate_tmp_public_url file_path: {file_path}")
268
276
 
269
277
  if not os.path.exists(file_path):
270
- raise FileNotFoundError(f"File not found: {file_path}")
278
+ return f"File not found: {file_path}"
279
+ # raise FileNotFoundError(f"File not found: {file_path}")
271
280
 
272
281
  return upload_and_get_tmp_public_url(file_path, botrun_flow_lang_url, user_id)
273
282
 
@@ -1,5 +1,6 @@
1
1
  import logging
2
2
  from typing import Union, List, Tuple
3
+ from datetime import datetime, timezone
3
4
  from google.cloud.exceptions import GoogleCloudError
4
5
  from botrun_flow_lang.constants import HATCH_SHARING_STORE_NAME, HATCH_STORE_NAME
5
6
  from botrun_flow_lang.services.base.firestore_base import FirestoreBase
@@ -27,6 +28,9 @@ class HatchFsStore(FirestoreBase):
27
28
 
28
29
  async def set_hatch(self, item: Hatch):
29
30
  try:
31
+ # Update updated_at timestamp with current UTC time
32
+ item.updated_at = datetime.now(timezone.utc).isoformat()
33
+
30
34
  # Proceed with saving the hatch
31
35
  doc_ref = self.collection.document(str(item.id))
32
36
  doc_ref.set(item.model_dump())
@@ -49,18 +53,29 @@ class HatchFsStore(FirestoreBase):
49
53
  return False
50
54
 
51
55
  async def get_hatches(
52
- self, user_id: str, offset: int = 0, limit: int = 20
56
+ self,
57
+ user_id: str,
58
+ offset: int = 0,
59
+ limit: int = 20,
60
+ sort_by: str = "updated_at",
61
+ order: str = "desc",
53
62
  ) -> Tuple[List[Hatch], str]:
54
63
  try:
55
- query = (
56
- self.collection.where(
57
- filter=firestore.FieldFilter("user_id", "==", user_id)
58
- )
59
- .order_by("name")
60
- .offset(offset)
61
- .limit(limit)
64
+ # Build base query
65
+ query = self.collection.where(
66
+ filter=firestore.FieldFilter("user_id", "==", user_id)
62
67
  )
63
68
 
69
+ # Add sorting
70
+ # Firestore direction: DESCENDING or ASCENDING
71
+ direction = (
72
+ firestore.Query.DESCENDING if order == "desc" else firestore.Query.ASCENDING
73
+ )
74
+ query = query.order_by(sort_by, direction=direction)
75
+
76
+ # Add pagination
77
+ query = query.offset(offset).limit(limit)
78
+
64
79
  docs = query.stream()
65
80
  hatches = [Hatch(**doc.to_dict()) for doc in docs]
66
81
  return hatches, ""
@@ -39,7 +39,11 @@ class StorageCsStore(StorageStore):
39
39
  {
40
40
  "action": {"type": "Delete"},
41
41
  "condition": {"age": 365, "matchesPrefix": ["tmp/"]},
42
- }
42
+ },
43
+ {
44
+ "action": {"type": "Delete"},
45
+ "condition": {"age": 7, "matchesPrefix": ["pdf-cache/"]},
46
+ },
43
47
  ]
44
48
 
45
49
  if not bucket.exists():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: botrun-flow-lang
3
- Version: 5.11.11
3
+ Version: 5.12.261
4
4
  Summary: A flow language for botrun
5
5
  Author-email: sebastian-hsu <sebastian.hsu@gmail.com>
6
6
  License: MIT
@@ -13,7 +13,7 @@ Requires-Python: <3.13,>=3.11
13
13
  Requires-Dist: aiohttp>=3.10.8
14
14
  Requires-Dist: anthropic>=0.61.0
15
15
  Requires-Dist: boto3>=1.40.3
16
- Requires-Dist: botrun-hatch>=5.10.82
16
+ Requires-Dist: botrun-hatch>=5.12.261
17
17
  Requires-Dist: botrun-log>=0.3.0
18
18
  Requires-Dist: cachetools>=5.5.2
19
19
  Requires-Dist: chardet>=5.2.0
@@ -47,6 +47,7 @@ Requires-Dist: pandas>=2.2.3
47
47
  Requires-Dist: pdfminer-six==20250506
48
48
  Requires-Dist: plotly>=6.0.0
49
49
  Requires-Dist: pydantic-settings>=2.5.2
50
+ Requires-Dist: pypdf==6.4.2
50
51
  Requires-Dist: python-multipart>=0.0.20
51
52
  Requires-Dist: pytz>=2024.2
52
53
  Requires-Dist: pyyaml>=6.0.2
@@ -8,9 +8,9 @@ botrun_flow_lang/api/auth_api.py,sha256=o_ThrZFcOMQieUcUJIF_B7rsyvbkCvOCjCjknl9G
8
8
  botrun_flow_lang/api/auth_utils.py,sha256=qE7RIPDnX30FPmhlgmlQNoVNkLU028x4SldVl6VC4KQ,6455
9
9
  botrun_flow_lang/api/botrun_back_api.py,sha256=mE2NSejaYIiE0L9GmNJbLc_FRWCy6BXlcqRwkB1kKmc,2397
10
10
  botrun_flow_lang/api/flow_api.py,sha256=DcxuoGE1OcbTgLSYKZ2SO9IdcH3UB5Ik3cVmX3v3-Po,108
11
- botrun_flow_lang/api/hatch_api.py,sha256=qZG-Wwi_8SHPuWNfbt-dhz-O41VYetTxrJzcVjHbJCo,15913
11
+ botrun_flow_lang/api/hatch_api.py,sha256=trenrAJt95ufjpAzwuTvcCoJdMR2x4EZCuWBup9e4hA,16984
12
12
  botrun_flow_lang/api/langgraph_api.py,sha256=zqu0xeTiy2Pr4UL6vvGqVVAy2KX3ZUn1uzcq-Tfb_aM,29291
13
- botrun_flow_lang/api/line_bot_api.py,sha256=ECCGgl-rbac4GwJ7O39jzrvTPR-M_tShQjQFm1esuag,49153
13
+ botrun_flow_lang/api/line_bot_api.py,sha256=INTWnI09LhRhQ6NcetHrHAQZU86eyoJ2zZ6g-KtX8MM,55500
14
14
  botrun_flow_lang/api/model_api.py,sha256=bXemey_XUUdylZwh7Z10eksoBWe9xSa8I9TEL7jIBtE,9483
15
15
  botrun_flow_lang/api/rate_limit_api.py,sha256=SkpjfvShHRdP5XJzy3DdrH4jLtdYAEHROGBMBkC9OIY,948
16
16
  botrun_flow_lang/api/routes.py,sha256=rd0IoMsteJT9BO3MQuyXirhPQbas6OeiKaEC8Yf2SZs,1570
@@ -23,8 +23,8 @@ botrun_flow_lang/api/version_api.py,sha256=Mcs7hKBP7T7nlHDaZS4U0dtOkNQqW0BtT62Iv
23
23
  botrun_flow_lang/api/youtube_api.py,sha256=R384jNRheMKnDyzvlLnbzackipZhiLYTZl4w4hB6vtw,753
24
24
  botrun_flow_lang/langgraph_agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  botrun_flow_lang/langgraph_agents/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
- botrun_flow_lang/langgraph_agents/agents/agent_runner.py,sha256=fOZgHDsCA_EDTTGQFBmhGUhpfLB3m_N6YW2UHgMpKBg,6241
27
- botrun_flow_lang/langgraph_agents/agents/langgraph_react_agent.py,sha256=Vwf2HbpOuulx1nS0ReoE4OkVndiLgK5aByusPvGAXA8,28827
26
+ botrun_flow_lang/langgraph_agents/agents/agent_runner.py,sha256=1BRIbEi7_NoIx1BuVUPFA-fDHErm3nHpX65HsY7YpWU,6495
27
+ botrun_flow_lang/langgraph_agents/agents/langgraph_react_agent.py,sha256=4fK_hMoUAqcEYv7rrHbAx6PFsJ7UcvGI0G2OgWhVhnw,29972
28
28
  botrun_flow_lang/langgraph_agents/agents/search_agent_graph.py,sha256=6fz-ewLQGacEx-uqGfF3-go9FdiioiMzW_sfANzYTcI,31182
29
29
  botrun_flow_lang/langgraph_agents/agents/agent_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  botrun_flow_lang/langgraph_agents/agents/agent_tools/step_planner.py,sha256=CgEhfGR28Rq7ui9cKxj_DczfNfjJNXIP9DXQNIwBLv0,2350
@@ -44,7 +44,9 @@ botrun_flow_lang/langgraph_agents/agents/util/img_util.py,sha256=FF5XUFCtYBul6DZ
44
44
  botrun_flow_lang/langgraph_agents/agents/util/local_files.py,sha256=ib3JVvuTgKhFj-D_8d5MH3vImFe6Fk1aMxyxNqjDWWc,13110
45
45
  botrun_flow_lang/langgraph_agents/agents/util/mermaid_util.py,sha256=Aw_ufAEBAqSENOtueemYtapxPVvbQ6HScedeWUZ8lS4,2556
46
46
  botrun_flow_lang/langgraph_agents/agents/util/model_utils.py,sha256=lCORhM77agNgmDxsA40XlUth-E8ThM5Kv-x0_DQnYrs,4811
47
- botrun_flow_lang/langgraph_agents/agents/util/pdf_analyzer.py,sha256=u318H8mXS-qx3-te8fBEHUoOv0hkgXMVdvxlfY80w6g,5091
47
+ botrun_flow_lang/langgraph_agents/agents/util/pdf_analyzer.py,sha256=R50ttYF9uun9aawjFzyFlTrXbM03HNbc-yanILdyRtM,15691
48
+ botrun_flow_lang/langgraph_agents/agents/util/pdf_cache.py,sha256=ptWaNtu_ls1piiBqQG2ZISjxWJ4gxMbIs7hvBdeas5k,7125
49
+ botrun_flow_lang/langgraph_agents/agents/util/pdf_processor.py,sha256=OgaloAzjoMmdymM3O1EiES7Ji6qqZtZPQmDT6HwmnYM,6040
48
50
  botrun_flow_lang/langgraph_agents/agents/util/perplexity_search.py,sha256=4ynmvT8yXbi4KFEVliXWffozB6fHd8jVueA3MmGKlD8,19073
49
51
  botrun_flow_lang/langgraph_agents/agents/util/plotly_util.py,sha256=8xKoj9ABwqCA8dzWFmw-qXCXStgCx6hMc5mVBBJ3ZGw,1913
50
52
  botrun_flow_lang/langgraph_agents/agents/util/tavily_search.py,sha256=hhiuxF6u92X8Mz1VLAreFrB-LyR-UOKR9Xxh1TBveTg,6623
@@ -56,7 +58,7 @@ botrun_flow_lang/llm_agent/llm_agent.py,sha256=Ae9YCK0R_zvSU38Oewo7_qbnBMYTaero6
56
58
  botrun_flow_lang/llm_agent/llm_agent_util.py,sha256=1slGk7LIYUylRjHvw4d92VAxD16uwiK4Efy0m_7tCJs,3048
57
59
  botrun_flow_lang/log/.gitignore,sha256=ZZ3Viy7hKc5dYybO_EM74DBeCqrwL7vmnECmsw--nVc,16
58
60
  botrun_flow_lang/mcp_server/__init__.py,sha256=P02XN_G9ALIeNgPwIsLPdKjGO7lk_XYOxME6NFrBrzE,208
59
- botrun_flow_lang/mcp_server/default_mcp.py,sha256=zkixaPFicuwJBx3B7DsQ9Drfj0FouPRcNY6Gm3B6y5E,28028
61
+ botrun_flow_lang/mcp_server/default_mcp.py,sha256=P38E6p6s9yT2U33hxlOMXG0iioUQ-JgJze-9zmlu5mY,28490
60
62
  botrun_flow_lang/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
63
  botrun_flow_lang/models/token_usage.py,sha256=hwGYZzklnTrcDCjNqCn03kddzS3VH-i1l0d5WnF6iqA,842
62
64
  botrun_flow_lang/models/nodes/utils.py,sha256=kN9RFOSHPvOZU7T4ZfVU6u2wkKgS03xtAKvjLOpryKM,6699
@@ -64,9 +66,9 @@ botrun_flow_lang/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
64
66
  botrun_flow_lang/services/base/firestore_base.py,sha256=Z561TzGvYOUmGKc3IQh03nsK8XHCa96Nlx5m23TySks,1045
65
67
  botrun_flow_lang/services/hatch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
68
  botrun_flow_lang/services/hatch/hatch_factory.py,sha256=ObCcb_hTp8YFXRNXOsXtI_dND_dz7cusypF2tDnMqYY,271
67
- botrun_flow_lang/services/hatch/hatch_fs_store.py,sha256=U8y5ipP2TBux06-sXGddmvkKDtsndUXDJfS54q7PJp8,13092
69
+ botrun_flow_lang/services/hatch/hatch_fs_store.py,sha256=2wmRlFInjCD1RRRHVfX47xX74vih4zJBhfRcy5Uk7ew,13620
68
70
  botrun_flow_lang/services/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
69
- botrun_flow_lang/services/storage/storage_cs_store.py,sha256=uGyYZ-2QVMhh29DwNKIEAp_Sdd_UV7LH3476MUbORTw,7730
71
+ botrun_flow_lang/services/storage/storage_cs_store.py,sha256=5NQekxfzjH6420QHi6HxLFHM5qY9kfiYis-dmsyuHO4,7896
70
72
  botrun_flow_lang/services/storage/storage_factory.py,sha256=Yn40nB79qoEvClksIRnRpQGojXT4J4q1ExBqb3ydets,354
71
73
  botrun_flow_lang/services/storage/storage_store.py,sha256=cb31kDJHNqVA4HyiyJJ1Pnyqv1n5nOkHMpPpA8tvgXg,1905
72
74
  botrun_flow_lang/services/user_setting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -95,6 +97,6 @@ botrun_flow_lang/utils/yaml_utils.py,sha256=1A6PSEE8TM0HSD_6l-fhUsjYnXJcrEKuPgot
95
97
  botrun_flow_lang/utils/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
96
98
  botrun_flow_lang/utils/clients/rate_limit_client.py,sha256=TRpA56OKrfYsoLoJ-TPYlC7Znp9s267-u6CX6BLyVko,8349
97
99
  botrun_flow_lang/utils/clients/token_verify_client.py,sha256=BtrfLvMe-DtS8UKeDhaIkVKDZHphZVP7kyqXn9jhXEc,5740
98
- botrun_flow_lang-5.11.11.dist-info/METADATA,sha256=iaavVUSFaUN3cAkwoJYi1X8XPw0Xd_heaMtQM6WkBlY,6191
99
- botrun_flow_lang-5.11.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
100
- botrun_flow_lang-5.11.11.dist-info/RECORD,,
100
+ botrun_flow_lang-5.12.261.dist-info/METADATA,sha256=vtLwjT6C29pqio3IV9gFQeWSuVexlZuCs_bjkUmCw4s,6221
101
+ botrun_flow_lang-5.12.261.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
102
+ botrun_flow_lang-5.12.261.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any