sepp81 commited on
Commit
6de7b7f
·
verified ·
1 Parent(s): ffc982a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -193
app.py CHANGED
@@ -11,7 +11,6 @@ def local_css():
11
  st.markdown("""
12
  <style>
13
  /* Global Styling */
14
-
15
 
16
  /* Game Container */
17
  .game-container {
@@ -20,19 +19,18 @@ def local_css():
20
  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
21
  margin-bottom: 20px;
22
  }
23
-
24
  /* Sentences Styling */
25
  .sentence-container {
26
  border-left: 4px solid #3498db;
27
  padding: 10px;
28
  margin-bottom: 10px;
29
- transition: all 0.3s ease;
 
 
30
  }
31
-
32
  .sentence-container:hover {
33
  transform: translateX(5px);
34
  }
35
-
36
  /* Buttons */
37
  .stButton>button {
38
  color: white;
@@ -41,46 +39,30 @@ def local_css():
41
  padding: 10px 20px;
42
  transition: all 0.3s ease;
43
  }
44
-
45
  .stButton>button:hover {
46
  transform: scale(1.05);
47
  }
48
-
49
  /* Radio Buttons */
50
  .stRadio>div {
51
  display: flex;
52
  flex-wrap: wrap;
53
  gap: 10px;
54
  }
55
-
56
  .stRadio>div>label {
57
  background-color: #ecf0f1;
58
  padding: 10px;
59
  border-radius: 10px;
60
  transition: all 0.3s ease;
61
  }
62
-
63
  .stRadio>div>label:hover {
64
  background-color: #3498db;
65
  color: white;
66
  }
67
-
68
  /* Sidebar */
69
  .css-1aumxhk {
70
  background-color: #2c3e50;
71
  color: white;
72
  }
73
-
74
- /* Reason Validation */
75
- .reason-valid {
76
- color: #2ecc71;
77
- font-weight: bold;
78
- }
79
-
80
- .reason-invalid {
81
- color: #e74c3c;
82
- font-weight: bold;
83
- }
84
  </style>
85
  """, unsafe_allow_html=True)
86
 
@@ -88,7 +70,7 @@ class RoFTGame:
88
  def __init__(self, dataset_path):
89
  """
90
  Initialize the RoFT Game with the dataset
91
-
92
  :param dataset_path: Path to the roft.csv file
93
  """
94
  self.df = pd.read_csv(dataset_path)
@@ -96,15 +78,14 @@ class RoFTGame:
96
  self.current_sentences = None
97
  self.true_boundary_index = None
98
  self.current_guess_index = None
99
- # Predefined reasons from the dataset description
100
  self.predefined_reasons = [
101
  "grammar",
102
- "repetition",
103
- "irrelevant",
104
- "contradicts_sentence",
105
- "contradicts_knowledge",
106
- "common_sense",
107
- "coreference",
108
  "generic"
109
  ]
110
 
@@ -112,46 +93,32 @@ class RoFTGame:
112
  """
113
  Load a random sample from the dataset
114
  """
115
- # Filter for samples with valid generations and reasons
116
  valid_samples = self.df[
117
- (self.df['gen_body'].notna()) &
118
- (self.df['reason'].notna()) &
119
  (self.df['reason'] != '[]')
120
  ]
121
-
122
- # Select a random sample
123
  self.current_sample = valid_samples.sample(n=1).iloc[0]
124
-
125
- # Prepare sentences
126
  prompt_sentences = self.current_sample['prompt_body'].split('_SEP_')
127
  gen_sentences = self.current_sample['gen_body'].split('_SEP_')
128
 
129
- # Combine and truncate to 10 sentences
130
  combined_sentences = prompt_sentences + gen_sentences
131
  self.current_sentences = combined_sentences[:10]
132
-
133
- # Store true boundary
134
  self.true_boundary_index = self.current_sample['true_boundary_index']
