Spaces:
				
			
			
	
			
			
		Runtime error
		
	
	
	
			
			
	
	
	
	
		
		
		Runtime error
		
	Merge pull request #3 from huggingface/feat/upgrade-gradio-flow
Browse files- .gitignore +1 -0
- README.md +1 -1
- app/app.py +152 -23
    	
        .gitignore
    CHANGED
    
    | @@ -160,3 +160,4 @@ cython_debug/ | |
| 160 | 
             
            #  and can be added to the global gitignore or merged into this file.  For a more nuclear
         | 
| 161 | 
             
            #  option (not recommended) you can uncomment the following to ignore the entire idea folder.
         | 
| 162 | 
             
            #.idea/
         | 
|  | 
|  | |
| 160 | 
             
            #  and can be added to the global gitignore or merged into this file.  For a more nuclear
         | 
| 161 | 
             
            #  option (not recommended) you can uncomment the following to ignore the entire idea folder.
         | 
| 162 | 
             
            #.idea/
         | 
| 163 | 
            +
            user_feedback
         | 
    	
        README.md
    CHANGED
    
    | @@ -4,7 +4,7 @@ emoji: 🚀 | |
| 4 | 
             
            colorFrom: blue
         | 
| 5 | 
             
            colorTo: gray
         | 
| 6 | 
             
            sdk: gradio
         | 
| 7 | 
            -
            sdk_version: 5. | 
| 8 | 
             
            app_file: app/app.py
         | 
| 9 | 
             
            pinned: false
         | 
| 10 | 
             
            ---
         | 
|  | |
| 4 | 
             
            colorFrom: blue
         | 
| 5 | 
             
            colorTo: gray
         | 
| 6 | 
             
            sdk: gradio
         | 
| 7 | 
            +
            sdk_version: 5.10.0
         | 
| 8 | 
             
            app_file: app/app.py
         | 
| 9 | 
             
            pinned: false
         | 
| 10 | 
             
            ---
         | 
    	
        app/app.py
    CHANGED
    
    | @@ -1,16 +1,18 @@ | |
| 1 | 
             
            import os
         | 
|  | |
| 2 | 
             
            import uuid
         | 
| 3 | 
             
            from base64 import b64encode
         | 
| 4 | 
             
            from datetime import datetime
         | 
| 5 | 
             
            from mimetypes import guess_type
         | 
| 6 | 
             
            from pathlib import Path
         | 
|  | |
| 7 |  | 
| 8 | 
             
            import gradio as gr
         | 
|  | |
|  | |
| 9 | 
             
            from huggingface_hub import InferenceClient
         | 
| 10 | 
             
            from pandas import DataFrame
         | 
| 11 |  | 
| 12 | 
            -
            from feedback import save_feedback
         | 
| 13 | 
            -
             | 
