import streamlit.components.v1 from htbuilder import HtmlElement, div, span, styles from htbuilder.units import px, rem, em def annotation(body, label="", background="#ddd", color="#333", **style): """Build an HtmlElement span object with the given body and annotation label. The end result will look something like this: [body | label] Parameters ---------- body : string The string to put in the "body" part of the annotation. label : string The string to put in the "label" part of the annotation. background : string The color to use for the background "chip" containing this annotation. color : string The color to use for the body and label text. **style : dict Any CSS you want to use to customize the containing "chip". Examples -------- Produce a simple annotation with default colors: >>> annotation("apple", "fruit") Produce an annotation with custom colors: >>> annotation("apple", "fruit", background="#FF0", color="black") Produce an annotation with crazy CSS: >>> annotation("apple", "fruit", background="#FF0", border="1px dashed red") """ if "font_family" not in style: style["font_family"] = "sans-serif" return span( style=styles( background=background, border_radius=rem(0.33), color=color, padding=(rem(0.17), rem(0.67)), display="inline-flex", justify_content="center", align_items="center", **style, ) )( body, span( style=styles( color=color, font_size=em(0.67), opacity=0.5, padding_left=rem(0.5), text_transform="uppercase", margin_bottom=px(-2), ) )(label), ) def annotated_text(*args, **kwargs): """Writes test with annotations into your Streamlit app. Parameters ---------- *args : str, tuple or htbuilder.HtmlElement Arguments can be: - strings, to draw the string as-is on the screen. - tuples of the form (main_text, annotation_text, background, color) where background and foreground colors are optional and should be an CSS-valid string such as "#aabbcc" or "rgb(10, 20, 30)" - HtmlElement objects in case you want to customize the annotations further. In particular, you can import the `annotation()` function from this module to easily produce annotations whose CSS you can customize via keyword arguments. Examples -------- >>> annotated_text( ... "This ", ... ("is", "verb", "#8ef"), ... " some ", ... ("annotated", "adj", "#faa"), ... ("text", "noun", "#afa"), ... " for those of ", ... ("you", "pronoun", "#fea"), ... " who ", ... ("like", "verb", "#8ef"), ... " this sort of ", ... ("thing", "noun", "#afa"), ... ) >>> annotated_text( ... "Hello ", ... annotation("world!", "noun", color="#8ef", border="1px dashed red"), ... ) """ out = div( style=styles( font_family="sans-serif", line_height="1.45", font_size=px(16), text_align="right", ) ) for arg in args: if isinstance(arg, str): out(arg) elif isinstance(arg, HtmlElement): out(arg) elif isinstance(arg, tuple): out(annotation(*arg)) else: raise Exception("Oh noes!") streamlit.components.v1.html(str(out), **kwargs) def shorten_text(text, n, reverse=False): if text.isspace() or text == "": return text if reverse: text = text[::-1] words = iter(text.split()) lines, current = [], next(words) for word in words: if len(current) + 1 + len(word) > n: break else: current += " " + word lines.append(current) if reverse: return lines[0][::-1] return lines[0] def annotate_answer(result): annotated_text( shorten_text( result["original"][: result["new_start"]], 500, reverse=True, ), (result["new_answer"], "جواب", "#8ef"), shorten_text(result["original"][result["new_end"] :], 500) + " ...... إلخ", )