Team Ai
Apppublic

alonsosilva/KnowledgeGraph

sourceHugging Facemitupdated 2y agoView on Hugging Face
0likes
app.py196 linesDownload Raw Back to root
1#from dotenv import load_dotenv, find_dotenv2#_ = load_dotenv(find_dotenv())3 4import solara5from typing import Any, Callable, Optional, TypeVar, Union, cast, overload, List6from typing_extensions import TypedDict7import time8import ipyvue9import reacton10from solara.alias import rv as v11import os12import openai13from openai import OpenAI14import instructor15from pydantic import BaseModel, Field16from graphviz import Digraph17 18 19 20from langsmith import traceable21from langsmith.wrappers import wrap_openai22 23# NEEDED FOR INPUT TEXT AREA INSTEAD OF INPUT TEXT24def use_change(el: reacton.core.Element, on_value: Callable[[Any], Any], enabled=True):25    """Trigger a callback when a blur events occurs or the enter key is pressed."""26    on_value_ref = solara.use_ref(on_value)27    on_value_ref.current = on_value28    def add_events():29        def on_change(widget, event, data):30            if enabled:31                on_value_ref.current(widget.v_model)32        widget = cast(ipyvue.VueWidget, solara.get_widget(el))33        if enabled:34            widget.on_event("blur", on_change)35            widget.on_event("keyup.enter", on_change)36        def cleanup():37            if enabled:38                widget.on_event("blur", on_change, remove=True)39                widget.on_event("keyup.enter", on_change, remove=True)40        return cleanup41    solara.use_effect(add_events, [enabled])42 43 44@solara.component45def InputTextarea(46    label: str,47    value: Union[str, solara.Reactive[str]] = "",48    on_value: Callable[[str], None] = None,49    disabled: bool = False,50    password: bool = False,51    continuous_update: bool = False,52    error: Union[bool, str] = False,53    message: Optional[str] = None,54):55    reactive_value = solara.use_reactive(value, on_value)56    del value, on_value57    def set_value_cast(value):58        reactive_value.value = str(value)59    def on_v_model(value):60        if continuous_update:61            set_value_cast(value)62    messages = []63    if error and isinstance(error, str):64        messages.append(error)65    elif message:66        messages.append(message)67    text_area = v.Textarea(68        v_model=reactive_value.value,69        on_v_model=on_v_model,70        label=label,71        disabled=disabled,72        type="password" if password else None,73        error=bool(error),74        messages=messages,75        solo=True,76        hide_details=True,77        outlined=True,78        rows=1,79        auto_grow=True,80    )81    use_change(text_area, set_value_cast, enabled=not continuous_update)82    return text_area83 84# EXTRACTION85openai.api_key = os.environ['OPENAI_API_KEY']86 87# Wrap the OpenAI client with LangSmith88client = wrap_openai(OpenAI())89 90# Patch the client with instructor91client = instructor.from_openai(client, mode=instructor.Mode.TOOLS)92 93class Node(BaseModel):94    id: int95    label: str96    color: str97 98class Edge(BaseModel):99    source: int100    target: int101    label: str102    color: str = "black"103 104class KnowledgeGraph(BaseModel):105    nodes: List[Node] = Field(description="Nodes in the knowledge graph")106    edges: List[Edge] = Field(description="Edges in the knowledge graph")107 108class MessageDict(TypedDict):109    role: str110    content: str111 112def add_chunk_to_ai_message(chunk: str):113    messages.value = [114        *messages.value[:-1],115        {116            "role": "assistant",117            "content": chunk,118        },119    ]120 121import ast122 123# DISPLAYED OUTPUT124@solara.component125def ChatInterface():126    with solara.lab.ChatBox():127        if len(messages.value)>0:128            if messages.value[-1]["role"] != "user":129                obj = messages.value[-1]["content"]130                if f"{obj}" != "":131                    obj = ast.literal_eval(f"{obj}")132                    dot = Digraph(comment="Knowledge Graph")133                    if obj['nodes'] not in [None, []]:134                        if obj['nodes'][0]['label'] not in [None, '']:135                            for i, node in enumerate(obj['nodes']):136                                if obj['nodes'][i]['label'] not in [None, '']:137                                    dot.node(138                                        name=str(obj['nodes'][i]['id']), 139                                        label=obj['nodes'][i]['label'], 140                                        color=obj['nodes'][i]['color']141                                    )142                    if obj['edges'] not in [None, []]:143                        if obj['edges'][0]['label'] not in [None, '']:144                            for i, edge in enumerate(obj['edges']):145                                if obj['edges'][i]['source'] not in [None,''] and obj['edges'][i]['target'] not in [None,''] and obj['edges'][i]['label'] not in [None,'']:146                                    dot.edge(147                                        tail_name=str(obj['edges'][i]['source']), 148                                        head_name=str(obj['edges'][i]['target']), 149                                        label=obj['edges'][i]['label'], 150                                        color=obj['edges'][i]['color']151                                    )152                    with solara.Card():153                        solara.display(dot)154 155messages: solara.Reactive[List[MessageDict]] = solara.reactive([])156aux = solara.reactive("")157text_block = solara.reactive("Alice loves Bob while Charles hates both Alice and Bob.")158@solara.component159def Page():160    title = "Knowledge Graph Generator"161    with solara.Head():162        solara.Title(f"{title}")163    with solara.Column(style={"width": "100%", "padding": "50px"}):164        solara.Markdown(f"#{title}")165        solara.Markdown("Enter some text and the language model will try to describe it as a knowledge graph. Done with :heart: by [alonsosilva](https://twitter.com/alonsosilva)")166        user_message_count = len([m for m in messages.value if m["role"] == "user"])167        def send():168            messages.value = [*messages.value, {"role": "user", "content": " "}]169        def response(message):170            extraction_stream = client.chat.completions.create_partial(171                model="gpt-3.5-turbo",172                response_model=KnowledgeGraph,173                messages=[174                    {175                        "role": "user",176                        "content": f"Help me understand the following by describing it as small knowledge graph: {text_block.value}. It is important to add variety of colors in the nodes.",177                    },178                ],179                temperature=0,180                stream=True,181            )182            for extraction in extraction_stream:183                obj = extraction.model_dump()184                if f"{obj}" != aux.value:185                    add_chunk_to_ai_message(f"{obj}")186                    aux.value = f"{obj}"187        def result():188            if messages.value != []:189                if messages.value[-1]["role"] == "user":190                    response(messages.value[-1]["content"])191        result = solara.lab.use_task(result, dependencies=[user_message_count])192        InputTextarea("Enter text:", value=text_block, continuous_update=False)193        solara.Button(label="Generate Knowledge Graph", on_click=send)194        ChatInterface()195Page()196