Compare commits

...

6 Commits

Author SHA1 Message Date
Kostanjevec 8a092c5602 added more stuff todo 2022-09-04 19:38:38 +02:00
Kostanjevec ae4077db26 fixing bugs... 2022-08-16 10:50:41 +02:00
Kostanjevec a9f2a75442 interval ui stuff and prob_deck removal 2022-08-16 10:50:03 +02:00
Kostanjevec ef1ba946c0 removing prob_deck stuff 2022-08-16 10:44:13 +02:00
Kostanjevec e5c44b8714 collecting all functionality related to this in one file 2022-08-16 10:41:56 +02:00
Kostanjevec 439a53dc7c added due cards and interval info to ui 2022-08-16 10:31:59 +02:00
7 changed files with 166 additions and 79 deletions

View File

@ -52,27 +52,39 @@ If you and at least one other user rate an **item** with a yes then a match will
### Feedback
If you have any questions, feedback, ideas or if you would like contribute, please contact us at gia@kompot.si.
## Build instructions
Comming soon...
## TODO
### Bugs
* email adress bug in matches
### Design issues
#### Sorting and matching
The overlap of this features creates some issues. Interest in terms of sorting is likely lost when an item is read, but it may not be lost in terms of matching.
* The overlap of this features creates some issues. Interest in terms of sorting is likely lost when an item is read, but it may not be lost in terms of matching.
* How to remove cards while still wanting to match on them (absolute interest vs match on "yes")
### Features
#### Links
* cards can be links
* allow importing of links
* db representation of link-cards
* display link in iframe or simmilar
#### Algorithm
* SR-algorithm for decks and appropriate db representation
* algorithm calculates due cards only with the help of rating history and time of rating.
* formula for next interval
* algorithm resets on every 'yes' vote.
### UI
* Flash messages should have an approriate color (error is red...)
* Visual cue to distinguish shared vs private cards
* PDF action to view more than 10 pages.
* Fix matches view
* Email when at least x cards are due, maybe like x = k max_due
* Keyboard support for all actions
* scroll PDF
* links and buttons
### Testing
* there is no testing.

6
app.py
View File

@ -1,4 +1,4 @@
from flask import Flask, redirect, render_template, session, request, url_for
from flask import Flask, redirect, render_template, session, url_for
from auth import login_required, bp as auth_bp
from deck import bp as deck_bp
@ -7,7 +7,6 @@ from sr_session import sr_session
from upload import bp as upload_bp
from matches import bp as matches_bp
from settings import bp as settings_bp
from prob_session import prob_session
from config import CONFIG
@ -31,8 +30,7 @@ def create_app(test_config=None):
@app.route('/deck', methods=["GET", "POST"])
def deck():
return prob_session()
#return sr_session()
return sr_session()
@app.route("/share_button", methods=["GET", "POST"])
def share_button():

45
menu.py
View File

