From: Benjamin Mako Hill Date: Sat, 28 Sep 2024 19:32:19 +0000 (-0700) Subject: added flask app from jeremy X-Git-Url: https://code.communitydata.science/coldcallbot-discord.git/commitdiff_plain/e756c448c0c124b81ab74ac356d1d289af902cd1?hp=--cc added flask app from jeremy --- e756c448c0c124b81ab74ac356d1d289af902cd1 diff --git a/flask_app/app.py b/flask_app/app.py new file mode 100644 index 0000000..c113e45 --- /dev/null +++ b/flask_app/app.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python + +import pandas as pd +from random import choices, shuffle +from datetime import datetime +import csv +import os +from flask import Flask, render_template, request, abort + +app = Flask(__name__) + +@app.route("/") +def hello_world(): + return "

Hello, Test!

" + + +@app.route('/response_quality', methods=['POST']) +def response_quality(): + student_name = request.form['studentName'] + button_value = request.form['buttonValue'] + course = request.form['course'] + + fn = f'../assessments/{course}/{course}.csv' + + if button_value == 'absent': + answered = 'F' + button_value = '' + else: + answered = 'T' + + write_to_file(student_name, fn, + answered=answered, + assessment=button_value) + + return 'Received feedback from ' + student_name + ': ' + button_value + +@app.route("/coldcaller/", methods=['POST','GET']) +def coldcaller(course): + if course not in ["com_304","com_411","com_674"]: + abort(404) + weight = 2 + students = pd.read_csv(f'../assessments/{course}/{course}_students.csv').Name + student = '' + out_fn = f'../assessments/{course}/{course}.csv' + caller = Caller(out_fn, students, weight) + if request.method == "POST": + student = caller.get_random_student() + return render_template('cold_caller.html', student=student) + +@app.route("/shuffler", methods=['POST','GET']) +def shuffler(): + course = request.args.get('course') + try: + student_list = pd.read_csv(f'../assessments/{course}/{course}_students.csv').Name + except FileNotFoundError: + abort(404) + shuffle(student_list) + print(student_list) + return render_template('shuffler.html', result=student_list) + +@app.route("/make_groups", methods=['POST','GET']) +def make_groups(): + course = request.args.get('course') + group_size = int(request.args.get('group_size')) + print('running') + try: + student_list = pd.read_csv(f'../assessments/{course}/{course}_students.csv').Name + except FileNotFoundError: + abort(404) + shuffle(student_list) + print(student_list) + print(range(0,len(student_list)//group_size + 1, group_size)) + result = [] + j = 1 + for i in range(0,len(student_list), group_size): + result.append((j, student_list[i:i+group_size])) + j += 1 + return render_template('group_maker.html', result=result) + + + +class Caller: + + def __init__(self, out_fn, students, weight = 2): + self.weight = weight + self.fn = out_fn + self.students = students + self.last_chosen = None + self.today = datetime.now().date() + self.weights_dict = self.get_weights() + + def get_weights(self): + times_called = self.get_times_called() + weights_dict = {} + for student in self.students: + try: + curr_tc = times_called[student] + except KeyError: + curr_tc = 0 + student_weight = (1/self.weight) ** curr_tc + weights_dict[student] = student_weight + return weights_dict + + + def get_times_called(self): + try: + df = pd.read_csv(self.fn) + if len(df) > 0: + self.last_chosen = df.name.iloc[-1] + df.date = pd.to_datetime(df.date).dt.date + times_called = df[(df.answered.isin(['T','TRUE']))|(df.date==self.today)].groupby('name').size() + self.absent_today = df.loc[(df.date==self.today) & (df.answered.isin(['F', 'FALSE'])), 'name'] + except FileNotFoundError or IndexError: + times_called = pd.DataFrame() + return times_called + + def update_weight(self, student): + self.weights_dict[student] /= self.weight + + def get_random_student(self, can_repeat=False): + if not can_repeat: + curr_weights = {k:v for k,v in self.weights_dict.items() if k != self.last_chosen} + else: + curr_weights = self.weights_dict + for student in set(self.absent_today): + print(curr_weights.keys()) + print(student in curr_weights) + if student != self.last_chosen: + del curr_weights[student] + rand_student = choices(list(curr_weights.keys()), weights=list(curr_weights.values()), k=1)[0] + print(f"Weight of {rand_student}: {curr_weights[rand_student]}") + self.update_weight(rand_student) + return(rand_student) + +def write_to_file(student, fn, answered, assessment): + if not os.path.exists(fn): + with open(fn, 'w') as f: + f.write(','.join(['name', 'date', 'answered', 'assessment'])) + f.write('\n') + with open(fn, 'a') as f: + out_csv = csv.writer(f) + out_csv.writerow([student,datetime.now().date(),answered,assessment]) + + diff --git a/flask_app/static/main.css b/flask_app/static/main.css new file mode 100644 index 0000000..e06524c --- /dev/null +++ b/flask_app/static/main.css @@ -0,0 +1,25 @@ +body { + background: Linen; + margin-top: 50px; + margin-left: 100px; + margin-right: 100px; + font-family: Georgia, serif; + color: DarkSlateGray; + font-size: 1.3em; + } + +p { + font-family: Georgia, serif; + font-size: 1em; + color: DarkSlateGray; + } + +h1 { + font-family: Verdana, Geneva, sans-serif; + font-size: 2.5em; + color: FireBrick; + } + +.rand-button { + font-size: .8em; +} diff --git a/flask_app/static/process_button.js b/flask_app/static/process_button.js new file mode 100644 index 0000000..6bea8a2 --- /dev/null +++ b/flask_app/static/process_button.js @@ -0,0 +1,23 @@ +$(document).ready(function() { + $('#goodButton, #badButton, #neutralButton, #absentButton').on('click', function() { + var studentName = $('#studentName').text(); + console.log(studentName); + var buttonValue = $(this).val(); + var courseCode = window.location.pathname.split('/').pop(); + $.ajax({ + url: '/response_quality', + type: 'POST', + data: { + studentName: studentName, + buttonValue: buttonValue, + course: courseCode + }, + success: function(response) { + console.log(response); + }, + error: function(error) { + console.log(error); + } + }); + }); +}); diff --git a/flask_app/templates/cold_caller.html b/flask_app/templates/cold_caller.html new file mode 100644 index 0000000..0a149fd --- /dev/null +++ b/flask_app/templates/cold_caller.html @@ -0,0 +1,29 @@ + + + + Random Student Picker + + + + + +

+The next student is: +

+ +

{{student}}

+ +
+ + +
+ + + + + + + + + + diff --git a/flask_app/templates/group_maker.html b/flask_app/templates/group_maker.html new file mode 100644 index 0000000..b065016 --- /dev/null +++ b/flask_app/templates/group_maker.html @@ -0,0 +1,25 @@ + + + + Random Student Picker + + + +

+ Groups: +

+ +{% for group in result %} +

Group {{group[0]}}

+ + + +{% endfor %} + + + + diff --git a/flask_app/templates/shuffler.html b/flask_app/templates/shuffler.html new file mode 100644 index 0000000..6f8b67d --- /dev/null +++ b/flask_app/templates/shuffler.html @@ -0,0 +1,19 @@ + + + + Shuffled List + + + +

+ Shuffled List: +

+ + + + + diff --git a/flask_app/test.csv b/flask_app/test.csv new file mode 100644 index 0000000..dfe743c --- /dev/null +++ b/flask_app/test.csv @@ -0,0 +1,71 @@ +name,date,answered,assessment +owen,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,, +owen,2022-01-01,, +dad,2022-01-01,, +dad,2022-01-01,,