File size: 7,430 Bytes
1e4764f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
"""
app.py
"""

# Standard library imports
import json
from typing import Tuple

# Third-party imports
import gradio as gr
import instructor
from fireworks.client import Fireworks
from pydantic import BaseModel, ValidationError

# Local imports
from config import (
    APP_HEADER,
    APP_TITLE,
    FIREWORKS_API_KEY,
    LLM_MAX_TOKENS,
    LLM_MODEL,
    LLM_SYSTEM_PROMPT,
)


# Initialize Instructor with the Fireworks client
client = Fireworks(api_key=FIREWORKS_API_KEY)
client = instructor.from_fireworks(client)


# Define response models for feedback and code using Pydantic
class CodeResponse(BaseModel):
    """Code Response"""

    planning: str
    full_python_code: str
    commentary: str


def get_llm_responses(
    user_input: str, conversation: list, current_code: str = None
) -> Tuple[list, str, str]:
    """
    Generates feedback and code based on user input using the Instructor LLM.

    Args:
        user_input (str): The input text from the user.
        conversation (list): The conversation history.
        current_code (str, optional): Existing code if any.

    Returns:
        Tuple[list, str, str]: A tuple containing updated conversation, generated code, and formatted conversation history.
    """
    try:
        # Update conversation history with user input
        conversation.append(
            {
                "role": "user",
                "content": (
                    user_input
                    if current_code is None
                    else f"{user_input} And here is the existing code: {current_code}"
                ),
            }
        )

        # Generate Feedback
        feedback_resp = client.chat.completions.create(
            model=LLM_MODEL,
            response_model=CodeResponse,
            max_tokens=LLM_MAX_TOKENS,
            messages=conversation,
        )

        code = feedback_resp.full_python_code

        # Update conversation history with assistant response
        conversation.append(
            {
                "role": "assistant",
                "content": feedback_resp.model_dump_json(),
            }
        )

        # Format conversation history for display
        conversation_text = ""

        conversation_to_print = conversation[1:]

        round_number = (
            len(conversation_to_print) // 2
        )  # Assuming each round has a user and assistant message

        # Add the latest conversation pair to the top
        if len(conversation_to_print) >= 2:
            latest_pair = conversation_to_print[-2:]
            conversation_text += f"## Version {round_number}\n\n"
            for message in latest_pair:
                if message["role"] != "system":
                    role = message["role"].capitalize()
                    try:
                        content = json.loads(message["content"])
                        content = content["commentary"]
                    except:
                        content = message["content"].split(
                            " And here is the existing code:"
                        )[0]
                        if content == "":
                            content = "_User edited the code directly_"

                    emoji = "πŸ‘€" if role == "User" else "πŸ€–"
                    conversation_text += f"**{emoji} {role}:** {content}\n\n"

        # Add the rest of the conversation history
        for i, message in enumerate(conversation_to_print[:-2]):
            if message["role"] != "system":
                if i % 2 == 0:
                    round_number = (len(conversation_to_print) - i) // 2
                    conversation_text += f"## Version {round_number-1}\n\n"

                role = message["role"].capitalize()
                try:
                    content = json.loads(message["content"])
                    content = content["commentary"]
                except:
                    content = message["content"].split(
                        " And here is the existing code:"
                    )[0]
                    if content == "":
                        content = "_User edited the code directly_"

                emoji = "πŸ‘€" if role == "User" else "πŸ€–"
                conversation_text += f"**{emoji} {role}:** {content}\n\n"

        return conversation, code, conversation_text

    except ValidationError as ve:
        error_msg = f"Response validation error: {ve}"
        raise gr.Error(error_msg)
    except Exception as e:
        error_msg = f"An error occurred: {e}"
        raise gr.Error(error_msg)


# Define the Gradio interface
with gr.Blocks(
    title=APP_TITLE, theme=gr.themes.Ocean(), fill_width=True, fill_height=True
) as demo:
    gr.HTML(APP_HEADER)

    with gr.Row():
        with gr.Column(scale=1):
            conversation_output = gr.Markdown(label="Chat History", height=500)

        with gr.Column(scale=2):
            code_output = gr.Code(
                label="LLM Generated Code",
                interactive=True,
                language="python",
                lines=30,
            )
            with gr.Row():
                add_comments_btn = gr.Button("Add Comments πŸ’¬")
                refactor_btn = gr.Button("Refactor πŸ”¨")

    with gr.Row():
        with gr.Column(scale=9):
            user_input = gr.Textbox(
                label="Enter Your Request here",
                placeholder="Type something here...",
                lines=2,
            )
        with gr.Column(scale=1):
            submit_btn = gr.Button("Submit πŸš€")
            reset_btn = gr.Button("Reset πŸ”„")

    # Initialize conversation history with system prompt using Gradio State
    initial_conversation = [
        {
            "role": "system",
            "content": LLM_SYSTEM_PROMPT,
        }
    ]

    conversation_state = gr.State(
        initial_conversation
    )  # Define a single State instance

    # Define the button click event
    def on_submit(user_input, conversation, current_code):
        result = get_llm_responses(user_input, conversation, current_code)
        return [""] + list(result)  # Clear the textbox by returning an empty string

    submit_btn.click(
        fn=on_submit,
        inputs=[user_input, conversation_state, code_output],
        outputs=[user_input, conversation_state, code_output, conversation_output],
    )

    def add_comments_fn(conversation, current_code):
        return on_submit(
            "Please add more comments to the code. Make it production ready.",
            conversation,
            current_code,
        )

    add_comments_btn.click(
        fn=add_comments_fn,
        inputs=[conversation_state, code_output],
        outputs=[user_input, conversation_state, code_output, conversation_output],
    )

    def refactor_fn(conversation, current_code):
        return on_submit(
            "Please refactor the code. Make it more efficient.",
            conversation,
            current_code,
        )

    refactor_btn.click(
        fn=refactor_fn,
        inputs=[conversation_state, code_output],
        outputs=[user_input, conversation_state, code_output, conversation_output],
    )

    def reset_fn():
        return "", initial_conversation, "", ""

    reset_btn.click(
        fn=reset_fn,
        outputs=[user_input, conversation_state, code_output, conversation_output],
    )

# Launch the Gradio app
if __name__ == "__main__":
    demo.launch()