135
-
136
- # Parse reasons from the dataset
137
  try:
138
  self.current_reasons = ast.literal_eval(self.current_sample['reason'])
139
  except:
140
  self.current_reasons = []
141
-
142
- # Reset current guess
143
  self.current_guess_index = None
144
 
145
  def check_guess(self, guess_index):
146
- """
147
- Check if the guess is correct
148
-
149
- :param guess_index: Index of the guessed boundary
150
- :return: Points earned
151
- """
152
  self.current_guess_index = guess_index
153
-
154
- # Calculate points based on closeness to true boundary
155
  if guess_index == self.true_boundary_index:
156
  return 5
157
  elif guess_index > self.true_boundary_index:
@@ -159,191 +126,80 @@ class RoFTGame:
159
  else:
160
  return 0
161
 
162
- def validate_reason(self, user_reason):
163
- """
164
- Validate user's reason against dataset reasons
165
-
166
- :param user_reason: Reason provided by user
167
- :return: Tuple of (is_valid, matching_reasons)
168
- """
169
- # Convert user reason to lowercase for matching
170
- user_reason_lower = user_reason.lower()
171
-
172
- # Check against predefined reasons and current sample's reasons
173
- matching_reasons = []
174
-
175
- # Check predefined reasons
176
- for reason in self.predefined_reasons:
177
- if reason.lower() in user_reason_lower:
178
- matching_reasons.append(reason)
179
-
180
- # Check original sample's reasons
181
- for orig_reason in self.current_reasons:
182
- if orig_reason.lower() in user_reason_lower:
183
- matching_reasons.append(orig_reason)
184
-
185
- return len(matching_reasons) > 0, matching_reasons
186
-
187
- def save_annotation(self, guess_index, reason, reason_validity):
188
- """
189
- Save annotation to a text file
190
-
191
- :param guess_index: Index of the guessed boundary
192
- :param reason: Reason for the guess
193
- :param reason_validity: Validity of the reason
194
- """
195
- # Ensure logs directory exists
196
  os.makedirs('logs', exist_ok=True)
197
-
198
- # Generate unique filename with timestamp
199
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
200
  filename = f'logs/annotation_{timestamp}.txt'
201
-
202
- # Prepare annotation details
203
  annotation_details = [
204
  f"Timestamp: {timestamp}",
205
  f"Model: {self.current_sample['model']}",
206
  f"Dataset: {self.current_sample['dataset']}",
207
  f"Guess Index: {guess_index + 1}",
208
  f"True Boundary Index: {self.true_boundary_index + 1}",
209
- f"Original Dataset Reasons: {self.current_reasons}",
210
- f"User Reason: {reason}",
211
- f"Reason Validity: {reason_validity[0]}",
212
- f"Matching Reasons: {reason_validity[1]}",
213
- "\nFull Text:\n" + "\n".join(f"{i+1}. {sent}" for i, sent in enumerate(self.current_sentences))
214
  ]
215
-
216
- # Write to file
217
  with open(filename, 'w') as f:
218
  f.write("\n".join(annotation_details))
219
 
220
  def main():
221
  local_css()
222
-
223
- # Fancy title with animation
224
  st.markdown("""
225
- <h1 style='text-align: center; color: #2c3e50;
226
- text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
227
- animation: fadeIn 2s;'>
228
  🕵️ Real or Fake Text Detective 🕵️‍♀️
229
  </h1>
230
  """, unsafe_allow_html=True)
231
 
232
- # Game introduction
233
- st.markdown("""
234
- <div class='game-container'>
235
- <p style='text-align: center; font-style: italic;'>
236
- Sharpen your AI detection skills! Read carefully and identify where human writing transforms into machine-generated text.
237
- </p>
238
- </div>
239
- """, unsafe_allow_html=True)
240
-
241
-
242
- # Initialize game session state
243
  if 'game' not in st.session_state:
