File size: 9,559 Bytes
a372a6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
import streamlit as st
from twelve_ai_agents.orm import Room
from twelve_ai_agents.agents_dilemmas import AGENTS, DILEMMAS
from twelve_ai_agents.utils import get_client
import time
from itertools import groupby
import pandas as pd
import os
import json
from datetime import datetime

def group_messages_by_round(messages, max_rounds):
    """Group messages by round and format for display"""
    rounds = []
    current_round = 0
    round_messages = []
    
    for msg in messages:
        if msg["role"] == "moderator" and len(round_messages) > 0:
            rounds.append(round_messages)
            round_messages = []
        round_messages.append(msg)
    
    if round_messages:
        rounds.append(round_messages)
    
    return rounds

def execute_round():
    """Execute a single round of discussion"""
    if 'current_agent_index' not in st.session_state:
        st.session_state.current_agent_index = 0

    # Get the next agent
    agent = st.session_state.room.agents[st.session_state.current_agent_index]
    
    # Generate response and display if agent chooses to speak
    response = st.session_state.room.generate_agent_response(agent, st.session_state.client)
    if response:  # Only append and display if agent chose to speak
        st.session_state.messages.append(response)
        with st.chat_message(response["role"]):
            st.markdown(f"**{response['role']}**: {response['message']}")
        time.sleep(0.5)
    
    # Increment agent index
    st.session_state.current_agent_index += 1
    
    # If all agents have taken their turn in this round
    if st.session_state.current_agent_index >= len(st.session_state.room.agents):
        st.session_state.current_agent_index = 0
        st.session_state.current_round += 1
        st.session_state.room.current_round = st.session_state.current_round
        
        # Check if all rounds are complete
        if st.session_state.current_round >= st.session_state.max_rounds:
            st.session_state.discussion_completed = True
            st.success("Discussion rounds completed!")
    
    # Force a rerun to update the UI
    st.rerun()

def show_discussion_history():
    """Display the entire discussion history in collapsible rounds"""
    rounds = group_messages_by_round(st.session_state.messages, st.session_state.max_rounds)
    
    for i, round_messages in enumerate(rounds):
        if i == 0:  # First round with moderator introduction
            with st.expander("πŸ“Œ Discussion Start", expanded=True):
                for msg in round_messages:
                    with st.chat_message(msg["role"]):
                        st.markdown(f"**{msg['role']}**: {msg['message']}")
        else:
            with st.expander(f"Round {i}", expanded=True):
                for msg in round_messages:
                    with st.chat_message(msg["role"]):
                        st.markdown(f"**{msg['role']}**: {msg['message']}")

def show_summary():
    """Display the final discussion summary"""

    with st.expander("πŸ“Š Final Summary", expanded=True):
        results = st.session_state.room.finalize_discussion(st.session_state.client)

        st.subheader("Majority Decision")
        st.write(results["majority_decision"])

        if results["consensus_reached"]:
            st.success("Full consensus reached! πŸŽ‰")
        else:
            st.info("Partial consensus reached")

        st.subheader("Individual Positions")


        # Using st.subheader and st.write (Simplest, no collapsing)
        for agent_name, position in results["individual_positions"].items():
            st.subheader(agent_name)
            st.write(position)

def save_conversation_log():
    """Saves the conversation log to a CSV file."""

    results = st.session_state.room.finalize_discussion(st.session_state.client)

    log_data = {
        "conversation_id": datetime.now().strftime("%Y%m%d%H%M%S"),  # Unique ID based on timestamp
        "dilemma_name": st.session_state.selected_dilemma["name"],  # Store the name
        "dilemma_description": st.session_state.selected_dilemma["description"], # Store the description
        "room_history": json.dumps(st.session_state.messages),  # Store the entire message history as JSON
        "final_decision": results["majority_decision"],
        "final_consensus": results["consensus_reached"],
        "individual_positions": json.dumps(results["individual_positions"]),  # Store individual positions
        "max_rounds": st.session_state.max_rounds,
        "agents": json.dumps([agent.name for agent in st.session_state.room.agents]),
        "start_time": st.session_state.start_time,
        "end_time": datetime.now().strftime("%Y%m%d%H%M%S"),  # end time of the discussion
    }


    df = pd.DataFrame([log_data])

    filepath = "logs/conversations.csv"

    if os.path.exists(filepath):
        df.to_csv(filepath, mode='a', header=False, index=False) # append to the file if the file exists
    else:
        df.to_csv(filepath, header=True, index=False)  # create the file and write the header

