-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathchairing.py
203 lines (163 loc) · 9.3 KB
/
chairing.py
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
#!/usr/bin/env python
from datetime import datetime, timedelta
from io import BytesIO
from pandas import read_csv
from reportlab.platypus import SimpleDocTemplate, PageBreak, Paragraph, Table
from reportlab.lib.colors import CMYKColor
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import mm
styles = getSampleStyleSheet()
styles["Heading1"].spaceBefore = 12
styles["Heading1"].spaceAfter = 0
styles["Heading1"].fontSize = 14
black = CMYKColor(0, 0, 0, 1)
BASE_DOC = [
"Dear {chair},",
"Many thanks for agreeing to chair the <b>{session}</b> session at RSECon2022. Please find below some guidance on your role as session chair.",
("Before the session", styles["Heading1"]),
"Your session starts at <b>{start_time} on {day}</b>. Please arrive at room <b>{room}</b> 10 minutes in advance of your session. Your room will have a volunteer present to help the event run smoothly—they will manage such things as moderating the Sli.do questions, ensuring speakers have microphones, and loading up presentations onto the PC to display. Please introduce yourself to your volunteer before the start of the session.",
"The speakers in your session should also be present before the start of the session to introduce themselves. <b>Please confirm the correct pronunciation of their names</b>, especially if the name is unfamiliar to you.",
"In case you need it, the username for the PC is <b>{login_username}</b>, and the password is <b>{login_password}</b>.",
("Before each talk", styles["Heading1"]),
"Please briefly introduce the speaker—a full bio is not needed, just the presenter’s name and the title of the talk. Remind the audience that they can ask questions via Sli.do.",
"Once the speaker begins, set a timer.",
("During each talk", styles["Heading1"]),
"Listen to the talk and identify possible questions to ask.",
"You can keep track of questions by going to Sli.do room <b>{slido_room_number}</b>.",
"Talks are 20 minutes long, with 5 further minutes for questions. After 15 minutes, please show the “5 minutes remaining” sign to the speaker. Similarly, at 18, 19, and 20 minutes show the 2, 1, and 0 minutes remaining signs.",
"If at 20 minutes the speaker shows no sign of concluding, then please stand up and look conspicuous. If after 30 seconds the speaker still shows no sign of concluding, then please interrupt them and ask them to briefly wrap up. (We have the luxury of a few minutes’ buffer between talks. This is to enable people to move between rooms, and to set up the next speaker; it is not to enable speakers to overrun.)",
("After each talk", styles["Heading1"]),
"After each talk is 5 minutes of Q&A. The volunteer will switch the display to show Sli.do. Invite the audience to ask questions and upvote others’ questions at the link on screen.",
"Read out the questions from Sli.do in descending order of upvotes. If there are no questions on Slido at the start of the Q&A then please ask one or two questions yourself.",
"Please do not take questions from the room unless and until questions from Slido have been exhausted.",
"If participants in the room try to get into protracted discussions with the speaker during the Q&A, please encourage them to use the coffee breaks to continue the discussion.",
"Please keep an eye on the time during the Q&A and close off questions in sufficient time to allow movement between rooms and setting up for the next speaker.",
"At this point you can pre-announce the next speaker and the start time of their talk.",
]
PANEL_SECTION = [
("Panels", styles["Heading1"]),
"Panels have their own chairs who take on some of the responsibilities above. Panels last 50 minutes, with 10 minutes slack to allow the panel to assemble and get ready at the start, and also to prepare for the next event at the end.",
"Once the panelists have assembled and have microphones ready, then please introduce the panel chair and topic similarly as for talks. Once the panel chair takes over and starts to introduce the panelists, please start a timer.",
"After 45 minutes, please show the “5 minutes remaining” sign to the panel chair. Similarly, at 48, 49, and 50 minutes show the 2, 1, and 0 minutes remaining signs.",
"If at 50 minutes the panel shows no signs of wrapping up, please stand up and look conspicuous. If after another minute the discussion or monologue is still continuing and the chair hasn’t taken action, then please interrupt them and ask the chair to wrap things up.",
]
REMOTE_SECTION = [
("Remote presenters", styles["Heading1"]),
"Your session includes a remote presenter. Your volunteer will launch Zoom on the PC in full screen mode, and the speaker will present via a shared screen. Please give the speaker audible notification of the remaining time, as they may not be looking at the camera feed from the room while presenting.",
"For reference, the link to join the meeting is {zoom_link}. Meeting ID <b>{zoom_id}</b>, passcode <b>{zoom_passcode}</b>."
]
def format_elements(template, session):
elements = []
for element in template:
if isinstance(element, str):
text = element
style = styles["Normal"]
else:
text, style = element
text = text.format(
chair=session["Confirmed chair"]
if isinstance(session["Confirmed chair"], str)
else "chair",
session=session["Session"],
start_time=session["Session start time"],
day=session["Day"],
room=session["Room"],
login_username=session["PC login username"],
login_password=session["PC login password"],
slido_room_number=session["Slido room number"],
zoom_link=session["Zoom link"],
zoom_id=session["Zoom meeting ID"],
zoom_passcode=session["Zoom passcode"]
)
elements.append(Paragraph(text, style))
return elements
def generate_infosheet(session, talks, filename):
buf = BytesIO()
output_doc = SimpleDocTemplate(
buf,
rightMargin=30 * mm,
leftMargin=15 * mm,
topMargin=15 * mm,
bottomMargin=15 * mm,
pagesize=A4,
)
doc_contents = generate_infosheet_contents(session, talks)
output_doc.build(doc_contents)
with open(filename, "wb") as f:
f.write(buf.getvalue())
def fix_time(oa_time_string):
incorrect_time = datetime.strptime(oa_time_string.split()[3][:-3], "%H:%M")
correct_time = incorrect_time - timedelta(hours=1)
return correct_time.time().strftime("%H:%M")
def tabulate(talks):
table_content = [["Start time", "End time", "Speaker", "Title", "Event type"]]
for _, talk in talks.sort_values("Program submission start time").iterrows():
if talk["Remote presentation"]:
if talk["Event type"].startswith("Panel"):
# Ugly hack to avoid text crashing but avoid consuming too much width
remote_tag = " Remote panelist"
else:
remote_tag = "Remote speaker"
else:
remote_tag = ""
table_content.append(
[
fix_time(talk["Program submission start time"]),
fix_time(talk["Program submission end time"]),
Paragraph(talk["Presenting"]),
Paragraph(talk["Title"]),
talk["Event type"],
remote_tag,
]
)
table_style = [
("LINEABOVE", (0, 1), (-1, 1), 1, black),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
]
table = Table(
table_content, colWidths=[18 * mm, 18 * mm, 28 * mm, 65 * mm, 15 * mm, 15 * mm]
)
table.setStyle(table_style)
table.hAlign = "CENTER"
return table
def generate_infosheet_contents(session, talks):
doc_contents = format_elements(BASE_DOC, session)
if session["Has panel"] == "Yes":
doc_contents.extend(format_elements(PANEL_SECTION, session))
doc_contents.append(PageBreak())
if talks["Remote presentation"].any():
doc_contents.extend(format_elements(REMOTE_SECTION, session))
doc_contents.append(Paragraph("Running order", styles["Heading1"]))
doc_contents.append(tabulate(talks))
return doc_contents
def get_filename(session):
if isinstance(session["Confirmed chair"], str):
filename = session["Confirmed chair"] + " - " + session["Session"] + ".pdf"
else:
filename = session["Session"] + ".pdf"
return filename.replace("/", "_")
def get_talks(session, talks):
return talks[talks["Program session"] == session["Session"]]
def main():
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument("sessions")
parser.add_argument("talks")
parser.add_argument("filename_prefix")
args = parser.parse_args()
sessions = read_csv(args.sessions, dtype={
"Slido room number": str,
"Zoom passcode": str
})
talks = read_csv(args.talks)
for _, session in sessions.iterrows():
if not isinstance(session["Session"], str):
continue
generate_infosheet(
session,
get_talks(session, talks),
args.filename_prefix + "/" + get_filename(session),
)
if __name__ == "__main__":
main()