{"repo": "baidubce/bce-qianfan-sdk", "files": {"dotenv_config_sample.env": {"6cacf6002140a3249c1c8d557def462c29c129c5": {"t": 1785674664.7353575, "n": 2094, "h": "584ffb6462ad3ea1", "c": "## 千帆 SDK 配置文件样例\n## 文件中环境变量均为默认值,去掉注释以更改对应值\n## **已设置的环境变量优先级会高于该配置文件**\n\n## SDK 默认会读取当前目录下 `.env` 文件,注意更改文件名\n## 或者可以通过该变量指定配置文件的路径\n## 但由于读取该文件前需先通过该变量获取配置文件路径,所以此处设置无效\n## 请通过设置环境变量的方式设置该值\n# QIANFAN_DOT_ENV_CONFIG_FILE=\".env\"\n\n# 鉴权相关\n## AK 与 SK 分别对应于千帆平台上 **应用** 的 API Key 与 Secret Key\n## 主要用于模型相关 API 鉴权\n## 获取位置:https://console.bce.baidu.com/qianfan/ais/console/applicationConsole/application\n# QIANFAN_AK=\"\"\n# QIANFAN_SK=\"\"\n\n## Access Token 是通过 AK 与 SK 获取的具有时效性的鉴权凭证\n## 提供 Access Token 时 SDK 将会直接使用该 token,不会自动刷新\n## 不推荐设置该值,请仅在无法获取 AK 与 SK 的场景下使用\n## 推荐使用上述提供 AK 与 SK 的方式,SDK会自动进行 Access Token 的维护\n# QIANFAN_ACCESS_TOKEN=\"\"\n\n## Access Key 与 Secret Key 对应于 [百度智能云控制台-安全认证] \n## 中的 Access Key 与 Secret Key\n## 获取位置:https://console.bce.baidu.com/iam/#/iam/accesslist\n## 主要用于非模型相关的、管控类的 API 鉴权\n## 注意与 AK 与 SK 的使用范围进行区分,详细参见文档\n# QIANFAN_ACCESS_KEY=\"\"\n# QIANFAN_SECRET_KEY=\"\"\n\n## 通过 Access Key 与 Secret Key 进行鉴权需要对请求进行签名\n## 签名具有时效性,可通过该变量控制签名过期时长(秒)\n# QIANFAN_IAM_SIGN_EXPIRATION_SEC=300\n\n## SDk 会在 Access Token 过期时自动刷新,为避免多线程同时刷新\n## 从而导致重复刷新多次,可通过该变量控制刷新的最小间隔(秒)\n# QIANFAN_ACCESS_TOKEN_REFRESH_MIN_INTERVAL=3600\n\n# 连接相关\n## 设置 SDK 通过 AK 与 SK 获取 Access Token 的超时时间(秒)\n# QIANFAN_AUTH_TIMEOUT=5\n\n# 流控相关\n## 为避免一次性发送多个请求导致 API 返回错误,SDK 可以控制发送频率\n## 可以通过该变量控制每秒发送请求的数量,0 表示不限制\n# QIANFAN_QPS_LIMIT=0\n\n# 重试(模型推理相关操作)\n## 重试次数\n# QIANFAN_LLM_API_RETRY_COUNT=3\n## 超时时间(秒)\n# QIANFAN_LLM_API_RETRY_TIMEOUT=300\n## 退避因子\n# QIANFAN_LLM_API_RETRY_BACKOFF_FACTOR=0\n\n# 重试(管控类相关操作)\n## 重试次数\n# QIANFAN_CONSOLE_API_RETRY_COUNT=1\n## 超时时间(秒)\n# QIANFAN_CONSOLE_API_RETRY_TIMEOUT=60\n## 退避因子\n# QIANFAN_CONSOLE_API_RETRY_BACKOFF_FACTOR=0\n\n# cookbook test 相关\n## 测试cookbook时需要使用该变量传入参数列表\n# KEYWORDS_DICT={\"your_bes_url\":\"BES_URL\",\"your_pinecone_ak\":\"PINE_AK\",\"your_wandb_ak\":\"WANDB_AK\",\"your_wandb_sk\":\"WANDB_SK\",\"your_app_id\": 123456,\"your_bucket_name\":\"BOSNAME\"}\n\n\n## !!!以下配置一般无需更改,修改前请确认理解字段含义 !!!\n\n# URL 相关\n## 千帆模型相关 API 域名\n# QIANFAN_BASE_URL=\"https://aip.baidubce.com\"\n\n## 千帆管控类 API 域名\n# QIANFAN_CONSOLE_API_BASE_URL=\"https://qianfan.baidubce.com\"\n\n## 千帆Cache目录\n# QIANFAN_CACHE_DIR=\"custom_cache_dir\"\n\n## 关闭鉴权\n# QIANFAN_NO_AUTH=True"}}, "python/qianfan/tests/prompt_resource_test.py": {"6cacf6002140a3249c1c8d557def462c29c129c5": {"t": 1785674671.7361536, "n": 8600, "h": "33c6555c1f902af0", "c": "# Copyright (c) 2023 Baidu, Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"\n Unit test for Prompt\n\"\"\"\n\nfrom qianfan.consts import PromptFrameworkType, PromptSceneType, PromptType\nfrom qianfan.resources import Prompt\n\n\ndef test_create_prompt():\n \"\"\"\n Test create prompt\n \"\"\"\n resp = Prompt.create(name=\"test name 1\", template=\"test {var1} prompt {var2}\")\n assert resp[\"_request\"] == {\n \"templateName\": \"test name 1\",\n \"templateContent\": \"test {var1} prompt {var2}\",\n \"templateVariables\": \"var1,var2\",\n \"variableIdentifier\": \"{}\",\n \"sceneType\": 1,\n \"frameworkType\": 0,\n }\n result = resp[\"result\"]\n assert \"templateId\" in result\n\n resp = Prompt.create(name=\"test name 2\", template=\"empty prompt\")\n assert resp[\"_request\"] == {\n \"templateName\": \"test name 2\",\n \"templateContent\": \"empty prompt\",\n \"templateVariables\": \"\",\n \"variableIdentifier\": \"{}\",\n \"sceneType\": 1,\n \"frameworkType\": 0,\n }\n\n resp = Prompt.create(\n name=\"test name 3\",\n template=\"{{x1}}other{{x2}}identifier{{x3}}\",\n identifier=\"{{}}\",\n )\n assert resp[\"_request\"] == {\n \"templateName\": \"test name 3\",\n \"templateContent\": \"{{x1}}other{{x2}}identifier{{x3}}\",\n \"templateVariables\": \"x1,x2,x3\",\n \"variableIdentifier\": \"{{}}\",\n \"sceneType\": 1,\n \"frameworkType\": 0,\n }\n\n resp = Prompt.create(\n name=\"test name 4\",\n template=\"{{x1}}custom{{x2}}identifier{{x3}}\",\n identifier=\"{{}}\",\n variables=[\"x1\", \"x3\"],\n )\n assert resp[\"_request\"] == {\n \"templateName\": \"test name 4\",\n \"templateContent\": \"{{x1}}custom{{x2}}identifier{{x3}}\",\n \"templateVariables\": \"x1,x3\",\n \"variableIdentifier\": \"{{}}\",\n \"sceneType\": 1,\n \"frameworkType\": 0,\n }\n\n resp = Prompt.create(\n name=\"test name 5\",\n template=\"[[x1]]text2[[x2]]image[[x3]]{{r}}{6}\",\n identifier=\"[[]]\",\n scene=PromptSceneType.Text2Image,\n label_ids=[1, 2],\n framework=PromptFrameworkType.Fewshot,\n negative_template=\"[[x1]]negative[[x4]]((r))\",\n )\n assert resp[\"_request\"] == {\n \"templateName\": \"test name 5\",\n \"templateContent\": \"[[x1]]text2[[x2]]image[[x3]]{{r}}{6}\",\n \"templateVariables\": \"x1,x2,x3\",\n \"variableIdentifier\": \"[[]]\",\n \"labelIds\": [1, 2],\n \"sceneType\": 2,\n \"frameworkType\": 3,\n \"negativeTemplateContent\": \"[[x1]]negative[[x4]]((r))\",\n \"negativeTemplateVariables\": \"x1,x4\",\n }\n\n resp = Prompt.create(\n name=\"test name 6\",\n template=\"[[x1]]text2[[x2]]image[[x3]]{{r}}{6}\",\n identifier=\"[[]]\",\n scene=PromptSceneType.Text2Image,\n label_ids=[1, 2],\n framework=PromptFrameworkType.Fewshot,\n negative_template=\"[[x1]]custom[[x4]]negative((r))\",\n negative_variables=[\"x1\"],\n )\n assert resp[\"_request\"] == {\n \"templateName\": \"test name 6\",\n \"templateContent\": \"[[x1]]text2[[x2]]image[[x3]]{{r}}{6}\",\n \"templateVariables\": \"x1,x2,x3\",\n \"variableIdentifier\": \"[[]]\",\n \"labelIds\": [1, 2],\n \"sceneType\": 2,\n \"frameworkType\": 3,\n \"negativeTemplateContent\": \"[[x1]]custom[[x4]]negative((r))\",\n \"negativeTemplateVariables\": \"x1\",\n }\n\n\ndef test_render_prompt():\n \"\"\"\n Test render prompt\n \"\"\"\n resp = Prompt.info(id=11, var1=\"v1\", var2=\"v2\")\n assert resp[\"_request\"] == {\"id\": \"11\", \"var1\": \"v1\", \"var2\": \"v2\"}\n assert \"templateId\" in resp[\"result\"]\n assert \"content\" in resp[\"result\"]\n\n\ndef test_update_prompt():\n \"\"\"\n Test update prompt\n \"\"\"\n resp = Prompt.update(id=1, name=\"test name\")\n assert resp[\"_request\"] == {\n \"templateId\": 1,\n \"templateName\": \"test name\",\n }\n result = resp[\"result\"]\n assert \"templateId\" in result\n\n resp = Prompt.update(\n id=2,\n name=\"test name\",\n label_ids=[1, 2],\n template=\"template{x1}\",\n identifier=\"(())\",\n negative_template=\"negative\",\n )\n assert resp[\"_request\"] == {\n \"templateId\": 2,\n \"templateName\": \"test name\",\n \"labelIds\": [1, 2],\n \"templateContent\": \"template{x1}\",\n \"variableIdentifier\": \"(())\",\n \"negativeTemplateContent\": \"negative\",\n }\n result = resp[\"result\"]\n assert \"templateId\" in result\n\n\ndef test_delete_prompt():\n \"\"\"\n Test delete prompt\n \"\"\"\n resp = Prompt.delete(id=122)\n assert resp[\"_request\"] == {\n \"templateId\": 122,\n }\n result = resp[\"result\"]\n assert result is True\n\n\ndef test_list_prompts():\n \"\"\"\n Test list prompts\n \"\"\"\n resp = Prompt.list()\n assert resp[\"_request\"] == {\"labelIds\": [], \"offset\": 0, \"pageSize\": 10}\n assert \"items\" in resp[\"result\"]\n\n resp = Prompt.list(\n offset=10,\n page_size=20,\n name=\"test name\",\n label_ids=[1, 2],\n type=PromptType.Preset,\n )\n assert resp[\"_request\"] == {\n \"offset\": 10,\n \"pageSize\": 20,\n \"name\": \"test name\",\n \"labelIds\": [1, 2],\n \"type\": 1,\n }\n\n\ndef test_list_prompt_labels():\n \"\"\"\n Test list prompt labels\n \"\"\"\n resp = Prompt.list_labels()\n assert resp[\"_request\"] == {\"offset\": 0, \"pageSize\": 10}\n assert \"items\" in resp[\"result\"]\n\n resp = Prompt.list_labels(offset=10, page_size=20)\n assert resp[\"_request\"] == {\n \"offset\": 10,\n \"pageSize\": 20,\n }\n\n\ndef test_create_prompt_optimize_task():\n \"\"\"\n Test create prompt optimize task\n \"\"\"\n operations = [\n {\"opType\": 1, \"payload\": 1},\n {\"opType\": 2, \"payload\": 1},\n {\"opType\": 3, \"payload\": 1},\n {\"opType\": 4, \"payload\": 0},\n ]\n resp = Prompt.create_optimiztion_task(\"prompt\", operations=operations)\n assert \"id\" in resp[\"result\"]\n request = resp[\"_request\"]\n assert request[\"content\"] == \"prompt\"\n assert request[\"operations\"] == operations\n\n resp = Prompt.create_optimiztion_task(\n \"prompt2\", operations=operations, app_id=555, service_name=\"service_name\"\n )\n assert \"id\" in resp[\"result\"]\n request = resp[\"_request\"]\n assert request[\"content\"] == \"prompt2\"\n assert request[\"operations\"] == operations\n assert request[\"appID\"] == 555\n assert request[\"serviceName\"] == \"service_name\"\n\n\ndef test_get_prompt_optimize_task():\n \"\"\"\n Test create prompt optimize task\n \"\"\"\n\n resp = Prompt.get_optimization_task(\"task-51801xxxx6656\")\n assert \"id\" in resp[\"result\"]\n assert resp[\"result\"][\"content\"] == \"原始prompt\"\n assert resp[\"result\"][\"optimizeContent\"] == \"optimized prompt\"\n\n request = resp[\"_request\"]\n assert request[\"id\"] == \"task-51801xxxx6656\"\n\n\ndef test_evaluate_score():\n \"\"\"\n Test evaluate score\n \"\"\"\n resp = Prompt.evaluation_score(\n 1,\n [\n {\n \"scene\": \"scene1\",\n \"response_list\": [\"output11\", \"output12\", \"output13\"],\n },\n {\n \"scene\": \"scene2\",\n \"response_list\": [\"output21\", \"output22\", \"output23\"],\n },\n ],\n )\n\n scores = resp[\"result\"][\"scores\"]\n assert len(scores) == 2\n for score in scores:\n assert len(score) == 3\n\n\ndef test_evaluate_summary():\n \"\"\"\n Test evaluate score\n \"\"\"\n data = [\n {\n \"prompt\": \"请帮我计算一下{formula}等于多少?只返回计算结果\",\n \"scene\": [\n {\n \"variables\": {\"formula\": \"45+43\"},\n \"expected_target\": \"88\",\n \"response\": \"计算结果为: 45+43=88\",\n \"new_prompt\": \"请帮我计算一下45+43等于多少?只返回计算结果\",\n }\n ],\n \"response_list\": [\"response1\", \"response2\"],\n }\n ]\n resp = Prompt.evaluation_summary(data + data + data)\n\n response = resp[\"result\"][\"responses\"]\n assert len(response) == 3\n\n request = resp[\"_request\"]\n assert request[\"data\"][0] == data[0]\n assert len(request[\"data\"]) == 3\n"}}, "python/qianfan/trainer/actions.py": {"6cacf6002140a3249c1c8d557def462c29c129c5": {"t": 1785846923.6836824, "n": 53183, "h": "0168ddeb3105cad8", "c": "# Copyright (c) 2023 Baidu, Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport copy\nimport time\nfrom typing import Any, Dict, List, Optional, Union, cast\n\nfrom qianfan import resources as api\nfrom qianfan.config import get_config\nfrom qianfan.dataset import BosDataSource, Dataset, QianfanDataSource\nfrom qianfan.dataset.data_source import DataSource\nfrom qianfan.errors import InternalError, InvalidArgumentError\nfrom qianfan.evaluation import EvaluationManager\nfrom qianfan.evaluation.evaluator import Evaluator, LocalEvaluator, QianfanEvaluator\nfrom qianfan.model import Model, Service\nfrom qianfan.model.configs import DeployConfig\nfrom qianfan.resources.console import consts as console_consts\nfrom qianfan.trainer.base import (\n ActionState,\n BaseAction,\n with_event,\n)\nfrom qianfan.trainer.configs import (\n CorpusConfig,\n CorpusConfigItem,\n DatasetConfig,\n PeftType,\n TrainConfig,\n TrainLimit,\n get_default_train_config,\n get_model_info,\n)\nfrom qianfan.trainer.consts import ServiceStatus, TrainStatus\nfrom qianfan.utils import (\n bos_uploader,\n log_debug,\n log_error,\n log_info,\n log_warn,\n utils,\n)\nfrom qianfan.utils.bos_uploader import is_valid_bos_path, parse_bos_path\nfrom qianfan.utils.utils import first_lower_case, snake_to_camel\n\n\nclass LoadDataSetAction(BaseAction[Dict[str, Any], Dict[str, Any]]):\n \"\"\"LoadDataSetAction\n Action for dataset's loading, invokes the dataset's save method\n to guarantee the dataset is loaded in Qianfan platform.\n Sample:\n ```\n load_action = LoadDataSetAction(dataset=Dataset(id=1))\n load_action.exec()\n ```\n\n input:\n none\n output:\n ```\n {\n \"datasets\": {\n \"sourceType\": (\n 2\n ),\n \"versions\": [\n {\n \"versionBosUri\": \"bos:/bbb/\"\n }\n ],\n }\n }\n ```\n \"\"\"\n\n datasets: List[Union[DataSource, Dict]] = []\n sampling_rates: List[float] = []\n result: Optional[Dict[str, Any]] = None\n eval_split_ratio: Optional[float] = None\n corpus_config: Optional[CorpusConfig] = None\n source_type: Optional[console_consts.TrainDatasetSourceType] = None\n\n def __init__(\n self,\n dataset: Union[DatasetConfig, Dataset, str, List[str]],\n dataset_template: Optional[console_consts.DataTemplateType] = None,\n corpus_config: Optional[CorpusConfig] = None,\n **kwargs: Any,\n ) -> None:\n super().__init__(**kwargs)\n self.eval_split_ratio = kwargs.get(\"eval_split_ratio\", 20)\n\n global_sampling_rate = kwargs.get(\"sampling_rate\")\n if kwargs.get(\"corpus_type\"):\n self.corpus_config = CorpusConfig()\n self.corpus_config.corpus_configs.append(CorpusConfigItem(**kwargs))\n if isinstance(dataset, str):\n dataset = [dataset]\n\n if isinstance(dataset, DatasetConfig):\n global_sampling_rate = global_sampling_rate or dataset.sampling_rate\n if isinstance(dataset.datasets[0], Dataset):\n self.datasets = [ds.inner_data_source_cache for ds in dataset.datasets]\n elif isinstance(dataset.datasets[0], DataSource):\n self.datasets = dataset.datasets\n elif isinstance(dataset.datasets[0], dict):\n self.datasets = dataset.datasets\n if dataset.sampling_rates:\n self.sampling_rates = dataset.sampling_rates\n if self.corpus_config is None:\n self.corpus_config = CorpusConfig()\n if dataset.corpus_type:\n self.corpus_config.corpus_configs.append(\n CorpusConfigItem( # type:ignore\n corpus_proportion=dataset.corpus_proportion,\n corpus_type=dataset.corpus_type,\n corpus_labels=dataset.corpus_labels,\n )\n )\n if dataset.eval_split_ratio is not None:\n self.eval_split_ratio = dataset.eval_split_ratio\n\n if dataset.sampling_rates is None and global_sampling_rate:\n self.sampling_rates = [\n global_sampling_rate for i in range(len(self.datasets))\n ]\n if self.sampling_rates and len(self.datasets) != len(self.sampling_rates):\n raise ValueError(\"sampling_rates not with the same counts to datasets\")\n if dataset.source_type:\n self.source_type = console_consts.TrainDatasetSourceType(\n dataset.source_type\n )\n elif isinstance(dataset, list):\n if len(dataset) > 0:\n if isinstance(dataset[0], str):\n for ds_str in dataset:\n if is_valid_bos_path(ds_str):\n bos_ds_src = LoadDataSetAction.create_bos_ds_src(ds_str)\n self.datasets.append(bos_ds_src)\n elif ds_str.startswith(\"ds-\"):\n self.datasets.append(\n QianfanDataSource.get_existed_dataset(ds_str)\n )\n else:\n raise InvalidArgumentError(f\"invalid dataset_str: {ds_str}\")\n elif isinstance(dataset[0], Dataset):\n self.datasets = dataset\n elif isinstance(dataset.inner_data_source_cache, QianfanDataSource):\n qf_data_src = cast(QianfanDataSource, dataset.inner_data_source_cache)\n if (\n dataset_template is not None\n and qf_data_src.template_type != dataset_template\n ):\n raise InvalidArgumentError(\n f\"dataset must be `{dataset_template}` template.\"\n )\n self.datasets = [dataset.inner_data_source_cache]\n elif isinstance(dataset.inner_data_source_cache, BosDataSource):\n self.datasets = [dataset.inner_data_source_cache]\n else:\n raise InvalidArgumentError(\n \"dataset must be either implemented with QianfanDataSource or\"\n \" BosDataSource or a bos path\"\n )\n if global_sampling_rate and self.sampling_rates is None:\n self.sampling_rates = [\n global_sampling_rate for i in range(len(self.datasets))\n ]\n if corpus_config is not None:\n self.corpus_config = corpus_config\n\n @with_event\n def exec(self, input: Dict[str, Any] = {}, **kwargs: Dict) -> Dict[str, Any]:\n resp = self._exec(input, **kwargs)\n if resp.get(\"datasets\") is None:\n return resp\n if self.eval_split_ratio is not None:\n resp[\"datasets\"][\"splitRatio\"] = self.eval_split_ratio\n if self.corpus_config and len(self.corpus_config.corpus_configs) > 0:\n resp[\"corpus_config\"] = self.corpus_config.dict(\n by_alias=True, exclude_none=True\n )\n if self.sampling_rates:\n for i, d in enumerate(resp[\"datasets\"][\"versions\"]):\n d[\"samplingRate\"] = self.sampling_rates[i]\n return resp\n\n def _exec(self, input: Dict[str, Any] = {}, **kwargs: Dict) -> Dict[str, Any]:\n \"\"\"\n Load dataset implementation, may called by exec and resume.\n \"\"\"\n result = self.get_action_result(**kwargs)\n if len(result[\"datasets\"][\"versions\"]) == 0:\n raise InvalidArgumentError(\n \"dataset must be set or input dataset is invalid\"\n )\n self.result = result\n return result\n\n def get_action_result(self, **kwargs: Any) -> Dict[str, Any]:\n result: Dict[str, Any] = {}\n versions: List[Dict[str, Any]] = []\n for i, dataset in enumerate(self.datasets):\n if isinstance(dataset, Dict):\n version = dataset\n elif isinstance(dataset, DataSource):\n sub_res = self.get_dataset_result(dataset, **kwargs)\n if sub_res is None:\n log_warn(f\"invalid dataset {dataset}\")\n continue\n if result.get(\"sourceType\") and sub_res.get(\"sourceType\") != result.get(\n \"sourceType\"\n ):\n log_warn(\n \"[load_dataset_action] dataset sourceType conflict, should all\"\n f\" be with one source type{sub_res}\"\n )\n else:\n self.source_type = sub_res.get(\"sourceType\")\n version = sub_res.get(\"version\", {})\n if self.sampling_rates:\n version[\"samplingRate\"] = self.sampling_rates[i]\n if isinstance(version, dict):\n versions.append(version)\n\n result[\"versions\"] = versions\n if self.source_type:\n result[\"sourceType\"] = self.source_type.value\n else:\n log_error(\n \"[load_dataset_action] dataset dict must be set with\"\n \" DatasetConfig.source_type\"\n )\n raise InvalidArgumentError(\"dataset dict must be set with source_type\")\n return {\"datasets\": result}\n\n def get_dataset_result(\n self,\n data_src: DataSource,\n **kwargs: Any,\n ) -> Optional[Dict[str, Any]]:\n from qianfan.dataset.data_source import BosDataSource, QianfanDataSource\n\n if isinstance(data_src, QianfanDataSource):\n log_debug(\"[load_dataset_action] prepare train-set\")\n qf_data_src = cast(QianfanDataSource, data_src)\n is_released = qf_data_src.release_dataset(**kwargs)\n if not is_released:\n log_error(\"[load_dataset_action] dataset not released\")\n raise InvalidArgumentError(\"dataset must be released\")\n log_debug(\"[load_dataset_action] dataset loaded successfully\")\n return {\n \"sourceType\": console_consts.TrainDatasetSourceType.Platform,\n \"version\": {\n \"versionId\": qf_data_src.id,\n },\n }\n elif isinstance(data_src, BosDataSource):\n log_debug(\"[load_dataset_action] prepare train-set in BOS\")\n bos_data_src = cast(BosDataSource, data_src)\n return {\n \"sourceType\": console_consts.TrainDatasetSourceType.PrivateBos,\n \"version\": {\n \"versionBosUri\": bos_uploader.generate_bos_file_path(\n bos_data_src.bucket, bos_data_src.bos_file_path\n )\n },\n }\n else:\n return None\n\n @staticmethod\n def create_bos_ds_src(bos_uri: str) -> BosDataSource:\n bucket, bos_path = parse_bos_path(bos_uri)\n return BosDataSource(\n region=get_config().BOS_HOST_REGION,\n bucket=bucket,\n bos_file_path=bos_path,\n )\n\n @staticmethod\n def get_data_src_from_action_result(\n dataset_result: Dict[str, Any]\n ) -> List[DataSource]:\n res = []\n dataset_src_type = dataset_result.get(\"sourceType\")\n for ds_dict in dataset_result.get(\"versions\", []):\n if dataset_src_type == console_consts.TrainDatasetSourceType.Platform.value:\n ds = Dataset.load(qianfan_dataset_id=ds_dict.get(\"versionId\"))\n if ds.inner_data_source_cache:\n res.append(\n ds.inner_data_source_cache,\n )\n elif (\n dataset_src_type\n == console_consts.TrainDatasetSourceType.PrivateBos.value\n ):\n bos_ds_src = LoadDataSetAction.create_bos_ds_src(\n ds_dict.get(\"versionBosUri\")\n )\n res.append(bos_ds_src)\n elif (\n dataset_src_type\n == console_consts.TrainDatasetSourceType.PrivateAfs.value\n ):\n continue\n else:\n log_warn(\"[load_dataset_action] invalid dataset source: {ds_dict}\")\n return res\n\n @with_event\n def resume(self, **kwargs: Dict) -> Dict[str, Any]:\n \"\"\"\n resume method for load dataset action.\n\n Returns:\n Dict[str, Any]: datasets meta_info including\n dataset_id and dataset_type.\n \"\"\"\n log_debug(\"[load_dataset_action] dataset loading resumed\")\n return self._exec(**kwargs)\n\n def persist(self) -> bytes:\n return self.serialize_helper.serialize(self._action_dict())\n\n def _action_dict(self) -> Dict[str, Any]:\n meta = {\n \"id\": self.id,\n \"type\": LoadDataSetAction.__name__,\n \"datasets\": self.get_action_result().get(\"datasets\"),\n \"output\": self.result,\n \"eval_split_ratio\": self.eval_split_ratio,\n }\n if self.corpus_config:\n meta[\"corpus_config\"] = self.corpus_config.dict(\n by_alias=True, exclude_none=True\n )\n return meta\n\n @classmethod\n def _load_from_dict(cls, meta: Dict[str, Any]) -> \"LoadDataSetAction\":\n init_params: Dict[str, Any] = {}\n if meta.get(\"datasets\") or meta.get(\"output\"):\n ds_dicts = meta.get(\"datasets\")\n if ds_dicts is None:\n ds_output = meta.get(\"output\")\n assert isinstance(ds_output, dict)\n ds_dicts = ds_output.get(\"datasets\")\n assert isinstance(ds_dicts, dict)\n datasets = LoadDataSetAction.get_data_src_from_action_result(ds_dicts)\n corpus_config_meta = meta.get(\"corpus_config\")\n init_params[\"dataset\"] = DatasetConfig(datasets=datasets)\n if corpus_config_meta:\n init_params[\"corpus_config\"] = CorpusConfig.parse_obj(\n corpus_config_meta\n )\n if meta.get(\"id\"):\n init_params[\"id\"] = meta.get(\"id\")\n if meta.get(\"eval_split_ratio\"):\n init_params[\"dataset\"].eval_split_ratio = meta.get(\"eval_split_ratio\")\n else:\n log_error(f\"unknown load_dataset_action: {meta}\")\n raise ValueError(\"unknown action meta\")\n action = cls(\n **init_params,\n )\n action.result = meta.get(\"output\")\n return action\n\n @classmethod\n def load(cls, b: bytes) -> \"LoadDataSetAction\":\n meta = cls.serialize_helper.deserialize(b)\n assert isinstance(meta, dict)\n return cls._load_from_dict(meta)\n\n\nclass TrainAction(\n BaseAction[Dict[str, Any], Dict[str, Any]],\n):\n \"\"\"\n Class for Train Action, Synchronous invocation of the training API,\n taking a dataset metadata dict as input and producing a model metadata\n as output. Concretely, `exec` is called for running.\n\n Note: this action is not involved with model publishing, please use use\n `ModelPublishAction` for publishing model.\n\n Sample:\n\n Input:\n ```\n {\n \"datasets\": {\n \"sourceType\": (\n 2\n ),\n \"versions\": [\n {\n \"versionBosUri\": \"bos:/bbb/\"\n }\n ],\n }\n }\n ```\n\n Output:\n ```\n {'task_id': \"task-ddd\", 'job_id': \"job-xxxx\"}\n ```\n \"\"\"\n\n task_id: Optional[str] = None\n \"\"\"train task id\"\"\"\n job_id: Optional[str] = None\n \"\"\"train job id\"\"\"\n train_type: Optional[str] = \"\"\n \"\"\"train_type\"\"\"\n is_incr: bool = False\n \"\"\"if it's incremental train or not\"\"\"\n _last_task_id: Optional[str] = None\n \"\"\"last task id\"\"\"\n _last_task_step: Optional[int] = None\n \"\"\"last task step\"\"\"\n train_config: Optional[TrainConfig] = None\n \"\"\"train config\"\"\"\n train_mode: console_consts.TrainMode\n \"\"\"train mode\"\"\"\n job_name: str = \"\"\n \"\"\"train task name\"\"\"\n task_description: Optional[str] = None\n \"\"\"train task description\"\"\"\n job_description: Optional[str] = None\n \"\"\"train job description\"\"\"\n _input: Optional[Dict[str, Any]] = None\n \"\"\"train input\"\"\"\n result: Optional[Dict[str, Any]] = None\n \"\"\"\"train result\"\"\"\n train_model_name: Optional[str] = None\n \"\"\"real name to start training\"\"\"\n task_status: Optional[str] = None\n \"\"\"train task status, e.g. `Running`\"\"\"\n progress: Optional[int] = 0\n \"\"\"training progress 0-100\"\"\"\n vdl_link: Optional[str] = None\n \"\"\"visualdl link\"\"\"\n log_link: Optional[str] = None\n \"\"\"log link\"\"\"\n extras: Dict[str, Any] = {}\n \"\"\"extra params which are not supported in the previous version\"\"\"\n\n def __init__(\n self,\n train_mode: Union[console_consts.TrainMode, str],\n train_type: Optional[str] = None,\n train_config: Optional[TrainConfig] = None,\n task_id: Optional[str] = None,\n job_id: Optional[str] = None,\n peft_type: Optional[PeftType] = None,\n job_name: Optional[str] = None,\n task_description: Optional[str] = None,\n job_description: Optional[str] = None,\n task_step: Optional[int] = None,\n **kwargs: Any,\n ) -> None:\n \"\"\"\n\n Parameters:\n train_mode Union[console_consts.TrainMode, str]:\n train mode, e.g. `SFT`, `PostPretrain`, `DPO`. Defaults to None.\n train_type (Optional[str], optional):\n train_type, must be specified when it's not increment training\n like 'ERNIE-Speed-8K'\n train_config (Optional[TrainConfig], optional):\n train_config, e.g. `epoch=10, batch_size=32`.\n task_id (Optional[int], optional):\n used in incr train, model train task_id. Defaults to None.\n job_id (Optional[int], optional):\n used in incr train, mod train job_id. Defaults to None.\n peft_type: Optional[PeftType], optional):\n peft_type, e.g. `pretrain`, `finetune`. Defaults to None.\n job_name (Optional[str], optional):\n train task name. Defaults to None.\n task_description (Optional[str], optional):\n train task description. Defaults to None.\n job_description (Optional[str], optional):\n train job description. Defaults to None.\n \"\"\"\n super().__init__(**kwargs)\n # for persist\n self._init_job_id = job_id\n self._init_task_id = task_id\n self._last_task_id = task_id\n self._last_task_step = task_step\n self.job_id = job_id\n self.train_mode = console_consts.TrainMode(train_mode)\n self.train_model_name = train_type\n if self._last_task_id is not None:\n # if incremental train\n pre_task_detail = api.FineTune.V2.task_detail(task_id=self._last_task_id)\n # 获取增量任务的训练model\n if pre_task_detail.get(\"result\") is not None:\n self.train_type = pre_task_detail[\"result\"][\"model\"]\n if self.train_mode.value == pre_task_detail[\"result\"][\"trainMode\"]:\n self.job_id = pre_task_detail.get(\"result\", {}).get(\"jobId\")\n self.is_incr = True\n else:\n if train_type is None:\n raise InvalidArgumentError(\"train_type must be specified\")\n # 从基础模型开始训练\n self.train_type = train_type\n model_info = get_model_info(self.train_mode, self.train_type)\n if model_info is None:\n log_warn(f\"unknown train model type: {self.train_type} is not found\")\n elif model_info.model != \"\":\n # 兼容改名模型\n self.train_model_name = model_info.model\n assert self.train_type is not None\n if train_config is None:\n train_config = self.get_default_train_config(\n self.train_type, self.train_mode, peft_type\n )\n self.train_config = train_config\n self.validateTrainConfig(strict=kwargs.get(\"validate_strict\", True))\n self.job_name = self._generate_job_name(job_name, self.train_type)\n self.task_description = task_description\n self.job_description = job_description\n self.extras = kwargs.get(\"train_extras\", {})\n\n def _generate_job_name(\n self, job_name: Optional[str], train_type: Optional[str]\n ) -> str:\n if job_name is not None:\n return job_name\n model_info = (\n get_model_info(self.train_mode, train_type)\n if train_type is not None\n else None\n )\n return (\n f\"job_{utils.generate_letter_num_random_id()}\"\n if model_info is None\n else f\"{model_info.short_name}_{utils.generate_letter_num_random_id(5)}\"\n )\n\n def validateTrainConfig(self, strict: bool = True) -> None:\n \"\"\"\n validate train_config with ModelInfo Limits\n\n Raises:\n InvalidArgumentError: _description_\n \"\"\"\n if self.train_config is None:\n raise InvalidArgumentError(\"none train_config\")\n else:\n assert self.train_type\n train_type_model_info = get_model_info(self.train_mode, self.train_type)\n if train_type_model_info is None:\n return\n if (\n self.train_config.peft_type\n not in train_type_model_info.support_peft_types\n ):\n log_warn(\n f\"[train_action] train_type {self.train_type}, peft_type\"\n f\" {self.train_config.peft_type} not found, it may be not supported\"\n )\n if strict:\n raise InvalidArgumentError(\n f\"[train_action] train_type {self.train_type}, peft_type\"\n f\" {self.train_config.peft_type} not found, it may be not\"\n \" supported\"\n )\n\n else:\n assert train_type_model_info\n res = False\n if (\n train_type_model_info.specific_peft_types_params_limit is not None\n and self.train_config.peft_type\n in train_type_model_info.specific_peft_types_params_limit\n ):\n res = self._validate_train_config(\n train_type_model_info.specific_peft_types_params_limit[\n self.train_config.peft_type\n ]\n | train_type_model_info.common_params_limit,\n )\n else:\n res = self._validate_train_config(\n train_type_model_info.common_params_limit\n )\n if not res and strict:\n raise InvalidArgumentError(\n \"invalid train_config, please check the config\"\n )\n\n def _validate_train_config(self, train_limit: TrainLimit) -> bool:\n \"\"\"\n validate train_config with a specific train_limit\n\n Args:\n train_limit (TrainLimit): _description_\n\n Raises:\n InvalidArgumentError: _description_\n \"\"\"\n if self.train_config is None:\n raise InvalidArgumentError(\"validate train_config is none\")\n return self.train_config.validate_config(train_limit)\n\n @with_event\n def exec(self, input: Dict[str, Any] = {}, **kwargs: Dict) -> Dict[str, Any]:\n \"\"\"\n exec method for train action\n\n Args:\n input (Dict[str, Any], optional):\n input with dataset meta:\n for example:\n Input:\n ```\n {'datasets':[{'type': 1, 'id': 111}]}\n ```\n Raises:\n InvalidArgumentError: invalid dataset input\n\n Returns:\n Dict[str, Any]:\n train task output with task_id and job_id\n for example:\n Output:\n ```\n {'task_id': 47923, 'job_id': 33512}\n ```\n \"\"\"\n # for resume\n if self._input is None:\n self._input = input\n return self._exec(self._input, **kwargs)\n\n def _exec(self, input: Dict[str, Any] = {}, **kwargs: Any) -> Dict[str, Any]:\n # 校验数据集\n ds_config = input.get(\"datasets\")\n if ds_config is None:\n raise InvalidArgumentError(\"train set must be set\")\n assert isinstance(ds_config, dict)\n assert self.train_config\n\n if not self.job_id:\n # request for create model train task\n assert self.train_type is not None\n resp = api.FineTune.V2.create_job(\n name=self.job_name,\n description=self.task_description,\n model=(\n self.train_model_name if self.train_model_name else self.train_type\n ),\n train_mode=self.train_mode,\n **kwargs,\n )\n\n self.job_id = str(resp[\"result\"][\"jobId\"])\n log_debug(\n f\"[train_action] create {self.train_mode} train job: {self.job_id}\"\n )\n\n assert self.train_config is not None\n hyper_params_dict = {\n **self.train_config.dict(\n exclude={\"peft_type\", \"trainset_rate\", \"extras\", \"resource_config\"},\n exclude_none=True,\n ),\n **self.train_config.extras,\n }\n hyper_params_dict = {\n first_lower_case(snake_to_camel(key)): value\n for key, value in hyper_params_dict.items()\n if value is not None\n }\n # custom fix\n if \"packing\" in hyper_params_dict:\n hyper_params_dict[\"Packing\"] = hyper_params_dict.pop(\"packing\")\n ds_config = input[\"datasets\"]\n log_debug(f\"train with ds_config: { ds_config}\")\n log_debug(f\"train with hyper_params: { hyper_params_dict}\")\n if self.is_incr:\n # 增量训练\n kwargs[\"increment_task_id\"] = self._last_task_id\n if self._last_task_step:\n kwargs[\"increment_checkpoint_step\"] = self._last_task_step\n log_info(\n f\"train with incrementTaskId: { self._last_task_id} with step:\"\n f\" { self._last_task_step}\"\n )\n assert self.train_config.peft_type is not None\n # 语料混合配置\n if input.get(\"corpus_config\"):\n kwargs[\"corpus_config\"] = input.get(\"corpus_config\")\n # 训练资源配置\n if self.train_config.resource_config:\n kwargs[\"resource_config\"] = {\n **self.train_config.resource_config.dict(\n by_alias=True,\n exclude={\"extras\"},\n exclude_none=True,\n ),\n **self.train_config.resource_config.extras,\n }\n create_task_resp = api.FineTune.V2.create_task(\n job_id=self.job_id,\n params_scale=self.train_config.peft_type,\n hyper_params=hyper_params_dict,\n dataset_config=ds_config,\n **self.extras,\n **kwargs,\n )\n self.task_id = str(create_task_resp[\"result\"][\"taskId\"])\n log_debug(f\"[train_action] create {self.train_mode} train task: {self.task_id}\")\n\n # 获取job状态,是否训练完成\n train_output = self._wait_model_trained(**kwargs)\n self.result = {\n **input,\n \"task_id\": self.task_id,\n \"job_id\": self.job_id,\n **train_output,\n }\n assert self.result is not None\n return self.result\n\n def _wait_model_trained(self, **kwargs: Dict) -> Dict[str, Any]:\n if self.task_id is None:\n raise InvalidArgumentError(\"task_id must not be None\")\n output = {}\n while True:\n task_status_resp = api.FineTune.V2.task_detail(\n task_id=self.task_id,\n retry_count=kwargs.get(\n \"retry_count\", get_config().TRAINER_STATUS_POLLING_RETRY_TIMES\n ),\n backoff_factor=kwargs.get(\n \"backoff_factor\", get_config().TRAINER_STATUS_POLLING_BACKOFF_FACTOR\n ),\n )\n task_status_result = task_status_resp.get(\"result\", {})\n task_status = task_status_result.get(\"runStatus\")\n # 更新任务状态\n self.task_status = task_status\n\n self.action_event(ActionState.Running, \"train running\", task_status_resp)\n if task_status == console_consts.TrainStatus.Finish:\n output[\"metrics\"] = task_status_result.get(\"metrics\", {})\n output[\"checkpoints\"] = task_status_result.get(\"checkpointList\", [])\n log_info(f\"[train_action] training task metrics: {output['metrics']}\")\n log_info(\n f\"[train_action] training task checkpoints: {output['checkpoints']}\"\n )\n break\n elif task_status in [\n console_consts.TrainStatus.Fail,\n console_consts.TrainStatus.Stop,\n ]:\n log_error(\n \"[train_action] training job\"\n f\" {self.job_id}/{self.task_id} has ended,\"\n f\" {task_status_resp}\"\n )\n raise InternalError(\n f\"[train_action]training job {self.job_id}/{self.task_id} has ended\"\n f\" with status: {task_status}\"\n )\n elif task_status == console_consts.TrainStatus.Running:\n job_progress_str = task_status_result.get(\"runProgress\")\n job_progress = int(job_progress_str[:-1])\n self.progress = job_progress\n log_prefix = log_prefix_mapping.get(self.train_mode, \"sft\")\n self.log_link = f\"https://console.bce.baidu.com/qianfan/train/{log_prefix}/{self.job_id}/{self.task_id}/detail/traininglog\"\n self.vdl_link = task_status_result.get(\"vdlLink\", \"\")\n log_info(\n \"[train_action] training ...\"\n f\" job_name:{self.job_name} current status: {task_status},\"\n f\" {job_progress}% check train task log in\"\n f\" {self.log_link}\"\n )\n if job_progress >= 50:\n log_info(f\" check vdl report in {self.vdl_link}\")\n time.sleep(get_config().TRAIN_STATUS_POLLING_INTERVAL)\n elif task_status == \"\":\n time.sleep(get_config().TRAIN_STATUS_POLLING_INTERVAL)\n elif task_status == console_consts.TrainStatus.Waiting:\n log_info(f\"[train_action] {self.job_id}/{self.task_id} queueing...\")\n time.sleep(get_config().TRAIN_STATUS_POLLING_INTERVAL)\n else:\n raise InternalError(\n f\"[train_action] job: {self.job_name} task:\"\n f\" {self.job_id}/{self.task_id} get unknown status: {task_status}\"\n )\n log_info(\n \"[train_action] training job has ended:\"\n f\" {self.job_id}/{self.task_id} with status: {task_status}\"\n )\n return output\n\n @with_event\n def resume(self, **kwargs: Dict) -> Dict[str, Any]:\n \"\"\"\n resume method for train action\n\n Parameters:\n **kwargs (Dict):\n input args for action resume\n\n \"\"\"\n if self.result is not None:\n log_warn(\"[train_action] already done\")\n return self.result\n self.action_event(ActionState.Running, \"train resume\")\n if self.task_id is not None and self.job_id is not None:\n log_info(\n f\"[train_action] resume from created job {self.task_id}/{self.job_id}\"\n )\n train_metrics = self._wait_model_trained(**kwargs)\n self.result = {\n \"task_id\": self.task_id,\n \"job_id\": self.job_id,\n **train_metrics,\n }\n return self.result\n else:\n if self._input is None:\n self._input = {}\n return self._exec(self._input, **kwargs)\n\n def stop(self, **kwargs: Dict) -> \"BaseAction\":\n \"\"\"\n stop method for train action\n\n Parameters:\n **kwargs (Dict):\n input args for action stop\n \"\"\"\n if self.task_id is None or self.job_id is None:\n log_warn(\"[train_action] task_id or job_id not set, training not started\")\n return self\n resp = api.FineTune.V2.stop_task(self.task_id)\n if resp.get(\"result\"):\n log_debug(f\"train task {self.task_id}/{self.job_id} stopped successfully\")\n else:\n log_debug(f\"train task {self.task_id}/{self.job_id} stopped failed\")\n return self\n\n def get_default_train_config(\n self,\n model_type: str,\n train_mode: console_consts.TrainMode,\n peft_type: Optional[PeftType] = None,\n ) -> TrainConfig:\n model_info = get_default_train_config(train_mode).get(\n model_type,\n )\n if model_info is None or len(model_info) == 0:\n raise InvalidArgumentError(f\"can not find default config for {model_type}\")\n if peft_type is None:\n peft_type = sorted(model_info.keys())[0]\n train_config = model_info[peft_type]\n train_config.peft_type = peft_type\n return train_config\n\n def persist(self) -> bytes:\n return self.serialize_helper.serialize(self._action_dict())\n\n def _action_dict(self) -> Dict[str, Any]:\n meta = {\n \"id\": self.id,\n \"type\": TrainAction.__name__,\n \"init_params\": {\n \"job_id\": self._init_job_id,\n \"task_id\": self._init_task_id,\n \"train_mode\": (\n self.train_mode\n if isinstance(self.train_mode, str)\n else self.train_mode.value\n ),\n \"train_type\": self.train_type,\n \"train_config\": (\n self.train_config.dict() if self.train_config is not None else {}\n ),\n \"is_incr\": self.is_incr,\n \"job_name\": self.job_name,\n \"task_description\": self.task_description,\n \"job_description\": self.job_description,\n },\n \"job_id\": self.job_id if hasattr(self, \"job_id\") else None,\n \"task_id\": self.task_id if hasattr(self, \"task_id\") else None,\n \"status\": self.task_status,\n \"progress\": self.progress,\n \"vdl_link\": self.vdl_link,\n \"log_link\": self.log_link,\n \"input\": self._input,\n \"output\": self.result,\n }\n return meta\n\n @classmethod\n def _load_from_dict(cls, meta: Dict[str, Any]) -> \"TrainAction\":\n params = meta.get(\"init_params\", {})\n if \"train_config\" in params:\n params[\"train_config\"] = TrainConfig(**params[\"train_config\"])\n action = cls(\n id=meta.get(\"id\"),\n **params,\n )\n action.job_id = meta.get(\"job_id\")\n action.task_id = meta.get(\"task_id\")\n action.is_incr = params.pop(\"is_incr\", False)\n action._input = meta.get(\"input\")\n action.result = meta.get(\"output\")\n action.task_status = meta.get(\"status\")\n action.progress = meta.get(\"progress\")\n action.vdl_link = meta.get(\"vdl_link\")\n action.log_link = meta.get(\"log_link\")\n return action\n\n\nclass ModelPublishAction(BaseAction[Dict[str, Any], Dict[str, Any]]):\n \"\"\"\n Class for Model publish action, Commonly used after `TrainAction`.\n\n Sample:\n\n Input:\n ```\n {'task_id': \"task-xxx\", 'job_id': \"job-xxx\"}\n ```\n\n Output:\n ```\n {'task_id': \"task-xxx\", 'job_id': \"job-xxx\", 'model_id': \"xxx\",\n 'model_version_id': \"aaa\", \"model\": }\n ```\n \"\"\"\n\n task_id: Optional[str] = None\n \"\"\"task id\"\"\"\n job_id: Optional[str] = None\n \"\"\"job id\"\"\"\n result: Optional[Dict[str, Any]] = None\n \"\"\"result of model publish action\"\"\"\n model: Optional[Model] = None\n \"\"\"model object\"\"\"\n\n @with_event\n def exec(self, input: Dict[str, Any] = {}, **kwargs: Dict) -> Dict[str, Any]:\n if self.task_id == \"\" or self.job_id == \"\":\n raise InvalidArgumentError(\"task_id or job_id must be set\")\n self.task_id = input.get(\"task_id\", \"\")\n self.job_id = input.get(\"job_id\", \"\")\n self.model = Model(task_id=self.task_id, job_id=self.job_id)\n return self._exec(input, **kwargs)\n\n def _exec(self, input: Dict[str, Any] = {}, **kwargs: Dict) -> Dict[str, Any]:\n self._input = input\n if self.model is None:\n raise InvalidArgumentError(\"model must be set when in model publish._exec\")\n log_debug(\n f\"[model_publish_action] start model publish task:, {self.task_id},\"\n f\" {self.job_id}\"\n )\n try:\n self.action_event(\n ActionState.Running,\n \"model publish\",\n {\n \"task_id\": self.task_id,\n \"job_id\": self.job_id,\n },\n )\n self.model.publish(name=input.get(\"name\", \"\"), **kwargs)\n log_debug(\n f\"[model publish] model: {self.task_id}_{self.job_id} has been\"\n \" published.\"\n )\n\n self.result = {\n **input,\n \"task_id\": self.task_id,\n \"job_id\": self.job_id,\n \"model_set_id\": self.model.set_id,\n \"model_id\": self.model.id,\n \"model\": self.model,\n }\n return self.result\n except Exception as e:\n log_error(f\"[model_publish_action] model publish error: {e}\")\n raise e\n\n @with_event\n def resume(self, **kwargs: Dict) -> Dict[str, Any]:\n # raise NotImplementedError(\"ModelPublishAction.resume() is not implemented\")\n if self.result is not None:\n return self.result\n if self.model is not None:\n return self._exec()\n if self.task_id is None or self.job_id is None:\n raise InvalidArgumentError(\"task_id or job_id not set, resume failed\")\n self.model = Model(task_id=self.task_id, job_id=self.job_id)\n return self._exec(**kwargs)\n\n def _action_dict(self) -> Dict[str, Any]:\n meta: Dict[str, Any] = {\n \"id\": self.id,\n \"type\": ModelPublishAction.__name__,\n \"input\": {\n \"task_id\": self.task_id,\n \"job_id\": self.job_id,\n },\n }\n if self.model:\n meta[\"model_id\"] = self.model.id\n if self.result:\n res = copy.deepcopy(self.result)\n if \"model\" in res:\n res.pop(\"model\")\n meta[\"output\"] = res\n\n return meta\n\n @classmethod\n def _load_from_dict(cls, meta: Dict[str, Any]) -> \"BaseAction\":\n params = meta.get(\"init_params\", {})\n action = cls(\n id=meta.get(\"id\"),\n **params,\n )\n action._input = meta.get(\"input\") # type: ignore\n action.result = meta.get(\"output\")\n action.model = Model(id=meta.get(\"model_id\") or meta.get(\"model_version_id\"))\n action.model.auto_complete_info()\n return action\n\n\nclass DeployAction(BaseAction[Dict[str, Any], Dict[str, Any]]):\n \"\"\"DeployAction\n Action for model service deployment. A TrainConfig must be supplied\n when instance initialized.\n Sample:\n ```\n deploy_config = DeployConfig(replicas=1, pool_type=1)\n deploy_action = DeployAction(deploy_config=deploy_config)\n\n output = deploy_action.exec(input)\n ```\n\n input:\n {'task_id': \"task-xxxx\", 'job_id': \"job-xxxx\", 'model_id': \"xx\",\n 'model_version_id': \"xxx\"}\n output:\n ```\n {'task_id': \"task-xxx\", 'job_id': \"job-xxxx\", 'model_id': \"xx\",\n 'model_version_id': \"xxx\",\n 'service_id': 164, 'service_endpoint': 'xbiimimv_xxx'}\n ```\n \"\"\"\n\n deploy_config: Optional[DeployConfig] = None\n \"\"\"deploy config include replicas and so on\"\"\"\n \"\"\"model id\"\"\"\n model_set_id: Optional[str] = None\n \"\"\"model set id\"\"\"\n model_id: Optional[str] = None\n \"\"\"model id \"\"\"\n _input: Optional[Dict[str, Any]] = None\n \"\"\"input of action\"\"\"\n result: Optional[Dict[str, Any]] = None\n \"\"\"result of action\"\"\"\n model: Optional[Model] = None\n\n def __init__(self, deploy_config: Optional[DeployConfig] = None, **kwargs: Any):\n \"\"\"\n\n Parameters:\n deploy_config (Optional[DeployConfig], optional):\n deploy config include replicas and so on. Defaults to None.\n \"\"\"\n super().__init__(**kwargs)\n self.deploy_config = deploy_config\n\n @with_event\n def exec(self, input: Dict[str, Any] = {}, **kwargs: Any) -> Dict[str, Any]:\n # for resume\n if self._input is None:\n self._input = input\n if self.deploy_config is None:\n raise InvalidArgumentError(\"deploy_config must be set\")\n if input.get(\"model\") is None:\n self.model_id = input.get(\"model_id\")\n self.model_set_id = input.get(\"model_set_id\")\n # TODO 迁移成str id\n if self.model_id is None or self.model_set_id is None:\n raise InvalidArgumentError(\"model_id or model_set_id must be set\")\n\n self.model = Model(self.model_set_id, self.model_id, auto_complete=True)\n self.model.auto_complete_info()\n else:\n self.model = cast(Model, input.get(\"model\"))\n if self.model is None:\n raise InvalidArgumentError(\n \"must input with model or model id and version id\"\n )\n self.model.auto_complete_info()\n # 自动补全\n\n return self._exec(**kwargs)\n\n def _exec(self, input: Dict[str, Any] = {}, **kwargs: Dict) -> Dict[str, Any]:\n if self.deploy_config is None:\n raise InvalidArgumentError(\"deploy_config must be set in deploy._exec\")\n assert self.model is not None\n log_debug(\n f\"[deploy_action] try deploy model {self.model.set_id}_{self.model.id}\"\n )\n self.action_event(\n ActionState.Running,\n \"ready to deploy\",\n {\n \"model\": self.model,\n },\n )\n # deploy model\n self.model.deploy(self.deploy_config, **kwargs)\n if self.model.service is not None:\n log_debug(\n \"[deploy_action] model\"\n f\" {self.model_set_id}_{self.model_id} deployed successfully with\"\n \" service:\"\n f\" {self.model.service.id} endpoint:{self.model.service.endpoint}\"\n )\n return {\n **input,\n \"service_id\": self.model.service.id,\n \"service_endpoint\": self.model.service.endpoint,\n \"service\": self.model.service,\n \"model\": self.model,\n }\n else:\n raise InternalError(\"model.service is not available\")\n\n @with_event\n def resume(self, **kwargs: Dict) -> Dict[str, Any]:\n \"\"\"\n resume method for deploy action\n\n Parameters:\n **kwargs (Dict):\n input args for action resume\n\n \"\"\"\n if self.model_id is not None and self.model_set_id is not None:\n self.model = Model(self.model_set_id, self.model_id)\n self.model.auto_complete_info()\n elif self.model is None:\n raise InvalidArgumentError(\"either (set_id and id) or model must be set\")\n return self._exec()\n\n def _action_dict(self) -> Dict[str, Any]:\n meta = {\n \"id\": self.id,\n \"type\": DeployAction.__name__,\n \"init_params\": {\n \"deploy_config\": (\n self.deploy_config.dict() if self.deploy_config else None\n ),\n },\n \"input\": {\n \"model_set_id\": self.model_set_id,\n \"model_id\": self.model_id,\n },\n }\n if self.model is not None and self.model.service is not None:\n meta[\"output\"] = {\n \"service_id\": self.model.service.id,\n \"service_endpoint\": self.model.service.endpoint,\n }\n return meta\n\n @classmethod\n def _load_from_dict(cls, meta: Dict[str, Any]) -> \"BaseAction\":\n deploy_config = meta.get(\"init_params\", {}).get(\"deploy_config\", {})\n action = cls(\n id=meta.get(\"id\"),\n deploy_config=DeployConfig(**deploy_config),\n )\n action._input = meta.get(\"input\")\n action.result = meta.get(\"output\")\n return action\n\n\nclass BatchInferAction(BaseAction[Dict[str, Any], Dict[str, Any]]):\n \"\"\"BatchInferAction\n Action for batch inference.\n Sample:\n input:\n ```\n {'model_id': \"am-xxxx\", 'model_version_id': \"amv-xxxx\"}\n ```\n output:\n ```\n {'infer_res': InferenceResult ...}\n ```\n \"\"\"\n\n # batch_inference_manager: Optional[BatchInferenceManager] = None\n \"\"\"batch inference manager for batch infer models or services.\"\"\"\n dataset: Optional[Dataset] = None\n\n\nclass EvaluateAction(BaseAction[Dict[str, Any], Dict[str, Any]]):\n \"\"\"EvaluateAction\n Action for evaluate models or services.\n Sample:\n input:\n ```\n {'model_id': \"am-xxxx\", 'model_version_id': \"amv-xxxx\"}\n ```\n output:\n ```\n {'eval_res': EvaluationResult ...}\n ```\n \"\"\"\n\n eval_manager: Optional[EvaluationManager] = None\n \"\"\"evaluation manager for evaluate models or services.\"\"\"\n eval_dataset: Optional[Dataset] = None\n _input: Optional[Dict[str, Any]] = None\n \"\"\"input of action\"\"\"\n result: Optional[Dict[str, Any]] = None\n \"\"\"result of action\"\"\"\n\n def __init__(\n self, eval_dataset: Dataset, evaluators: List[Evaluator], **kwargs: Any\n ):\n \"\"\"\n init method for evaluate action\n\n Parameters:\n eval_dataset Dataset:\n dataset for evaluation, use Dataset.load() to create.\n evaluators List[Evaluator]:\n evaluators for evaluation, include local and qianfan remote evaluators.\n Specifically, qianfan_evaluators are only available for Model.\n \"\"\"\n super().__init__(**kwargs)\n self.eval_dataset = eval_dataset\n local_evaluators = [\n eval for eval in evaluators if isinstance(eval, LocalEvaluator)\n ]\n qianfan_evaluators = [\n eval for eval in evaluators if isinstance(eval, QianfanEvaluator)\n ]\n self.eval_manager = EvaluationManager(\n local_evaluators=local_evaluators if len(local_evaluators) > 0 else None,\n qianfan_evaluators=(\n qianfan_evaluators if len(qianfan_evaluators) > 0 else None\n ),\n )\n\n @with_event\n def exec(self, input: Dict[str, Any] = {}, **kwargs: Any) -> Dict[str, Any]:\n \"\"\"\n exec evaluation\n\n Parameters:\n input (Dict[str, Any], optional): input dict with model/service info.\n Defaults to {}.\n\n Returns:\n Dict[str, Any]: output the result with the original input\n \"\"\"\n self._input = input\n log_info(f\"[evaluation_action] begin to do evaluation, input: {self._input}\")\n llm = self._parse_from_input(self._input)\n res = self._exec(llm, **kwargs)\n self.result = {\"eval_res\": res, **input}\n return self.result\n\n def _parse_from_input(self, input: Dict[str, Any] = {}) -> Union[Model, Service]:\n \"\"\"\n Parses and returns the model or service object based on the input parameters.\n\n Parameters:\n input (Dict[str, Any], optional): . Defaults to {}.\n\n Returns:\n Union[Model, Service]: parsed model or service object\n \"\"\"\n\n if input.get(\"service\"):\n llm = input.get(\"service\")\n elif input.get(\"model\"):\n llm = input.get(\"model\")\n elif input.get(\"model_set_id\") and input.get(\"model_id\"):\n llm = Model(input[\"model_set_id\"], input[\"model_id\"])\n else:\n log_error(f\"[evaluation_action] invalid llm input error {self._input}\")\n raise InvalidArgumentError(\n \"model or service must be set in evaluation action\"\n )\n assert isinstance(llm, (Model, Service))\n return llm\n\n def _exec(self, llm: Union[Model, Service], **kwargs: Any) -> Any:\n \"\"\"\n accept a llm model/service to do evaluation\n\n Parameters:\n llm (Union[Model, Service]): model to do evaluation\n\n Returns:\n Any: evaluation result object\n \"\"\"\n assert self.eval_manager is not None\n if self.eval_dataset is None:\n raise InvalidArgumentError(\"eval_dataset must be set\")\n self.action_event(\n ActionState.Running,\n \"ready to evaluate\",\n {\n \"llm\": llm,\n \"dataset\": self.eval_dataset,\n },\n )\n log_info(\"[evaluation_action] running evaluation...\")\n return self.eval_manager.eval([llm], self.eval_dataset, **kwargs)\n\n @with_event\n def resume(self, **kwargs: Dict) -> Dict[str, Any]:\n \"\"\"\n resume method for eval action\n\n Parameters:\n **kwargs (Dict):\n input args for action resume\n\n \"\"\"\n if self._input is None:\n log_error(\n \"[evaluation_action] previous input not found, call run() instead.\"\n )\n raise ValueError(\"input not found\")\n llm = self._parse_from_input(self._input)\n res = self._exec(llm, **kwargs)\n self.result = {\"eval_res\": res, **self._input}\n return self.result\n\n def _action_dict(self) -> Dict[str, Any]:\n meta = {\n \"id\": self.id,\n \"type\": EvaluateAction.__name__,\n \"init_params\": {},\n # \"input\": self._input,\n # \"output\": self.result,\n }\n return meta\n\n @classmethod\n def _load_from_dict(cls, meta: Dict[str, Any]) -> \"EvaluateAction\":\n raise NotImplementedError()\n\n\naction_mapping: Dict[str, Dict[str, Any]] = {\n LoadDataSetAction.__name__: {\n ActionState.Preceding: TrainStatus.DatasetLoading,\n ActionState.Running: TrainStatus.DatasetLoading,\n ActionState.Done: TrainStatus.DatasetLoaded,\n ActionState.Error: TrainStatus.DatasetLoadFailed,\n ActionState.Stopped: TrainStatus.DatasetLoadStopped,\n },\n TrainAction.__name__: {\n ActionState.Preceding: TrainStatus.TrainCreated,\n ActionState.Running: TrainStatus.Training,\n ActionState.Done: TrainStatus.TrainFinished,\n ActionState.Error: TrainStatus.TrainFailed,\n ActionState.Stopped: TrainStatus.TrainStopped,\n },\n ModelPublishAction.__name__: {\n ActionState.Preceding: TrainStatus.ModelPublishing,\n ActionState.Running: TrainStatus.ModelPublishing,\n ActionState.Done: TrainStatus.ModelPublished,\n ActionState.Error: TrainStatus.ModelPublishFailed,\n ActionState.Stopped: TrainStatus.ModelPublishFailed,\n },\n DeployAction.__name__: {\n ActionState.Preceding: ServiceStatus.Created,\n ActionState.Running: ServiceStatus.Deploying,\n ActionState.Done: ServiceStatus.Deployed,\n ActionState.Error: ServiceStatus.DeployFailed,\n ActionState.Stopped: ServiceStatus.DeployStopped,\n },\n EvaluateAction.__name__: {\n ActionState.Preceding: TrainStatus.EvaluationCreated,\n ActionState.Running: TrainStatus.EvaluationRunning,\n ActionState.Done: TrainStatus.EvaluationFinished,\n ActionState.Error: TrainStatus.EvaluationFailed,\n ActionState.Stopped: TrainStatus.EvaluationStopped,\n },\n}\n\n\nlog_prefix_mapping = {\n console_consts.TrainMode.SFT: \"sft\",\n console_consts.TrainMode.PostPretrain: \"postPretrain\",\n console_consts.TrainMode.DPO: \"dpo\",\n}\n"}}}}