@ -1,9 +1,8 @@
from flask import (
Blueprint, flash, redirect, render_template, request, session, url_for
)
from create_db import Deck, Card, get_session
from deck import get_deck, probabilistic_deck_generator
from create_db import Card, get_session
from sr_session import remaining_by_status, schedule_status
from settings import get_settings
from auth import login
@ -11,7 +10,6 @@ bp = Blueprint('menu', __name__, url_prefix='/menu')
@bp.route("/", methods=("GET", "POST"))
def index():
deck_status = []
dbsession = get_session()
if 'user_id' not in session:
return login()
@ -20,48 +18,22 @@ def index():
user_id = session['user_id']
username = session['username']
print(username)
old_deck = dbsession.query(Deck).filter(Deck.completed == 0, Deck.owner_id == user_id).all()
if old_deck != []:
deck_status = "old"
status = schedule_status(user_id)
remaining_new = remaining_by_status(user_id, "new")
remaining_due = remaining_by_status(user_id, "due")-remaining_new
if request.method == "POST":
action = request.form.get("menu", False) #internetna rešitev, nevem kako, ampak dela, tj. dobi info iz meni buttonov
print(action)
if action == "new_session":
old_deck = dbsession.query(Deck).filter(Deck.completed == 0, Deck.owner_id == user_id).all()
if old_deck != []:
return redirect(url_for("deck"))
#preverimo če so sploh karte v collectionu
print("userID", user_id)
c = dbsession.query(Card).filter(Card.owner_id == user_id).all()
if c == []:
print("ne najdem collectiona")
return render_template("error/no_cards_in_collection.html", username=username)
#ustvari novi vnos v Deck
user_settings = get_settings(user_id)
if user_settings['max_new'] == "0" and user_settings['max_due'] == "0":
flash("Error: Attempted to make deck with 0 cards.")
return render_template("menu.html")
deck = probabilistic_deck_generator(user_id, int(user_settings['max_new']), int(user_settings['max_due']))
cards_by_id = get_deck(deck)
if cards_by_id == "":
return render_template("error/no_cards_in_collection.html", username=username)
else:
number_of_cards = len(cards_by_id.split(","))
print(cards_by_id, number_of_cards)
deck = Deck(cards_by_id=cards_by_id, owner_id=user_id, number_of_cards=number_of_cards, current_card=0, completed=False)
dbsession.add(deck)
dbsession.commit()
dbsession.close()
return redirect(url_for("deck"))
return redirect(url_for("deck"))
elif action == "matches":
return redirect(url_for("matches.index"))
elif action == "upload":
@ -71,8 +43,5 @@ def index():
return render_template("settings.html", username=username, user_id=user_id, settings=settings)
elif action == "instructions":
return render_template("instructions.html", username=username, user_id=user_id)
# elif action == "about":
# return render_template("about.html", username=username, user_id=user_id)
return render_template("menu.html", username=username, deck_status=deck_status)
return render_template("menu.html", username=username, deck_status=status, remaining_due=remaining_due, remaining_new=remaining_new)

View File

@ -4,7 +4,10 @@ from share import share
"""
Refactoring the 'deck' function from app.py
rabi še deck funkcionalnosti, ki so bile prej v menu.py itd...
"""
def prob_session():
dbsession = get_session()
if not 'user_id' in session:
@ -92,3 +95,76 @@ def prob_session():
# Prikaži obrazec
return render_template("deck.html", username=username, card=show_card)
"""
Old menu function
def index():
deck_status = []
dbsession = get_session()
if 'user_id' not in session:
return login()
if 'user_id' in session:
user_id = session['user_id']
username = session['username']
print(username)
old_deck = dbsession.query(Deck).filter(Deck.completed == 0, Deck.owner_id == user_id).all()
if old_deck != []:
deck_status = "old"
if request.method == "POST":
action = request.form.get("menu", False) #internetna rešitev, nevem kako, ampak dela, tj. dobi info iz meni buttonov
print(action)
if action == "new_session":
old_deck = dbsession.query(Deck).filter(Deck.completed == 0, Deck.owner_id == user_id).all()
if old_deck != []:
return redirect(url_for("deck"))
#preverimo če so sploh karte v collectionu
print("userID", user_id)
c = dbsession.query(Card).filter(Card.owner_id == user_id).all()
if c == []:
print("ne najdem collectiona")
return render_template("error/no_cards_in_collection.html", username=username)
#ustvari novi vnos v Deck
user_settings = get_settings(user_id)
if user_settings['max_new'] == "0" and user_settings['max_due'] == "0":
flash("Error: Attempted to make deck with 0 cards.")
return render_template("menu.html")
deck = probabilistic_deck_generator(user_id, int(user_settings['max_new']), int(user_settings['max_due']))
cards_by_id = get_deck(deck)
if cards_by_id == "":
return render_template("error/no_cards_in_collection.html", username=username)
else:
number_of_cards = len(cards_by_id.split(","))
print(cards_by_id, number_of_cards)
deck = Deck(cards_by_id=cards_by_id, owner_id=user_id, number_of_cards=number_of_cards, current_card=0, completed=False)
dbsession.add(deck)
dbsession.commit()
dbsession.close()
return redirect(url_for("deck"))
elif action == "matches":
return redirect(url_for("matches.index"))
elif action == "upload":
return redirect(url_for("upload.index"))
elif action == "settings":
settings = get_settings(user_id)
return render_template("settings.html", username=username, user_id=user_id, settings=settings)
elif action == "instructions":
return render_template("instructions.html", username=username, user_id=user_id)
# elif action == "about":
# return render_template("about.html", username=username, user_id=user_id)
return render_template("menu.html", username=username, deck_status=deck_status)
"""

