Source code for streamlit_rich_message_history.components
"""Component handling for the streamlit_rich_message_history package.This module defines the core MessageComponent class that detects, processes, andrenders different types of content in a Streamlit application."""importtracebackfromtypingimportAny,Optional,Unionimportstreamlitasstfrom.builtin_componentsimportinitialize_builtinsfrom.enumsimportComponentTypefrom.registryimportComponentRegistry# Initialize built-in componentsinitialize_builtins()
[docs]classMessageComponent:""" Base class for all message components with automatic type detection. This class handles the automatic detection, proper rendering, and error handling for different types of content within a message in a Streamlit application. Attributes: content: The actual content to be displayed component_type: The type of component (automatically detected if not specified) title: Optional title for the component description: Optional description text for the component expanded: Whether expandable sections should be expanded by default kwargs: Additional keyword arguments for rendering """
[docs]def__init__(self,content:Any,component_type:Optional[ComponentType]=None,title:Optional[str]=None,description:Optional[str]=None,expanded:bool=False,**kwargs,):""" Initialize a new message component. Args: content: The content to be displayed component_type: Manually specify the component type (auto-detected if None) title: Optional title for the component (creates an expander if provided) description: Optional description text for the component expanded: Whether expandable sections should be expanded by default **kwargs: Additional keyword arguments that control rendering behavior Special flags include: - is_error: Treat string content as an error message - is_code: Treat string content as code with syntax highlighting - language: The programming language for code highlighting - is_metric: Treat numeric content as a metric - is_table: Treat content as a static table - is_json: Treat dictionaries or lists as JSON data - is_html: Treat string content as HTML """self.content=contentself.kwargs=kwargsifcomponent_typeisNone:component_type=self._detect_component_type(content)self.component_type=component_typeself.title=titleself.description=descriptionself.expanded=expanded
def_detect_component_type(self,content:Any)->ComponentType:""" Detect the appropriate component type based on content. """# Try custom and builtin detectors in orderforcomp_typeinComponentRegistry._detector_order:detector=ComponentRegistry.get_detector(comp_type)ifdetectoranddetector(content,self.kwargs):returncomp_type# Default fallbackreturnComponentType.TEXT
[docs]defrender(self):""" Render the component with appropriate context. If a title is provided, the component is wrapped in an expander. If a description is provided, it's shown before the content. """ifself.title:withst.expander(self.title,expanded=self.expanded):ifself.description:st.markdown(self.description)self._render_content()else:ifself.description:st.markdown(self.description)self._render_content()
def_render_content(self):""" Render the component based on its detected type. This method handles the rendering of all built-in component types and delegates to custom renderers for custom component types. It also includes error handling to prevent component rendering errors from breaking the entire application. """try:# First check if there's a custom renderercustom_renderer=ComponentRegistry.get_renderer(self.component_type)ifcustom_renderer:custom_renderer(self.content,self.kwargs)return# Special handling for collections which recurseif(self.component_type==ComponentType.LISTorself.component_type==ComponentType.TUPLE):foridx,iteminenumerate(self.content):self._render_collection_item(item,idx)elifself.component_type==ComponentType.DICT:forkey,valueinself.content.items():self._render_collection_item(value,key)else:st.write(str(self.content))exceptExceptionase:error_message=f"Error rendering component of type {self.component_type.value}: {str(e)}"stack_trace=traceback.format_exc()st.error(error_message)withst.expander("Stack Trace",expanded=False):st.code(stack_trace,language="python")# Try to show the original content as simple text if possiblewithst.expander("Component Content (Debug View)",expanded=False):try:ifhasattr(self.content,"__repr__"):st.code(repr(self.content),language="python")else:st.code(str(self.content),language="python")exceptExceptionase:st.error(f"Unable to display component content: {e}")def_render_collection_item(self,item:Any,index:Optional[Union[int,str]]=None):""" Render a single item from a collection. Args: item: The item to render index: Optional index or key for error reporting """try:# Create a new MessageComponent for the itemitem_component=MessageComponent(item)# Render the itemitem_component._render_content()exceptExceptionase:ifisinstance(index,(int,str)):index_str=f" at index/key '{index}'"else:index_str=""error_message=f"Error rendering collection item{index_str}: {str(e)}"st.error(error_message)withst.expander("Item Debug View",expanded=False):try:st.code(repr(item),language="python")exceptExceptionase:st.error(f"Unable to display item content: {e}")