-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaccorns_app.py
206 lines (183 loc) · 7.15 KB
/
accorns_app.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
204
205
206
# ******************************************
# ----------- ACCORNS: ADMIN APP -----------
# ******************************************
import shared.shared as shared
import ACCORNS.accorns_shared as accorns_shared
from modules.user_management_module import user_management_server, user_management_ui
from modules.login_module import login_server, login_ui
from modules.topics_module import topics_ui, topics_server
from modules.vectorDB_management_module import (
vectorDB_management_ui,
vectorDB_management_server,
)
from modules.quiz_generation_module import quiz_generation_ui, quiz_generation_server
from modules.feedback_module import feedback_ui, feedback_server
from modules.groups_module import groups_ui, groups_server
# -- General
import os
import traceback
import concurrent.futures
# -- Shiny
from shiny import App, reactive, render, ui
from htmltools import HTML
# The following is needed to prevent async issues when inserting new data in vector DB
# https://github.com/run-llama/llama_index/issues/9978
# import nest_asyncio
# nest_asyncio.apply()
# ----------- SHINY APP -----------
# *********************************
uID = reactive.value(0) # if registered admins make reactive later
pool = concurrent.futures.ThreadPoolExecutor()
# --- SETUP and CHECKS ---
# Generate local databases if needed
if not (shared.remoteAppDB):
print(accorns_shared.createLocalAccornsDB())
print(accorns_shared.createLocalVectorDB())
else:
# Check if a remote database is used and if it's accessible
print(shared.checkRemoteDB(postgresUser=shared.postgresAccorns))
# Add the demo to the database if requested
if shared.addDemo:
print(accorns_shared.addDemo(None))
# --- RENDERING UI ---
# ********************
curDir = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
os.path.join(curDir, "ACCORNS")
# --- UI LAYOUT ---
app_ui = ui.page_fluid(
ui.head_content(
ui.include_css(os.path.join(curDir, "shared", "shared_css", "shared.css")),
ui.include_css(os.path.join(curDir, "ACCORNS", "accorns_css", "accorns.css")),
ui.include_js(os.path.join(curDir, "ACCORNS", "accorns_js", "accorns.js")),
ui.include_js(os.path.join(curDir, "shared", "shared_js", "shared.js")),
),
ui.output_ui("accornsTabs"),
# Customised feedback button (floating at right side of screen)
feedback_ui("feedback"),
id="tab",
title="ACCORNS",
)
# --- SERVER ---
# **************
def server(input, output, session):
# Register the session start in the DB
conn = shared.appDBConn(postgresUser=shared.postgresAccorns)
cursor = conn.cursor()
sID = shared.executeQuery(
cursor,
'INSERT INTO "session" ("shinyToken", "uID", "appID", "start")'
"VALUES(?, 1, 1, ?)",
(session.id, shared.dt()),
lastRowId="sID",
)
conn.commit()
conn.close()
# Check which user is using the app
user = login_server(
"login", postgresUser=shared.postgresAccorns, sessionID=sID, minAdminLevel=2
)
_ = feedback_server("feedback", sID=sID, postgresUser=shared.postgresAccorns)
# Which tabs to show based on the user
@render.ui
@reactive.event(user)
def accornsTabs():
if user.get()["adminLevel"] < 2 or user.get()["adminLevel"] is None:
return ui.TagList(
ui.navset_pill(
# TAB 1 - HOME & LOGIN - shown before login
ui.nav_panel(
"Home",
ui.layout_columns(
ui.card(
ui.card_header("Welcome to ACCORNS"),
HTML("""
<p>To access the ACCORNS you need an admin account. If this is the first time you are accessing the
application, please use the access code provided by your administrator to create an account</p>"""),
),
col_widths=12,
),
login_ui("login"),
),
id="preLoginTabs",
)
)
else:
uiList = ui.TagList(
ui.navset_pill(
# TAB 2 - VECTOR DATABASE
ui.nav_panel(
"Files Database",
vectorDB_management_ui("vectorDB"),
value="vTab",
),
# TAB 3 - TOPICS
ui.nav_panel("Groups", groups_ui("groups"), value="gTab"),
# TAB 4 - TOPICS
ui.nav_panel("Topics", topics_ui("topics"), value="tTab"),
# TAB 5 - QUIZ QUESTIONS
ui.nav_panel(
"Quiz Questions",
# Select a topic and a question with options to add or archive
quiz_generation_ui("quizGeneration"),
value="qTab",
),
# TAB 6 - USER MANAGEMENT
ui.nav_panel(
"User Management",
user_management_ui("userManagement"),
value="uTab",
),
id="postLoginTabs",
)
)
# Server functions for the different tabs are found in their respective modules
groups = groups_server(
"groups", sID=sID, user=user, postgresUser=shared.postgresAccorns
)
topics, concepts = topics_server(
"topics",
sID=sID,
user=user,
groups=groups,
postgresUser=shared.postgresAccorns,
)
_ = user_management_server(
"userManagement", user=user, postgresUser=shared.postgresAccorns
)
files = vectorDB_management_server("vectorDB", user=user, pool=pool)
_ = quiz_generation_server(
"quizGeneration",
sID=sID,
user=user,
topicsx=topics,
groups=groups,
postgresUser=shared.postgresAccorns,
pool=pool,
)
# Tabs to show after successful login
return uiList
# Code to run at the END of the session (i.e. when user disconnects)
_ = session.on_ended(lambda: theEnd())
def theEnd():
# Add logs to the database after user exits
conn = shared.appDBConn(postgresUser=shared.postgresAccorns)
cursor = conn.cursor()
# Register the end of the session and if an error occurred, log it
errMsg = traceback.format_exc().strip()
if errMsg == "NoneType: None":
_ = shared.executeQuery(
cursor,
'UPDATE "session" SET "end" = ? WHERE "sID" = ?',
(shared.dt(), sID),
)
else:
_ = shared.executeQuery(
cursor,
'UPDATE "session" SET "end" = ?, "error" = ? WHERE "sID" = ?',
(shared.dt(), errMsg, sID),
)
conn.commit()
conn.close()
return
app = App(app_ui, server)
app.on_shutdown(pool.shutdown)