244
  st.session_state.game = RoFTGame('roft.csv')
245
  st.session_state.game.load_random_sample()
246
  st.session_state.total_points = 0
247
  st.session_state.rounds_played = 0
248
-
249
- # Game container
250
- st.markdown("<div class='game-container'>", unsafe_allow_html=True)
251
-
252
- # Game information in sidebar with icons
253
  st.sidebar.markdown("## 🎮 Game Stats")
254
  st.sidebar.markdown(f"### 🏆 Total Points: {st.session_state.total_points}")
255
  st.sidebar.markdown(f"### 🎲 Rounds Played: {st.session_state.rounds_played}")
256
 
257
- # Animated difficulty indicator
258
- difficulty_map = {
259
- 'gpt2': '🟢 Easy',
260
- 'gpt2-xl': '🟠 Medium',
261
- 'ctrl': '🔴 Hard'
262
- }
263
- current_model = st.session_state.game.current_sample['model']
264
- difficulty = difficulty_map.get(current_model, '⚪ Unknown')
265
- st.sidebar.markdown(f"### 🎯 Difficulty: {difficulty}")
266
-
267
- # Display sentences with enhanced styling
268
  st.subheader("🔍 Examine the Text Carefully")
 
269
  for i, sentence in enumerate(st.session_state.game.current_sentences):
270
- st.markdown(f"""
271
- <div class='sentence-container'>
272
- <strong>{i+1}.</strong> {sentence}
273
- </div>
274
- """, unsafe_allow_html=True)
275
-
276
- # Boundary selection with visual improvements
277
- st.markdown("### 🚨 Detect AI Transition Point")
278
- guess = st.radio(
279
- "Where do you think the AI-generated text begins?",
280
- options=[str(i+1) for i in range(len(st.session_state.game.current_sentences))]
281
- )
282
-
283
- # Reason input with predefined options and visual enhancements
284
- st.markdown("### 🧐 Explain Your Reasoning")
285
- reason_options = st.session_state.game.predefined_reasons
286
- selected_predefined_reasons = st.multiselect(
287
- "Select indicators of AI generation",
288
- options=reason_options
289
- )
290
-
291
- # Custom reason input
292
- custom_reason = st.text_area("Additional detective notes (optional)")
293
-
294
- # Combine predefined and custom reasons
295
- full_reason = " ".join(selected_predefined_reasons)
296
- if custom_reason:
297
- full_reason += f" {custom_reason}"
298
 
299
-
300
-
301
- # Guess submission
302
  if st.button("Submit Guess"):
303
- if not full_reason.strip():
304
- st.warning("Please provide a reason for your guess.")
305
  else:
306
- # Convert guess to index (subtract 1 for 0-based indexing)
307
- guess_index = int(guess) - 1
308
-
309
- # Check guess and update points
310
- points_earned = st.session_state.game.check_guess(guess_index)
311
  st.session_state.total_points += points_earned
312
  st.session_state.rounds_played += 1
313
-
314
- # Validate reason
315
- reason_validity = st.session_state.game.validate_reason(full_reason)
316
-
317
- # Save annotation
318
- st.session_state.game.save_annotation(guess_index, full_reason, reason_validity)
319
-
320
- # Show results
321
  st.subheader("Results")
322
- st.write(f"Your Guess: Sentence {guess}")
323
  st.write(f"Actual Boundary: Sentence {st.session_state.game.true_boundary_index + 1}")
324
  st.write(f"Points Earned: {points_earned}")
325
-
326
- # Display reason validation
327
- st.write("Reason Validation:")
328
- st.write(f"Valid Reason: {reason_validity[0]}")
329
- if reason_validity[1]:
330
- st.write("Matching Reasons:", ", ".join(reason_validity[1]))
331
-
332
- # Option to continue
 
333
  if st.button("Next Round"):
334
  st.session_state.game.load_random_sample()
335
  st.experimental_rerun()