| 14 | 
             
            client = InferenceClient(
         | 
| 15 | 
             
                token=os.getenv("HF_TOKEN"),
         | 
| 16 | 
             
                model=(
         | 
| @@ -30,7 +32,7 @@ def add_user_message(history, message): | |
| 30 | 
             
                return history, gr.MultimodalTextbox(value=None, interactive=False)
         | 
| 31 |  | 
| 32 |  | 
| 33 | 
            -
            def  | 
| 34 | 
             
                messages = []
         | 
| 35 | 
             
                current_role = None
         | 
| 36 | 
             
                current_message_content = []
         | 
| @@ -84,46 +86,152 @@ def _process_content(content) -> str | list[str]: | |
| 84 | 
             
                return content
         | 
| 85 |  | 
| 86 |  | 
| 87 | 
            -
            def  | 
| 88 | 
            -
                 | 
| 89 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 90 | 
             
                response = client.chat.completions.create(
         | 
| 91 | 
             
                    messages=messages,
         | 
| 92 | 
             
                    max_tokens=2000,
         | 
| 93 | 
             
                    stream=False,
         | 
|  | |
|  | |
| 94 | 
             
                )
         | 
| 95 | 
             
                content = response.choices[0].message.content
         | 
| 96 | 
            -
                # TODO: Add a response to the user message
         | 
| 97 | 
            -
             | 
| 98 | 
             
                message = gr.ChatMessage(role="assistant", content=content)
         | 
| 99 | 
             
                history.append(message)
         | 
| 100 | 
             
                return history
         | 
| 101 |  | 
| 102 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 103 | 
             
            def wrangle_like_data(x: gr.LikeData, history) -> DataFrame:
         | 
| 104 | 
             
                """Wrangle conversations and liked data into a DataFrame"""
         | 
| 105 |  | 
| 106 | 
            -
                 | 
|  | |
|  | |
|  | |
| 107 |  | 
| 108 | 
             
                output_data = []
         | 
| 109 | 
             
                for idx, message in enumerate(history):
         | 
|  | |
|  | |
| 110 | 
             
                    if idx == liked_index:
         | 
| 111 | 
             
                        message["metadata"] = {"title": "liked" if x.liked else "disliked"}
         | 
|  | |
|  | |
| 112 | 
             
                    rating = message["metadata"].get("title")
         | 
| 113 | 
             
                    if rating == "liked":
         | 
| 114 | 
             
                        message["rating"] = 1
         | 
| 115 | 
             
                    elif rating == "disliked":
         | 
| 116 | 
             
                        message["rating"] = -1
         | 
| 117 | 
             
                    else:
         | 
| 118 | 
            -
                        message["rating"] =  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 119 |  | 
| 120 | 
             
                    output_data.append(
         | 
| 121 | 
            -
                        dict( | 
|  | |
|  | |
| 122 | 
             
                    )
         | 
| 123 |  | 
| 124 | 
             
                return history, DataFrame(data=output_data)
         | 
| 125 |  | 
| 126 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 127 | 
             
            def submit_conversation(dataframe, session_id):
         | 
| 128 | 
             
                """ "Submit the conversation to dataset repo"""
         | 
| 129 | 
             
                if dataframe.empty:
         | 
| @@ -142,7 +250,14 @@ def submit_conversation(dataframe, session_id): | |
| 142 | 
             
                return (gr.Dataframe(value=None, interactive=False), [])
         | 
| 143 |  | 
| 144 |  | 
| 145 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 146 | 
             
                ##############################
         | 
| 147 | 
             
                # Chatbot
         | 
| 148 | 
             
                ##############################
         | 
| @@ -154,8 +269,10 @@ with gr.Blocks() as demo: | |
| 154 |  | 
| 155 | 
             
                chatbot = gr.Chatbot(
         | 
| 156 | 
             
                    elem_id="chatbot",
         | 
|  | |
| 157 | 
             
                    bubble_full_width=False,
         | 
| 158 | 
             
                    type="messages",
         | 
|  | |
| 159 | 
             
                )
         | 
| 160 |  | 
| 161 | 
             
                chat_input = gr.MultimodalTextbox(
         | 
| @@ -166,21 +283,23 @@ with gr.Blocks() as demo: | |
| 166 | 
             
                    submit_btn=True,
         | 
| 167 | 
             
                )
         | 
| 168 |  | 
| 169 | 
            -
                 | 
| 170 | 
            -
                    fn=add_user_message, inputs=[chatbot, chat_input], outputs=[chatbot, chat_input]
         | 
| 171 | 
            -
                )
         | 
| 172 |  | 
| 173 | 
            -
                 | 
| 174 | 
            -
                     | 
| 175 | 
             
                )
         | 
| 176 |  | 
| 177 | 
            -
                bot_msg.then(lambda: gr.Textbox(interactive=True), None, [chat_input])
         | 
| 178 | 
            -
             | 
| 179 | 
             
                ##############################
         | 
| 180 | 
             
                # Deal with feedback
         | 
| 181 | 
             
                ##############################
         | 
| 182 |  | 
| 183 | 
            -
                 | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 184 |  | 
| 185 | 
             
                chatbot.like(
         | 
| 186 | 
             
                    fn=wrangle_like_data,
         | 
| @@ -189,9 +308,19 @@ with gr.Blocks() as demo: | |
| 189 | 
             
                    like_user_message=False,
         | 
| 190 | 
             
                )
         | 
| 191 |  | 
| 192 | 
            -
                 | 
| 193 | 
            -
                     | 
| 194 | 
            -
             | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 195 | 
             
                    fn=submit_conversation,
         | 
| 196 | 
             
                    inputs=[dataframe, session_id],
         | 
| 197 | 
             
                    outputs=[dataframe, chatbot],
         | 
|  | |
| 1 | 
             
            import os
         | 
| 2 | 
            +
            import random
         | 
| 3 | 
             
            import uuid
         | 
| 4 | 
             
            from base64 import b64encode
         | 
| 5 | 
             
            from datetime import datetime
         | 
| 6 | 
             
            from mimetypes import guess_type
         | 
| 7 | 
             
            from pathlib import Path
         | 
| 8 | 
            +
            from typing import Optional
         | 
| 9 |  | 
| 10 | 
             
            import gradio as gr
         | 
| 11 | 
            +
            from feedback import save_feedback
         | 
| 12 | 
            +
            from gradio.components.chatbot import Option
         | 
| 13 | 
             
            from huggingface_hub import InferenceClient
         | 
| 14 | 
             
            from pandas import DataFrame
         | 
| 15 |  | 
|  | |
|  | |
| 16 | 
             
            client = InferenceClient(
         | 
| 17 | 
             
                token=os.getenv("HF_TOKEN"),
         | 
| 18 | 
             
                model=(
         | 
|  | |
| 32 | 
             
                return history, gr.MultimodalTextbox(value=None, interactive=False)
         | 
| 33 |  | 
| 34 |  | 
| 35 | 
            +
            def format_history_as_messages(history: list):
         | 
| 36 | 
             
                messages = []
         | 
| 37 | 
             
                current_role = None
         | 
| 38 | 
             
                current_message_content = []
         | 
|  | |
| 86 | 
             
                return content
         | 
| 87 |  | 
| 88 |  | 
| 89 | 
            +
            def add_fake_like_data(history: list, session_id: str, liked: bool = False) -> None:
         | 
| 90 | 
            +
                data = {
         | 
| 91 | 
            +
                    "index": len(history) - 1,
         | 
| 92 | 
            +
                    "value": history[-1],
         | 
| 93 | 
            +
                    "liked": True,
         | 
| 94 | 
            +
                }
         | 
| 95 | 
            +
                _, dataframe = wrangle_like_data(
         | 
| 96 | 
            +
                    gr.LikeData(target=None, data=data), history.copy()
         | 
| 97 | 
            +
                )
         | 
| 98 | 
            +
                submit_conversation(dataframe, session_id)
         | 
| 99 | 
            +
             | 
| 100 | 
            +
             | 
| 101 | 
            +
            def respond_system_message(
         | 
| 102 | 
            +
                history: list, temperature: Optional[float] = None, seed: Optional[int] = None
         | 
| 103 | 
            +
            ) -> list:  # -> list:
         | 
| 104 | 
            +
                """Respond to the user message with a system message
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                Return the history with the new message"""
         | 
| 107 | 
            +
                messages = format_history_as_messages(history)
         | 
| 108 | 
             
                response = client.chat.completions.create(
         | 
| 109 | 
             
                    messages=messages,
         | 
| 110 | 
             
                    max_tokens=2000,
         | 
| 111 | 
             
                    stream=False,
         | 
| 112 | 
            +
                    seed=seed,
         | 
| 113 | 
            +
                    temperature=temperature,
         | 
| 114 | 
             
                )
         | 
| 115 | 
             
                content = response.choices[0].message.content
         | 
|  | |
|  | |
| 116 | 
             
                message = gr.ChatMessage(role="assistant", content=content)
         | 
| 117 | 
             
                history.append(message)
         | 
| 118 | 
             
                return history
         | 
| 119 |  | 
| 120 |  | 
| 121 | 
            +
            def update_dataframe(dataframe: DataFrame, history: list) -> DataFrame:
         | 
| 122 | 
            +
                """Update the dataframe with the new message"""
         | 
| 123 | 
            +
                data = {
         | 
| 124 | 
            +
                    "index": 9999,
         | 
| 125 | 
            +
                    "value": None,
         | 
| 126 | 
            +
                    "liked": False,
         | 
| 127 | 
            +
                }
         | 
| 128 | 
            +
                _, dataframe = wrangle_like_data(
         | 
| 129 | 
            +
                    gr.LikeData(target=None, data=data), history.copy()
         | 
| 130 | 
            +
                )
         | 
| 131 | 
            +
                return dataframe
         | 
| 132 | 
            +
             | 
| 133 | 
            +
             | 
| 134 | 
             
            def wrangle_like_data(x: gr.LikeData, history) -> DataFrame:
         | 
| 135 | 
             
                """Wrangle conversations and liked data into a DataFrame"""
         | 
| 136 |  | 
| 137 | 
            +
                if isinstance(x.index, int):
         | 
| 138 | 
            +
                    liked_index = x.index
         | 
| 139 | 
            +
                else:
         | 
| 140 | 
            +
                    liked_index = x.index[0]
         | 
| 141 |  | 
| 142 | 
             
                output_data = []
         | 
| 143 | 
             
                for idx, message in enumerate(history):
         | 
| 144 | 
            +
                    if isinstance(message, gr.ChatMessage):
         | 
| 145 | 
            +
                        message = message.__dict__
         | 
| 146 | 
             
                    if idx == liked_index:
         | 
| 147 | 
             
                        message["metadata"] = {"title": "liked" if x.liked else "disliked"}
         | 
| 148 | 
            +
                    if not isinstance(message["metadata"], dict):
         | 
| 149 | 
            +
                        message["metadata"] = message["metadata"].__dict__
         | 
| 150 | 
             
                    rating = message["metadata"].get("title")
         | 
| 151 | 
             
                    if rating == "liked":
         | 
| 152 | 
             
                        message["rating"] = 1
         | 
| 153 | 
             
                    elif rating == "disliked":
         | 
| 154 | 
             
                        message["rating"] = -1
         | 
| 155 | 
             
                    else:
         | 
| 156 | 
            +
                        message["rating"] = 0
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                    message["chosen"] = ""
         | 
| 159 | 
            +
                    message["rejected"] = ""
         | 
| 160 | 
            +
                    if message["options"]:
         | 
| 161 | 
            +
                        for option in message["options"]:
         | 
| 162 | 
            +
                            if not isinstance(option, dict):
         | 
| 163 | 
            +
                                option = option.__dict__
         | 
| 164 | 
            +
                            message[option["label"]] = option["value"]
         | 
| 165 | 
            +
                    else:
         | 
| 166 | 
            +
                        if message["rating"] == 1:
         | 
| 167 | 
            +
                            message["chosen"] = message["content"]
         | 
| 168 | 
            +
                        elif message["rating"] == -1:
         | 
| 169 | 
            +
                            message["rejected"] = message["content"]
         | 
| 170 |  | 
| 171 | 
             
                    output_data.append(
         | 
| 172 | 
            +
                        dict(
         | 
| 173 | 
            +
                            [(k, v) for k, v in message.items() if k not in ["metadata", "options"]]
         | 
| 174 | 
            +
                        )
         | 
| 175 | 
             
                    )
         | 
| 176 |  | 
| 177 | 
             
                return history, DataFrame(data=output_data)
         | 
| 178 |  | 
| 179 |  | 
| 180 | 
            +
            def wrangle_edit_data(
         | 
| 181 | 
            +
                x: gr.EditData, history: list, dataframe: DataFrame, session_id: str
         | 
| 182 | 
            +
            ) -> list:
         | 
| 183 | 
            +
                """Edit the conversation and add negative feedback if assistant message is edited, otherwise regenerate the message
         | 
| 184 | 
            +
             | 
| 185 | 
            +
                Return the history with the new message"""
         | 
| 186 | 
            +
                if isinstance(x.index, int):
         | 
| 187 | 
            +
                    index = x.index
         | 
| 188 | 
            +
                else:
         | 
| 189 | 
            +
                    index = x.index[0]
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                original_message = gr.ChatMessage(
         | 
| 192 | 
            +
                    role="assistant", content=dataframe.iloc[index]["content"]
         | 
| 193 | 
            +
                ).__dict__
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                if history[index]["role"] == "user":
         | 
| 196 | 
            +
                    # Add feedback on original and corrected message
         | 
| 197 | 
            +
                    add_fake_like_data(history[: index + 2], session_id, liked=True)
         | 
| 198 | 
            +
                    add_fake_like_data(history[: index + 1] + [original_message], session_id)
         | 
| 199 | 
            +
                    history = respond_system_message(
         | 
| 200 | 
            +
                        history[: index + 1],
         | 
| 201 | 
            +
                        temperature=random.randint(1, 100) / 100,
         | 
| 202 | 
            +
                        seed=random.randint(0, 1000000),
         | 
| 203 | 
            +
                    )
         | 
| 204 | 
            +
                    return history
         | 
| 205 | 
            +
                else:
         | 
| 206 | 
            +
                    # Add feedback on original and corrected message
         | 
| 207 | 
            +
                    add_fake_like_data(history[: index + 1], session_id, liked=True)
         | 
| 208 | 
            +
                    add_fake_like_data(history[:index] + [original_message], session_id)
         | 
| 209 | 
            +
                    history = history[: index + 1]
         | 
| 210 | 
            +
                    # add chosen and rejected options
         | 
| 211 | 
            +
                    history[-1]["options"] = [
         | 
| 212 | 
            +
                        Option(label="chosen", value=x.value),
         | 
| 213 | 
            +
                        Option(label="rejected", value=original_message["content"]),
         | 
| 214 | 
            +
                    ]
         | 
| 215 | 
            +
                    return history
         | 
| 216 | 
            +
             | 
| 217 | 
            +
             | 
| 218 | 
            +
            def wrangle_retry_data(
         | 
| 219 | 
            +
                x: gr.RetryData, history: list, dataframe: DataFrame, session_id: str
         | 
| 220 | 
            +
            ) -> list:
         | 
| 221 | 
            +
                """Respond to the user message with a system message and add negative feedback on the original message
         | 
| 222 | 
            +
             | 
| 223 | 
            +
                Return the history with the new message"""
         | 
| 224 | 
            +
                add_fake_like_data(history, session_id)
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                # Return the history without a new message
         | 
| 227 | 
            +
                history = respond_system_message(
         | 
| 228 | 
            +
                    history[:-1],
         | 
| 229 | 
            +
                    temperature=random.randint(1, 100) / 100,
         | 
| 230 | 
            +
                    seed=random.randint(0, 1000000),
         | 
| 231 | 
            +
                )
         | 
| 232 | 
            +
                return history, update_dataframe(dataframe, history)
         | 
| 233 | 
            +
             | 
| 234 | 
            +
             | 
| 235 | 
             
            def submit_conversation(dataframe, session_id):
         | 
| 236 | 
             
                """ "Submit the conversation to dataset repo"""
         | 
| 237 | 
             
                if dataframe.empty:
         | 
|  | |
| 250 | 
             
                return (gr.Dataframe(value=None, interactive=False), [])
         | 
| 251 |  | 
| 252 |  | 
| 253 | 
            +
            css = """
         | 
| 254 | 
            +
            .options {
         | 
| 255 | 
            +
                display: none !important;
         | 
| 256 | 
            +
            }
         | 
| 257 | 
            +
            """
         | 
| 258 | 
            +
             | 
| 259 | 
            +
             | 
| 260 | 
            +
            with gr.Blocks(css=css) as demo:
         | 
| 261 | 
             
                ##############################
         | 
| 262 | 
             
                # Chatbot
         | 
| 263 | 
             
                ##############################
         | 
|  | |
| 269 |  | 
| 270 | 
             
                chatbot = gr.Chatbot(
         | 
| 271 | 
             
                    elem_id="chatbot",
         | 
| 272 | 
            +
                    editable="all",
         | 
| 273 | 
             
                    bubble_full_width=False,
         | 
| 274 | 
             
                    type="messages",
         | 
| 275 | 
            +
                    feedback_options=["Like", "Dislike"],
         | 
| 276 | 
             
                )
         | 
| 277 |  | 
| 278 | 
             
                chat_input = gr.MultimodalTextbox(
         | 
|  | |
| 283 | 
             
                    submit_btn=True,
         | 
| 284 | 
             
                )
         | 
| 285 |  | 
| 286 | 
            +
                dataframe = gr.Dataframe(wrap=True)
         | 
|  | |
|  | |
| 287 |  | 
| 288 | 
            +
                submit_btn = gr.Button(
         | 
| 289 | 
            +
                    value="Submit conversation",
         | 
| 290 | 
             
                )
         | 
| 291 |  | 
|  | |
|  | |
| 292 | 
             
                ##############################
         | 
| 293 | 
             
                # Deal with feedback
         | 
| 294 | 
             
                ##############################
         | 
| 295 |  | 
| 296 | 
            +
                chat_input.submit(
         | 
| 297 | 
            +
                    fn=add_user_message,
         | 
| 298 | 
            +
                    inputs=[chatbot, chat_input],
         | 
| 299 | 
            +
                    outputs=[chatbot, chat_input],
         | 
| 300 | 
            +
                ).then(respond_system_message, chatbot, chatbot, api_name="bot_response").then(
         | 
| 301 | 
            +
                    lambda: gr.Textbox(interactive=True), None, [chat_input]
         | 
| 302 | 
            +
                ).then(update_dataframe, inputs=[dataframe, chatbot], outputs=[dataframe])
         | 
| 303 |  | 
| 304 | 
             
                chatbot.like(
         | 
| 305 | 
             
                    fn=wrangle_like_data,
         | 
|  | |
| 308 | 
             
                    like_user_message=False,
         | 
| 309 | 
             
                )
         | 
| 310 |  | 
| 311 | 
            +
                chatbot.retry(
         | 
| 312 | 
            +
                    fn=wrangle_retry_data,
         | 
| 313 | 
            +
                    inputs=[chatbot, dataframe, session_id],
         | 
| 314 | 
            +
                    outputs=[chatbot, dataframe],
         | 
| 315 | 
            +
                )
         | 
| 316 | 
            +
             | 
| 317 | 
            +
                chatbot.edit(
         | 
| 318 | 
            +
                    fn=wrangle_edit_data,
         | 
| 319 | 
            +
                    inputs=[chatbot, dataframe, session_id],
         | 
| 320 | 
            +
                    outputs=[chatbot],
         | 
| 321 | 
            +
                ).then(update_dataframe, inputs=[dataframe, chatbot], outputs=[dataframe])
         | 
| 322 | 
            +
             | 
| 323 | 
            +
                submit_btn.click(
         | 
| 324 | 
             
                    fn=submit_conversation,
         | 
| 325 | 
             
                    inputs=[dataframe, session_id],
         | 
| 326 | 
             
                    outputs=[dataframe, chatbot],
         | 

