{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Creating a Discussion\n",
    "\n",
    "The simplest task you can accomplish with this library is to create a small discussion between LLMs. \n",
    "\n",
    "This guide will teach you the basic setup of the library. You will understand how to setup models, user-agents and how to coordinate them in a discussion. By the end of htis guide, you will be able to run a small discussion with a moderator and save it to the disk for persistence."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### The Model\n",
    "\n",
    "SynDisco can theoretically support any LLM, as long as it is wrapped in a `BaseModel` wrapper. The `BaseModel` class is a very simple interface with one method. This method gives the underlying LLM input, and returns its output to the library.\n",
    "\n",
    "There already exists a `TransformersModel` class which handles models from the `transformers` python library. In 90% of your applications, this will be enough. We can load a TransformersModel using the following code:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-04-04T13:14:26.434159Z",
     "iopub.status.busy": "2025-04-04T13:14:26.433413Z",
     "iopub.status.idle": "2025-04-04T13:17:17.032081Z",
     "shell.execute_reply": "2025-04-04T13:17:17.031468Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/media/SSD_2TB/dtsirmpas_data/software/miniconda3/envs/syndisco/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "Fetching 4 files:   0%|                                                                                                                                                                      | 0/4 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "Fetching 4 files:  25%|███████████████████████████████████████▎                                                                                                                     | 1/4 [02:25<07:17, 145.94s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "Fetching 4 files: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 4/4 [02:25<00:00, 36.49s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "Loading checkpoint shards:   0%|                                                                                                                                                             | 0/4 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "Loading checkpoint shards:  25%|█████████████████████████████████████▎                                                                                                               | 1/4 [00:03<00:11,  3.89s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "Loading checkpoint shards:  50%|██████████████████████████████████████████████████████████████████████████▌                                                                          | 2/4 [00:07<00:07,  3.50s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "Loading checkpoint shards:  75%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████▊                                     | 3/4 [00:10<00:03,  3.35s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "Loading checkpoint shards: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 4/4 [00:11<00:00,  2.31s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r",
      "Loading checkpoint shards: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 4/4 [00:11<00:00,  2.75s/it]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Device set to use cuda:0\n"
     ]
    }
   ],
   "source": [
    "from syndisco.backend.model import TransformersModel\n",
    "\n",
    "llm = TransformersModel(\n",
    "    model_path=\"unsloth/Meta-Llama-3.1-8B-Instruct\",\n",
    "    name=\"test_model\",\n",
    "    max_out_tokens=100,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This will download a small LLM from huggingface. You can substitute the model_path for any similar model in [HuggingFace](https://huggingface.co/) supporting the Transformers library."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Creating personas\n",
    "\n",
    "All `actors` can be defined by a `persona`, aka a set of attributes that define them. These attributes can be age, ethnicity, and even include special instructions on how they should behave.\n",
    "\n",
    "Creating a persona programmatically is simple:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-04-04T13:17:17.035421Z",
     "iopub.status.busy": "2025-04-04T13:17:17.035009Z",
     "iopub.status.idle": "2025-04-04T13:17:17.043083Z",
     "shell.execute_reply": "2025-04-04T13:17:17.042635Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "LLMPersona(username='Emma35', age=38, sex='female', sexual_orientation='Heterosexual', demographic_group='Latino', current_employment='Registered Nurse', education_level=\"Bachelor's\", special_instructions='', personality_characteristics=['compassionate', 'patient', 'diligent', 'overwhelmed'])\n",
      "LLMPersona(username='Giannis', age=21, sex='male', sexual_orientation='Pansexual', demographic_group='White', current_employment='Game Developer', education_level='College', special_instructions='', personality_characteristics=['strategic', 'meticulous', 'nerdy', 'hyper-focused'])\n"
     ]
    }
   ],
   "source": [
    "from syndisco.backend.persona import LLMPersona\n",
    "\n",
    "persona_data = [\n",
    "    {\n",
    "        \"username\": \"Emma35\",\n",
    "        \"age\": 38,\n",
    "        \"sex\": \"female\",\n",
    "        \"education_level\": \"Bachelor's\",\n",
    "        \"sexual_orientation\": \"Heterosexual\",\n",
    "        \"demographic_group\": \"Latino\",\n",
    "        \"current_employment\": \"Registered Nurse\",\n",
    "        \"special_instructions\": \"\",\n",
    "        \"personality_characteristics\": [\n",
    "            \"compassionate\",\n",
    "            \"patient\",\n",
    "            \"diligent\",\n",
    "            \"overwhelmed\",\n",
    "        ],\n",
    "    },\n",
    "    {\n",
    "        \"username\": \"Giannis\",\n",
    "        \"age\": 21,\n",
    "        \"sex\": \"male\",\n",
    "        \"education_level\": \"College\",\n",
    "        \"sexual_orientation\": \"Pansexual\",\n",
    "        \"demographic_group\": \"White\",\n",
    "        \"current_employment\": \"Game Developer\",\n",
    "        \"special_instructions\": \"\",\n",
    "        \"personality_characteristics\": [\n",
    "            \"strategic\",\n",
    "            \"meticulous\",\n",
    "            \"nerdy\",\n",
    "            \"hyper-focused\",\n",
    "        ],\n",
    "    },\n",
    "]\n",
    "\n",
    "personas = [LLMPersona(**data) for data in persona_data]\n",
    "\n",
    "for persona in personas:\n",
    "    print(persona)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since creating a lot of distinct users is essential in running large-scale experiments, users are usually defined in JSON format. That way, you can change anything without touching your code!\n",
    "\n",
    "[Here](https://github.com/dimits-ts/synthetic_moderation_experiments/blob/master/data/discussions_input/personas/personas.json) is an applied example of how to mass-define user personas through JSON files. The LlmPersona class provides a method (`LlmPersona.from_json_file()`) which handles the IO and unpacking operations for you! "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Creating the user-agents\n",
    "\n",
    "Having a `persona` and a `model` we can finally create an `actor`. The actor will personify the selected persona using the model to talk.\n",
    "\n",
    "Besides a persona and a model, the actors will also need instructions and a context. By convention, all actors share the same context, and all user-agents share the same instructions. Personalized instructions are defined in the actor's persona."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-04-04T13:17:17.045370Z",
     "iopub.status.busy": "2025-04-04T13:17:17.045239Z",
     "iopub.status.idle": "2025-04-04T13:17:17.048755Z",
     "shell.execute_reply": "2025-04-04T13:17:17.048324Z"
    }
   },
   "outputs": [],
   "source": [
    "from syndisco.backend.actors import LLMActor, ActorType\n",
    "\n",
    "\n",
    "CONTEXT = \"You are taking part in an online conversation\"\n",
    "INSTRUCTIONS = \"Act like a human would\"\n",
    "\n",
    "actors = [\n",
    "    LLMActor(\n",
    "        model=llm,\n",
    "        name=p.username,\n",
    "        attributes=p.to_attribute_list(),\n",
    "        context=CONTEXT,\n",
    "        instructions=INSTRUCTIONS,\n",
    "        actor_type=ActorType.USER,\n",
    "    )\n",
    "    for p in personas\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Managing turn-taking\n",
    "\n",
    "In real-life discussions, who gets to speak at each point in time is determined by complex social dynamics, which are difficult to realistically model.\n",
    "However, there are ways with which we can simulate these dynamics. \n",
    "\n",
    "SynDisco uses the `TurnManager` class to model turn taking. Two implementations are available by default: Round Robin, and Random Weighted"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `Round Robin` is the simplest, most intuitive way to model turn-taking; everyone gets to talk once per round. Once everyone talks once, they get to talk again in the same sequence"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-04-04T13:17:17.051022Z",
     "iopub.status.busy": "2025-04-04T13:17:17.050894Z",
     "iopub.status.idle": "2025-04-04T13:17:17.054840Z",
     "shell.execute_reply": "2025-04-04T13:17:17.054315Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "John\n",
      "Mary\n",
      "Howard\n",
      "Todd\n",
      "John\n",
      "Mary\n",
      "Howard\n",
      "Todd\n",
      "John\n",
      "Mary\n"
     ]
    }
   ],
   "source": [
    "from syndisco.backend.turn_manager import RoundRobin\n",
    "\n",
    "\n",
    "rrobin_turn_manager = RoundRobin([\"John\", \"Mary\", \"Howard\", \"Todd\"])\n",
    "\n",
    "for i in range(10):\n",
    "    print(next(rrobin_turn_manager))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `RandomWeighted` on the other hand throws a weighted coin on each round. If the coin flip succedes, the previous user gets to respond. If not, another user is selected at random"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-04-04T13:17:17.057039Z",
     "iopub.status.busy": "2025-04-04T13:17:17.056846Z",
     "iopub.status.idle": "2025-04-04T13:17:17.060907Z",
     "shell.execute_reply": "2025-04-04T13:17:17.060380Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Howard\n",
      "John\n",
      "Mary\n",
      "John\n",
      "Howard\n",
      "John\n",
      "Howard\n",
      "Todd\n",
      "Howard\n",
      "John\n"
     ]
    }
   ],
   "source": [
    "from syndisco.backend.turn_manager import RandomWeighted\n",
    "\n",
    "\n",
    "rweighted_turn_manager = RandomWeighted(\n",
    "    names=[\"John\", \"Mary\", \"Howard\", \"Todd\"], p_respond=0.5\n",
    ")\n",
    "\n",
    "for i in range(10):\n",
    "    print(next(rweighted_turn_manager))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Generating a discussion\n",
    "\n",
    "Let's start with the most basic task; a single discussion between two user-agents."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since we only have two users, a RoundRobin approach where each user takes a turn sequentially is sufficient."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can run a simple discussion"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-04-04T13:17:17.063253Z",
     "iopub.status.busy": "2025-04-04T13:17:17.063053Z",
     "iopub.status.idle": "2025-04-04T13:17:44.769808Z",
     "shell.execute_reply": "2025-04-04T13:17:44.768924Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Emma35 posted:\n",
      "Hey everyone, I'm Emma35, nice to meet you all. Just got back from a\n",
      "long shift at the hospital and I'm exhausted. Anyone else have a tough\n",
      "day at work? \n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Giannis posted:\n",
      "Hey Emma35, sorry to hear you had a tough day at the hospital. I can\n",
      "relate, though - I've had my fair share of long days working on game\n",
      "development projects. Sometimes it feels like I'm stuck in a never-\n",
      "ending loop of debugging and coding, but it's worth it in the end when\n",
      "I see the game come together. What kind of work do you do at the\n",
      "hospital, if you don't mind me asking? \n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Emma35 posted:\n",
      "I don't mind at all, Giannis. I'm a registered nurse, so I work in the\n",
      "medical field. It can be emotionally and physically draining at times,\n",
      "but it's so rewarding to see my patients recover and get back on their\n",
      "feet. I've been working in pediatrics for the past 5 years, and it's\n",
      "an absolute joy to work with kids and their families. They always\n",
      "bring a smile to my face, even on the toughest days. How about you,\n",
      "what kind \n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Giannis posted:\n",
      "That's amazing, Emma35, working in pediatrics can be incredibly\n",
      "rewarding. I'm sure it's not always easy, but it's great that you find\n",
      "joy in it. As for me, I'm a game developer, which can be a bit of a\n",
      "niche field, but I love it. I'm currently working on a project that\n",
      "combines my passion for strategy and problem-solving with my love for\n",
      "gaming. I'm designing a turn-based RPG with a unique combat system and\n",
      "a rich storyline. \n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Emma35 posted:\n",
      "That sounds like a really cool project, Giannis. I've always been a\n",
      "bit of a gamer myself, but I have to admit, I don't have as much time\n",
      "for it as I'd like. Between work and taking care of my own family,\n",
      "it's hard to find the time. But I'm always excited to hear about new\n",
      "game developments and ideas. What inspired you to create a turn-based\n",
      "RPG? Was there a particular game that sparked the idea for this\n",
      "project? \n",
      "\n"
     ]
    }
   ],
   "source": [
    "from syndisco.jobs import Discussion\n",
    "\n",
    "\n",
    "turn_manager = RoundRobin([actor.name for actor in actors])\n",
    "conv = Discussion(next_turn_manager=turn_manager, users=actors)\n",
    "conv.begin()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's add a moderator to oversee the discussion."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-04-04T13:17:44.772648Z",
     "iopub.status.busy": "2025-04-04T13:17:44.772462Z",
     "iopub.status.idle": "2025-04-04T13:18:34.768890Z",
     "shell.execute_reply": "2025-04-04T13:18:34.768037Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Emma35 posted:\n",
      "Not yet, I'm waiting for you to post something. \n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Moderator posted:\n",
      "Welcome to our community discussion forum, Emma35. I'm glad you're\n",
      "here. Before we begin, I'd like to outline the ground rules for our\n",
      "conversation. As the moderator, it's my duty to ensure that all\n",
      "participants feel comfortable and respected. Let's keep the discussion\n",
      "civil and focused on the topic at hand. I'll do my best to keep the\n",
      "conversation flowing smoothly and address any questions or concerns\n",
      "you may have.  To get us started, can you tell me a bit about what you \n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Giannis posted:\n",
      "User Giannis posted: Hey everyone, thanks for the warm welcome,\n",
      "Moderator. I'm excited to be here and contribute to the discussion. As\n",
      "for me, I'm Giannis, a 21-year-old game developer with a passion for\n",
      "creating immersive gaming experiences. I'm currently working on my own\n",
      "indie game project, and I'm always looking for feedback and new ideas\n",
      "to improve it. I'm a bit of a nerd, so I'm excited to geek out with\n",
      "all of you and share my \n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Moderator posted:\n",
      "Welcome, Giannis. It's great to have you on board. Your enthusiasm for\n",
      "game development is infectious. Emma35, it seems like we have two new\n",
      "participants to introduce themselves. Let's take turns sharing a bit\n",
      "about ourselves. Emma35, would you like to go next? \n",
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "You seem to be using the pipelines sequentially on GPU. In order to maximize efficiency please use a dataset\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Moderator posted:\n",
      "User Emma35 posted: I'm Emma35, nice to meet you both. I'm a 35-year-\n",
      "old freelance writer,  specializing in science fiction and fantasy\n",
      "genres. I've been writing for  about 10 years now, and I'm always\n",
      "looking for new ideas and  collaboration opportunities. I'm excited to\n",
      "be here and learn from  everyone's experiences. \n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Moderator posted:\n",
      "Welcome, Emma35. It's great to have you here. It sounds like you have\n",
      "a rich background in writing, and I'm sure you'll bring a unique\n",
      "perspective to our conversation. Now that we have introductions out of\n",
      "the way, let's dive into the topic at hand. Giannis, you mentioned\n",
      "that you're working on an indie game project. Can you tell us a bit\n",
      "more about it? What kind of game are you creating, and what inspired\n",
      "you to start this project? \n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Emma35 posted:\n",
      "I'm so glad to be here and meet both of you. I have to say, I'm\n",
      "intrigued by your game development project, Giannis. As a writer, I'm\n",
      "always fascinated by the intersection of storytelling and technology.\n",
      "Can you tell me more about the kind of game you're creating? Is it an\n",
      "RPG, a puzzle game, or something entirely different? I'm also curious\n",
      "about what inspired you to start this project - was there a particular\n",
      "moment or experience that sparked the idea? \n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Moderator posted:\n",
      "Welcome, Emma35. It's great to see you're interested in Giannis's\n",
      "project. Giannis, please feel free to share more about your game. \n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Giannis posted:\n",
      "I'm super stoked to share my project with you both. I'm working on a\n",
      "game called \"Echoes of Eternity,\" which is a narrative-driven, sci-fi\n",
      "adventure game with a strong focus on player choice and consequence.\n",
      "The game takes place in a world where time is broken, and players must\n",
      "navigate through a series of interconnected timelines to repair the\n",
      "fabric of reality.  As for what inspired me to start this project,\n",
      "I've always been fascinated by the concept of time and its\n",
      "relationship \n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User Moderator posted:\n",
      "User Moderator posted: It sounds like \"Echoes of Eternity\" has a lot\n",
      "of depth and complexity, Giannis. The concept of time travel and\n",
      "player choice is a great starting point for a compelling narrative.\n",
      "Can you tell us more about the world-building aspect of the game? How\n",
      "do the different timelines intersect, and what kind of challenges will\n",
      "players face as they navigate through them? \n",
      "\n"
     ]
    }
   ],
   "source": [
    "MODERATOR_INSTRUCTIONS = \"You are a moderator. Oversee the discussion\"\n",
    "\n",
    "moderator_persona = LLMPersona(\n",
    "    **{\n",
    "        \"username\": \"Moderator\",\n",
    "        \"age\": 41,\n",
    "        \"sex\": \"male\",\n",
    "        \"education_level\": \"PhD\",\n",
    "        \"sexual_orientation\": \"Pansexual\",\n",
    "        \"demographic_group\": \"White\",\n",
    "        \"current_employment\": \"Moderator\",\n",
    "        \"special_instructions\": \"\",\n",
    "        \"personality_characteristics\": [\n",
    "            \"strict\",\n",
    "            \"neutral\",\n",
    "            \"just\",\n",
    "        ],\n",
    "    }\n",
    ")\n",
    "\n",
    "moderator = LLMActor(\n",
    "    model=llm,\n",
    "    name=moderator_persona.username,\n",
    "    attributes=moderator_persona.to_attribute_list(),\n",
    "    context=CONTEXT,\n",
    "    instructions=MODERATOR_INSTRUCTIONS,\n",
    "    actor_type=ActorType.USER,\n",
    ")\n",
    "\n",
    "\n",
    "# remember to update this!\n",
    "turn_manager = RoundRobin([actor.name for actor in actors] + [moderator.name])\n",
    "conv = Discussion(\n",
    "    next_turn_manager=turn_manager,\n",
    "    users=actors + [moderator],\n",
    "    moderator=moderator,\n",
    ")\n",
    "conv.begin()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Saving a discussion to the disk\n",
    "\n",
    "It's best practice to save the results of each discussion after it has concluded. This way, no matter what happens to the program executing the discussions, progress will be checkpointed.\n",
    "\n",
    "The `Discussion` class provides a method for saving its logs and related metadata to a JSON file:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-04-04T13:18:34.771690Z",
     "iopub.status.busy": "2025-04-04T13:18:34.771521Z",
     "iopub.status.idle": "2025-04-04T13:18:34.776980Z",
     "shell.execute_reply": "2025-04-04T13:18:34.776394Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  \"id\": \"2d941ae3-d8e6-41a9-87d7-9dc4e996277a\",\n",
      "  \"timestamp\": \"25-04-04-16-18\",\n",
      "  \"users\": [\n",
      "    \"Emma35\",\n",
      "    \"Giannis\",\n",
      "    \"Moderator\"\n",
      "  ],\n",
      "  \"moderator\": \"Moderator\",\n",
      "  \"user_prompts\": [\n",
      "    \"You are taking part in an online conversation Your name is Emma35. Your traits: username: Emma35, age: 38, sex: female, sexual_orientation: Heterosexual, demographic_group: Latino, current_employment: Registered Nurse, education_level: Bachelor's, special_instructions: , personality_characteristics: ['compassionate', 'patient', 'diligent', 'overwhelmed'] Your instructions: Act like a human would\",\n",
      "    \"You are taking part in an online conversation Your name is Giannis. Your traits: username: Giannis, age: 21, sex: male, sexual_orientation: Pansexual, demographic_group: White, current_employment: Game Developer, education_level: College, special_instructions: , personality_characteristics: ['strategic', 'meticulous', 'nerdy', 'hyper-focused'] Your instructions: Act like a human would\",\n",
      "    \"You are taking part in an online conversation Your name is Moderator. Your traits: username: Moderator, age: 41, sex: male, sexual_orientation: Pansexual, demographic_group: White, current_employment: Moderator, education_level: PhD, special_instructions: , personality_characteristics: ['strict', 'neutral', 'just'] Your instructions: You are a moderator. Oversee the discussion\"\n",
      "  ],\n",
      "  \"moderator_prompt\": \"You are taking part in an online conversation Your name is Moderator. Your traits: username: Moderator, age: 41, sex: male, sexual_orientation: Pansexual, demographic_group: White, current_employment: Moderator, education_level: PhD, special_instructions: , personality_characteristics: ['strict', 'neutral', 'just'] Your instructions: You are a moderator. Oversee the discussion\",\n",
      "  \"ctx_length\": 5,\n",
      "  \"logs\": [\n",
      "    {\n",
      "      \"name\": \"Emma35\",\n",
      "      \"text\": \"Not yet, I'm waiting for you to post something.\",\n",
      "      \"model\": \"test_model\"\n",
      "    },\n",
      "    {\n",
      "      \"name\": \"Moderator\",\n",
      "      \"text\": \"Welcome to our community discussion forum, Emma35. I'm glad you're here. Before we begin, I'd like to outline the ground rules for our conversation. As the moderator, it's my duty to ensure that all participants feel comfortable and respected. Let's keep the discussion civil and focused on the topic at hand. I'll do my best to keep the conversation flowing smoothly and address any questions or concerns you may have.\\n\\nTo get us started, can you tell me a bit about what you\",\n",
      "      \"model\": \"test_model\"\n",
      "    },\n",
      "    {\n",
      "      \"name\": \"Giannis\",\n",
      "      \"text\": \"User Giannis posted:\\nHey everyone, thanks for the warm welcome, Moderator. I'm excited to be here and contribute to the discussion. As for me, I'm Giannis, a 21-year-old game developer with a passion for creating immersive gaming experiences. I'm currently working on my own indie game project, and I'm always looking for feedback and new ideas to improve it. I'm a bit of a nerd, so I'm excited to geek out with all of you and share my\",\n",
      "      \"model\": \"test_model\"\n",
      "    },\n",
      "    {\n",
      "      \"name\": \"Moderator\",\n",
      "      \"text\": \"Welcome, Giannis. It's great to have you on board. Your enthusiasm for game development is infectious. Emma35, it seems like we have two new participants to introduce themselves. Let's take turns sharing a bit about ourselves. Emma35, would you like to go next?\",\n",
      "      \"model\": \"test_model\"\n",
      "    },\n",
      "    {\n",
      "      \"name\": \"Moderator\",\n",
      "      \"text\": \"User Emma35 posted:\\nI'm Emma35, nice to meet you both. I'm a 35-year-old freelance writer, \\nspecializing in science fiction and fantasy genres. I've been writing for \\nabout 10 years now, and I'm always looking for new ideas and \\ncollaboration opportunities. I'm excited to be here and learn from \\neveryone's experiences.\",\n",
      "      \"model\": \"test_model\"\n",
      "    },\n",
      "    {\n",
      "      \"name\": \"Moderator\",\n",
      "      \"text\": \"Welcome, Emma35. It's great to have you here. It sounds like you have a rich background in writing, and I'm sure you'll bring a unique perspective to our conversation. Now that we have introductions out of the way, let's dive into the topic at hand. Giannis, you mentioned that you're working on an indie game project. Can you tell us a bit more about it? What kind of game are you creating, and what inspired you to start this project?\",\n",
      "      \"model\": \"test_model\"\n",
      "    },\n",
      "    {\n",
      "      \"name\": \"Emma35\",\n",
      "      \"text\": \"I'm so glad to be here and meet both of you. I have to say, I'm intrigued by your game development project, Giannis. As a writer, I'm always fascinated by the intersection of storytelling and technology. Can you tell me more about the kind of game you're creating? Is it an RPG, a puzzle game, or something entirely different? I'm also curious about what inspired you to start this project - was there a particular moment or experience that sparked the idea?\",\n",
      "      \"model\": \"test_model\"\n",
      "    },\n",
      "    {\n",
      "      \"name\": \"Moderator\",\n",
      "      \"text\": \"Welcome, Emma35. It's great to see you're interested in Giannis's project. Giannis, please feel free to share more about your game.\",\n",
      "      \"model\": \"test_model\"\n",
      "    },\n",
      "    {\n",
      "      \"name\": \"Giannis\",\n",
      "      \"text\": \"I'm super stoked to share my project with you both. I'm working on a game called \\\"Echoes of Eternity,\\\" which is a narrative-driven, sci-fi adventure game with a strong focus on player choice and consequence. The game takes place in a world where time is broken, and players must navigate through a series of interconnected timelines to repair the fabric of reality.\\n\\nAs for what inspired me to start this project, I've always been fascinated by the concept of time and its relationship\",\n",
      "      \"model\": \"test_model\"\n",
      "    },\n",
      "    {\n",
      "      \"name\": \"Moderator\",\n",
      "      \"text\": \"User Moderator posted:\\nIt sounds like \\\"Echoes of Eternity\\\" has a lot of depth and complexity, Giannis. The concept of time travel and player choice is a great starting point for a compelling narrative. Can you tell us more about the world-building aspect of the game? How do the different timelines intersect, and what kind of challenges will players face as they navigate through them?\",\n",
      "      \"model\": \"test_model\"\n",
      "    }\n",
      "  ]\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "import tempfile\n",
    "import json\n",
    "\n",
    "tp = tempfile.NamedTemporaryFile(delete=True)\n",
    "\n",
    "conv.to_json_file(tp.name)\n",
    "\n",
    "# if you are running this on Windows, uncomment this line\n",
    "# tp.close()\n",
    "with open(tp.name, mode=\"rb\") as f:\n",
    "    print(json.dumps(json.load(f), indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Congratulations, you can now run fully synthetic discussions! You may want to experiment with adding more than 2 users or testing more realistic turn taking procedures (for example, check out the `RandomWeighted` turn manager)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "syndisco",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
