Maxwell Wang commited on
Commit
3e7a501
1 Parent(s): 94f83b5
Files changed (4) hide show
  1. app.py +93 -0
  2. app_utils.py +24 -0
  3. pages/1_Profile.py +72 -0
  4. pages/2_Query.py +124 -0
app.py ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # source .venv/bin/activate
2
+ # streamlit run <>.py
3
+
4
+ import streamlit as st
5
+ import app_utils as util
6
+ from pathlib import Path
7
+ from PIL import Image
8
+ from io import BytesIO
9
+ import requests
10
+ import time
11
+
12
+ st.set_page_config(page_title="SAnDL", page_icon="🩴", layout="wide", initial_sidebar_state="collapsed")
13
+
14
+ # Example URL
15
+ image_url = "https://media.discordapp.net/attachments/1013678935231442944/1175575324210249740/sandll2.png?ex=656bbad6&is=655945d6&hm=d8f4a93a7c3ae90978f820093e2e7c17c18b6125546255afaaeca8ed6716bd4d&=&width=2268&height=486"
16
+
17
+ # Open image from URL
18
+ response = requests.get(image_url)
19
+ img = Image.open(BytesIO(response.content))
20
+
21
+ # close taskbar, page margin, ...
22
+ st.markdown("""
23
+ <style>
24
+ .st-emotion-cache-1yeub2j {
25
+ display: none;
26
+ }
27
+ .st-emotion-cache-79elbk {
28
+ margin-top: -45px;
29
+ }
30
+ .slogan-font {
31
+ font-size:18px !important;
32
+ margin-bottom: 40px;
33
+ margin-top: 0px;
34
+ text-align: center;
35
+ }
36
+ .bolded {
37
+ font-weight: 1000;
38
+ }
39
+ [data-testid="stSidebarNav"] {
40
+ background-image: url(https://media.discordapp.net/attachments/1013678935231442944/1175577023574454402/sandlsmall_2.png?ex=656bbc6b&is=6559476b&hm=c920463c2062c3c42e555224fb0dc0afc5188e9451b45c9eb62c64f297c1a1f1&=&width=596&height=127);
41
+ background-repeat: no-repeat;
42
+ margin-top: 20px;
43
+ background-position: 20px 20px;
44
+ }
45
+ section[data-testid="stSidebar"][aria-expanded="true"]{
46
+ display: none;
47
+ }
48
+ </style>
49
+ """, unsafe_allow_html=True)
50
+
51
+ logincol1, logincol2, logincol3 = st.columns([1, 8, 1])
52
+
53
+ with logincol2:
54
+
55
+ # logo
56
+ st.image(img)
57
+ # caption
58
+ st.markdown('<p class="slogan-font">' + "Developing <span class = \"bolded\">anomaly detection</span> systems for filtration of <span class = \"bolded\">large language model</span> prompts." + '</p>', unsafe_allow_html=True)
59
+
60
+ #login form
61
+ profilecontainer = st.container()
62
+ login_form = profilecontainer.form('Login')
63
+ username = login_form.text_input('Username').lower()
64
+ st.session_state['username'] = username
65
+ password = login_form.text_input('Password', type='password')
66
+ if login_form.form_submit_button('Login'):
67
+ st.session_state.pop('FormSubmitter:Login-Login', None)
68
+
69
+ # deletes all keys from previous logins
70
+ for key in st.session_state.keys():
71
+ if (key != 'username'):
72
+ st.session_state.pop(key)
73
+
74
+ res = requests.post("https://sandl-backend-ny3lmzb4dq-uc.a.run.app/login", json={"email": username, "password": password})
75
+ error = res.status_code
76
+
77
+ # login validation
78
+ if error == 200:
79
+ st.session_state['userdata'] = res.json()["jwt"]
80
+ st.success('Login Successful!', icon="✅")
81
+ util.switch_page("query")
82
+ # username exists in db, but password is incorrect
83
+ elif error == 400:
84
+ st.error('Incorrect Password.', icon="🚨")
85
+ # makes new account
86
+ elif error == 500:
87
+ st.info('Account Not Found: New account created.', icon="ℹ️")
88
+ res = requests.post("https://sandl-backend-ny3lmzb4dq-uc.a.run.app/sign_up", json={"email": username, "password": password})
89
+ res = requests.post("https://sandl-backend-ny3lmzb4dq-uc.a.run.app/login", json={"email": username, "password": password})
90
+ st.session_state['userdata'] = res.json()["jwt"]
91
+ requests.post("https://sandl-backend-ny3lmzb4dq-uc.a.run.app/add_api_key", json={"jwt": st.session_state['userdata']})
92
+ time.sleep(.5)
93
+ util.switch_page("query")
app_utils.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # switch page util
2
+ def switch_page(page_name: str):
3
+ from streamlit.runtime.scriptrunner import RerunData, RerunException
4
+ from streamlit.source_util import get_pages
5
+
6
+ def standardize_name(name: str) -> str:
7
+ return name.lower().replace("_", " ")
8
+
9
+ page_name = standardize_name(page_name)
10
+
11
+ pages = get_pages("app.py")
12
+
13
+ for page_hash, config in pages.items():
14
+ if standardize_name(config["page_name"]) == page_name:
15
+ raise RerunException(
16
+ RerunData(
17
+ page_script_hash=page_hash,
18
+ page_name=page_name,
19
+ )
20
+ )
21
+
22
+ page_names = [standardize_name(config["page_name"]) for config in pages.values()]
23
+
24
+ raise ValueError(f"Could not find page {page_name}. Must be one of {page_names}")
pages/1_Profile.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import streamlit as st;
3
+ import app_utils as util
4
+
5
+ st.set_page_config(page_title="sandl", page_icon="🩴", layout="wide", initial_sidebar_state="collapsed")
6
+
7
+ # goes to login page if not logged in
8
+ try:
9
+ set = st.session_state['username']
10
+ except:
11
+ util.switch_page('app')
12
+ # position: relative;
13
+
14
+ st.markdown("""
15
+ <style>
16
+ .st-emotion-cache-79elbk {
17
+ margin-top: -65px;
18
+ }
19
+ .st-emotion-cache-1wmy9hl {
20
+ margin-top: -32px;
21
+ }
22
+
23
+ .circle-image {
24
+ width: 200px;
25
+ height: 200px;
26
+ border-radius: 25px;
27
+ overflow: hidden;
28
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
29
+ }
30
+
31
+ .circle-image img {
32
+ width: 100%;
33
+ height: 100%;
34
+ object-fit: cover;
35
+ }
36
+ [data-testid="stSidebarNav"] {
37
+ background-image: url(https://media.discordapp.net/attachments/1013678935231442944/1175577023574454402/sandlsmall_2.png?ex=656bbc6b&is=6559476b&hm=c920463c2062c3c42e555224fb0dc0afc5188e9451b45c9eb62c64f297c1a1f1&=&width=596&height=127);
38
+ background-repeat: no-repeat;
39
+ margin-top: 20px;
40
+ background-position: 20px 20px;
41
+ }
42
+ </style>
43
+ """, unsafe_allow_html=True)
44
+
45
+ profilecol1, profilecol2, profilecol3 = st.columns([1, 8, 1])
46
+
47
+ with profilecol1:
48
+ # goes to prompt page
49
+ if st.button('◀ Back'):
50
+ util.switch_page('query')
51
+
52
+ with profilecol2:
53
+ # pfp
54
+ st.write('')
55
+ st.markdown("<div class=\"circle-image\"><img src=\"https://img.pikbest.com/png-images/qiantu/blue-hand-drawn-rounded-socks-cartoon-icon_2687993.png!sw800\"></div>", unsafe_allow_html=True)
56
+
57
+ st.header(st.session_state['username'], divider='gray', anchor=False)
58
+
59
+ st.write("")
60
+ if st.button('Show API Key'):
61
+ # gets the api key
62
+ res = requests.post("https://sandl-backend-ny3lmzb4dq-uc.a.run.app/get_api_keys", json={"jwt": st.session_state['userdata']})
63
+ # # test code
64
+ # print(res.status_code)
65
+ apikey = res.json()["keys"][0]
66
+
67
+ st.text(apikey)
68
+
69
+ st.write('')
70
+ if st.button('Logout'):
71
+ util.switch_page('app')
72
+
pages/2_Query.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import app_utils as util
2
+ import streamlit as st
3
+ import time
4
+ from pathlib import Path
5
+ from datetime import datetime
6
+ import requests
7
+
8
+ st.set_page_config(page_title="sandl", page_icon="🩴", layout="wide", initial_sidebar_state="collapsed")
9
+ # sidebar, page, sidebar
10
+ # margin-bottom: 30px;
11
+ st.markdown("""
12
+ <style>
13
+ .prompt-font {
14
+ font-size:18px !important;
15
+ margin-bottom: 10px;
16
+ margin-top: 20px;
17
+ }
18
+ .percent-font {
19
+ font-size:30px !important;
20
+ margin-top: 50px;
21
+ }
22
+
23
+ .st-emotion-cache-79elbk {
24
+ margin-top: -65px;
25
+ }
26
+ .st-emotion-cache-1wmy9hl {
27
+ margin-top: -32px;
28
+ }
29
+
30
+ [data-testid="stSidebarNav"] {
31
+ background-image: url(https://media.discordapp.net/attachments/1013678935231442944/1175577023574454402/sandlsmall_2.png?ex=656bbc6b&is=6559476b&hm=c920463c2062c3c42e555224fb0dc0afc5188e9451b45c9eb62c64f297c1a1f1&=&width=596&height=127);
32
+ background-repeat: no-repeat;
33
+ margin-top: 20px;
34
+ background-position: 20px 20px;
35
+ }
36
+ </style>
37
+ """, unsafe_allow_html=True)
38
+
39
+
40
+ # Create a row with 3 columns
41
+ col1, col2, col3 = st.columns([1, 8, 1])
42
+
43
+ with col3:
44
+ if st.button('👤 Profile'):
45
+ util.switch_page('profile')
46
+
47
+ with col2:
48
+
49
+ # tab bar
50
+ query = r"$\textsf{\large Query}$"
51
+ recents = r"$\textsf{\large History}$"
52
+ q, searches = st.tabs([query, recents])
53
+
54
+ # query tab
55
+ with q:
56
+
57
+ st.write('')
58
+
59
+ st.markdown('<p class="prompt-font">Prompt:</p>', unsafe_allow_html=True)
60
+ promptcontainer = st.container()
61
+
62
+ user_input = promptcontainer.text_area("", height=50, on_change=None)
63
+
64
+ container2 = st.container()
65
+
66
+ if (user_input == ''):
67
+ container2.write('')
68
+ container2.write('')
69
+ else:
70
+ # TO-DO:
71
+ # call api to get value (this would be added to value put into the dict (prob at first pos. hopefully its a set num of chars))
72
+ # Verify Login **
73
+ if 'userdata' not in st.session_state.keys():
74
+ st.info('Not Logged In: Redirecting to Login page...')
75
+ time.sleep(.5)
76
+ util.switch_page('app')
77
+ else:
78
+ res = requests.post("https://sandl-backend-ny3lmzb4dq-uc.a.run.app/get_intent", json={"jwt": st.session_state['userdata'], "prompt": user_input})
79
+ value = round(res.json()["certaintyValue"] * 100)
80
+ if (value < 10):
81
+ value = '0' + str(value)
82
+ else:
83
+ value = str(value)
84
+
85
+ # visualization (loading bar)
86
+ container2.markdown("<p class='percent-font'>" + value + "%</p>", unsafe_allow_html=True)
87
+ my_bar = container2.progress(0, text='')
88
+ for percent_complete in range(int(value)):
89
+ time.sleep(0.01)
90
+ my_bar.progress(percent_complete + 1, text='')
91
+ container2.text('Your prompt has a ' + value + "% chance to be non-malicious.")
92
+
93
+ container2.text('')
94
+ container2.text('')
95
+ container2.text("SAnDL: Sophisticated Anomaly Detection for LLMs")
96
+ now = datetime.now()
97
+ current_time = now.strftime("%H:%M:%S")
98
+
99
+ if (user_input != ''):
100
+ st.session_state[value + user_input + " " + current_time] = value + user_input + " " + current_time
101
+
102
+ # Searches Tab:
103
+ with searches:
104
+ st.write('')
105
+ x = st.header('Recent Searches:', divider='grey', anchor=False)
106
+
107
+ containerx = st.container()
108
+ containerx.write('')
109
+ containerx.write('')
110
+
111
+ # sorts dict by reverse time stamp
112
+ t = dict(sorted(st.session_state.items(), key=lambda item: item[1][len(item[1]) - 8:], reverse = True))
113
+ for key in t.keys():
114
+ if (key == st.session_state[key]):
115
+ # everything besides the time stamp
116
+ tempstring = st.session_state[key][2:len(st.session_state[key]) - 8]
117
+
118
+ percent = st.session_state[key][:2]
119
+
120
+ # adds ... if tempstring too long
121
+ if len(tempstring) > 110:
122
+ tempstring = st.session_state[key][2:112] + "..."
123
+ containerx.text(tempstring + ' — ' + percent + '%')
124
+