Spaces:
Sleeping
Sleeping
Updated app.py
Browse files
app.py
CHANGED
@@ -19,6 +19,7 @@ client = storage.Client(credentials=creds)
|
|
19 |
|
20 |
bucket_name = "kapnotes"
|
21 |
bucket = client.bucket(bucket_name)
|
|
|
22 |
|
23 |
def get_client_names():
|
24 |
blobs = list(bucket.list_blobs(prefix=""))
|
@@ -28,16 +29,43 @@ def get_client_names():
|
|
28 |
client_names.add(client_name)
|
29 |
return sorted(client_names)
|
30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
def login():
|
32 |
st.markdown("""
|
33 |
<style>
|
34 |
.stApp {
|
35 |
-
background: linear-gradient(
|
36 |
-
125deg,
|
37 |
-
#F0F4F8 0%,
|
38 |
-
#D9E4F5 50%,
|
39 |
-
#E5EFF8 100%
|
40 |
-
);
|
41 |
background-size: 200% 200%;
|
42 |
animation: gradientMove 10s ease infinite;
|
43 |
}
|
@@ -54,46 +82,9 @@ def login():
|
|
54 |
margin-bottom: 3rem;
|
55 |
letter-spacing: 2px;
|
56 |
}
|
57 |
-
.login-form-container {
|
58 |
-
width: 400px;
|
59 |
-
margin: 0 auto;
|
60 |
-
padding: 2rem;
|
61 |
-
background: linear-gradient(
|
62 |
-
135deg,
|
63 |
-
rgba(0, 0, 0, 0.1) 0%,
|
64 |
-
rgba(0, 0, 0, 0.15) 100%
|
65 |
-
);
|
66 |
-
backdrop-filter: blur(15px);
|
67 |
-
border-radius: 24px;
|
68 |
-
box-shadow:
|
69 |
-
0 8px 32px rgba(31, 38, 135, 0.37),
|
70 |
-
inset -4px -4px 8px rgba(255, 255, 255, 0.1),
|
71 |
-
inset 4px 4px 8px rgba(0, 0, 0, 0.2);
|
72 |
-
border: 1px solid rgba(255, 255, 255, 0.18);
|
73 |
-
}
|
74 |
-
.stSelectbox label, .stDateInput label {
|
75 |
-
color: #333333 !important;
|
76 |
-
font-weight: bold;
|
77 |
-
font-size: 1rem;
|
78 |
-
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
|
79 |
-
}
|
80 |
-
.stSelectbox > div > div, .stDateInput > div > div {
|
81 |
-
background: #2E3A47;
|
82 |
-
border: 1px solid rgba(255, 255, 255, 0.3);
|
83 |
-
border-radius: 12px;
|
84 |
-
color: #FFFFFF;
|
85 |
-
font-weight: bold;
|
86 |
-
box-shadow:
|
87 |
-
inset 2px 2px 5px rgba(0, 0, 0, 0.3),
|
88 |
-
inset -2px -2px 5px rgba(255, 255, 255, 0.2);
|
89 |
-
}
|
90 |
.stButton > button {
|
91 |
width: 100%;
|
92 |
-
background: linear-gradient(
|
93 |
-
45deg,
|
94 |
-
#2563eb 0%,
|
95 |
-
#3b82f6 100%
|
96 |
-
);
|
97 |
color: white;
|
98 |
border: none;
|
99 |
border-radius: 16px;
|
@@ -102,45 +93,55 @@ def login():
|
|
102 |
font-weight: bold;
|
103 |
cursor: pointer;
|
104 |
margin-top: 2rem;
|
105 |
-
box-shadow:
|
106 |
-
|
107 |
-
|
108 |
-
inset 0 4px 8px rgba(255, 255, 255, 0.2);
|
109 |
transition: all 0.3s ease;
|
110 |
}
|
111 |
.stButton > button:hover {
|
112 |
transform: translateY(-3px) scale(1.03);
|
113 |
-
box-shadow:
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
background: linear-gradient(
|
118 |
-
45deg,
|
119 |
-
#1d4ed8 0%,
|
120 |
-
#2563eb 100%
|
121 |
-
);
|
122 |
}
|
123 |
</style>
|
124 |
""", unsafe_allow_html=True)
|
|
|
|
|
|
|
125 |
|
126 |
st.markdown("<h1>KAP NOTES</h1>", unsafe_allow_html=True)
|
127 |
-
|
128 |
client_names = get_client_names()
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
submit_button = st.form_submit_button("Sign In")
|
135 |
|
136 |
-
if
|
137 |
-
|
138 |
-
|
139 |
-
st.
|
140 |
-
st.
|
141 |
-
|
142 |
-
|
143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
|
145 |
if 'logged_in' not in st.session_state:
|
146 |
st.session_state.logged_in = False
|
@@ -148,9 +149,14 @@ if 'logged_in' not in st.session_state:
|
|
148 |
if not st.session_state.logged_in:
|
149 |
login()
|
150 |
else:
|
151 |
-
st.set_page_config(page_title="Kap Notes", layout="wide")
|
152 |
client_name = st.session_state.client_name
|
153 |
date = st.session_state.date
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
|
155 |
st.sidebar.markdown(f'''
|
156 |
<div class="client-name-container">
|
@@ -185,7 +191,7 @@ else:
|
|
185 |
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
186 |
}
|
187 |
.summary-box:hover, .keypoints-box:hover, .action-items-box:hover {
|
188 |
-
transform: translateY(-1px) scale(1.05);
|
189 |
box-shadow: 0px 12px 25px rgba(0, 0, 0, 0.25), 0px 18px 35px rgba(0, 0, 0, 0.2);
|
190 |
}
|
191 |
.summary-box {
|
@@ -357,9 +363,9 @@ else:
|
|
357 |
'''
|
358 |
st.markdown(css, unsafe_allow_html=True)
|
359 |
|
360 |
-
summary_blob_name = f"{client_name}/{date
|
361 |
-
transcription_blob_name = f"{client_name}/{date
|
362 |
-
audio_blob_name = f"{client_name}/{date
|
363 |
|
364 |
bucket = client.bucket(bucket_name)
|
365 |
|
@@ -369,9 +375,17 @@ else:
|
|
369 |
audio_blob = bucket.blob(audio_blob_name)
|
370 |
audio_url = audio_blob.generate_signed_url(expiration=timedelta(hours=1), method='GET')
|
371 |
|
372 |
-
|
373 |
-
|
374 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
375 |
|
376 |
transcription_blob = bucket.blob(transcription_blob_name)
|
377 |
with transcription_blob.open("r") as file:
|
@@ -524,5 +538,4 @@ else:
|
|
524 |
xaxis=dict(title="Time (in seconds)"),
|
525 |
yaxis=dict(title="Sentiment Score", range=[-1, 1]),
|
526 |
)
|
527 |
-
|
528 |
st.plotly_chart(fig)
|
|
|
19 |
|
20 |
bucket_name = "kapnotes"
|
21 |
bucket = client.bucket(bucket_name)
|
22 |
+
st.set_page_config(page_title="Kap Notes", layout="wide")
|
23 |
|
24 |
def get_client_names():
|
25 |
blobs = list(bucket.list_blobs(prefix=""))
|
|
|
29 |
client_names.add(client_name)
|
30 |
return sorted(client_names)
|
31 |
|
32 |
+
def validate_data(client_name, date, meeting):
|
33 |
+
summary_blob_name = f"{client_name}/{date}/{meeting}/summary.txt"
|
34 |
+
transcription_blob_name = f"{client_name}/{date}/{meeting}/transcription.txt"
|
35 |
+
audio_blob_name = f"{client_name}/{date}/{meeting}/audio.wav"
|
36 |
+
summary_blob = bucket.blob(summary_blob_name)
|
37 |
+
transcription_blob = bucket.blob(transcription_blob_name)
|
38 |
+
audio_blob = bucket.blob(audio_blob_name)
|
39 |
+
return summary_blob.exists() and transcription_blob.exists() and audio_blob.exists()
|
40 |
+
|
41 |
+
def get_meetings_for_date(client_name, date):
|
42 |
+
prefix = f"{client_name}/{date}/"
|
43 |
+
blobs = bucket.list_blobs(prefix=prefix)
|
44 |
+
meetings = set()
|
45 |
+
for blob in blobs:
|
46 |
+
parts = blob.name[len(prefix):].split('/')
|
47 |
+
if len(parts) > 1:
|
48 |
+
meetings.add(parts[0])
|
49 |
+
return sorted(meetings)
|
50 |
+
|
51 |
+
def get_dates_for_client(client_name):
|
52 |
+
client = storage.Client()
|
53 |
+
bucket_name = "kapnotes"
|
54 |
+
bucket = client.get_bucket(bucket_name)
|
55 |
+
prefix = f"{client_name}/"
|
56 |
+
blobs = bucket.list_blobs(prefix=prefix)
|
57 |
+
folder_names = set()
|
58 |
+
for blob in blobs:
|
59 |
+
parts = blob.name[len(prefix):].split('/')
|
60 |
+
if len(parts) > 1:
|
61 |
+
folder_names.add(parts[0])
|
62 |
+
return sorted(folder_names)
|
63 |
+
|
64 |
def login():
|
65 |
st.markdown("""
|
66 |
<style>
|
67 |
.stApp {
|
68 |
+
background: linear-gradient(125deg,rgb(253, 250, 220) 0%,rgb(214, 245, 255) 50%, #F8F8FF 100%);
|
|
|
|
|
|
|
|
|
|
|
69 |
background-size: 200% 200%;
|
70 |
animation: gradientMove 10s ease infinite;
|
71 |
}
|
|
|
82 |
margin-bottom: 3rem;
|
83 |
letter-spacing: 2px;
|
84 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
.stButton > button {
|
86 |
width: 100%;
|
87 |
+
background: linear-gradient(45deg, #2563eb 0%, #3b82f6 100%);
|
|
|
|
|
|
|
|
|
88 |
color: white;
|
89 |
border: none;
|
90 |
border-radius: 16px;
|
|
|
93 |
font-weight: bold;
|
94 |
cursor: pointer;
|
95 |
margin-top: 2rem;
|
96 |
+
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.4),
|
97 |
+
inset 0 -4px 8px rgba(0, 0, 0, 0.2),
|
98 |
+
inset 0 4px 8px rgba(255, 255, 255, 0.2);
|
|
|
99 |
transition: all 0.3s ease;
|
100 |
}
|
101 |
.stButton > button:hover {
|
102 |
transform: translateY(-3px) scale(1.03);
|
103 |
+
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.5),
|
104 |
+
inset 0 -4px 8px rgba(0, 0, 0, 0.2),
|
105 |
+
inset 0 4px 8px rgba(255, 255, 255, 0.2);
|
106 |
+
background: linear-gradient(45deg, #1d4ed8 0%, #2563eb 100%);
|
|
|
|
|
|
|
|
|
|
|
107 |
}
|
108 |
</style>
|
109 |
""", unsafe_allow_html=True)
|
110 |
+
|
111 |
+
if 'password' not in st.session_state:
|
112 |
+
st.session_state.password = ""
|
113 |
|
114 |
st.markdown("<h1>KAP NOTES</h1>", unsafe_allow_html=True)
|
115 |
+
|
116 |
client_names = get_client_names()
|
117 |
+
client_name = st.selectbox("Select Client", client_names)
|
118 |
+
|
119 |
+
if client_name:
|
120 |
+
available_dates = get_dates_for_client(client_name)
|
121 |
+
selected_date = st.selectbox(f"Available Dates for {client_name}", available_dates)
|
|
|
122 |
|
123 |
+
if selected_date:
|
124 |
+
available_meetings = get_meetings_for_date(client_name, selected_date)
|
125 |
+
selected_meeting = st.selectbox(f"Available Meetings for {selected_date}", available_meetings)
|
126 |
+
password = st.text_input("Enter Password", type="password", value=st.session_state.password)
|
127 |
+
sign_in_button = st.button("Sign In", key="sign_in")
|
128 |
+
if sign_in_button:
|
129 |
+
if password == "kapnotes12345":
|
130 |
+
if validate_data(client_name, selected_date, selected_meeting):
|
131 |
+
st.session_state.client_name = client_name
|
132 |
+
st.session_state.date = selected_date
|
133 |
+
st.session_state.meeting = selected_meeting
|
134 |
+
st.session_state.logged_in = True
|
135 |
+
st.session_state.password = password
|
136 |
+
st.rerun()
|
137 |
+
else:
|
138 |
+
st.error(f"No records available for {client_name} on {selected_date}. Please select another option.")
|
139 |
+
elif not password:
|
140 |
+
st.error("Please enter password.")
|
141 |
+
else:
|
142 |
+
st.error("Incorrect Password. Please try again.")
|
143 |
+
st.session_state.password = password
|
144 |
+
|
145 |
|
146 |
if 'logged_in' not in st.session_state:
|
147 |
st.session_state.logged_in = False
|
|
|
149 |
if not st.session_state.logged_in:
|
150 |
login()
|
151 |
else:
|
|
|
152 |
client_name = st.session_state.client_name
|
153 |
date = st.session_state.date
|
154 |
+
meeting = st.session_state.meeting
|
155 |
+
password= st.session_state.password
|
156 |
+
|
157 |
+
if st.sidebar.button("Back"):
|
158 |
+
st.session_state.logged_in = False
|
159 |
+
st.rerun()
|
160 |
|
161 |
st.sidebar.markdown(f'''
|
162 |
<div class="client-name-container">
|
|
|
191 |
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
192 |
}
|
193 |
.summary-box:hover, .keypoints-box:hover, .action-items-box:hover {
|
194 |
+
transform: translateY(-0.1px) scale(1.05);
|
195 |
box-shadow: 0px 12px 25px rgba(0, 0, 0, 0.25), 0px 18px 35px rgba(0, 0, 0, 0.2);
|
196 |
}
|
197 |
.summary-box {
|
|
|
363 |
'''
|
364 |
st.markdown(css, unsafe_allow_html=True)
|
365 |
|
366 |
+
summary_blob_name = f"{client_name}/{date}/{meeting}/summary.txt"
|
367 |
+
transcription_blob_name = f"{client_name}/{date}/{meeting}/transcription.txt"
|
368 |
+
audio_blob_name = f"{client_name}/{date}/{meeting}/audio.wav"
|
369 |
|
370 |
bucket = client.bucket(bucket_name)
|
371 |
|
|
|
375 |
audio_blob = bucket.blob(audio_blob_name)
|
376 |
audio_url = audio_blob.generate_signed_url(expiration=timedelta(hours=1), method='GET')
|
377 |
|
378 |
+
summary_match = re.search(r"Summary:\s*(.*?)(?=\nKey Points:)", summary_content, re.DOTALL)
|
379 |
+
summary = summary_match.group(1).strip() if summary_match else "Summary not found."
|
380 |
+
|
381 |
+
key_points_match = re.search(r"Key Points:\s*(.*?)(?=\nAction Items:)", summary_content, re.DOTALL)
|
382 |
+
key_points = re.findall(r"- (.*?)\n", key_points_match.group(1)) if key_points_match else ["Key points not found."]
|
383 |
+
|
384 |
+
action_items_match = re.search(r"Action Items:\s*(.*)", summary_content, re.DOTALL)
|
385 |
+
if action_items_match:
|
386 |
+
action_items = re.findall(r"- (.*?)(?=\n- |$)", action_items_match.group(1), re.DOTALL)
|
387 |
+
else:
|
388 |
+
action_items = ["Action items not found."]
|
389 |
|
390 |
transcription_blob = bucket.blob(transcription_blob_name)
|
391 |
with transcription_blob.open("r") as file:
|
|
|
538 |
xaxis=dict(title="Time (in seconds)"),
|
539 |
yaxis=dict(title="Sentiment Score", range=[-1, 1]),
|
540 |
)
|
|
|
541 |
st.plotly_chart(fig)
|