component.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. #
  2. # Copyright 2019 The FATE Authors. All Rights Reserved.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. #
  16. import os
  17. import json
  18. from datetime import datetime
  19. import click
  20. from contextlib import closing
  21. from flow_client.flow_cli.utils import cli_args
  22. from flow_client.flow_cli.utils.cli_utils import (prettify, preprocess, download_from_request,
  23. access_server, check_abs_path)
  24. @click.group(short_help="Component Operations")
  25. @click.pass_context
  26. def component(ctx):
  27. """
  28. \b
  29. Provides numbers of component operational commands, including metrics, parameters and etc.
  30. For more details, please check out the help text.
  31. """
  32. pass
  33. @component.command("list", short_help="List Components Command")
  34. @cli_args.JOBID_REQUIRED
  35. @click.pass_context
  36. def list(ctx, **kwargs):
  37. """
  38. \b
  39. - DESCRIPTION:
  40. List components of a specified job.
  41. \b
  42. - USAGE:
  43. flow component list -j $JOB_ID
  44. """
  45. config_data, dsl_data = preprocess(**kwargs)
  46. access_server('post', ctx, 'tracking/component/list', config_data)
  47. @component.command("metrics", short_help="Component Metrics Command")
  48. @cli_args.JOBID_REQUIRED
  49. @cli_args.ROLE_REQUIRED
  50. @cli_args.PARTYID_REQUIRED
  51. @cli_args.COMPONENT_NAME_REQUIRED
  52. @click.pass_context
  53. def metrics(ctx, **kwargs):
  54. """
  55. \b
  56. - DESCRIPTION:
  57. Query the List of Metrics.
  58. \b
  59. - USAGE:
  60. flow component metrics -j $JOB_ID -r host -p 10000 -cpn hetero_feature_binning_0
  61. """
  62. config_data, dsl_data = preprocess(**kwargs)
  63. access_server('post', ctx, 'tracking/component/metrics', config_data)
  64. @component.command("metric-all", short_help="Component Metric All Command")
  65. @cli_args.JOBID_REQUIRED
  66. @cli_args.ROLE_REQUIRED
  67. @cli_args.PARTYID_REQUIRED
  68. @cli_args.COMPONENT_NAME_REQUIRED
  69. @click.pass_context
  70. def metric_all(ctx, **kwargs):
  71. """
  72. \b
  73. - DESCRIPTION:
  74. Query All Metric Data.
  75. \b
  76. - USAGE:
  77. flow component metric-all -j $JOB_ID -r host -p 10000 -cpn hetero_feature_binning_0
  78. """
  79. config_data, dsl_data = preprocess(**kwargs)
  80. access_server('post', ctx, 'tracking/component/metric/all', config_data)
  81. @component.command("metric-delete", short_help="Delete Metric Command")
  82. @click.option('-d', '--date', type=click.STRING,
  83. help="An 8-digit valid date, format like 'YYYYMMDD'")
  84. @cli_args.JOBID
  85. @click.pass_context
  86. def metric_delete(ctx, **kwargs):
  87. """
  88. \b
  89. - DESCRIPTION:
  90. Delete specified metric.
  91. If you input both two optional arguments, the 'date' argument will be detected in priority,
  92. while the job id will be ignored.
  93. \b
  94. - USAGE:
  95. flow component metric-delete -d 20200101
  96. flow component metric-delete -j $JOB_ID
  97. """
  98. config_data, dsl_data = preprocess(**kwargs)
  99. if config_data.get('date'):
  100. config_data['model'] = config_data.pop('date')
  101. access_server('post', ctx, 'tracking/component/metric/delete', config_data)
  102. @component.command("parameters", short_help="Component Parameters Command")
  103. @cli_args.JOBID_REQUIRED
  104. @cli_args.ROLE_REQUIRED
  105. @cli_args.PARTYID_REQUIRED
  106. @cli_args.COMPONENT_NAME_REQUIRED
  107. @click.pass_context
  108. def parameters(ctx, **kwargs):
  109. """
  110. \b
  111. - DESCRIPTION:
  112. Query the parameters of a specified component.
  113. \b
  114. - USAGE:
  115. flow component parameters -j $JOB_ID -r host -p 10000 -cpn hetero_feature_binning_0
  116. """
  117. config_data, dsl_data = preprocess(**kwargs)
  118. access_server('post', ctx, 'tracking/component/parameters', config_data)
  119. @component.command("output-data", short_help="Component Output Data Command")
  120. @cli_args.JOBID_REQUIRED
  121. @cli_args.ROLE_REQUIRED
  122. @cli_args.PARTYID_REQUIRED
  123. @cli_args.COMPONENT_NAME_REQUIRED
  124. @cli_args.OUTPUT_PATH_REQUIRED
  125. @click.option('-l', '--limit', type=click.INT, default=-1,
  126. help='limit count, defaults is -1 (download all output data)')
  127. @click.pass_context
  128. def output_data(ctx, **kwargs):
  129. """
  130. \b
  131. - DESCRIPTION:
  132. Download the Output Data of A Specified Component.
  133. \b
  134. - USAGE:
  135. flow component output-data -j $JOB_ID -r host -p 10000 -cpn hetero_feature_binning_0 --output-path ./examples/
  136. """
  137. config_data, dsl_data = preprocess(**kwargs)
  138. tar_file_name = 'job_{}_{}_{}_{}_output_data.tar.gz'.format(config_data['job_id'],
  139. config_data['component_name'],
  140. config_data['role'],
  141. config_data['party_id'])
  142. extract_dir = os.path.join(config_data['output_path'], tar_file_name.replace('.tar.gz', ''))
  143. with closing(access_server('get', ctx, 'tracking/component/output/data/download',
  144. config_data, False, stream=True)) as response:
  145. if response.status_code == 200:
  146. try:
  147. download_from_request(http_response=response, tar_file_name=tar_file_name, extract_dir=extract_dir)
  148. res = {
  149. 'retcode': 0,
  150. 'directory': os.path.abspath(extract_dir),
  151. 'retmsg': 'Download successfully, please check {} directory'.format(
  152. os.path.abspath(extract_dir))}
  153. except BaseException:
  154. res = {'retcode': 100,
  155. 'retmsg': 'Download failed, please check if the parameters are correct.'}
  156. else:
  157. try:
  158. res = response.json()
  159. except Exception:
  160. res = {'retcode': 100,
  161. 'retmsg': 'Download failed, for more details please check logs/fate_flow/fate_flow_stat.log.'}
  162. prettify(res)
  163. @component.command("output-model", short_help="Component Output Model Command")
  164. @cli_args.JOBID_REQUIRED
  165. @cli_args.ROLE_REQUIRED
  166. @cli_args.PARTYID_REQUIRED
  167. @cli_args.COMPONENT_NAME_REQUIRED
  168. @click.pass_context
  169. def output_model(ctx, **kwargs):
  170. """
  171. \b
  172. - DESCRIPTION:
  173. Query the Model of A Speicied Component.
  174. \b
  175. - USAGE:
  176. flow component output-model -j $JOB_ID -r host -p 10000 -cpn hetero_feature_binning_0
  177. """
  178. config_data, dsl_data = preprocess(**kwargs)
  179. access_server('post', ctx, 'tracking/component/output/model', config_data)
  180. @component.command("output-data-table", short_help="Component Output Data Table Command")
  181. @cli_args.JOBID_REQUIRED
  182. @cli_args.ROLE_REQUIRED
  183. @cli_args.PARTYID_REQUIRED
  184. @cli_args.COMPONENT_NAME_REQUIRED
  185. @click.pass_context
  186. def output_data_table(ctx, **kwargs):
  187. """
  188. \b
  189. - DESCRIPTION:
  190. View Table Name and Namespace.
  191. \b
  192. - USAGE:
  193. flow component output-data-table -j $JOB_ID -r host -p 10000 -cpn hetero_feature_binning_0
  194. """
  195. config_data, dsl_data = preprocess(**kwargs)
  196. access_server('post', ctx, 'tracking/component/output/data/table', config_data)
  197. @component.command("get-summary", short_help="Download Component Summary Command")
  198. @cli_args.JOBID_REQUIRED
  199. @cli_args.ROLE_REQUIRED
  200. @cli_args.PARTYID_REQUIRED
  201. @cli_args.COMPONENT_NAME_REQUIRED
  202. @cli_args.OUTPUT_PATH
  203. @click.pass_context
  204. def get_summary(ctx, **kwargs):
  205. """
  206. \b
  207. - DESCRIPTION:
  208. Download summary of a specified component and save it as a json file.
  209. \b
  210. - USAGE:
  211. flow component get-summary -j $JOB_ID -r host -p 10000 -cpn hetero_feature_binning_0
  212. flow component get-summary -j $JOB_ID -r host -p 10000 -cpn hetero_feature_binning_0 -o ./examples/
  213. """
  214. config_data, dsl_data = preprocess(**kwargs)
  215. if config_data.get("output_path"):
  216. if not os.path.isdir(config_data.get("output_path")):
  217. res = {
  218. "retcode": 100,
  219. "retmsg": "Please input a valid directory path."
  220. }
  221. else:
  222. config_data["filename"] = "summary_{}_{}.json".format(config_data['component_name'],
  223. datetime.now().strftime('%Y%m%d%H%M%S'))
  224. config_data["output_path"] = os.path.join(check_abs_path(
  225. config_data["output_path"]), config_data["filename"])
  226. with closing(access_server("post", ctx, "tracking/component/summary/download",
  227. config_data, False, stream=True)) as response:
  228. if response.status_code == 200:
  229. with open(config_data["output_path"], "wb") as fout:
  230. for chunk in response.iter_content(1024):
  231. if chunk:
  232. fout.write(chunk)
  233. res = {
  234. "retcode": 0,
  235. "retmsg": "The summary of component <{}> has been stored successfully. "
  236. "File path is: {}.".format(config_data["component_name"],
  237. config_data["output_path"])
  238. }
  239. else:
  240. try:
  241. res = response.json()
  242. except Exception:
  243. res = {"retcode": 100,
  244. "retmsg": "Download component summary failed, "
  245. "for more details, please check logs/fate_flow/fate_flow_stat.log."}
  246. prettify(res)
  247. else:
  248. access_server("post", ctx, "tracking/component/summary/download", config_data)
  249. @component.command('hetero-model-merge', short_help='Merge Hetero Model Command')
  250. @cli_args.MODEL_ID_REQUIRED
  251. @cli_args.MODEL_VERSION_REQUIRED
  252. @cli_args.GUEST_PARTYID_REQUIRED
  253. @cli_args.HOST_PARTYIDS_REQUIRED
  254. @cli_args.COMPONENT_NAME_REQUIRED
  255. @click.option('--model-type', type=click.STRING, required=True)
  256. @click.option('--output-format', type=click.STRING, required=True)
  257. @click.option('--target-name', type=click.STRING)
  258. @click.option('--host-rename/--no-host-rename', is_flag=True, default=None)
  259. @click.option('--include-guest-coef/--no-include-guest-coef', is_flag=True, default=None)
  260. @cli_args.OUTPUT_PATH_REQUIRED
  261. @click.pass_context
  262. def hetero_model_merge(ctx, **kwargs):
  263. """
  264. \b
  265. - DESCRIPTION:
  266. Merge a hetero model.
  267. \b
  268. - USAGE:
  269. flow component hetero-model-merge --model-id guest-9999#host-9998#model --model-version 202208241838502253290 --guest-party-id 9999 --host-party-ids 9998,9997 --component-name hetero_secure_boost_0 --model-type secureboost --output-format pmml --target-name y --no-host-rename --no-include-guest-coef --output-path model.xml
  270. """
  271. config_data, dsl_data = preprocess(**kwargs)
  272. config_data['host_party_ids'] = config_data['host_party_ids'].split(',')
  273. response = access_server('post', ctx, 'component/hetero/merge', config_data, False)
  274. if not response.json().get('data'):
  275. prettify(response)
  276. return
  277. with open(config_data['output_path'], 'w', encoding='utf-8') as f:
  278. f.write(response.json()['data'])
  279. @component.command('woe-array-extract', short_help='Extract WOE Array Command')
  280. @cli_args.MODEL_ID_REQUIRED
  281. @cli_args.MODEL_VERSION_REQUIRED
  282. @cli_args.ROLE_REQUIRED
  283. @cli_args.PARTYID_REQUIRED
  284. @cli_args.COMPONENT_NAME_REQUIRED
  285. @cli_args.OUTPUT_PATH_REQUIRED
  286. @click.pass_context
  287. def woe_array_extract(ctx, **kwargs):
  288. """
  289. \b
  290. - DESCRIPTION:
  291. Extract WOE array from a guest model.
  292. \b
  293. - USAGE:
  294. flow component woe-array-extract --model-id guest-9999#host-10000#model --model-version 202211142055541649630 --role guest --party-id 9999 --component-name hetero_feature_binning_0 --output-path woe_array.json
  295. """
  296. config_data, dsl_data = preprocess(**kwargs)
  297. response = access_server('post', ctx, 'component/woe_array/extract', config_data, False)
  298. if not response.json().get('data'):
  299. prettify(response)
  300. return
  301. with open(config_data['output_path'], 'w', encoding='utf-8') as f:
  302. json.dump(response.json()['data'], f)
  303. @component.command('woe-array-merge', short_help='Merge WOE Array Command')
  304. @cli_args.MODEL_ID_REQUIRED
  305. @cli_args.MODEL_VERSION_REQUIRED
  306. @cli_args.ROLE_REQUIRED
  307. @cli_args.PARTYID_REQUIRED
  308. @cli_args.COMPONENT_NAME_REQUIRED
  309. @cli_args.INPUT_PATH_REQUIRED
  310. @click.pass_context
  311. def woe_array_merge(ctx, **kwargs):
  312. """
  313. \b
  314. - DESCRIPTION:
  315. Merge WOE array into a host model.
  316. \b
  317. - USAGE:
  318. flow component woe-array-merge --model-id guest-9999#host-10000#model --model-version 202211142055541649630 --role host --party-id 10000 --component-name hetero_feature_binning_0 --input-path woe_array.json
  319. """
  320. config_data, dsl_data = preprocess(**kwargs)
  321. with open(config_data.pop('input_path'), 'r', encoding='utf-8') as f:
  322. config_data['woe_array'] = json.load(f)
  323. access_server('post', ctx, 'component/woe_array/merge', config_data)