Cgs
Browse files
app.py
CHANGED
|
@@ -22,13 +22,15 @@ total_pages = 1
|
|
| 22 |
async def fetch_conversations(api_key: str, page: int = 1) -> Dict[str, Any]:
|
| 23 |
bee = Bee(api_key)
|
| 24 |
logging.info(f"Fetching conversations for user 'me', page {page}")
|
| 25 |
-
conversations = await bee.get_conversations("me", page=page)
|
| 26 |
return conversations
|
| 27 |
|
| 28 |
def format_end_time(end_time: str) -> str:
|
| 29 |
utc_time = datetime.fromisoformat(end_time.replace('Z', '+00:00'))
|
| 30 |
-
|
| 31 |
-
|
|
|
|
|
|
|
| 32 |
|
| 33 |
async def fetch_conversation(api_key: str, conversation_id: int) -> Dict[str, Any]:
|
| 34 |
bee = Bee(api_key)
|
|
@@ -45,7 +47,7 @@ def format_conversation(data: Dict[str, Any]) -> str:
|
|
| 45 |
try:
|
| 46 |
conversation = data.get("conversation", {})
|
| 47 |
logging.debug(f"Conversation keys: {conversation.keys()}")
|
| 48 |
-
formatted = f"# Conversation
|
| 49 |
# Format start_time and end_time
|
| 50 |
start_time = conversation.get('start_time')
|
| 51 |
end_time = conversation.get('end_time')
|
|
@@ -57,16 +59,16 @@ def format_conversation(data: Dict[str, Any]) -> str:
|
|
| 57 |
end_pacific = end_dt.astimezone(pacific_tz)
|
| 58 |
|
| 59 |
if start_pacific.date() == end_pacific.date():
|
| 60 |
-
formatted += f"
|
| 61 |
else:
|
| 62 |
-
formatted += f"**Start
|
| 63 |
-
formatted += f"**End
|
| 64 |
elif start_time:
|
| 65 |
start_time_formatted = format_end_time(start_time)
|
| 66 |
-
formatted += f"**Start
|
| 67 |
elif end_time:
|
| 68 |
end_time_formatted = format_end_time(end_time)
|
| 69 |
-
formatted += f"**End
|
| 70 |
|
| 71 |
# Display short_summary nicely
|
| 72 |
if 'short_summary' in conversation:
|
|
@@ -87,13 +89,26 @@ def format_conversation(data: Dict[str, Any]) -> str:
|
|
| 87 |
speaker = utterance.get('speaker')
|
| 88 |
text = utterance.get('text')
|
| 89 |
|
| 90 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
return formatted
|
| 93 |
except Exception as e:
|
| 94 |
logging.error(f"Error formatting conversation: {str(e)}")
|
| 95 |
return f"Error formatting conversation: {str(e)}\n\nRaw data: {conversation}"
|
| 96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
async def list_conversations(api_key: str) -> Tuple[pd.DataFrame, str, int, int]:
|
| 98 |
global current_page, total_pages
|
| 99 |
conversations_data = await fetch_conversations(api_key, current_page)
|
|
@@ -102,12 +117,13 @@ async def list_conversations(api_key: str) -> Tuple[pd.DataFrame, str, int, int]
|
|
| 102 |
df = pd.DataFrame([
|
| 103 |
{
|
| 104 |
"ID": c['id'],
|
| 105 |
-
"
|
| 106 |
-
"Summary": c['short_summary'][1:
|
|
|
|
| 107 |
}
|
| 108 |
for c in conversations
|
| 109 |
])
|
| 110 |
-
df = df[["ID", "End Time", "Summary"]] # Reorder columns to ensure ID is first
|
| 111 |
info = f"Page {current_page} of {total_pages}"
|
| 112 |
return df, info, current_page, total_pages
|
| 113 |
|
|
@@ -192,7 +208,11 @@ with gr.Blocks() as demo:
|
|
| 192 |
with gr.Column(scale=1):
|
| 193 |
api_key = gr.Textbox(label="Enter your Bee API Key", type="password")
|
| 194 |
load_button = gr.Button("Load Conversations")
|
| 195 |
-
conversation_table = gr.Dataframe(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
info_text = gr.Textbox(label="Info", interactive=False)
|
| 197 |
prev_page = gr.Button("Previous Page")
|
| 198 |
next_page = gr.Button("Next Page")
|
|
@@ -224,14 +244,36 @@ with gr.Blocks() as demo:
|
|
| 224 |
logging.info(f"SelectData event: index={evt.index}, value={evt.value}")
|
| 225 |
conversation_id = int(evt.value)
|
| 226 |
logging.info(f"Updating conversation with ID: {conversation_id}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 227 |
formatted_conversation = await display_conversation(api_key, conversation_id)
|
| 228 |
-
|
|
|
|
|
|
|
| 229 |
except Exception as e:
|
| 230 |
error_message = f"Error updating conversation: {str(e)}"
|
| 231 |
logging.error(error_message)
|
| 232 |
-
|
| 233 |
|
| 234 |
-
conversation_table.select(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 235 |
|
| 236 |
delete_button.click(
|
| 237 |
delete_selected_conversation,
|
|
|
|
| 22 |
async def fetch_conversations(api_key: str, page: int = 1) -> Dict[str, Any]:
|
| 23 |
bee = Bee(api_key)
|
| 24 |
logging.info(f"Fetching conversations for user 'me', page {page}")
|
| 25 |
+
conversations = await bee.get_conversations("me", page=page, limit=15)
|
| 26 |
return conversations
|
| 27 |
|
| 28 |
def format_end_time(end_time: str) -> str:
|
| 29 |
utc_time = datetime.fromisoformat(end_time.replace('Z', '+00:00'))
|
| 30 |
+
user_timezone = pytz.timezone('US/Pacific') # TODO: Replace with actual user timezone
|
| 31 |
+
local_time = utc_time.astimezone(user_timezone)
|
| 32 |
+
timezone_abbr = local_time.strftime('%Z')
|
| 33 |
+
return f"{local_time.strftime('%I:%M %p')} {timezone_abbr}"
|
| 34 |
|
| 35 |
async def fetch_conversation(api_key: str, conversation_id: int) -> Dict[str, Any]:
|
| 36 |
bee = Bee(api_key)
|
|
|
|
| 47 |
try:
|
| 48 |
conversation = data.get("conversation", {})
|
| 49 |
logging.debug(f"Conversation keys: {conversation.keys()}")
|
| 50 |
+
formatted = f"# Conversation [{conversation['id']}] "
|
| 51 |
# Format start_time and end_time
|
| 52 |
start_time = conversation.get('start_time')
|
| 53 |
end_time = conversation.get('end_time')
|
|
|
|
| 59 |
end_pacific = end_dt.astimezone(pacific_tz)
|
| 60 |
|
| 61 |
if start_pacific.date() == end_pacific.date():
|
| 62 |
+
formatted += f"{start_pacific.strftime('%I:%M %p')} - {end_pacific.strftime('%I:%M %p')} PT\n\n"
|
| 63 |
else:
|
| 64 |
+
formatted += f"\n\n**Start**: {start_pacific.strftime('%Y-%m-%d %I:%M %p')} PT\n"
|
| 65 |
+
formatted += f"**End**: {end_pacific.strftime('%Y-%m-%d %I:%M %p')} PT\n"
|
| 66 |
elif start_time:
|
| 67 |
start_time_formatted = format_end_time(start_time)
|
| 68 |
+
formatted += f"**Start**: {start_time_formatted}\n"
|
| 69 |
elif end_time:
|
| 70 |
end_time_formatted = format_end_time(end_time)
|
| 71 |
+
formatted += f"**End**: {end_time_formatted}\n"
|
| 72 |
|
| 73 |
# Display short_summary nicely
|
| 74 |
if 'short_summary' in conversation:
|
|
|
|
| 89 |
speaker = utterance.get('speaker')
|
| 90 |
text = utterance.get('text')
|
| 91 |
|
| 92 |
+
if last_timestamp is not None:
|
| 93 |
+
time_diff = datetime.fromisoformat(current_timestamp.replace('Z', '+00:00')) - datetime.fromisoformat(last_timestamp.replace('Z', '+00:00'))
|
| 94 |
+
if time_diff.total_seconds() > 300: # More than 5 minutes
|
| 95 |
+
local_time = datetime.fromisoformat(current_timestamp.replace('Z', '+00:00')).astimezone().strftime('%I:%M %p')
|
| 96 |
+
formatted += f"[{local_time}]\n\n"
|
| 97 |
+
|
| 98 |
+
formatted += f"Speaker **[{speaker}](https://kagi.com/search?q={current_timestamp})**: {text}\n\n"
|
| 99 |
+
last_timestamp = current_timestamp
|
| 100 |
|
| 101 |
return formatted
|
| 102 |
except Exception as e:
|
| 103 |
logging.error(f"Error formatting conversation: {str(e)}")
|
| 104 |
return f"Error formatting conversation: {str(e)}\n\nRaw data: {conversation}"
|
| 105 |
|
| 106 |
+
def format_duration(start_time: str, end_time: str) -> str:
|
| 107 |
+
start_dt = datetime.fromisoformat(start_time.replace('Z', '+00:00'))
|
| 108 |
+
end_dt = datetime.fromisoformat(end_time.replace('Z', '+00:00'))
|
| 109 |
+
duration = end_dt - start_dt
|
| 110 |
+
return f"{duration.total_seconds() // 3600:.0f}h {((duration.total_seconds() % 3600) // 60):.0f}m"
|
| 111 |
+
|
| 112 |
async def list_conversations(api_key: str) -> Tuple[pd.DataFrame, str, int, int]:
|
| 113 |
global current_page, total_pages
|
| 114 |
conversations_data = await fetch_conversations(api_key, current_page)
|
|
|
|
| 117 |
df = pd.DataFrame([
|
| 118 |
{
|
| 119 |
"ID": c['id'],
|
| 120 |
+
"Duration": format_duration(c['start_time'], c['end_time']) if c['start_time'] and c['end_time'] else "",
|
| 121 |
+
"Summary": ' '.join(c['short_summary'].split()[1:21]) + "..." if c['short_summary'] else "",
|
| 122 |
+
"End Time": format_end_time(c['end_time']) if c['end_time'] else "",
|
| 123 |
}
|
| 124 |
for c in conversations
|
| 125 |
])
|
| 126 |
+
df = df[["ID", "End Time", "Duration", "Summary"]] # Reorder columns to ensure ID is first
|
| 127 |
info = f"Page {current_page} of {total_pages}"
|
| 128 |
return df, info, current_page, total_pages
|
| 129 |
|
|
|
|
| 208 |
with gr.Column(scale=1):
|
| 209 |
api_key = gr.Textbox(label="Enter your Bee API Key", type="password")
|
| 210 |
load_button = gr.Button("Load Conversations")
|
| 211 |
+
conversation_table = gr.Dataframe(
|
| 212 |
+
label="Select a conversation (CLICK ON THE ID!!!)",
|
| 213 |
+
interactive=True,
|
| 214 |
+
row_count=10 # Adjust this number to approximate the desired height
|
| 215 |
+
)
|
| 216 |
info_text = gr.Textbox(label="Info", interactive=False)
|
| 217 |
prev_page = gr.Button("Previous Page")
|
| 218 |
next_page = gr.Button("Next Page")
|
|
|
|
| 244 |
logging.info(f"SelectData event: index={evt.index}, value={evt.value}")
|
| 245 |
conversation_id = int(evt.value)
|
| 246 |
logging.info(f"Updating conversation with ID: {conversation_id}")
|
| 247 |
+
|
| 248 |
+
# Return a loading message immediately
|
| 249 |
+
yield gr.update(value="Loading conversation details...", visible=True), gr.update(visible=False), None
|
| 250 |
+
|
| 251 |
+
# Fetch and format the conversation
|
| 252 |
formatted_conversation = await display_conversation(api_key, conversation_id)
|
| 253 |
+
|
| 254 |
+
# Return the formatted conversation and update the UI
|
| 255 |
+
yield formatted_conversation, gr.update(visible=True), conversation_id
|
| 256 |
except Exception as e:
|
| 257 |
error_message = f"Error updating conversation: {str(e)}"
|
| 258 |
logging.error(error_message)
|
| 259 |
+
yield error_message, gr.update(visible=False), None
|
| 260 |
|
| 261 |
+
conversation_table.select(
|
| 262 |
+
update_conversation,
|
| 263 |
+
inputs=[api_key],
|
| 264 |
+
outputs=[conversation_details, delete_button, selected_conversation_id],
|
| 265 |
+
_js="(api_key, evt) => [api_key, evt]", # This ensures the evt object is passed correctly
|
| 266 |
+
).then(
|
| 267 |
+
lambda: None, # This is a no-op function
|
| 268 |
+
None, # No inputs
|
| 269 |
+
None, # No outputs
|
| 270 |
+
_js="""
|
| 271 |
+
() => {
|
| 272 |
+
// Scroll to the conversation details
|
| 273 |
+
document.querySelector('#conversation_details').scrollIntoView({behavior: 'smooth'});
|
| 274 |
+
}
|
| 275 |
+
"""
|
| 276 |
+
)
|
| 277 |
|
| 278 |
delete_button.click(
|
| 279 |
delete_selected_conversation,
|