Thanks for your reply! AI has usually been magic for me (doing mostly python automation scripting) and I almost never code anything by hand. I have found Claude to be the best one, ChatGPT gets lazy after a while, and Gemini is the laziest one that I only use when I have an error that neither Claude nor ChatGPT can resolve. It often can provide guidance but never the full code.
Specifically I am rendering a list of slides and talking points, calling an API that calls a Claude api to generate a transcript and then I want to re-render the updated transcript in the screen.
It’s either re-rendering the transcript and getting a “duplicate widget id” error, or not re-rendering at all.
Here’s the code current code (getting a dupliicate widget id error:
import streamlit as st
from services.dreamfactory_service import dreamfactory_service
from app import load_css
import asyncio
import aiohttp
from dotenv import load_dotenv
import os
# Load environment variables from .env file
load_dotenv()
# Get the FastAPI URL from environment variables
FASTAPI_URL = os.getenv('FASTAPI_URL')
async def generate_transcript(image_url, talking_points):
"""
Asynchronously sends a POST request to generate a transcript using the given image URL and talking points.
"""
if not talking_points:
return {"error": "Talking points are empty"}
# Debug print
print(f"Sending request with talking points: {talking_points}")
payload = {
'image_url': image_url,
'talking_points': talking_points
}
# Debug print
print(f"Full payload: {payload}")
async with aiohttp.ClientSession() as session:
async with session.post(f'{FASTAPI_URL}/claude/generate_transcript', json=payload) as response:
if response.status == 200:
return await response.json()
else:
error_text = await response.text()
# Debug print
print(f"Error response: {error_text}")
return {"error": f"Failed to generate transcript: {error_text}"}
def fetch_module_data(module_id):
"""
Fetches module data from the DreamFactory service using the module ID.
"""
module_data = dreamfactory_service.get_data('modules', filter=f"id={module_id}")
return module_data['resource'][0] if module_data['resource'] else None
def fetch_slides_data(module_id):
"""
Fetches slides data associated with a given module ID.
"""
slides_data = dreamfactory_service.get_data('slides', filter=f"module_id={module_id}", order="display_order")
return slides_data['resource'] if slides_data['resource'] else []
def fetch_videos_data(slide_id):
"""
Fetches video data associated with a given slide ID.
"""
videos_data = dreamfactory_service.get_data('slide_videos', filter=f"slide_id={slide_id}")
return videos_data['resource'] if videos_data['resource'] else []
def save_module(module_id, description):
"""
Saves the module's description to the DreamFactory service.
"""
updated_module = {
'id': module_id,
'description': description
}
result = dreamfactory_service.create_or_update('modules', updated_module)
return result is not None
def save_slide(slide):
"""
Saves slide data to the DreamFactory service.
"""
result = dreamfactory_service.create_or_update('slides', slide)
return result is not None
def display_module_description(module):
"""
Displays the module description in a text area and returns the entered text.
"""
return st.text_area("Module Description", value=module['description'], key="module_description")
def display_slide(slide, index):
st.subheader(f"Slide {index + 1}: {slide['title']}")
col1, col2 = st.columns(2)
with col1:
st.image(slide['image_link'], use_column_width=True)
with col2:
talking_points_key = f"tp_{slide['id']}"
transcript_key = f"tr_{slide['id']}"
# Initialize session state
if talking_points_key not in st.session_state:
st.session_state[talking_points_key] = slide.get('talking_points', '')
if transcript_key not in st.session_state:
st.session_state[transcript_key] = slide.get('transcript', '')
# Create text areas
talking_points = st.text_area("Talking Points", key=f"tp_input_{slide['id']}",
value=st.session_state[talking_points_key], height=200)
# Create an empty container for the transcript
transcript_container = st.empty()
# Update the transcript container
transcript = transcript_container.text_area("Transcript", key=f"tr_input_{slide['id']}",
value=st.session_state[transcript_key], height=200)
# Update session state based on current values
st.session_state[talking_points_key] = talking_points
st.session_state[transcript_key] = transcript
col_gen, col_save = st.columns(2)
with col_gen:
if st.button("Generate Transcript", key=f"gen_button_{slide['id']}"):
generate_transcript_callback(slide['image_link'], talking_points_key, transcript_key, slide['id'], transcript_container)
with col_save:
if st.button("Save Slide", key=f"save_button_{slide['id']}"):
save_slide_callback(slide['id'], talking_points_key, transcript_key)
# Display videos if available
videos = fetch_videos_data(slide['id'])
if videos:
st.subheader("Videos")
for video in videos:
st.video(video['video_link'])
st.audio(video['audio_link'])
def generate_transcript_callback(image_url, talking_points_key, transcript_key, slide_id, transcript_container):
with st.spinner("Generating transcript..."):
result = asyncio.run(generate_transcript(image_url, st.session_state[talking_points_key]))
if result and 'transcript' in result:
st.session_state[transcript_key] = result['transcript']
save_slide({
'id': slide_id,
'transcript': st.session_state[transcript_key],
'talking_points': st.session_state[talking_points_key]
})
# Update the transcript container with the new content
transcript_container.text_area("Transcript", key=f"tr_input_{slide_id}",
value=st.session_state[transcript_key], height=200)
st.success("Transcript generated and saved successfully!")
else:
st.error(f"Failed to generate transcript: {result.get('error', 'Unknown error')}")
def save_slide_callback(slide_id, talking_points_key, transcript_key):
updated_slide = {
'id': slide_id,
'talking_points': st.session_state[talking_points_key],
'transcript': st.session_state[transcript_key]
}
if save_slide(updated_slide):
st.success("Slide saved successfully!")
else:
st.error("Failed to save slide.")
async def call_generate_transcript(image_url, talking_points, transcript_key, slide_id):
"""
Calls the generate_transcript endpoint and updates the UI with the result.
"""
result = await generate_transcript(image_url, talking_points)
if result and 'transcript' in result:
st.session_state[transcript_key] = result['transcript']
save_slide({
'id': slide_id,
'transcript': st.session_state[transcript_key]
})
st.success("Transcript generated and saved successfully!")
else:
st.error("Failed to generate transcript. Please try again.")
st.session_state[transcript_key] = ""
def module_edit():
"""
Main function to edit a module and manage slides.
"""
load_css()
st.title("Edit Module")
# Fetch the module ID from session state
module_id = st.session_state.get('module_id')
if not module_id:
st.error("No module selected.")
if st.button("Back to Course Sections"):
st.switch_page("pages/course_sections.py")
return
# Fetch module data
module = fetch_module_data(module_id)
if not module:
st.error("Module not found.")
if st.button("Back to Course Sections"):
st.switch_page("pages/course_sections.py")
return
# Display the module title
st.header(f"Editing Module: {module['name']}")
# Display module description
description = display_module_description(module)
col1, col2 = st.columns(2)
with col1:
if st.button("Save All Changes", key="save_all"):
with st.spinner("Saving all changes..."):
# Save module description and slides
module_saved = save_module(module_id, description)
slides = fetch_slides_data(module_id)
slides_saved = all(save_slide({
'id': slide['id'],
'talking_points': st.session_state.get(f"tp_{slide['id']}", ""),
'transcript': st.session_state.get(f"tr_{slide['id']}", "")
}) for slide in slides)
if module_saved and slides_saved:
st.success("All changes saved successfully!")
else:
st.error("Failed to save some changes. Please try again.")
with col2:
if st.button("Generate All Transcripts", key="generate_all"):
slides = fetch_slides_data(module_id)
asyncio.run(generate_all_transcripts(slides))
# Display each slide
slides = fetch_slides_data(module_id)
for i, slide in enumerate(slides):
display_slide(slide, i)
# Button to navigate back to the course sections
if st.button("Back to Course Sections"):
st.switch_page("pages/course_sections.py")
async def generate_all_transcripts(slides):
for slide in slides:
talking_points_key = f"tp_{slide['id']}"
transcript_key = f"tr_{slide['id']}"
if not st.session_state[transcript_key]: # Only generate if transcript is empty
result = await generate_transcript(slide['image_link'], st.session_state[talking_points_key])
if result and 'transcript' in result:
st.session_state[transcript_key] = result['transcript']
# Save the generated transcript immediately
save_slide({
'id': slide['id'],
'transcript': st.session_state[transcript_key]
})
st.success("All transcripts generated and saved successfully!")
st.experimental_rerun()
module_edit()