Automatic Speech Recognition
Transformers
Safetensors
Chinese
English
ming_v3_asr
text-generation
audio
speech-recognition
contextual-asr
custom_code
Instructions to use ArchiveStudio/Ming-3.0-asr-tiny with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use ArchiveStudio/Ming-3.0-asr-tiny with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("automatic-speech-recognition", model="ArchiveStudio/Ming-3.0-asr-tiny", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("ArchiveStudio/Ming-3.0-asr-tiny", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
Download chat_format.py from ArchiveStudio/Ming-3.0-asr-tiny: direct link, hf CLI and curl.
- Browser
- Download file 33.4 kB
-
https://huggingface.co/ArchiveStudio/Ming-3.0-asr-tiny/resolve/main/chat_format.py
- Command line
-
hf download hf://ArchiveStudio/Ming-3.0-asr-tiny/chat_format.py
-
curl -L -o chat_format.py https://huggingface.co/ArchiveStudio/Ming-3.0-asr-tiny/resolve/main/chat_format.py
33.4 kB
| """AntGLM Chat-model data format. | |
| 格式化 AntGLM 以及各种开源模型的符号系统: | |
| - 确定 Chat 模型依赖的文件数据结构协议 | |
| - 确定单轮/多轮的统一结构 | |
| - 确定 Chat 符号系统的协议, 包括角色定义、分隔符等 | |
| - 方便做开源模型依赖的 prompt 转换 | |
| - 支持工具、代码、推理等支持 | |
| 参考 FastChat Conversation 对象的设计思路. | |
| Reference: https://github.com/lm-sys/FastChat/blob/main/fastchat/conversation.py | |
| """ | |
| import copy | |
| import dataclasses | |
| import logging | |
| import re | |
| import uuid | |
| from copy import deepcopy | |
| from enum import IntEnum, auto | |
| from typing import Dict, List, Optional, Tuple | |
| logger = logging.getLogger(__name__) | |
| class PromptStyle(IntEnum): | |
| """Prompt styles.""" | |
| # 原始 antglm format 格式, 单轮指令没有结构, 多轮 `第1轮\n用户: xx\n机器人: xx\n` | |
| ANTGLM_RAW = auto() | |
| # Chat format 格式, 单轮多轮统一为 chat format 格式 | |
| ANTGLM_CHAT = auto() | |
| # 单轮指令没有结构, 只有多轮为 chat format 格式 | |
| ANTGLM_ONLY_MULTITURN_CHAT = auto() | |
| # OpenAI ChatML 格式, 包括千问 | |
| CHATML = auto() | |
| # LLAMA2 格式 | |
| LLAMA2 = auto() | |
| # ChatGLM 1/2 格式 | |
| CHATGLM = auto() | |
| # ChatGLM3 格式 | |
| CHATGLM3 = auto() | |
| # 百川格式 | |
| BAICHUAN2 = auto() | |
| class Chat: | |
| """Chat 数据符号结构, 格式化 AntGLM 以及各种开源模型的符号系统. | |
| Examples: | |
| ```python | |
| >>> from antllm.data.chat_format import Chat | |
| >>> ### 从 json 数据结构创建 chat 对象, 并且 format 结构使用 AntGLM 原始结构 | |
| >>> input_json = { | |
| ... "messages": [ | |
| ... {"role": "HUMAN", "content": "讲一个笑话"}, | |
| ... {"role": "ASSISTANT", "content": "为什么猪不能上网?因为它们会被网上的“猪”骗!哈哈哈!"}, | |
| ... {"role": "HUMAN", "content": "不好笑,换个程序员的笑话"} | |
| ... ], | |
| ... } | |
| >>> chat = Chat.from_json(input_json, name='antglm_raw') | |
| >>> ### 根据 chat 对象创建大模型训练所需 pack 数据 | |
| >>> pack_data = chat.prompt_pack | |
| >>> print(pack_data) | |
| >>> ### 根据 chat 对象创建大模型训练所需 input, output 数据 | |
| >>> data = chat.prompt_inout | |
| >>> print(data) | |
| >>> ### 根据 chat 对象创建大模型预测用的 prompt | |
| >>> prompt = chat.prompt_str | |
| >>> print(prompt) | |
| >>> ### 从大模型训练数据 {"input": "xx", "output": "xx"} 中创建 chat 对象 | |
| >>> data = { | |
| ... 'input': ( | |
| ... '第1轮\n用户: 讲一个笑话\n机器人: 为什么猪不能上网?因为它们会被网上的“猪”骗!哈哈哈!\n' | |
| ... '第2轮\n用户: 不好笑,换个程序员的笑话\n机器人:' | |
| ... ), | |
| ... 'output': '' | |
| ... } | |
| >>> chat = Chat.from_inout(data, name='antglm_raw') | |
| >>> ### 从大模型 pack 训练数据创建 chat 对象列表 | |
| >>> pack_data = { | |
| ... 'inputs': ['第1轮\n用户: 讲一个笑话\n机器人:', '第2轮\n用户: 不好笑,换个程序员的笑话\n机器人:', '第1轮\n用户: 写首诗\n机器人:'], | |
| ... 'outputs': [ | |
| ... '为什么猪不能上网?因为它们会被网上的“猪”骗!哈哈哈!\n', | |
| ... '为什么程序员总是喜欢使用黑色主题?因为他们喜欢“黑暗模式”(Dark Mode),这样他们就可以在晚上加班时更好地隐藏自己的错误!', | |
| ... ''] | |
| ... } | |
| >>> chats = Chat.from_pack(pack_data, name='antglm_raw') | |
| >>> assert len(chats) == 2 | |
| >>> print(chats[0]) | |
| >>> print(chats[1]) | |
| >>> ### 显示总交互轮数 (以用户输出多少次为轮数个数) | |
| >>> print(chat.turns_num) | |
| >>> ### 根据 chat 对象创建 json 格式化输出 | |
| >>> data_json = chat.to_json() | |
| >>> print(data_json) | |
| >>> ### 增加轮次信息 | |
| >>> content = ( | |
| ... '为什么程序员总是喜欢使用黑色主题?' | |
| ... '因为他们喜欢“黑暗模式”(Dark Mode),这样他们就可以在晚上加班时更好地隐藏自己的错误!' | |
| ... ) | |
| >>> chat.append_message(chat.role_assistant, content) | |
| >>> ### 将 chat 对象转成 OpenAI ChatCompletion 接口的入参 | |
| >>> openai_messages = chat.to_openai_api_messages() | |
| >>> print(openai_messages) | |
| >>> ### 复制一个 chat 对象 | |
| >>> chat_new = chat.copy() | |
| ``` | |
| """ | |
| # 数据结构名称 | |
| id: str = None | |
| # format 支持: antglm_raw, antglm_chat, chatglm1, chatglm2, llama2, qwen, baichuan2 | |
| name: Optional[str] = None | |
| # Prompt 风格 | |
| prompt_style: Optional[PromptStyle] = None | |
| # System Template 和 message | |
| system_template: str = "<role>SYSTEM</role>{}" | |
| system_message: str = "" | |
| # 角色定义 | |
| role_human: str = "HUMAN" | |
| role_assistant: str = "ASSISTANT" | |
| role_observation: str = "OBSERVATION" | |
| role_template: str = "<role>{}</role>" | |
| # 每轮符号定义 | |
| turn_start: str = "" | |
| human_end: str = "" | |
| assistant_start: str = "" | |
| assistant_end: str = "" | |
| assistant_end_ids: Optional[List[int]] = None | |
| general_role_end: str = "" | |
| # agent 符号定义 | |
| tool_template = "<tool>{}</tool>" | |
| code_template = "<code>{}</code>" | |
| arithemetic_templte = "<arithemetic>{}</arithemetic>" | |
| # All messages. Each item is (role, message). | |
| messages: List[Tuple[str, str]] = () | |
| # messages 中用于 few-shot messages | |
| offset: int = 0 | |
| # 其他 meta data | |
| source: Optional[str] = None | |
| lang: Optional[str] = None | |
| topic: Optional[str] = None | |
| # 原始 json 数据 | |
| origin_json: Optional[dict] = None | |
| def support_names(self) -> Dict[str, str]: | |
| """支持的数据对象名称.""" | |
| return { | |
| "antglm_raw": "原始 antglm format 格式, 单轮指令没有结构, 多轮 `第1轮\\n用户:xx\\n机器人xx\\n`", | |
| "antglm_chat": "Chat format 格式, 单轮多轮统一为 chat format 格式", | |
| "chatglm1": "chatglm1 format", | |
| "chatglm2": "chatglm2 format", | |
| "llama2": "llama2 format", | |
| "qwen": "千问 format", | |
| "baichuan2": "百川 2 format", | |
| } | |
| def from_json( | |
| cls, | |
| input: dict, | |
| name: Optional[str] = None, | |
| prompt_style: Optional[PromptStyle] = None, | |
| ): | |
| """从文件数据结构到数据对象的转换. | |
| Params: | |
| name: `Optional[str]`, 符号系统名称 | |
| - format 支持: antglm_raw, antglm_chat, chatglm1, chatglm2, llama2, qwen, baichuan2 | |
| - 如果指定了 format name, 使用该 name 符号系统, 否则使用 input 中 `name` 字段 | |
| prompt_style: `Optional[PromptStyle]`, 指定 prompt 风格, 默认使用和 name 一致的风格 | |
| input: `dict`, 文件中的 json dict 对象, 协议为: | |
| - 既支持 `messages` 字段, 也支持 `turns` 字段 | |
| { | |
| "id": "xxx", | |
| "name": "antglm", | |
| "source": "xxx", | |
| "lang": "xx", | |
| "topic": "xx", | |
| "system_template": "", | |
| "system_message": "xx", | |
| "messages": [ | |
| { | |
| "role": "HUMAN", | |
| "content": "Hi" | |
| }, | |
| { | |
| "role": "ASSISTANT", | |
| "content": "Hello" | |
| }, | |
| { | |
| "role": "OBSERVATION", | |
| "content": "xxx" | |
| }, | |
| { | |
| "role": "ASSISTANT", | |
| "content": "xxx" | |
| } | |
| ], | |
| "turns": [ | |
| {"HUMAN": "xxx", "OBSERVATION": "xx", "ASSISTANT": "xx"} | |
| ] | |
| } | |
| Returns: | |
| `Chat` 对象 | |
| """ | |
| _id = input.get("id") | |
| if name: | |
| _name = name | |
| else: | |
| _name = input.get("name") | |
| source = input.get("source") | |
| lang = input.get("lang") | |
| topic = input.get("topic") | |
| kwargs = {} | |
| if "system_template" in input: | |
| kwargs["system_template"] = input["system_template"] | |
| if "system_message" in input: | |
| kwargs["system_message"] = input["system_message"] | |
| # 转换成 Chat 对象 | |
| chat = cls( | |
| id=_id, | |
| name=_name, | |
| prompt_style=prompt_style, | |
| source=source, | |
| lang=lang, | |
| topic=topic, | |
| origin_json=deepcopy(input), | |
| **kwargs, | |
| ) | |
| if "messages" in input: | |
| for msg in input["messages"]: | |
| if msg["role"] == "HUMAN": | |
| role = chat.role_human | |
| elif msg["role"] == "OBSERVATION": | |
| role = chat.role_observation | |
| elif msg["role"] == "ASSISTANT": | |
| role = chat.role_assistant | |
| else: | |
| raise ValueError(f"不支持数据集中的 role: {msg['role']}") | |
| chat.append_message(role, msg["content"]) | |
| elif "turns" in input: | |
| for turn in input["turns"]: | |
| if "HUMAN" in turn: | |
| content = turn["HUMAN"] | |
| chat.append_message(chat.role_human, content) | |
| if "OBSERVATION" in turn: | |
| content = turn["OBSERVATION"] | |
| chat.append_message(chat.role_observation, content) | |
| if "ASSISTANT" in turn: | |
| content = turn["ASSISTANT"] | |
| chat.append_message(chat.role_assistant, content) | |
| return chat | |
| def from_pack( | |
| cls, | |
| packs: Dict[str, List[str]], | |
| name: str, | |
| prompt_style: Optional[PromptStyle] = None, | |
| ) -> list: | |
| """根据 pack 数据创建 Chat 对象. | |
| Params: | |
| packs: `dict`, pack 样本数据 | |
| { | |
| 'inputs': ['xx', 'xx'], | |
| 'outputs': ['xx', 'xx'], | |
| } | |
| name: `str`, 符号系统名称 | |
| prompt_style: `Optional[PromptStyle]`, 指定 prompt 风格, 默认使用和 name 一致的风格 | |
| """ | |
| chat = cls(name=name, prompt_style=prompt_style) | |
| packs = cls._format_packs(packs) | |
| sys_pattern = re.compile(chat.system_template.format(r"(.*?)"), re.DOTALL) | |
| turn_pattern = re.compile(chat.turn_start.format(r"(\d+)"), re.DOTALL) | |
| human_pattern = re.compile( | |
| chat.role_template.format(chat.role_human).strip(), re.DOTALL | |
| ) | |
| observe_pattern = re.compile( | |
| chat.role_template.format(chat.role_observation).strip(), re.DOTALL | |
| ) | |
| assistant_pattern = re.compile( | |
| chat.role_template.format(chat.role_assistant).strip(), re.DOTALL | |
| ) | |
| chats = [] | |
| for input, output in zip(packs["input"], packs["output"]): | |
| # system message | |
| sys_match = sys_pattern.search(input) | |
| if sys_match and sys_match.group(0): | |
| # system 指令只在首轮, 新增 chat 对象 | |
| if len(chat.messages) > 0: | |
| chats.append(chat) | |
| chat = cls(name=name, prompt_style=prompt_style) | |
| input = input[sys_match.end() :] | |
| chat.system_message = sys_match.group(1) | |
| # turn start | |
| turn_match = turn_pattern.search(input) | |
| if turn_match and turn_match.group(0): | |
| # 当出现下一个轮次开始信息, 新增 chat 对象 | |
| if name in ["antglm", "antglm_raw", "chatglm2"]: | |
| round_start = 1 | |
| else: | |
| round_start = 0 | |
| if all( | |
| [ | |
| len(turn_match.groups()) > 0, | |
| int(turn_match.group(1)) == round_start, | |
| len(chat.messages) > 0, | |
| ] | |
| ): | |
| chats.append(chat) | |
| chat = cls(name=name, prompt_style=prompt_style) | |
| input = input[turn_match.end() :] | |
| human_iter = human_pattern.finditer(input) | |
| observe_iter = observe_pattern.finditer(input) | |
| assistant_iter = assistant_pattern.finditer(input) | |
| human_match = next(human_iter, None) | |
| observe_match = next(observe_iter, None) | |
| assistant_match = next(assistant_iter, None) | |
| if not human_match and not observe_match: | |
| # 无 role format | |
| chat.append_message(chat.role_human, input) | |
| while human_match or observe_match: | |
| next_human_match = next(human_iter, None) | |
| next_observe_match = next(observe_iter, None) | |
| input = cls._append_human_observation( | |
| chat, | |
| input, | |
| human_match=human_match, | |
| next_human_match=next_human_match, | |
| observe_match=observe_match, | |
| next_observe_match=next_observe_match, | |
| assistant_match=assistant_match, | |
| ) | |
| human_match = next_human_match | |
| observe_match = next_observe_match | |
| next_human_match = next(human_iter, None) | |
| next_observe_match = next(observe_iter, None) | |
| if output: | |
| chat.append_message(chat.role_assistant, output) | |
| if chat.messages: | |
| chats.append(chat) | |
| return chats | |
| def _append_human_observation( | |
| cls, | |
| chat, | |
| input: str, | |
| human_match: Optional[re.Match] = None, | |
| next_human_match: Optional[re.Match] = None, | |
| observe_match: Optional[re.Match] = None, | |
| next_observe_match: Optional[re.Match] = None, | |
| assistant_match: Optional[re.Match] = None, | |
| ) -> str: | |
| """给 chat 对象增加 human/observation message.""" | |
| if observe_match: | |
| # observation 在 human 之后 | |
| if observe_match.span()[0] > observe_match.span()[0]: | |
| human_str = input[observe_match.span()[1] : observe_match.span()[0]] | |
| observe_str = input[observe_match.span()[1] : assistant_match.span()[0]] | |
| chat.append_message(chat.role_human, human_str.strip()) | |
| input_end = observe_match.span()[1] | |
| if observe_match.span()[0] < next_human_match.span()[0]: | |
| chat.append_message(chat.role_observation, observe_str.strip()) | |
| input_end = assistant_match.span()[1] | |
| else: | |
| # observation 在 human 之前 | |
| human_str = input[observe_match.span()[1] : assistant_match.span()[0]] | |
| observe_str = input[observe_match.span()[1] : observe_match.span()[0]] | |
| chat.append_message(chat.role_observation, observe_str.strip()) | |
| input_end = observe_match.span()[1] | |
| if observe_match.span()[0] < next_observe_match.span()[0]: | |
| chat.append_message(chat.role_human, human_str.strip()) | |
| input_end = assistant_match.span()[1] | |
| else: | |
| if assistant_match: | |
| human_str = input[human_match.span()[1] : assistant_match.span()[0]] | |
| input_end = assistant_match.span()[1] | |
| else: | |
| human_str = input[human_match.span()[1] :] | |
| input_end = len(input) | |
| chat.append_message(chat.role_human, human_str.strip()) | |
| return input[input_end:] | |
| def from_inout( | |
| cls, | |
| sample: Dict[str, str], | |
| name: str, | |
| prompt_style: Optional[PromptStyle] = None, | |
| ): | |
| """根据单样本创建一个 Chat 对象. | |
| Params: | |
| sample: `Dict[str, str]`, input/output 数据样本 | |
| { | |
| "input": "xxx", | |
| "output": "xxx", | |
| } | |
| name: `str`, 符号系统名称 | |
| prompt_style: `Optional[PromptStyle]`, 指定 prompt 风格, 默认使用和 name 一致的风格 | |
| """ | |
| chat = cls(name=name, prompt_style=prompt_style) | |
| input = sample["input"] | |
| output = sample["output"] | |
| sys_pattern = re.compile(chat.system_template.format(r"(.*?)"), re.DOTALL) | |
| turn_pattern = re.compile(chat.turn_start.format(r"(\d+)"), re.DOTALL) | |
| human_pattern = re.compile( | |
| chat.role_template.format(chat.role_human).strip(), re.DOTALL | |
| ) | |
| observe_pattern = re.compile( | |
| chat.role_template.format(chat.role_observation).strip(), re.DOTALL | |
| ) | |
| assistant_pattern = re.compile( | |
| chat.role_template.format(chat.role_assistant).strip(), re.DOTALL | |
| ) | |
| # 去除轮次信息 | |
| input = turn_pattern.sub("", input) | |
| # system message search | |
| sys_match = sys_pattern.search(input) | |
| if sys_match and sys_match.group(0): | |
| input = input[sys_match.end() :] | |
| chat.system_message = sys_match.group(1) | |
| human_iter = human_pattern.finditer(input) | |
| observe_iter = observe_pattern.finditer(input) | |
| assistant_iter = assistant_pattern.finditer(input) | |
| human_match = next(human_iter, None) | |
| observe_match = next(observe_iter, None) | |
| assistant_match = next(assistant_iter, None) | |
| next_human_match = next(human_iter, None) | |
| next_observe_match = next(observe_iter, None) | |
| while any( | |
| [ | |
| human_match, | |
| observe_match, | |
| assistant_match, | |
| ] | |
| ): | |
| # human/observation 先后顺序可能不一样, 并且有可能有多个 | |
| # 判断 assitant 之前是否还有 human/observation | |
| while any( | |
| [ | |
| human_match and human_match.span()[0] < assistant_match.span()[0], | |
| observe_match | |
| and observe_match.span()[0] < assistant_match.span()[0], | |
| next_human_match | |
| and next_human_match.span()[0] < assistant_match.span()[0], | |
| next_observe_match | |
| and next_observe_match.span()[0] < assistant_match.span()[0], | |
| ] | |
| ): | |
| if not input: | |
| break | |
| cls._append_human_observation( | |
| chat, | |
| input, | |
| human_match=human_match, | |
| next_human_match=next_human_match, | |
| observe_match=observe_match, | |
| next_observe_match=next_observe_match, | |
| assistant_match=assistant_match, | |
| ) | |
| human_match = next_human_match | |
| observe_match = next_observe_match | |
| next_human_match = next(human_iter, None) | |
| next_observe_match = next(observe_iter, None) | |
| # assistant message | |
| if assistant_match and assistant_match.span(): | |
| if observe_match: | |
| if ( | |
| observe_match.span() | |
| and observe_match.span()[0] < human_match.span()[0] | |
| ): | |
| assistant_str = input[ | |
| assistant_match.span()[1] : observe_match.span()[0] | |
| ] | |
| elif human_match: | |
| if human_match.span(): | |
| assistant_str = input[ | |
| assistant_match.span()[1] : human_match.span()[0] | |
| ] | |
| else: | |
| assistant_str = input[assistant_match.span()[1] :] | |
| if assistant_str: | |
| chat.append_message(chat.role_assistant, assistant_str) | |
| assistant_match = next(assistant_iter, None) | |
| if output: | |
| chat.append_message(chat.role_assistant, output) | |
| return chat | |
| def __hash__(self): | |
| """数据对象的 hash 函数.""" | |
| return hash(self.id) | |
| def __post_init__(self): | |
| """对象初始化后的处理, 处理包括: | |
| - 根据数据对象名称, 支持转成其他开源数据对象的基本信息 | |
| """ | |
| self.id = str(uuid.uuid4()) | |
| if not self.messages: | |
| self.messages = [] | |
| if not self.name and not self.prompt_style: | |
| logger.error( | |
| "构造 Chat 对象至少包含以下一个入参: `name/prompt_style`.\n\n" | |
| "`name` 支持以下 format 名称:" | |
| ) | |
| logger.error( | |
| "\n".join([f"{k}: {v}" for k, v in self.support_names.items()]) | |
| ) | |
| logger.error("\n`prompt_style` 参考 antllm.data.chat_format.PromptStyle") | |
| raise ValueError | |
| if self.name == "antglm": | |
| # 默认 antglm 使用原始 antglm_raw - 第1轮\n用户: xx\n机器人: xx\n | |
| self.name = "antglm_raw" | |
| if not self.name and self.prompt_style == PromptStyle.ANTGLM_CHAT: | |
| logger.info( | |
| "Chat 对象入参没有 `name`, 默认使用 `ANTGLM_CHAT`, format:\n" | |
| f"role_human: {self.role_human}\n" | |
| f"role_assistant: {self.role_assistant}\n" | |
| f"role_observation: {self.role_observation}\n" | |
| f"role_template: {self.role_template}\n" | |
| f"turn_start: {self.turn_start}\n" | |
| f"human_end: {self.human_end}\n" | |
| f"assistant_start: {self.assistant_start}\n" | |
| f"assistant_end: {self.assistant_end}\n" | |
| f"assistant_end_ids: {self.assistant_end_ids}\n" | |
| f"general_role_end: {self.general_role_end}\n" | |
| f"tool_template: {self.tool_template}\n" | |
| f"code_template: {self.code_template}\n" | |
| f"arithemetic_templte: {self.arithemetic_templte}\n" | |
| f"\n入参 `name` 支持: ``" | |
| ) | |
| return | |
| if self.name == "antglm_raw" or self.prompt_style == PromptStyle.ANTGLM_RAW: | |
| self.prompt_style = PromptStyle.ANTGLM_RAW | |
| self.role_template = "{}" | |
| self.role_human = "用户: " | |
| self.role_assistant = "机器人: " | |
| self.turn_start = "第{}轮\n" | |
| self.general_role_end = "\n" | |
| if ( | |
| self.name in ["chatglm1", "chatglm2"] | |
| or self.prompt_style == PromptStyle.CHATGLM | |
| ): | |
| self.prompt_style = PromptStyle.CHATGLM | |
| self.role_template = "{}" | |
| self.role_human = "问:" | |
| self.role_assistant = "答:" | |
| self.turn_start = "[Round {}]\n" | |
| if self.name == "chatglm1": | |
| self.general_role_end = "\n" | |
| else: | |
| self.general_role_end = "\n\n" | |
| elif self.name == "chatglm3" or self.prompt_style == PromptStyle.CHATGLM3: | |
| self.prompt_style = PromptStyle.CHATGLM3 | |
| self.system_template = "<|system|>\n {}" | |
| self.role_human = "<|user|>\n " | |
| self.role_assistant = "<|assistant|>\n " | |
| self.role_template = "{}" | |
| elif self.name == "llama2" or self.prompt_style == PromptStyle.LLAMA2: | |
| self.prompt_style = PromptStyle.LLAMA2 | |
| self.role_template = "{}" | |
| self.system_template = "[INST] <<SYS>>\n{}\n<</SYS>>\n\n" | |
| self.role_human = "[INST] " | |
| self.role_assistant = "[/INST] " | |
| self.human_end = " " | |
| self.assistant_end = " </s><s>" | |
| elif self.name == "qwen": | |
| self.prompt_style = PromptStyle.CHATML | |
| self.role_template = "{}" | |
| self.system_template = "<|im_start|>system\n{}" | |
| if not self.system_message: | |
| self.system_message = "You are a helpful assistant." | |
| self.role_human = "<|im_start|>user\n" | |
| self.role_assistant = "<|im_start|>assistant\n" | |
| self.general_role_end = "<|im_end|>\n" | |
| elif self.name == "baichuan": | |
| self.prompt_style = PromptStyle.BAICHUAN2 | |
| self.role_template = "{}" | |
| self.system_template = "{}" | |
| self.role_human = "<token_id-195>" | |
| self.role_assistant = "<token_id-196>" | |
| if not self.system_template: | |
| self.system_template = "{}" | |
| def readable_messages(self) -> str: | |
| """将 messages 输出为人类可读的字符串, 方便分析数据.""" | |
| pass | |
| def prompt_str(self) -> str: | |
| """将 Chat 对象转成 prompt str, 合并 human/assitant 输出为 format 字符串.""" | |
| return f"{self.prompt_inout['input']}{self.prompt_inout['output']}" | |
| def _format_packs(cls, packs: Dict[str, List[str]]) -> Dict[str, List[str]]: | |
| """格式化 pack 样本, 输出相同 pack inputs, outputs 个数.""" | |
| _packs = copy.deepcopy(packs) | |
| if len(_packs["input"]) - 1 == len(_packs["output"]): | |
| _packs["output"].append("") | |
| if len(_packs["input"]) != len(_packs["output"]): | |
| print(packs) | |
| raise ValueError( | |
| "输入 input 和 output 数量不匹配, " | |
| f"input num: {len(packs['input'])}, " | |
| f"output num: {len(packs['output'])}" | |
| ) | |
| return _packs | |
| def prompt_inout(self) -> Dict[str, str]: | |
| """将 Chat 对象转成 input prompt, output prompt 字符串. | |
| Returns: | |
| `Dict[str, str]`, 示例: | |
| { | |
| "input": "<role>SYSTEM</role>xxxx<role>HUMAN</role>你好<role>ASSISTANT</role>你好,有什么可以帮您?<role>ASSISTANT</role>", # noqa | |
| "output": "你好,有什么可以帮您?" | |
| } | |
| """ | |
| packs = self._format_packs(self.prompt_pack) | |
| # 兼容逻辑 | |
| if self.prompt_style == PromptStyle.ANTGLM_RAW: | |
| packs["input"] = [f"{item} " for item in packs["input"]] | |
| prompt_input = "".join( | |
| [f"{x}{y}" for x, y in zip(packs["input"][:-1], packs["output"][:-1])] | |
| ) | |
| prompt_input += packs["input"][-1] | |
| prompt_output = packs["output"][-1] | |
| # 兼容逻辑 | |
| if self.prompt_style == PromptStyle.ANTGLM_RAW: | |
| prompt_input = prompt_input.strip() | |
| return { | |
| "input": prompt_input, | |
| "output": prompt_output, | |
| } | |
| def prompt_pack(self) -> Dict[str, List[str]]: | |
| """将数据对象转成 pack input prompt, output prompt 字符串列表.: | |
| Returns: | |
| `Dict[str, List[str]]`, 示例: | |
| { | |
| "input": [ | |
| "<role>SYSTEM</role>xxxx<role>HUMAN</role>你好<role>ASSISTANT</role>", | |
| "<role>HUMAN</role>讲个笑话<role>ASSISTANT</role>", | |
| "<role>OBSERVATION</role>{\"weather\": \"晴\"}<role>ASSISTANT</role>" | |
| ], | |
| "output": [ | |
| "你好,有什么可以帮您?", | |
| "笑话 1", | |
| "今天天气 xxx" | |
| ] | |
| } | |
| """ | |
| inputs = [] | |
| outputs = [] | |
| # 最开始 system 构造 | |
| system_prompt = "" | |
| if self.system_message: | |
| system_prompt = self.system_template.format(self.system_message) | |
| if system_prompt: | |
| ret = system_prompt + self.general_role_end | |
| else: | |
| ret = "" | |
| # 有些 prompt style 单轮指令没有 format | |
| if self.prompt_style in [ | |
| PromptStyle.ANTGLM_RAW, | |
| PromptStyle.ANTGLM_ONLY_MULTITURN_CHAT, | |
| ]: | |
| if len(self.messages) <= 2: | |
| output = "" | |
| for role, message in self.messages: | |
| if role == self.role_assistant: | |
| output = message | |
| else: | |
| input = ret + message | |
| return { | |
| "input": [input], | |
| "output": [output], | |
| } | |
| # 多轮对话 | |
| if self.name in ["antglm_raw", "chatglm2"]: | |
| round_start = 1 | |
| else: | |
| round_start = 0 | |
| for i, (role, message) in enumerate(self.messages): | |
| # 轮次信息 | |
| if self.name in ["antglm_raw", "chatglm1", "chatglm2"]: | |
| if i % 2 == 0: | |
| ret += self.turn_start.format(i // 2 + round_start) | |
| # 角色 + 内容 | |
| role_end = self.general_role_end | |
| if role == self.role_assistant and self.assistant_end: | |
| role_end = self.assistant_end | |
| elif self.human_end: | |
| role_end = self.human_end | |
| ret += self.role_template.format(role) + message + role_end | |
| if role == self.role_assistant: | |
| # output 只保留实际 assistant 内容 | |
| if not message: | |
| outputs.append("") | |
| else: | |
| outputs.append(message + role_end) | |
| # input 需要连接 assistant role | |
| inputs[-1] += ret[: -len(message + role_end)] | |
| elif all( | |
| [ | |
| role == self.role_observation, | |
| len(self.messages) > 1, | |
| self.messages[i - 1][0] != self.role_assistant, | |
| ] | |
| ): | |
| # observation 之前不是 assistant, 需要将 observation 和上一个 input 连接一起 | |
| continue | |
| else: | |
| inputs.append(ret) | |
| ret = "" | |
| # 最后一轮不是机器人回复, 需要拼接机器人 role, 用于模型生成 | |
| if i == len(self.messages) - 1 and role != self.role_assistant: | |
| inputs[-1] += self.role_template.format(self.role_assistant).strip() | |
| # 兼容逻辑, 去除 inputs 最后空格符号 | |
| if self.prompt_style == PromptStyle.ANTGLM_RAW: | |
| inputs = [item.strip() for item in inputs] | |
| return { | |
| "input": inputs, | |
| "output": outputs, | |
| } | |
| def turns_num(self) -> int: | |
| """和机器人的交互轮数, 以用户输出多少次为轮数个数.""" | |
| return sum([1 if msg[0] == self.role_human else 0 for msg in self.messages]) | |
| def to_json(self) -> dict: | |
| """输出 chat json dict 格式, 包含不同角色和机器人交互的每轮信息. | |
| Returns | |
| `List[dict]`, { | |
| "id": "xx", | |
| "messages": [ | |
| {"role": "HUMAN", "content": "xxx"} | |
| ] | |
| "turns": [ | |
| {"HUMAN": "xx", "OBSERVATION": "xx", "ASSISTANT": "xx"} | |
| ] | |
| } | |
| """ | |
| turns = [] | |
| messages = [] | |
| turn = {} | |
| for msg in self.messages: | |
| if msg[0] == self.role_assistant: | |
| messages.append({"role": "ASSISTANT", "content": msg[1]}) | |
| turn["ASSISTANT"] = msg[1] | |
| turns.append(turn) | |
| turn = {} | |
| if msg[0] == self.role_human: | |
| messages.append({"role": "HUMAN", "content": msg[1]}) | |
| turn["HUMAN"] = msg[1] | |
| if msg[0] == self.role_observation: | |
| messages.append({"role": "OBSERVATION", "content": msg[1]}) | |
| turn["OBSERVATION"] = msg[1] | |
| if self.messages[-1][0] == self.role_human: | |
| messages.append({"role": "ASSISTANT", "content": ""}) | |
| turn["ASSISTANT"] = "" | |
| turns.append(turn) | |
| result = self.origin_json or {} | |
| result.update( | |
| { | |
| "id": self.id, | |
| "name": self.name, | |
| "source": self.source, | |
| "lang": self.lang, | |
| "topic": self.topic, | |
| "system_template": self.system_template, | |
| "system_message": self.system_message, | |
| "turns": turns, | |
| "messages": messages, | |
| } | |
| ) | |
| return result | |
| def set_system_message(self, system_message: str): | |
| """Set the system message.""" | |
| self.system_message = system_message | |
| def append_message(self, role: str, message: str): | |
| """Append a new message.""" | |
| if not message: | |
| message = "" | |
| self.messages.append([role, message]) | |
| def to_openai_api_messages(self) -> List[dict]: | |
| """Convert the conversation to OpenAI chat completion format.""" | |
| ret = [{"role": "system", "content": self.system_message}] | |
| for i, (_, msg) in enumerate(self.messages[self.offset :]): | |
| if i % 2 == 0: | |
| ret.append({"role": "user", "content": msg}) | |
| else: | |
| if msg is not None: | |
| ret.append({"role": "assistant", "content": msg}) | |
| return ret | |
| def copy(self): | |
| return copy.deepcopy(self) | |