View File

@ -11,29 +11,34 @@ testing
def autofill_ratings():
dbsession = get_session()
for i in range(100):
card = Rating(user_id="1", card_id="10", rating_value=choice(["Yes", "Maybe", "No"]), rating_time=date.today()-timedelta(choice([i for i in range(100)])))
card = Rating(user_id="1", card_id=choice([10, 13, 14, 75]), rating_value=choice(["Maybe", "No"]), rating_time=date.today()-timedelta(choice([i for i in range(100)])))
dbsession.add(card)
dbsession.commit()
dbsession.close()
return None
autofill_ratings()
"""
Config
"""
maybe_factor = 1.2
no_factor = 2.1
"""
Main fuctions
"""
def calculate_interval(sorted_rates):
maybe_factor = 1.2
no_factor = 2.1
def calculate_interval(sorted_rates, maybe_factor, no_factor):
if sorted_rates == []:
return 1
elif sorted_rates[0].rating_value == "Yes":
return 1
elif sorted_rates[0].rating_value == "Maybe":
sorted_rates.pop(0)
return calculate_interval(sorted_rates) * maybe_factor
return calculate_interval(sorted_rates, maybe_factor, no_factor) * maybe_factor
elif sorted_rates[0].rating_value == "No":
sorted_rates.pop(0)
return calculate_interval(sorted_rates) * no_factor
return calculate_interval(sorted_rates, maybe_factor, no_factor) * no_factor
elif sorted_rates[0].rating_value == "Delete":
return -1 #"Deleted"
@ -49,10 +54,10 @@ def get_interval(card_id):
print("ni kart... kaj zdaj") #@TODO
return None
else:
interval = calculate_interval(sorted_rates_by_card)
interval = calculate_interval(sorted_rates_by_card, maybe_factor, no_factor)
return round(interval)
#to vključuje tudi new...
def is_due(card_id):
dbsession = get_session()
interval = get_interval(card_id)
@ -67,7 +72,7 @@ def is_due(card_id):
return date.today() >= due_date
def list_of_due_card_by_ids(user_id):
def list_of_due_cards_by_ids(user_id):
dbsession = get_session()
cards = dbsession.query(Card).filter(Card.owner_id == user_id).all()
l = []
@ -89,21 +94,8 @@ def list_of_new_cards_by_ids(user_id):
dbsession.close()
return l
#obsolete
def make_deck(user_id, max_new, max_due):
due_cards = list_of_due_card_by_ids(user_id)
new_cards = list_of_new_cards_by_ids(user_id)
due_deck = []
due_deck.append(choices(due_cards, k=max_due))
new_deck = []
new_deck.append(choices(new_cards, k=max_new))
deck = new_deck + due_deck
return deck
#TODO sus ker ni user id?
def rated_today_by_staus (card_status):
"""
Returns number of cards rated today by user by status (new or due)
@ -140,12 +132,48 @@ def get_a_card_by_status(user_id, card_status):
card_id = l[0]
print(l, "00000000" , card_id)
if card_status == "due":
l = list_of_due_card_by_ids(user_id)
l = list_of_due_cards_by_ids(user_id)
card_id = l[0]
print(l, "00000000" , card_id)
return card_id
"""
Export functions
"""
def schedule_status(user_id):
"""
Returns information needed for start/continue/done menu ui
"""
user_settings = get_settings(user_id)
max_new = int(user_settings["max_new"])
max_due = int(user_settings["max_due"])
rated_new = rated_today_by_staus("new")
rated_due = rated_today_by_staus("due")
scheduled_new = len(list_of_new_cards_by_ids(user_id))
scheduled_due = len(list_of_due_cards_by_ids(user_id))-scheduled_new #TODO ta problem je mogoče še kje...
max_today_new = min(max_new, scheduled_new+rated_new)
max_today_due = min(max_due, scheduled_due+rated_due)
if rated_due+rated_new == 0:
return "start"
elif max_today_due+max_today_new > rated_due+rated_new:
return "continue"
elif max_today_due+max_today_new == rated_due+rated_new:
return "done"
else:
raise Exception("Arithmetic problem with collection // rated too much?")
def remaining_by_status(user_id, status):
if status == "new":
l = len(list_of_new_cards_by_ids(user_id))
elif status == "due":
l = len(list_of_due_cards_by_ids(user_id))
return l
"""
Engine
"""
@ -190,7 +218,7 @@ def sr_session():
max_due = user_settings["max_due"]
all_new = len(list_of_new_cards_by_ids(user_id))
all_due = len(list_of_due_card_by_ids(user_id))
all_due = len(list_of_due_cards_by_ids(user_id))
rated_today_new = rated_today_by_staus("new")
rated_today_due = rated_today_by_staus("due")
@ -206,5 +234,7 @@ def sr_session():
return redirect("/menu")
show_card = dbsession.query(Card).get(new_card_id)
interval = get_interval(new_card_id)
return render_template("deck.html", username=username, card=show_card)
#these factors should be better packaged
return render_template("deck.html", username=username, card=show_card, maybe_in=round(interval*maybe_factor), no_in=round(no_factor*interval))

View File

@ -15,9 +15,9 @@
<input type="hidden" name="card_id" value="{{ card['id'] }}">
<!-- <span id="buttonContainer" style="display: flex; justify-content: space-around;"> -->
<span id="buttonContainer">
<button type="submit" name="rate" value="Yes" accesskey="1">Yes</button> <!--ti keyi so alt+shit+key...-->
<button type="submit" name="rate" value="Maybe" accesskey="2">Maybe</button>
<button type="submit" name="rate" value="No" accesskey="3">No</button>
<button type="submit" name="rate" value="Yes" accesskey="1">Yes (1)</button> <!--ti keyi so alt+shit+key...-->
<button type="submit" name="rate" value="Maybe" accesskey="2">Maybe ({{maybe_in}})</button>
<button type="submit" name="rate" value="No" accesskey="3">No ({{no_in}})</button>
<button type="submit" name="rate" value="Delete" accesskey="d">Delete</button>
<button type="submit" name="share" value="Share" accesskey="s">Share</button>
</span>

View File

@ -5,10 +5,12 @@
{% block content %}
<main>
<form method="post">
{% if deck_status == "old" %}
<button type="submit" name="menu" value="new_session">Continue</button>
{% else %}
<button type="submit" name="menu" value="new_session">Start</button>
{% if deck_status == "start" %}
<button type="submit" name="menu" value="new_session">Start {{remaining_new}}/{{remaining_due}}</button>
{% elif deck_status == "continue" %}
<button type="submit" name="menu" value="new_session">Continue {{remaining_new}}/{{remaining_due}}</button>
{% elif deck_status == "done" %}
<button disabled type="submit" name="menu" value="new_session">Start</button>
{% endif %}
<button type="submit" name="menu" value="matches">Matches</button>