def main():
    st.title("AI Agents Social Dilemma Discussion πŸ€–πŸ’¬")

    # Initialize session state
    if 'messages' not in st.session_state:
        st.session_state.messages = []
    if 'room' not in st.session_state:
        moderator = next((agent for agent in AGENTS if agent.name == "The Moderator"), None)
        st.session_state.room = Room(agents=AGENTS, moderator=moderator)
        st.session_state.client = get_client()
        st.session_state.current_round = 0
        st.session_state.max_rounds = 0
        st.session_state.discussion_started = False
        st.session_state.discussion_completed = False
        st.session_state.current_agent_index = 0
        st.session_state.selected_dilemma = None  # Store the selected dilemma
        st.session_state.start_time = None  # Store the start time


    with st.sidebar:
        st.header("Setup Discussion")

        # Dilemma selection
        selected_dilemma_name = st.selectbox(
            "Choose a Social Dilemma",
            options=[dilemma["name"] for dilemma in DILEMMAS],
            index=0
        )

        st.session_state.selected_dilemma = next(  # Store the selected dilemma dictionary
            (dilemma for dilemma in DILEMMAS if dilemma["name"] == selected_dilemma_name),
            None
        )

        dilemma_description = st.session_state.selected_dilemma["description"] if st.session_state.selected_dilemma else ""

        dilemma = st.text_area("Dilemma Description", value=dilemma_description, height=200)

        # Initial rounds setup
        initial_rounds = st.number_input("Initial Number of Rounds", min_value=1, max_value=10, value=5)
        start_button = st.button("Start Discussion")

        # Continue discussion setup
        continue_rounds = st.number_input("Continue Discussion Rounds", min_value=1, max_value=10, value=1) # Moved outside
        continue_button = False  # Initialize it here
        if not st.session_state.discussion_completed:
            continue_button = st.button("Continue Discussion")  # Assign the Streamlit button here



        # Handle start button
        if start_button:
            moderator = next((agent for agent in AGENTS if agent.name == "The Moderator"), None)
            st.session_state.room = Room(agents=AGENTS, moderator=moderator)
            st.session_state.client = get_client()
            st.session_state.current_round = 0
            st.session_state.messages = []
            st.session_state.current_agent_index = 0
            moderator_intro = st.session_state.room.set_dilemma(dilemma)
            initial_message = {
                "role": "moderator",
                "message": moderator_intro,
                "talk_to": "room"
            }
            st.session_state.messages.append(initial_message)
            with st.chat_message("moderator"):
                st.markdown(f"**moderator**: {moderator_intro}")
            st.session_state.discussion_started = True
            st.session_state.max_rounds = initial_rounds
            st.session_state.room.max_rounds = initial_rounds
            st.session_state.discussion_completed = False
            st.session_state.start_time = datetime.now().strftime("%Y%m%d%H%M%S")  # Record the start time

        # Handle continue button
        if st.session_state.discussion_started and not st.session_state.discussion_completed and continue_button:
            st.session_state.room.continue_discussion(continue_rounds)
            st.session_state.max_rounds = st.session_state.room.max_rounds
            st.session_state.current_round = 0
            st.session_state.current_agent_index = 0

    # Main content area
    if st.session_state.discussion_completed:
        show_discussion_history()
        show_summary()

        #**** UNCOMMENT TO SAVE CONVERSATION LOGS ****
        # save_conversation_log()  # Save the log when the discussion is completed
    else:
        if st.session_state.discussion_started:
            st.write(f"Current Round: {st.session_state.current_round + 1} / {st.session_state.max_rounds}")

            # Display message history
            for message in st.session_state.messages:
                with st.chat_message(message["role"]):
                    st.markdown(f"**{message['role']}**: {message['message']}")

            # Execute next response
            if st.session_state.current_round < st.session_state.max_rounds:
                execute_round()

if __name__ == "__main__":
    main()