336
-
337
- st.markdown("</div>", unsafe_allow_html=True)
338
 
339
- # Optional: Show metadata for current sample
340
- if st.checkbox("Show Sample Metadata"):
341
- st.write("Current Sample Details:")
342
- sample = st.session_state.game.current_sample
343
- st.write(f"Model: {sample['model']}")
344
- st.write(f"Dataset: {sample['dataset']}")
345
- st.write(f"Sampling Strategy (p): {sample['dec_strat_value']}")
346
- st.write(f"Original Reasons: {st.session_state.game.current_reasons}")
347
 
348
  if __name__ == "__main__":
349
  main()
 
11
  st.markdown("""
12
  <style>
13
  /* Global Styling */
 
14
 
15
  /* Game Container */
16
  .game-container {
 
19
  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
20
  margin-bottom: 20px;
21
  }
 
22
  /* Sentences Styling */
23
  .sentence-container {
24
  border-left: 4px solid #3498db;
25
  padding: 10px;
26
  margin-bottom: 10px;
27
+ display: flex;
28
+ align-items: center;
29
+ justify-content: space-between;
30
  }
 
31
  .sentence-container:hover {
32
  transform: translateX(5px);
33
  }
 
34
  /* Buttons */
35
  .stButton>button {
36
  color: white;
 
39
  padding: 10px 20px;
40
  transition: all 0.3s ease;
41
  }
 
42
  .stButton>button:hover {
43
  transform: scale(1.05);
44
  }
 
45
  /* Radio Buttons */
46
  .stRadio>div {
47
  display: flex;
48
  flex-wrap: wrap;
49
  gap: 10px;
50
  }
 
51
  .stRadio>div>label {
52
  background-color: #ecf0f1;
53
  padding: 10px;
54
  border-radius: 10px;
55
  transition: all 0.3s ease;
56
  }
 
57
  .stRadio>div>label:hover {
58
  background-color: #3498db;
59
  color: white;
60
  }
 
61
  /* Sidebar */
62
  .css-1aumxhk {
63
  background-color: #2c3e50;
64
  color: white;
65
  }
 
 
 
 
 
 
 
 
 
 
 
66
  </style>
67
  """, unsafe_allow_html=True)
68
 
 
70
  def __init__(self, dataset_path):
71
  """
72
  Initialize the RoFT Game with the dataset
73
+
74
  :param dataset_path: Path to the roft.csv file
75
  """
76
  self.df = pd.read_csv(dataset_path)
 
78
  self.current_sentences = None
79
  self.true_boundary_index = None
80
  self.current_guess_index = None
 
81
  self.predefined_reasons = [
82
  "grammar",
83
+ "repetition",
84
+ "irrelevant",
85
+ "contradicts_sentence",
86
+ "contradicts_knowledge",
87
+ "common_sense",
88
+ "coreference",
89
  "generic"
90
  ]
91
 
 
93
  """
94
  Load a random sample from the dataset
95
  """
 
96
  valid_samples = self.df[
97
+ (self.df['gen_body'].notna()) &
98
+ (self.df['reason'].notna()) &
99
  (self.df['reason'] != '[]')
100
  ]
101
+
 
102
  self.current_sample = valid_samples.sample(n=1).iloc[0]
103
+
 
104
  prompt_sentences = self.current_sample['prompt_body'].split('_SEP_')
105
  gen_sentences = self.current_sample['gen_body'].split('_SEP_')
106
 
 
107
  combined_sentences = prompt_sentences + gen_sentences
108
  self.current_sentences = combined_sentences[:10]
109
+
 
110
  self.true_boundary_index = self.current_sample['true_boundary_index']
111
+
 
112
  try:
113
  self.current_reasons = ast.literal_eval(self.current_sample['reason'])
114
  except:
115
  self.current_reasons = []
116
+
 
117
  self.current_guess_index = None
118
 
