mcp-query-table 0.3.3__py3-none-any.whl → 0.3.5__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.
@@ -3,4 +3,5 @@ from ._version import __version__
3
3
  from .enums import QueryType, Site, Provider
4
4
  from .tool import BrowserManager, query, chat
5
5
 
6
- TIMEOUT = 1000 * 60 * 2 # 2分钟,在抓取EventStream数据时等待数据返回,防止外层30秒超时
6
+ TIMEOUT = 1000 * 60 * 3 # 3分钟,在抓取EventStream数据时等待数据返回,防止外层30秒超时
7
+ TIMEOUT_60 = 1000 * 60 # 1分钟
@@ -1 +1 @@
1
- __version__ = "0.3.3"
1
+ __version__ = "0.3.5"
@@ -5,14 +5,14 @@
5
5
  """
6
6
  import json
7
7
 
8
- from loguru import logger
9
8
  from playwright.async_api import Page
10
9
 
11
10
  import mcp_query_table
12
- from mcp_query_table.tool import GlobalVars
11
+ from mcp_query_table.tool import GlobalVars, split_images
13
12
 
14
13
  _PAGE0_ = "https://chat.baidu.com/search"
15
14
  _PAGE1_ = "https://chat.baidu.com/aichat/api/conversation"
15
+ _PAGE2_ = "https://chat.baidu.com/aichat/api/file/upload"
16
16
 
17
17
  G = GlobalVars()
18
18
 
@@ -69,16 +69,30 @@ async def chat(page: Page,
69
69
  create: bool,
70
70
  files: list[str],
71
71
  ) -> str:
72
+ async def on_file_chooser(file_chooser):
73
+ # 文件选择对话框
74
+ await file_chooser.set_files(files)
75
+
72
76
  if not page.url.startswith(_PAGE0_):
73
77
  create = True
74
78
 
75
79
  if create:
76
80
  await page.goto(_PAGE0_)
77
81
 
82
+ # 文件上传
78
83
  if len(files) > 0:
79
- # TODO
80
- logger.warning("抱歉,百度AI搜索的上传文件功能未突破")
81
-
84
+ imgs, docs = split_images(files)
85
+ assert len(imgs) == 0 or len(docs) == 0, "不能同时包含图片和文档"
86
+
87
+ page.on("filechooser", on_file_chooser)
88
+ async with page.expect_response(f"{_PAGE2_}*", timeout=mcp_query_table.TIMEOUT_60) as response_info:
89
+ if len(imgs) > 0:
90
+ await page.locator(".cs-input-upload-icon").last.click()
91
+ else:
92
+ await page.locator(".cs-input-upload-icon").first.click()
93
+ page.remove_listener("filechooser", on_file_chooser)
94
+
95
+ # 提交问题
82
96
  await page.route(_PAGE1_, on_route)
83
97
  async with page.expect_response(_PAGE1_, timeout=mcp_query_table.TIMEOUT) as response_info:
84
98
  await page.locator("#chat-input-box").fill(prompt)
@@ -93,7 +93,7 @@ async def chat(page: Page,
93
93
  await page.goto(_PAGE0_)
94
94
  if len(files) > 0:
95
95
  # 只能在新会话中上传文件
96
- async with page.expect_response(_PAGE3_, timeout=mcp_query_table.TIMEOUT) as response_info:
96
+ async with page.expect_response(_PAGE3_, timeout=mcp_query_table.TIMEOUT_60) as response_info:
97
97
  await page.locator("input[type=\"file\"]").set_input_files(files)
98
98
  else:
99
99
  name = "提出后续问题,Enter发送,Shift+Enter 换行"
@@ -7,7 +7,7 @@ import re
7
7
  from playwright.async_api import Page
8
8
 
9
9
  import mcp_query_table
10
- from mcp_query_table.tool import GlobalVars, is_image
10
+ from mcp_query_table.tool import GlobalVars, split_images
11
11
 
12
12
  _PAGE0_ = "https://yuanbao.tencent.com/"
13
13
  _PAGE1_ = "https://yuanbao.tencent.com/api/chat"
@@ -76,20 +76,15 @@ async def chat(page: Page,
76
76
  await page.goto(_PAGE0_)
77
77
 
78
78
  if len(files) > 0:
79
- is_img, is_doc = False, False
80
- for f in files:
81
- if is_image(f):
82
- is_img = True
83
- else:
84
- is_doc = True
85
- assert is_img ^ is_doc, "不能同时包含图片和文档"
79
+ imgs, docs = split_images(files)
80
+ assert len(imgs) == 0 or len(docs) == 0, "不能同时包含图片和文档"
86
81
 
87
82
  # 点击上传文件按钮,才会出现上传文件的input
88
83
  await page.get_by_role("button").filter(has_text=re.compile(r"^$")).last.click()
89
84
 
90
85
  # 上传文件
91
- async with page.expect_response(_PAGE2_, timeout=mcp_query_table.TIMEOUT) as response_info:
92
- if is_img:
86
+ async with page.expect_response(_PAGE2_, timeout=mcp_query_table.TIMEOUT_60) as response_info:
87
+ if len(imgs) > 0:
93
88
  await page.locator("input[type=\"file\"]").nth(-2).set_input_files(files)
94
89
  else:
95
90
  await page.locator("input[type=\"file\"]").last.set_input_files(files)
@@ -21,7 +21,7 @@ _queryType_ = {
21
21
  QueryType.Fund: 'JJ',
22
22
  QueryType.Index: 'ZS',
23
23
  QueryType.Info: 'ZX',
24
- QueryType.Board: 'ZX', # 板块也走指数
24
+ QueryType.Board: 'ZS', # 板块也走指数
25
25
  }
26
26
 
27
27
 
mcp_query_table/tool.py CHANGED
@@ -2,7 +2,7 @@ import subprocess
2
2
  import sys
3
3
  import time
4
4
  from pathlib import Path
5
- from typing import Optional
5
+ from typing import Optional, List, Tuple
6
6
 
7
7
  import pandas as pd
8
8
  from loguru import logger
@@ -142,6 +142,12 @@ class BrowserManager:
142
142
  # 防止开发者工具被使用
143
143
  if page.url.startswith("devtools://"):
144
144
  continue
145
+ # 防止chrome扩展被使用
146
+ if page.url.startswith("chrome-extension://"):
147
+ continue
148
+ # 防止edge扩展被使用
149
+ if page.url.startswith("extension://"):
150
+ continue
145
151
  self.pages.append(page)
146
152
 
147
153
  async def _try_launch(self) -> None:
@@ -275,3 +281,15 @@ def is_image(path: str) -> bool:
275
281
  img_ext = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']
276
282
  ext = Path(path).suffix.lower()
277
283
  return ext in img_ext
284
+
285
+
286
+ def split_images(files: List[str]) -> Tuple[List[str], List[str]]:
287
+ """图片列表分成两部分"""
288
+ imgs = []
289
+ docs = []
290
+ for f in files:
291
+ if is_image(f):
292
+ imgs.append(f)
293
+ else:
294
+ docs.append(f)
295
+ return imgs, docs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp_query_table
3
- Version: 0.3.3
3
+ Version: 0.3.5
4
4
  Summary: query table from website, support MCP
5
5
  Author-email: wukan <wu-kan@163.com>
6
6
  License: MIT License
@@ -205,6 +205,12 @@ npx @modelcontextprotocol/inspector python -m mcp_query_table --format markdown
205
205
  - 向东方财富板块查询 “去年涨的最差的行业板块”,再查询此板块中去年涨的最好的5只股票
206
206
  > 分成两步查询,先查询板块,再查询股票。但最好不要全自动,因为第一步的结果它不理解“今日涨幅”和“区间涨幅”,需要交互修正
207
207
 
208
+ ## 支持`Streamlit`
209
+
210
+ 实现在同一页面中查询金融数据,并手工输入到`AI`中进行深度分析。参考`streamlit`目录下的`README.md`文件。
211
+
212
+ ![streamlit](docs/img/streamlit.png)
213
+
208
214
  ## 参考
209
215
 
210
216
  - [Playwright](https://playwright.dev/python/docs/intro)
@@ -0,0 +1,19 @@
1
+ mcp_query_table/__init__.py,sha256=NmnAOKcJjQoeTJMbIY79-JsNNdj-PJpnZ-x8MPjpE4o,272
2
+ mcp_query_table/__main__.py,sha256=W3tMnZZTvkhjlLHmSYHng3CTvYX6-LjyaBDhf-ypH7w,1186
3
+ mcp_query_table/_version.py,sha256=ThnCuF3X7rsQSd5PAea_jfYA70ZmhLvkFcLBxBPwZnY,22
4
+ mcp_query_table/enums.py,sha256=Hen0X1f2of69f08epun6HvYIgbpw_rf8BvoRQ184kS4,679
5
+ mcp_query_table/server.py,sha256=oV8CSi-EW5-xlPn38R1wLu7U-pCHgAJci1W8rJFsXSk,3430
6
+ mcp_query_table/tool.py,sha256=kCnfBNv1T88gNnFLsz-ZjXNuxbzhGvLPcPfNkkJ7Dyg,9096
7
+ mcp_query_table/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ mcp_query_table/providers/baidu.py,sha256=q0vZxl_UTO8v4LbznwT2b1hM-00jswDR8CqB3tc-X9U,3389
9
+ mcp_query_table/providers/n.py,sha256=J0Xo-BlXveIQdDbwKkuEP4I1mfAr8i1rviD0UTztI9Y,3009
10
+ mcp_query_table/providers/yuanbao.py,sha256=4DzoLfgg7dSP1BhiS_tKyTQ0byc1zHRuZQjyq-2pZfQ,3148
11
+ mcp_query_table/sites/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ mcp_query_table/sites/eastmoney.py,sha256=LImjpYVuM5YnXwnNzB2hkKfHofocZZScetGqMOCHZpk,4477
13
+ mcp_query_table/sites/iwencai.py,sha256=g56pj3pbxu4mXLNnaaS3Hdx-DvEy_9OBrQJe26z4z08,5059
14
+ mcp_query_table/sites/tdx.py,sha256=P-GNFUsS5_INy3sicaZbUBdudgQBZuhu_QyVvyw4yDg,4126
15
+ mcp_query_table-0.3.5.dist-info/licenses/LICENSE,sha256=rbvv_CTd7biGwT21tvhgQ2zkbPFXOoON7WFQWEdElBA,1063
16
+ mcp_query_table-0.3.5.dist-info/METADATA,sha256=CVf5UB9Dn4WFuAcPwGW1jxUJ4TQrRWELQpW0I_MeCeU,8574
17
+ mcp_query_table-0.3.5.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
18
+ mcp_query_table-0.3.5.dist-info/top_level.txt,sha256=5M_8dkO1USOX7_EWbWS6O_TEsZ5yo-AodFNKeUEgvEQ,16
19
+ mcp_query_table-0.3.5.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- mcp_query_table/__init__.py,sha256=gNXLL6MtH667HEdsUbJ4OAbGqwYO1dLdkqorV3-RtLM,238
2
- mcp_query_table/__main__.py,sha256=W3tMnZZTvkhjlLHmSYHng3CTvYX6-LjyaBDhf-ypH7w,1186
3
- mcp_query_table/_version.py,sha256=8KcCYTXH99C2-gCLuPILJvtT9YftRWJsartIx6TQ2ZY,22
4
- mcp_query_table/enums.py,sha256=Hen0X1f2of69f08epun6HvYIgbpw_rf8BvoRQ184kS4,679
5
- mcp_query_table/server.py,sha256=oV8CSi-EW5-xlPn38R1wLu7U-pCHgAJci1W8rJFsXSk,3430
6
- mcp_query_table/tool.py,sha256=uKqqrUrnUnvwlOipX0YODUg9WMq_Us994X8sysxe1cM,8571
7
- mcp_query_table/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- mcp_query_table/providers/baidu.py,sha256=VkjAN6mSD4xa9kfDvbCb_Xj9Su5F2dakzYNgjoLGsR4,2738
9
- mcp_query_table/providers/n.py,sha256=GcqNMra1pc_DTw3QB3a2SUNzZCOrGjiuvuVDS-hTz5o,3006
10
- mcp_query_table/providers/yuanbao.py,sha256=BfHg3A6RGOT-GxfxkrAoiOQFFo6qydtI5tZSoRGtPiY,3244
11
- mcp_query_table/sites/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- mcp_query_table/sites/eastmoney.py,sha256=LImjpYVuM5YnXwnNzB2hkKfHofocZZScetGqMOCHZpk,4477
13
- mcp_query_table/sites/iwencai.py,sha256=g56pj3pbxu4mXLNnaaS3Hdx-DvEy_9OBrQJe26z4z08,5059
14
- mcp_query_table/sites/tdx.py,sha256=RIUQaB7Tn4AVyWaevk9SzTKIDwVO2f9erIlI-adXPLY,4126
15
- mcp_query_table-0.3.3.dist-info/licenses/LICENSE,sha256=rbvv_CTd7biGwT21tvhgQ2zkbPFXOoON7WFQWEdElBA,1063
16
- mcp_query_table-0.3.3.dist-info/METADATA,sha256=cRXUETyJhkJ12POY1fMsZv2YHvFdBor8c_BqNOZhy5g,8372
17
- mcp_query_table-0.3.3.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
18
- mcp_query_table-0.3.3.dist-info/top_level.txt,sha256=5M_8dkO1USOX7_EWbWS6O_TEsZ5yo-AodFNKeUEgvEQ,16
19
- mcp_query_table-0.3.3.dist-info/RECORD,,