# %% from typing import Optional, List from dataclasses import field, dataclass @dataclass class OpusV1Turn: role: str content: str names: List[str] = field(default_factory=list) # If set to true, will not append <|im_end|>, so the model will continue the turn. # In RP you can for example use the following to force a specific character response: # role="text" # names=["Jack"] # open="true" open: bool = False @dataclass class OpusV1Character: name: str description: str @dataclass class OpusV1StorySystemPrompt: format: str = "prose" plot_description: str = "" style_description: str = "" characters: List[OpusV1Character] = field(default_factory=list) @dataclass class OpusV1Prompt: story: Optional[OpusV1StorySystemPrompt] = None turns: List[OpusV1Turn] = field(default_factory=list) def format_opus_v1_prompt(prompt) -> str: turns = prompt.turns if prompt.story is not None: system = format_opus_v1_system_prompt(prompt.story) turns = [OpusV1Turn(role="system", content=system)] + turns parts = [] for i, turn in enumerate(turns): assert turn.role in ["user", "text", "system", "assistant"] assert turn.role != "system" or i == 0 is_last = i == len(turns) - 1 open = is_last and turn.open parts.append(format_turn(turn.role, turn.content, turn.names, open=open)) return "".join(parts) def format_turn( role: str, content: str, names: List[str] = [], open: bool = False ) -> str: im_start = "<|im_start|>" im_end = "<|im_end|>" body = im_start + role if len(names) > 0: body += f" names= {'; '.join(names)}" body += "\n" if open: return body + content.lstrip() else: return body + content.strip() + im_end + "\n" def format_opus_v1_system_prompt(prompt) -> str: format_text = "story" if prompt.format == "prose" else "role-play" system = f""" You are an intelligent, skilled, versatile writer. Your task is to write a {format_text} based on the information below. Write the {format_text} as if it's a book. """.strip() if len(prompt.plot_description) > 0: system += "\n\n\n## Plot description:\n\n" system += prompt.plot_description.strip() if len(prompt.style_description) > 0: system += "\n\n\n## Style description:\n\n" system += prompt.style_description.strip() if len(prompt.characters) > 0: system += "\n\n\n## Characters:\n\n" for character in prompt.characters: system += f"### {character.name}\n\n" system += character.description.strip() system += "\n\n" return system.strip()