119
  def check_guess(self, guess_index):
 
 
 
 
 
 
120
  self.current_guess_index = guess_index
121
+
 
122
  if guess_index == self.true_boundary_index:
123
  return 5
124
  elif guess_index > self.true_boundary_index:
 
126
  else:
127
  return 0
128
 
129
+ def save_annotation(self, guess_index, reason):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  os.makedirs('logs', exist_ok=True)
 
 
131
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
132
  filename = f'logs/annotation_{timestamp}.txt'
133
+
 
134
  annotation_details = [
135
  f"Timestamp: {timestamp}",
136
  f"Model: {self.current_sample['model']}",
137
  f"Dataset: {self.current_sample['dataset']}",
138
  f"Guess Index: {guess_index + 1}",
139
  f"True Boundary Index: {self.true_boundary_index + 1}",
140
+ f"User Reason: {reason}"
 
 
 
 
141
  ]
142
+
 
143
  with open(filename, 'w') as f:
144
  f.write("\n".join(annotation_details))
145
 
146
  def main():
147
  local_css()
148
+
 
149
  st.markdown("""
150
+ <h1 style='text-align: center; color: #2c3e50;'>
 
 
151
  🕵️ Real or Fake Text Detective 🕵️‍♀️
152
  </h1>
153
  """, unsafe_allow_html=True)
154
 
 
 
 
 
 
 
 
 
 
 
 
155
  if 'game' not in st.session_state:
156
  st.session_state.game = RoFTGame('roft.csv')
157
  st.session_state.game.load_random_sample()
158
  st.session_state.total_points = 0
159
  st.session_state.rounds_played = 0
160
+
 
 
 
 
161
  st.sidebar.markdown("## 🎮 Game Stats")
162
  st.sidebar.markdown(f"### 🏆 Total Points: {st.session_state.total_points}")
163
  st.sidebar.markdown(f"### 🎲 Rounds Played: {st.session_state.rounds_played}")
164
 
165
+ st.markdown("<div class='game-container'>", unsafe_allow_html=True)
166
+
 
 
 
 
 
 
 
 
 
167
  st.subheader("🔍 Examine the Text Carefully")
168
+ guess = None
169
  for i, sentence in enumerate(st.session_state.game.current_sentences):
170
+ col1, col2 = st.columns([9, 1])
171
+ with col1:
172
+ st.markdown(f"<div class='sentence-container'><strong>{i+1}.</strong> {sentence}</div>", unsafe_allow_html=True)
173
+ with col2:
174
+ if st.radio("", ["", str(i + 1)], key=f"guess_{i}"):
175
+ guess = i
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
 
 
 
177
  if st.button("Submit Guess"):
178
+ if guess is None:
179
+ st.warning("Please select where the AI-generated text begins.")
180
  else:
181
+ points_earned = st.session_state.game.check_guess(guess)
 
 
 
 
182
  st.session_state.total_points += points_earned
183
  st.session_state.rounds_played += 1
184
+
 
 
 
 
 
 
 
185
  st.subheader("Results")
186
+ st.write(f"Your Guess: Sentence {guess + 1}")
187
  st.write(f"Actual Boundary: Sentence {st.session_state.game.true_boundary_index + 1}")
188
  st.write(f"Points Earned: {points_earned}")
189
+
190
+ if points_earned > 0:
191
+ reason = st.text_area("Explain Your Reason")
192
+ if reason:
193
+ st.session_state.game.save_annotation(guess, reason)
194
+ st.success("Reason saved successfully.")
195
+ else:
196
+ st.info("You didn't get the boundary right. Try again in the next round!")
197
+
198
  if st.button("Next Round"):
199
  st.session_state.game.load_random_sample()
200
  st.experimental_rerun()
 
 
201
 
202
+ st.markdown("</div>", unsafe_allow_html=True)
 
 
 
 
 
 
 
203
 
204
  if __name__ == "__main__":
205
  main()