zerone-cli 0.1.1__tar.gz → 0.1.2__tar.gz

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 (29) hide show
  1. {zerone_cli-0.1.1 → zerone_cli-0.1.2}/PKG-INFO +1 -1
  2. zerone_cli-0.1.2/cli/__init__.py +1 -0
  3. zerone_cli-0.1.2/cli/client.py +176 -0
  4. zerone_cli-0.1.2/cli/commands/__init__.py +19 -0
  5. zerone_cli-0.1.2/cli/commands/basic_info.py +77 -0
  6. zerone_cli-0.1.2/cli/commands/config_cmd.py +47 -0
  7. zerone_cli-0.1.2/cli/commands/entity_exit_list.py +47 -0
  8. zerone_cli-0.1.2/cli/commands/entity_financial_list.py +42 -0
  9. zerone_cli-0.1.2/cli/commands/entity_invest_list.py +47 -0
  10. zerone_cli-0.1.2/cli/commands/entity_managed_funds_list.py +42 -0
  11. zerone_cli-0.1.2/cli/commands/entity_profile.py +40 -0
  12. zerone_cli-0.1.2/cli/commands/entity_search.py +31 -0
  13. zerone_cli-0.1.2/cli/commands/financing.py +84 -0
  14. zerone_cli-0.1.2/cli/commands/model_financing_probability.py +39 -0
  15. zerone_cli-0.1.2/cli/commands/shareholders.py +88 -0
  16. zerone_cli-0.1.2/cli/config.py +69 -0
  17. zerone_cli-0.1.2/cli/main.py +29 -0
  18. zerone_cli-0.1.2/cli/utils/__init__.py +3 -0
  19. zerone_cli-0.1.2/cli/utils/errors.py +0 -0
  20. zerone_cli-0.1.2/cli/utils/output.py +97 -0
  21. {zerone_cli-0.1.1 → zerone_cli-0.1.2}/pyproject.toml +4 -3
  22. zerone_cli-0.1.2/zerone_cli.egg-info/PKG-INFO +110 -0
  23. zerone_cli-0.1.2/zerone_cli.egg-info/SOURCES.txt +27 -0
  24. zerone_cli-0.1.2/zerone_cli.egg-info/dependency_links.txt +1 -0
  25. zerone_cli-0.1.2/zerone_cli.egg-info/entry_points.txt +3 -0
  26. zerone_cli-0.1.2/zerone_cli.egg-info/requires.txt +6 -0
  27. zerone_cli-0.1.2/zerone_cli.egg-info/top_level.txt +1 -0
  28. {zerone_cli-0.1.1 → zerone_cli-0.1.2}/README.md +0 -0
  29. {zerone_cli-0.1.1 → zerone_cli-0.1.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zerone-cli
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Zerone 私募股权数据 CLI 工具
5
5
  Author-email: Zerone <tech@zerone.com.cn>
6
6
  License: MIT
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
@@ -0,0 +1,176 @@
1
+ from typing import Optional
2
+
3
+ import httpx
4
+
5
+ from cli.config import config_manager
6
+
7
+
8
+ class MCPClient:
9
+
10
+ def __init__(self):
11
+ self.api_key = config_manager.get_api_key()
12
+ self.server_url = config_manager.get_server_url()
13
+ self.client = httpx.Client(timeout=30.0)
14
+
15
+ def _request(
16
+ self,
17
+ method: str,
18
+ path: str,
19
+ json_data: Optional[dict] = None,
20
+ params: Optional[dict] = None,
21
+ ) -> dict:
22
+ url = f"{self.server_url}{path}"
23
+ headers = {
24
+ "Authorization": f"Bearer {self.api_key}",
25
+ "Content-Type": "application/json",
26
+ }
27
+
28
+ try:
29
+ response = self.client.request(
30
+ method=method,
31
+ url=url,
32
+ headers=headers,
33
+ json=json_data,
34
+ params=params,
35
+ )
36
+ response.raise_for_status()
37
+ data = response.json()
38
+ if not data.get("success", True):
39
+ error = data.get("error", {})
40
+ raise ValueError(f"[{error.get('code', 'UNKNOWN')}] {error.get('message', '未知错误')}")
41
+ return data
42
+ except httpx.HTTPStatusError as e:
43
+ try:
44
+ error_data = e.response.json()
45
+ detail = error_data.get("detail", "")
46
+ if detail:
47
+ raise ValueError(f"[HTTP {e.response.status_code}] {detail}")
48
+ except ValueError:
49
+ raise
50
+ except Exception:
51
+ pass
52
+ raise ValueError(f"请求失败: {e.response.status_code} - {e.response.text}")
53
+ except httpx.ConnectError:
54
+ raise ValueError(f"无法连接到 MCP Server,请检查 server_url 配置:{self.server_url}")
55
+ except httpx.TimeoutException:
56
+ raise ValueError("请求超时,请检查网络连接或稍后重试")
57
+
58
+ def entity_search(self, keyword: str) -> dict:
59
+ return self._request(
60
+ "POST",
61
+ "/rest-api/tool/entity_search",
62
+ json_data={"keyword": keyword},
63
+ )
64
+
65
+ def entity_profile(
66
+ self,
67
+ entity_name: str,
68
+ entity_type: Optional[str] = None,
69
+ ) -> dict:
70
+ return self._request(
71
+ "POST",
72
+ "/rest-api/tool/entity_profile",
73
+ json_data={
74
+ "entity_name": entity_name,
75
+ "entity_type": entity_type or "",
76
+ },
77
+ )
78
+
79
+ def entity_financial_list(
80
+ self,
81
+ entity_name: str,
82
+ entity_type: Optional[str] = None,
83
+ page: int = 1,
84
+ page_size: int = 20,
85
+ ) -> dict:
86
+ return self._request(
87
+ "POST",
88
+ "/rest-api/tool/entity_financial_list",
89
+ json_data={
90
+ "entity_name": entity_name,
91
+ "entity_type": entity_type or "",
92
+ "page": page,
93
+ "page_size": page_size,
94
+ },
95
+ )
96
+
97
+ def entity_managed_funds_list(
98
+ self,
99
+ entity_name: str,
100
+ entity_type: Optional[str] = None,
101
+ page: int = 1,
102
+ page_size: int = 20,
103
+ ) -> dict:
104
+ return self._request(
105
+ "POST",
106
+ "/rest-api/tool/entity_managed_funds_list",
107
+ json_data={
108
+ "entity_name": entity_name,
109
+ "entity_type": entity_type or "",
110
+ "page": page,
111
+ "page_size": page_size,
112
+ },
113
+ )
114
+
115
+ def entity_exit_list(
116
+ self,
117
+ entity_name: str,
118
+ entity_type: Optional[str] = None,
119
+ exit_type: Optional[str] = None,
120
+ page: int = 1,
121
+ page_size: int = 20,
122
+ ) -> dict:
123
+ return self._request(
124
+ "POST",
125
+ "/rest-api/tool/entity_exit_list",
126
+ json_data={
127
+ "entity_name": entity_name,
128
+ "entity_type": entity_type or "",
129
+ "exit_type": exit_type or "",
130
+ "page": page,
131
+ "page_size": page_size,
132
+ },
133
+ )
134
+
135
+ def entity_invest_list(
136
+ self,
137
+ entity_name: str,
138
+ entity_type: Optional[str] = None,
139
+ invest_type: Optional[str] = None,
140
+ page: int = 1,
141
+ page_size: int = 20,
142
+ ) -> dict:
143
+ return self._request(
144
+ "POST",
145
+ "/rest-api/tool/entity_invest_list",
146
+ json_data={
147
+ "entity_name": entity_name,
148
+ "entity_type": entity_type or "",
149
+ "invest_type": invest_type or "",
150
+ "page": page,
151
+ "page_size": page_size,
152
+ },
153
+ )
154
+
155
+ def model_financing_probability(
156
+ self,
157
+ entity_name: str,
158
+ entity_type: Optional[str] = None,
159
+ ) -> dict:
160
+ return self._request(
161
+ "POST",
162
+ "/rest-api/tool/model_financing_probability",
163
+ json_data={
164
+ "entity_name": entity_name,
165
+ "entity_type": entity_type or "",
166
+ },
167
+ )
168
+
169
+ def close(self):
170
+ self.client.close()
171
+
172
+ def __enter__(self):
173
+ return self
174
+
175
+ def __exit__(self, exc_type, exc_val, exc_tb):
176
+ self.close()
@@ -0,0 +1,19 @@
1
+ from cli.commands import config_cmd
2
+ from cli.commands.entity_search import entity_search
3
+ from cli.commands.entity_profile import entity_profile
4
+ from cli.commands.entity_financial_list import entity_financial_list
5
+ from cli.commands.entity_managed_funds_list import entity_managed_funds_list
6
+ from cli.commands.entity_exit_list import entity_exit_list
7
+ from cli.commands.entity_invest_list import entity_invest_list
8
+ from cli.commands.model_financing_probability import model_financing_probability
9
+
10
+ __all__ = [
11
+ "config_cmd",
12
+ "entity_search",
13
+ "entity_profile",
14
+ "entity_financial_list",
15
+ "entity_managed_funds_list",
16
+ "entity_exit_list",
17
+ "entity_invest_list",
18
+ "model_financing_probability",
19
+ ]
@@ -0,0 +1,77 @@
1
+ """
2
+ 查询基本信息命令模块
3
+ """
4
+
5
+ import asyncio
6
+ from typing import Optional
7
+
8
+ import typer
9
+
10
+ from cli.config import config_manager
11
+ from cli.utils.output import print_result
12
+ from mcp_server.tools.executor import ToolExecutor
13
+ from mcp_server.router.entity_router import EntityRouter
14
+ from mcp_server.router.type_router import TypeRouter
15
+ from mcp_server.services.entity_service import EntityService
16
+ from mcp_server.utils.field_mapper import FieldMapper
17
+ from mcp_server.openapi_client.client import OpenAPIClient
18
+
19
+
20
+ async def execute(entity_name: str, entity_type: Optional[str] = None) -> dict:
21
+ """
22
+ 执行查询基本信息
23
+
24
+ Args:
25
+ entity_name: 实体名称
26
+ entity_type: 实体类型 (gp/lp/fund/company/preipo/list/neeq)
27
+
28
+ Returns:
29
+ 查询结果字典
30
+ """
31
+ app_id, app_key = config_manager.get_credentials()
32
+ config = config_manager.load()
33
+
34
+ client = OpenAPIClient(base_url=config.base_url)
35
+ entity_service = EntityService()
36
+ executor = ToolExecutor(
37
+ entity_router=EntityRouter(entity_service),
38
+ type_router=TypeRouter(),
39
+ field_mapper=FieldMapper(),
40
+ openapi_client=client,
41
+ )
42
+
43
+ try:
44
+ result = await executor.execute_get_basic_info(
45
+ entity_name=entity_name,
46
+ entity_type=entity_type,
47
+ app_id=app_id,
48
+ app_key=app_key,
49
+ )
50
+ return result
51
+ finally:
52
+ await client.close()
53
+
54
+
55
+ def get_basic_info(
56
+ entity_name: str = typer.Argument(..., help="实体名称,如'字节跳动'"),
57
+ entity_type: Optional[str] = typer.Option(
58
+ None, "--type", "-t", help="实体类型:gp/lp/fund/company/preipo/list/neeq"
59
+ ),
60
+ output: str = typer.Option(
61
+ "table", "--output", "-o", help="输出格式:table/json/csv"
62
+ ),
63
+ ):
64
+ """
65
+ 查询实体基本信息
66
+
67
+ 示例:
68
+ zerone-cli get-basic-info "字节跳动"
69
+ zerone-cli get-basic-info "红杉资本" --type gp
70
+ zerone-cli get-basic-info "字节跳动" --output json
71
+ """
72
+ try:
73
+ result = asyncio.run(execute(entity_name, entity_type))
74
+ print_result(result, output)
75
+ except ValueError as e:
76
+ typer.echo(f"[red]错误: {e}[/red]", err=True)
77
+ raise typer.Exit(1)
@@ -0,0 +1,47 @@
1
+ import typer
2
+
3
+ from cli.config import config_manager
4
+
5
+ app = typer.Typer(help="管理 CLI 配置")
6
+
7
+
8
+ @app.command("show")
9
+ def show_config():
10
+ """显示当前配置"""
11
+ config = config_manager.load()
12
+ typer.echo("=== 当前配置 ===")
13
+ typer.echo(f"api_key: {'*' * 10 if config.api_key else '(未设置)'}")
14
+ typer.echo(f"server_url: {config.server_url}")
15
+ typer.echo(f"output_format: {config.output_format}")
16
+
17
+
18
+ @app.command("set-api-key")
19
+ def set_api_key(api_key: str = typer.Argument(..., help="API Key(从平台获取)")):
20
+ """设置 API Key"""
21
+ config = config_manager.load()
22
+ config.api_key = api_key
23
+ config_manager.save(config)
24
+ typer.echo("✓ API Key 已设置")
25
+
26
+
27
+ @app.command("set-server-url")
28
+ def set_server_url(url: str = typer.Argument(..., help="MCP Server 地址,如 http://localhost:8080")):
29
+ """设置 MCP Server 地址"""
30
+ config = config_manager.load()
31
+ config.server_url = url
32
+ config_manager.save(config)
33
+ typer.echo(f"✓ Server URL 已设置: {url}")
34
+
35
+
36
+ @app.command("set-output-format")
37
+ def set_output_format(
38
+ fmt: str = typer.Argument(..., help="输出格式 (table/json/csv)")
39
+ ):
40
+ """设置默认输出格式"""
41
+ if fmt not in ("table", "json", "csv"):
42
+ typer.echo("✗ 无效的输出格式,请选择: table, json, csv")
43
+ raise typer.Exit(1)
44
+ config = config_manager.load()
45
+ config.output_format = fmt
46
+ config_manager.save(config)
47
+ typer.echo(f"✓ Output format 已设置: {fmt}")
@@ -0,0 +1,47 @@
1
+ from typing import Optional
2
+
3
+ import typer
4
+
5
+ from cli.client import MCPClient
6
+ from cli.utils.output import print_result
7
+
8
+
9
+ def entity_exit_list(
10
+ entity_name: str = typer.Argument(..., help="实体名称,如'高瓴资本'"),
11
+ entity_type: Optional[str] = typer.Option(
12
+ None, "--type", "-t",
13
+ help="实体类型:GP/LP/FUND"
14
+ ),
15
+ exit_type: Optional[str] = typer.Option(
16
+ None, "--exit-type", "-e",
17
+ help="退出类型:COMPANY/FUND"
18
+ ),
19
+ page: int = typer.Option(1, "--page", "-p", help="页码,从 1 开始"),
20
+ page_size: int = typer.Option(20, "--page-size", "-s", help="每页条数,默认 20"),
21
+ output: str = typer.Option("table", "--output", "-o", help="输出格式:table/json/csv"),
22
+ ):
23
+ """
24
+ 查询退出列表(分页)
25
+
26
+ 支持 GP/LP/FUND 类型。
27
+
28
+ 示例:
29
+ zerone entity-exit-list "高瓴资本" --type GP
30
+ zerone entity-exit-list "高瓴资本" --type GP --exit-type COMPANY
31
+ """
32
+ try:
33
+ with MCPClient() as client:
34
+ result = client.entity_exit_list(
35
+ entity_name=entity_name,
36
+ entity_type=entity_type,
37
+ exit_type=exit_type,
38
+ page=page,
39
+ page_size=page_size,
40
+ )
41
+ print_result(result, output)
42
+ except ValueError as e:
43
+ typer.echo(f"错误: {e}", err=True)
44
+ raise typer.Exit(1)
45
+ except Exception as e:
46
+ typer.echo(f"请求失败: {e}", err=True)
47
+ raise typer.Exit(1)
@@ -0,0 +1,42 @@
1
+ from typing import Optional
2
+
3
+ import typer
4
+
5
+ from cli.client import MCPClient
6
+ from cli.utils.output import print_result
7
+
8
+
9
+ def entity_financial_list(
10
+ entity_name: str = typer.Argument(..., help="实体名称,如'美团'"),
11
+ entity_type: Optional[str] = typer.Option(
12
+ None, "--type", "-t",
13
+ help="实体类型:LISTED/PREIPO/NEEQ"
14
+ ),
15
+ page: int = typer.Option(1, "--page", "-p", help="页码,从 1 开始"),
16
+ page_size: int = typer.Option(20, "--page-size", "-s", help="每页条数,默认 20"),
17
+ output: str = typer.Option("table", "--output", "-o", help="输出格式:table/json/csv"),
18
+ ):
19
+ """
20
+ 查询实体财务数据列表(分页)
21
+
22
+ 仅支持 LISTED/PREIPO/NEEQ 类型。
23
+
24
+ 示例:
25
+ zerone entity-financial-list "美团" --type LISTED
26
+ zerone entity-financial-list "美团" --type LISTED --page 2
27
+ """
28
+ try:
29
+ with MCPClient() as client:
30
+ result = client.entity_financial_list(
31
+ entity_name=entity_name,
32
+ entity_type=entity_type,
33
+ page=page,
34
+ page_size=page_size,
35
+ )
36
+ print_result(result, output)
37
+ except ValueError as e:
38
+ typer.echo(f"错误: {e}", err=True)
39
+ raise typer.Exit(1)
40
+ except Exception as e:
41
+ typer.echo(f"请求失败: {e}", err=True)
42
+ raise typer.Exit(1)
@@ -0,0 +1,47 @@
1
+ from typing import Optional
2
+
3
+ import typer
4
+
5
+ from cli.client import MCPClient
6
+ from cli.utils.output import print_result
7
+
8
+
9
+ def entity_invest_list(
10
+ entity_name: str = typer.Argument(..., help="实体名称,如'高瓴资本'"),
11
+ entity_type: Optional[str] = typer.Option(
12
+ None, "--type", "-t",
13
+ help="实体类型:GP/LP/FUND"
14
+ ),
15
+ invest_type: Optional[str] = typer.Option(
16
+ None, "--invest-type", "-i",
17
+ help="投资类型:COMPANY/FUND/OTHER"
18
+ ),
19
+ page: int = typer.Option(1, "--page", "-p", help="页码,从 1 开始"),
20
+ page_size: int = typer.Option(20, "--page-size", "-s", help="每页条数,默认 20"),
21
+ output: str = typer.Option("table", "--output", "-o", help="输出格式:table/json/csv"),
22
+ ):
23
+ """
24
+ 查询投资列表(分页)
25
+
26
+ 支持 GP/LP/FUND 类型。
27
+
28
+ 示例:
29
+ zerone entity-invest-list "高瓴资本" --type GP
30
+ zerone entity-invest-list "高瓴资本" --type GP --invest-type COMPANY
31
+ """
32
+ try:
33
+ with MCPClient() as client:
34
+ result = client.entity_invest_list(
35
+ entity_name=entity_name,
36
+ entity_type=entity_type,
37
+ invest_type=invest_type,
38
+ page=page,
39
+ page_size=page_size,
40
+ )
41
+ print_result(result, output)
42
+ except ValueError as e:
43
+ typer.echo(f"错误: {e}", err=True)
44
+ raise typer.Exit(1)
45
+ except Exception as e:
46
+ typer.echo(f"请求失败: {e}", err=True)
47
+ raise typer.Exit(1)
@@ -0,0 +1,42 @@
1
+ from typing import Optional
2
+
3
+ import typer
4
+
5
+ from cli.client import MCPClient
6
+ from cli.utils.output import print_result
7
+
8
+
9
+ def entity_managed_funds_list(
10
+ entity_name: str = typer.Argument(..., help="实体名称,如'红杉资本'"),
11
+ entity_type: Optional[str] = typer.Option(
12
+ None, "--type", "-t",
13
+ help="实体类型:GP/FUND_MANAGER"
14
+ ),
15
+ page: int = typer.Option(1, "--page", "-p", help="页码,从 1 开始"),
16
+ page_size: int = typer.Option(20, "--page-size", "-s", help="每页条数,默认 20"),
17
+ output: str = typer.Option("table", "--output", "-o", help="输出格式:table/json/csv"),
18
+ ):
19
+ """
20
+ 查询管理基金列表(分页)
21
+
22
+ 支持 GP 和 FUND_MANAGER 类型。
23
+
24
+ 示例:
25
+ zerone entity-managed-funds-list "红杉资本" --type GP
26
+ zerone entity-managed-funds-list "红杉资本" --type GP --page 2
27
+ """
28
+ try:
29
+ with MCPClient() as client:
30
+ result = client.entity_managed_funds_list(
31
+ entity_name=entity_name,
32
+ entity_type=entity_type,
33
+ page=page,
34
+ page_size=page_size,
35
+ )
36
+ print_result(result, output)
37
+ except ValueError as e:
38
+ typer.echo(f"错误: {e}", err=True)
39
+ raise typer.Exit(1)
40
+ except Exception as e:
41
+ typer.echo(f"请求失败: {e}", err=True)
42
+ raise typer.Exit(1)
@@ -0,0 +1,40 @@
1
+ from typing import Optional
2
+
3
+ import typer
4
+
5
+ from cli.client import MCPClient
6
+ from cli.utils.output import print_result
7
+
8
+
9
+ def entity_profile(
10
+ entity_name: str = typer.Argument(..., help="实体名称,如'字节跳动'"),
11
+ entity_type: Optional[str] = typer.Option(
12
+ None, "--type", "-t",
13
+ help="实体类型:GP/FUND/LP/COMPANY/PREIPO/LISTED/NEEQ/FUND_MANAGER"
14
+ ),
15
+ output: str = typer.Option("table", "--output", "-o", help="输出格式:table/json/csv"),
16
+ ):
17
+ """
18
+ 查询实体综合画像
19
+
20
+ 返回基本信息、标签画像、概览数据、股东列表、融资历史、关联GP列表等。
21
+ 支持全部 8 种实体类型:GP/FUND/LP/COMPANY/FUND_MANAGER/PREIPO/LISTED/NEEQ。
22
+
23
+ 示例:
24
+ zerone entity-profile "字节跳动"
25
+ zerone entity-profile "红杉资本" --type GP
26
+ zerone entity-profile "字节跳动" --output json
27
+ """
28
+ try:
29
+ with MCPClient() as client:
30
+ result = client.entity_profile(
31
+ entity_name=entity_name,
32
+ entity_type=entity_type,
33
+ )
34
+ print_result(result, output)
35
+ except ValueError as e:
36
+ typer.echo(f"错误: {e}", err=True)
37
+ raise typer.Exit(1)
38
+ except Exception as e:
39
+ typer.echo(f"请求失败: {e}", err=True)
40
+ raise typer.Exit(1)
@@ -0,0 +1,31 @@
1
+ from typing import Optional
2
+
3
+ import typer
4
+
5
+ from cli.client import MCPClient
6
+ from cli.utils.output import print_result
7
+
8
+
9
+ def entity_search(
10
+ keyword: str = typer.Argument(..., help="搜索关键词"),
11
+ output: str = typer.Option("table", "--output", "-o", help="输出格式:table/json/csv"),
12
+ ):
13
+ """
14
+ 实体模糊搜索
15
+
16
+ 根据关键词搜索匹配的实体,返回候选实体列表。
17
+
18
+ 示例:
19
+ zerone entity-search "字节跳动"
20
+ zerone entity-search "红杉" --output json
21
+ """
22
+ try:
23
+ with MCPClient() as client:
24
+ result = client.entity_search(keyword=keyword)
25
+ print_result(result, output)
26
+ except ValueError as e:
27
+ typer.echo(f"错误: {e}", err=True)
28
+ raise typer.Exit(1)
29
+ except Exception as e:
30
+ typer.echo(f"请求失败: {e}", err=True)
31
+ raise typer.Exit(1)
@@ -0,0 +1,84 @@
1
+ """
2
+ 查询融资概率命令模块
3
+ """
4
+
5
+ import asyncio
6
+ from typing import Optional
7
+
8
+ import typer
9
+
10
+ from cli.config import config_manager
11
+ from cli.utils.output import print_result
12
+ from mcp_server.tools.executor import ToolExecutor
13
+ from mcp_server.router.entity_router import EntityRouter
14
+ from mcp_server.router.type_router import TypeRouter
15
+ from mcp_server.services.entity_service import EntityService
16
+ from mcp_server.utils.field_mapper import FieldMapper
17
+ from mcp_server.openapi_client.client import OpenAPIClient
18
+
19
+
20
+ async def execute(
21
+ entity_name: str,
22
+ entity_type: Optional[str] = None,
23
+ ) -> dict:
24
+ """
25
+ 执行查询融资概率
26
+
27
+ 注意:此命令仅支持项目公司类型(company/preipo/list/neeq)
28
+
29
+ Args:
30
+ entity_name: 实体名称
31
+ entity_type: 实体类型
32
+
33
+ Returns:
34
+ 查询结果字典
35
+ """
36
+ app_id, app_key = config_manager.get_credentials()
37
+ config = config_manager.load()
38
+
39
+ client = OpenAPIClient(base_url=config.base_url)
40
+ entity_service = EntityService()
41
+ executor = ToolExecutor(
42
+ entity_router=EntityRouter(entity_service),
43
+ type_router=TypeRouter(),
44
+ field_mapper=FieldMapper(),
45
+ openapi_client=client,
46
+ )
47
+
48
+ try:
49
+ result = await executor.execute_get_financing_probability(
50
+ entity_name=entity_name,
51
+ entity_type=entity_type,
52
+ app_id=app_id,
53
+ app_key=app_key,
54
+ )
55
+ return result
56
+ finally:
57
+ await client.close()
58
+
59
+
60
+ def get_financing_probability(
61
+ entity_name: str = typer.Argument(..., help="实体名称,如'字节跳动'"),
62
+ entity_type: Optional[str] = typer.Option(
63
+ None, "--type", "-t", help="实体类型:company/preipo/list/neeq"
64
+ ),
65
+ output: str = typer.Option(
66
+ "table", "--output", "-o", help="输出格式:table/json/csv"
67
+ ),
68
+ ):
69
+ """
70
+ 查询公司融资概率(2年)
71
+
72
+ 注意:此命令仅支持项目公司类型(company/preipo/list/neeq)
73
+
74
+ 示例:
75
+ zerone-cli get-financing-probability "蔚来汽车"
76
+ zerone-cli get-financing-probability "字节跳动" --type company
77
+ zerone-cli get-financing-probability "蔚来汽车" --output json
78
+ """
79
+ try:
80
+ result = asyncio.run(execute(entity_name, entity_type))
81
+ print_result(result, output)
82
+ except ValueError as e:
83
+ typer.echo(f"[red]错误: {e}[/red]", err=True)
84
+ raise typer.Exit(1)
@@ -0,0 +1,39 @@
1
+ from typing import Optional
2
+
3
+ import typer
4
+
5
+ from cli.client import MCPClient
6
+ from cli.utils.output import print_result
7
+
8
+
9
+ def model_financing_probability(
10
+ entity_name: str = typer.Argument(..., help="实体名称,如'蔚来汽车'"),
11
+ entity_type: Optional[str] = typer.Option(
12
+ None, "--type", "-t",
13
+ help="实体类型:COMPANY/PREIPO/LISTED/NEEQ"
14
+ ),
15
+ output: str = typer.Option("table", "--output", "-o", help="输出格式:table/json/csv"),
16
+ ):
17
+ """
18
+ 查询项目公司融资概率预测模型
19
+
20
+ 仅支持 COMPANY/PREIPO/LISTED/NEEQ 类型。
21
+ 返回融资概率(2年)和模型指标数据。
22
+
23
+ 示例:
24
+ zerone model-financing-probability "蔚来汽车"
25
+ zerone model-financing-probability "蔚来汽车" --type COMPANY
26
+ """
27
+ try:
28
+ with MCPClient() as client:
29
+ result = client.model_financing_probability(
30
+ entity_name=entity_name,
31
+ entity_type=entity_type,
32
+ )
33
+ print_result(result, output)
34
+ except ValueError as e:
35
+ typer.echo(f"错误: {e}", err=True)
36
+ raise typer.Exit(1)
37
+ except Exception as e:
38
+ typer.echo(f"请求失败: {e}", err=True)
39
+ raise typer.Exit(1)
@@ -0,0 +1,88 @@
1
+ """
2
+ 查询股东信息命令模块
3
+ """
4
+
5
+ import asyncio
6
+ from typing import Optional
7
+
8
+ import typer
9
+
10
+ from cli.config import config_manager
11
+ from cli.utils.output import print_result
12
+ from mcp_server.tools.executor import ToolExecutor
13
+ from mcp_server.router.entity_router import EntityRouter
14
+ from mcp_server.router.type_router import TypeRouter
15
+ from mcp_server.services.entity_service import EntityService
16
+ from mcp_server.utils.field_mapper import FieldMapper
17
+ from mcp_server.openapi_client.client import OpenAPIClient
18
+
19
+
20
+ async def execute(
21
+ entity_name: str,
22
+ entity_type: Optional[str] = None,
23
+ page: int = 1,
24
+ page_size: int = 20,
25
+ ) -> dict:
26
+ """
27
+ 执行查询股东信息
28
+
29
+ Args:
30
+ entity_name: 实体名称
31
+ entity_type: 实体类型
32
+ page: 页码,从 1 开始
33
+ page_size: 每页数量
34
+
35
+ Returns:
36
+ 查询结果字典
37
+ """
38
+ app_id, app_key = config_manager.get_credentials()
39
+ config = config_manager.load()
40
+
41
+ client = OpenAPIClient(base_url=config.base_url)
42
+ entity_service = EntityService()
43
+ executor = ToolExecutor(
44
+ entity_router=EntityRouter(entity_service),
45
+ type_router=TypeRouter(),
46
+ field_mapper=FieldMapper(),
47
+ openapi_client=client,
48
+ )
49
+
50
+ try:
51
+ result = await executor.execute_get_shareholders(
52
+ entity_name=entity_name,
53
+ entity_type=entity_type,
54
+ page=page,
55
+ page_size=page_size,
56
+ app_id=app_id,
57
+ app_key=app_key,
58
+ )
59
+ return result
60
+ finally:
61
+ await client.close()
62
+
63
+
64
+ def get_shareholders(
65
+ entity_name: str = typer.Argument(..., help="实体名称,如'字节跳动'"),
66
+ entity_type: Optional[str] = typer.Option(
67
+ None, "--type", "-t", help="实体类型:gp/lp/fund/company/preipo/list/neeq"
68
+ ),
69
+ page: int = typer.Option(1, "--page", "-p", help="页码"),
70
+ page_size: int = typer.Option(20, "--page-size", "-s", help="每页数量"),
71
+ output: str = typer.Option(
72
+ "table", "--output", "-o", help="输出格式:table/json/csv"
73
+ ),
74
+ ):
75
+ """
76
+ 查询实体股东信息(支持分页)
77
+
78
+ 示例:
79
+ zerone-cli get-shareholders "美团"
80
+ zerone-cli get-shareholders "高瓴资本" --type gp --page 1 --page-size 10
81
+ zerone-cli get-shareholders "美团" --output csv
82
+ """
83
+ try:
84
+ result = asyncio.run(execute(entity_name, entity_type, page, page_size))
85
+ print_result(result, output)
86
+ except ValueError as e:
87
+ typer.echo(f"[red]错误: {e}[/red]", err=True)
88
+ raise typer.Exit(1)
@@ -0,0 +1,69 @@
1
+ import os
2
+ import yaml
3
+ from pathlib import Path
4
+ from typing import Optional
5
+
6
+ from pydantic import BaseModel
7
+
8
+ SERVER_URL_PROD = "https://ai.zerone.com.cn/mcp"
9
+ SERVER_URL_DEV = "http://ai-dev.zerone.com.cn/mcp"
10
+
11
+ _env = os.getenv("ZERONE_ENV", "prod").lower()
12
+ DEFAULT_SERVER_URL = SERVER_URL_DEV if _env == "dev" else SERVER_URL_PROD
13
+
14
+
15
+ class CLIConfig(BaseModel):
16
+ api_key: Optional[str] = None
17
+ server_url: str = DEFAULT_SERVER_URL
18
+ output_format: str = "table"
19
+
20
+
21
+ class ConfigManager:
22
+
23
+ CONFIG_DIR = Path.home() / ".zerone"
24
+ CONFIG_FILE = CONFIG_DIR / "config.yaml"
25
+
26
+ def __init__(self):
27
+ self._config: Optional[CLIConfig] = None
28
+
29
+ def _ensure_config_dir(self):
30
+ self.CONFIG_DIR.mkdir(parents=True, exist_ok=True)
31
+
32
+ def load(self) -> CLIConfig:
33
+ if self._config:
34
+ return self._config
35
+
36
+ if self.CONFIG_FILE.exists():
37
+ with open(self.CONFIG_FILE, "r", encoding="utf-8") as f:
38
+ data = yaml.safe_load(f) or {}
39
+ else:
40
+ data = {}
41
+
42
+ data["api_key"] = os.getenv("ZERONE_API_KEY", data.get("api_key"))
43
+ data["server_url"] = os.getenv("ZERONE_SERVER_URL", data.get("server_url", DEFAULT_SERVER_URL))
44
+
45
+ self._config = CLIConfig(**data)
46
+ return self._config
47
+
48
+ def save(self, config: CLIConfig):
49
+ self._ensure_config_dir()
50
+ self._config = config
51
+ with open(self.CONFIG_FILE, "w", encoding="utf-8") as f:
52
+ yaml.dump(config.model_dump(), f, allow_unicode=True, default_flow_style=False)
53
+
54
+ def get_api_key(self) -> str:
55
+ config = self.load()
56
+ if not config.api_key:
57
+ raise ValueError(
58
+ "未配置 API Key。\n"
59
+ "请运行:zerone config set-api-key <your-api-key>\n"
60
+ "或设置环境变量:ZERONE_API_KEY"
61
+ )
62
+ return config.api_key
63
+
64
+ def get_server_url(self) -> str:
65
+ config = self.load()
66
+ return config.server_url
67
+
68
+
69
+ config_manager = ConfigManager()
@@ -0,0 +1,29 @@
1
+ import typer
2
+
3
+ from cli.commands import config_cmd
4
+ from cli.commands.entity_search import entity_search
5
+ from cli.commands.entity_profile import entity_profile
6
+ from cli.commands.entity_financial_list import entity_financial_list
7
+ from cli.commands.entity_managed_funds_list import entity_managed_funds_list
8
+ from cli.commands.entity_exit_list import entity_exit_list
9
+ from cli.commands.entity_invest_list import entity_invest_list
10
+ from cli.commands.model_financing_probability import model_financing_probability
11
+
12
+ app = typer.Typer(
13
+ name="zerone",
14
+ help="Zerone 私募股权数据 CLI 工具 - MCP HTTP 客户端",
15
+ no_args_is_help=True,
16
+ )
17
+
18
+ app.add_typer(config_cmd.app, name="config")
19
+
20
+ app.command("entity-search")(entity_search)
21
+ app.command("entity-profile")(entity_profile)
22
+ app.command("entity-financial-list")(entity_financial_list)
23
+ app.command("entity-managed-funds-list")(entity_managed_funds_list)
24
+ app.command("entity-exit-list")(entity_exit_list)
25
+ app.command("entity-invest-list")(entity_invest_list)
26
+ app.command("model-financing-probability")(model_financing_probability)
27
+
28
+ if __name__ == "__main__":
29
+ app()
@@ -0,0 +1,3 @@
1
+ from .output import print_result, print_error
2
+
3
+ __all__ = ["print_result", "print_error"]
File without changes
@@ -0,0 +1,97 @@
1
+ """
2
+ CLI 输出格式化模块
3
+
4
+ 支持 table、json、csv 三种输出格式。
5
+ """
6
+
7
+ import csv
8
+ import io
9
+ import json
10
+ from typing import Any
11
+
12
+ from rich.console import Console
13
+ from rich.table import Table
14
+
15
+ console = Console()
16
+
17
+
18
+ def print_result(result: dict, output_format: str = "table"):
19
+ """
20
+ 主入口函数,根据格式输出结果
21
+
22
+ Args:
23
+ result: 包含 data、metadata 的结果字典
24
+ output_format: 输出格式 (table/json/csv)
25
+ """
26
+ if "error" in result:
27
+ print_error(result)
28
+ return
29
+
30
+ data = result.get("data", {})
31
+ metadata = result.get("metadata", {})
32
+
33
+ if output_format == "json":
34
+ print_json(data)
35
+ elif output_format == "csv":
36
+ print_csv(data)
37
+ else:
38
+ print_table(data, metadata)
39
+
40
+
41
+ def print_table(data: Any, metadata: dict):
42
+ """表格格式输出"""
43
+ if isinstance(data, list):
44
+ if not data:
45
+ console.print("[yellow]没有查询到数据[/yellow]")
46
+ return
47
+ keys = list(data[0].keys()) if data else []
48
+ table = Table(show_header=True, header_style="bold cyan", box=None)
49
+ for key in keys:
50
+ table.add_column(key, style="white")
51
+ for row in data:
52
+ table.add_row(*[str(row.get(k, "")) for k in keys])
53
+ console.print(table)
54
+ elif isinstance(data, dict):
55
+ table = Table(show_header=True, header_style="bold cyan", box=None)
56
+ table.add_column("字段", style="cyan")
57
+ table.add_column("值", style="white")
58
+ for key, value in data.items():
59
+ table.add_row(key, str(value) if value is not None else "")
60
+ console.print(table)
61
+ else:
62
+ console.print(str(data))
63
+
64
+ entity_name = metadata.get("entityName", "")
65
+ entity_type = metadata.get("entityType", "")
66
+ if entity_name:
67
+ console.print(f"\n[dim]实体名称: {entity_name} | 类型: {entity_type}[/dim]")
68
+
69
+
70
+ def print_json(data: Any):
71
+ """JSON 格式输出"""
72
+ console.print(json.dumps(data, ensure_ascii=False, indent=2))
73
+
74
+
75
+ def print_csv(data: Any):
76
+ """CSV 格式输出"""
77
+ output = io.StringIO()
78
+ if isinstance(data, list):
79
+ if not data:
80
+ return
81
+ writer = csv.DictWriter(output, fieldnames=data[0].keys())
82
+ writer.writeheader()
83
+ writer.writerows(data)
84
+ elif isinstance(data, dict):
85
+ writer = csv.DictWriter(output, fieldnames=data.keys())
86
+ writer.writeheader()
87
+ writer.writerow(data)
88
+ else:
89
+ output.write(str(data))
90
+ console.print(output.getvalue())
91
+
92
+
93
+ def print_error(error: dict):
94
+ """错误信息输出"""
95
+ code = error.get("code", error.get("error_code", "UNKNOWN"))
96
+ message = error.get("message", error.get("msg", "未知错误"))
97
+ console.print(f"[bold red]错误 {code}:[/bold red] {message}")
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "zerone-cli"
3
- version = "0.1.1"
3
+ version = "0.1.2"
4
4
  description = "Zerone 私募股权数据 CLI 工具"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -42,8 +42,9 @@ requires = ["setuptools>=61.0", "wheel"]
42
42
  build-backend = "setuptools.build_meta"
43
43
 
44
44
  [tool.setuptools.packages.find]
45
- where = [".."]
46
- include = ["cli*"]
45
+ where = ["."]
46
+ include = ["cli", "cli.commands", "cli.utils"]
47
+ namespaces = false
47
48
 
48
49
  # 环境说明:
49
50
  # prod(默认): ZERONE_ENV=prod -> https://ai.zerone.com.cn/mcp
@@ -0,0 +1,110 @@
1
+ Metadata-Version: 2.4
2
+ Name: zerone-cli
3
+ Version: 0.1.2
4
+ Summary: Zerone 私募股权数据 CLI 工具
5
+ Author-email: Zerone <tech@zerone.com.cn>
6
+ License: MIT
7
+ Project-URL: Homepage, https://ai.zerone.com.cn
8
+ Project-URL: Documentation, https://ai.zerone.com.cn
9
+ Keywords: cli,private-equity,finance,mcp,zerone
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Environment :: Console
17
+ Classifier: Intended Audience :: Financial and Insurance Industry
18
+ Classifier: Topic :: Office/Business :: Financial
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: typer>=0.9.0
22
+ Requires-Dist: httpx>=0.24.0
23
+ Requires-Dist: pydantic>=2.0.0
24
+ Requires-Dist: pyyaml>=6.0
25
+ Requires-Dist: rich>=13.0.0
26
+ Requires-Dist: pandas>=2.0.0
27
+
28
+ # Zerone CLI
29
+
30
+ Zerone 私募股权数据命令行工具,通过 API Key 直接查询 Zerone 数据平台。
31
+
32
+ ## 安装
33
+
34
+ ```bash
35
+ pip install zerone-cli
36
+ ```
37
+
38
+ ## 快速开始
39
+
40
+ ### 1. 配置 API Key
41
+
42
+ ```bash
43
+ zerone config set-api-key YOUR_API_KEY
44
+ ```
45
+
46
+ > 如何获取 API Key?请访问 [https://ai.zerone.com.cn](https://ai.zerone.com.cn) 注册账号后申请。
47
+
48
+ ### 2. 查看帮助
49
+
50
+ ```bash
51
+ zerone --help
52
+ ```
53
+
54
+ ### 3. 开始查询
55
+
56
+ ```bash
57
+ # 搜索实体
58
+ zerone entity-search "字节跳动"
59
+
60
+ # 查询实体综合画像
61
+ zerone entity-profile "中国石油"
62
+
63
+ # 查询财务数据列表
64
+ zerone entity-financial-list "中国石油"
65
+
66
+ # 查询管理基金列表
67
+ zerone entity-managed-funds-list "深创投"
68
+
69
+ # 查询退出列表
70
+ zerone entity-exit-list "深创投"
71
+
72
+ # 查询投资列表
73
+ zerone entity-invest-list "深创投"
74
+
75
+ # 查询融资概率预测
76
+ zerone model-financing-probability "字节跳动"
77
+ ```
78
+
79
+ ## 命令列表
80
+
81
+ | 命令 | 说明 |
82
+ |------|------|
83
+ | `zerone config set-api-key` | 设置 API Key |
84
+ | `zerone config set-server-url` | 设置服务器地址(可选) |
85
+ | `zerone config show` | 查看当前配置 |
86
+ | `zerone entity-search` | 实体模糊搜索 |
87
+ | `zerone entity-profile` | 查询实体综合画像 |
88
+ | `zerone entity-financial-list` | 查询实体财务数据列表(分页) |
89
+ | `zerone entity-managed-funds-list` | 查询管理基金列表(分页) |
90
+ | `zerone entity-exit-list` | 查询退出列表(分页) |
91
+ | `zerone entity-invest-list` | 查询投资列表(分页) |
92
+ | `zerone model-financing-probability` | 查询融资概率预测模型 |
93
+
94
+ ## 配置说明
95
+
96
+ 配置文件保存在 `~/.zerone/config.yaml`,支持以下环境变量覆盖:
97
+
98
+ | 环境变量 | 说明 |
99
+ |----------|------|
100
+ | `ZERONE_API_KEY` | API Key |
101
+ | `ZERONE_SERVER_URL` | 服务器地址 |
102
+
103
+ ## 系统要求
104
+
105
+ - Python 3.9+
106
+ - 有效的 Zerone API Key
107
+
108
+ ## 许可证
109
+
110
+ MIT
@@ -0,0 +1,27 @@
1
+ README.md
2
+ pyproject.toml
3
+ cli/__init__.py
4
+ cli/client.py
5
+ cli/config.py
6
+ cli/main.py
7
+ cli/commands/__init__.py
8
+ cli/commands/basic_info.py
9
+ cli/commands/config_cmd.py
10
+ cli/commands/entity_exit_list.py
11
+ cli/commands/entity_financial_list.py
12
+ cli/commands/entity_invest_list.py
13
+ cli/commands/entity_managed_funds_list.py
14
+ cli/commands/entity_profile.py
15
+ cli/commands/entity_search.py
16
+ cli/commands/financing.py
17
+ cli/commands/model_financing_probability.py
18
+ cli/commands/shareholders.py
19
+ cli/utils/__init__.py
20
+ cli/utils/errors.py
21
+ cli/utils/output.py
22
+ zerone_cli.egg-info/PKG-INFO
23
+ zerone_cli.egg-info/SOURCES.txt
24
+ zerone_cli.egg-info/dependency_links.txt
25
+ zerone_cli.egg-info/entry_points.txt
26
+ zerone_cli.egg-info/requires.txt
27
+ zerone_cli.egg-info/top_level.txt
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ zerone = cli.main:app
3
+ zerone-cli = cli.main:app
@@ -0,0 +1,6 @@
1
+ typer>=0.9.0
2
+ httpx>=0.24.0
3
+ pydantic>=2.0.0
4
+ pyyaml>=6.0
5
+ rich>=13.0.0
6
+ pandas>=2.0.0
File without changes
File without changes