import os
import json
import re
import streamlit as st
import plotly.graph_objects as go
from google.cloud import storage
from google.auth import credentials
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
from scipy.ndimage import gaussian_filter1d
from datetime import timedelta, datetime
gcp_credentials = os.getenv('GCP_CREDENTIALS')
credentials_dict = json.loads(gcp_credentials)
creds = credentials.Credentials.from_service_account_info(credentials_dict)
client = storage.Client(credentials=creds)
bucket_name = "kapnotes"
bucket = client.bucket(bucket_name)
def get_client_names():
blobs = list(bucket.list_blobs(prefix=""))
client_names = set()
for blob in blobs:
client_name = blob.name.split("/")[0]
client_names.add(client_name)
return sorted(client_names)
def login():
st.markdown("""
""", unsafe_allow_html=True)
st.markdown("
KAP NOTES ", unsafe_allow_html=True)
client_names = get_client_names()
with st.form(key="login_form"):
client_name = st.selectbox("Select Client", client_names)
min_date = datetime(2000, 1, 1)
date_input = st.date_input("Enter the Date", min_value=min_date, max_value=datetime.today())
submit_button = st.form_submit_button("Sign In")
if submit_button:
date_str = date_input.strftime("%d-%m-%Y")
date_str = date_str.replace("-", "_")
st.session_state.client_name = client_name
st.session_state.date = date_str
st.session_state.logged_in = True
st.rerun()
if 'logged_in' not in st.session_state:
st.session_state.logged_in = False
if not st.session_state.logged_in:
login()
else:
st.set_page_config(page_title="Kap Notes", layout="wide")
css = '''
'''
st.markdown(css, unsafe_allow_html=True)
client_name = st.session_state.client_name
date = st.session_state.date
summary_blob_name = f"{client_name}/{date.replace('_', '-')}/summary.txt"
transcription_blob_name = f"{client_name}/{date.replace('_', '-')}/transcription.txt"
audio_blob_name = f"{client_name}/{date.replace('_', '-')}/audio/audio.wav"
bucket = client.bucket(bucket_name)
summary_blob = bucket.blob(summary_blob_name)
summary_content = summary_blob.download_as_text()
audio_blob = bucket.blob(audio_blob_name)
audio_url = audio_blob.generate_signed_url(expiration=timedelta(hours=1), method='GET')
summary = re.search(r"\*\*Summary\*\*\n(.*?)\n\n", summary_content, re.DOTALL).group(1).strip()
key_points = re.findall(r"- (.*?)\n", re.search(r"\*\*Key Points\*\*\n(.*?)\n\n", summary_content, re.DOTALL).group(1))
action_items = re.findall(r"- (.*?)\n", re.search(r"\*\*Action Items\*\*\n(.*)", summary_content, re.DOTALL).group(1))
transcription_blob = bucket.blob(transcription_blob_name)
with transcription_blob.open("r") as file:
meeting_data = json.load(file)
speaker_data = {}
total_talktime = 0
for entry in meeting_data:
speaker = entry["speaker"]
duration = entry["end"] - entry["start"]
text = entry["text"]
total_talktime += duration
if speaker not in speaker_data:
speaker_data[speaker] = {"talktime": 0, "text": "", "words": 0}
speaker_data[speaker]["talktime"] += duration
speaker_data[speaker]["text"] += " " + text
speaker_data[speaker]["words"] += len(text.split())
for speaker, data in speaker_data.items():
data["word_per_minute"] = round((data["words"] / data["talktime"] * 60), 2)
data["talktime_percentage"] = round((data["talktime"] / total_talktime * 100), 2)
combined_text = " ".join(data["text"] for data in speaker_data.values())
analyzer = SentimentIntensityAnalyzer()
sentences = combined_text.split('.')
sentiment_polarity = [analyzer.polarity_scores(sentence)["compound"] for sentence in sentences if sentence.strip()]
smoothed_polarity = gaussian_filter1d(sentiment_polarity, sigma=2)
st.title("Kap Notes - Unveiling the story behind your meeting")
st.markdown(f"### Summary\n{summary}
", unsafe_allow_html=True)
st.markdown("### Meeting Highlights")
st.markdown(
f"" + " ".join(f"• {point}" for point in key_points) + "
",
unsafe_allow_html=True
)
st.markdown("### Actionable Items")
st.markdown(
f"" + " ".join(f"• {item}" for item in action_items) + "
",
unsafe_allow_html=True
)
st.markdown("### Comments")
if 'comments' not in st.session_state:
st.session_state.comments = []
def add_comment(comment):
st.session_state.comments.append({"name": "", "comment": comment, "date": datetime.now().strftime("%d, %b %Y")})
if 'name' not in st.session_state:
st.session_state.name = ""
if 'comment' not in st.session_state:
st.session_state.comment = ""
for comment in st.session_state.comments:
st.markdown(
f"""
""", unsafe_allow_html=True)
with st.form(key="comment_form"):
st.markdown('', unsafe_allow_html=True)
comment_input = st.text_area("Your Comment", height=100, value=st.session_state.comment)
submit_button = st.form_submit_button("Submit")
st.markdown('
', unsafe_allow_html=True)
if submit_button:
if not comment_input:
st.error("Enter your comment")
else:
add_comment(comment_input)
st.session_state.comment = ""
with st.sidebar:
speaker_names = list(speaker_data.keys())
talk_time_percentages = [data["talktime_percentage"] for data in speaker_data.values()]
color_palette = ["#A3BFF1", "#F4A7B9", "#C4F1D2", "#D6A7F2", "#FFD5A6", "#9BE1E6", "#F4A3C0", "#C1E7B4", "#F1D0FF", "#F9E9A6"]
speaker_colors = {speaker: color_palette[i % len(color_palette)] for i, speaker in enumerate(speaker_names)}
st.markdown(f"""
Listen to the Meeting Audio
Your browser does not support the audio element.
""", unsafe_allow_html=True)
st.title("Chat Conversation")
with st.expander("Click to view the chat conversation", expanded=False):
chat_conversation = ""
for index, entry in enumerate(meeting_data):
speaker = entry["speaker"]
text = entry["text"]
talk_time = entry["end"] - entry["start"]
speaker_color = speaker_colors[speaker]
chat_conversation += f"""
{speaker}
{talk_time:.2f} mins
{text}
"""
st.markdown(chat_conversation, unsafe_allow_html=True)
fig = go.Figure(data=[go.Pie(labels=speaker_names, values=talk_time_percentages, marker=dict(colors=list(speaker_colors.values())), hole=0.3)])
fig.update_layout(
title="Speaker Analytics",
showlegend=True,
legend=dict(
orientation="h",
yanchor="top",
y=-0.2,
xanchor="center",
x=0.5
)
)
st.plotly_chart(fig)
st.markdown("### Sentiment Analysis of the Meeting")
fig = go.Figure()
fig.add_trace(go.Scatter(x=list(range(len(smoothed_polarity))), y=smoothed_polarity, mode='lines', name='Sentiment', line=dict(color='blue')))
fig.update_layout(
xaxis=dict(title="Time (in seconds)"),
yaxis=dict(title="Sentiment Score", range=[-1, 1]),
)
st.plotly_chart(fig)