as-cle-bert
commited on
Commit
•
59d87f3
1
Parent(s):
39652f5
Create main.py
Browse files
main.py
ADDED
@@ -0,0 +1,184 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from langchain_openai import ChatOpenAI
|
2 |
+
from langchain_core.prompts import ChatPromptTemplate
|
3 |
+
import os
|
4 |
+
from langchain_core.pydantic_v1 import BaseModel, Field
|
5 |
+
import gradio as gr
|
6 |
+
|
7 |
+
|
8 |
+
class code(BaseModel):
|
9 |
+
"""Code output"""
|
10 |
+
|
11 |
+
prefix: str = Field(description="Description of the problem and approach")
|
12 |
+
imports: str = Field(description="Code block import statements")
|
13 |
+
code: str = Field(description="Code block not including import statements")
|
14 |
+
possible_errors: str = Field(description="Description of potential error and vulnerabilities in the code")
|
15 |
+
description = "Schema for code solutions to questions about Code."
|
16 |
+
|
17 |
+
class revision(BaseModel):
|
18 |
+
"""Revision output"""
|
19 |
+
|
20 |
+
imports_revision: str = Field(description="Revision of imports")
|
21 |
+
code_revision: str = Field(description="Revision of code")
|
22 |
+
overall_evaluation: str = Field(description="Thorough evaluation of the imports and of the code")
|
23 |
+
description = "Schema for code solutions to questions about Code."
|
24 |
+
|
25 |
+
def dict_to_string(d):
|
26 |
+
# Create a list of strings in the form '-key value'
|
27 |
+
parts = [f"{key}:\n\t{value}" for key, value in d.items()]
|
28 |
+
# Join the parts with a space separator
|
29 |
+
result = '\n'.join(parts)
|
30 |
+
return result
|
31 |
+
|
32 |
+
def coder_reply_to_string(solution: code):
|
33 |
+
d = solution.__dict__
|
34 |
+
return dict_to_string(d)
|
35 |
+
|
36 |
+
class CodeGenerator:
|
37 |
+
def __init__(self, coder, revisor, maxiters):
|
38 |
+
self.coder = coder
|
39 |
+
self.revisor = revisor
|
40 |
+
self.maxiters = maxiters
|
41 |
+
def generate(self, prompt, context):
|
42 |
+
i = 0
|
43 |
+
while i < self.maxiters:
|
44 |
+
solution = self.coder.invoke({"context": context, "messages": [("user", prompt)]})
|
45 |
+
revision = self.revisor.invoke({"messages": [("user", coder_reply_to_string(solution))]})
|
46 |
+
context = coder_reply_to_string(revision)
|
47 |
+
i+=1
|
48 |
+
return solution
|
49 |
+
|
50 |
+
class modularized_code(BaseModel):
|
51 |
+
prefix: str = Field(description="Description of the problem and approach")
|
52 |
+
imports: str = Field(description="Code block import statements")
|
53 |
+
code: str = Field(description="Modularized code block not including import statements")
|
54 |
+
description = "Schema for code solutions to questions about Code."
|
55 |
+
|
56 |
+
def check_code(solution):
|
57 |
+
try:
|
58 |
+
exec(solution.imports)
|
59 |
+
except Exception as e:
|
60 |
+
return f"An error occurred during import phase: {e}"
|
61 |
+
try:
|
62 |
+
exec(solution.imports+"\n"+solution.code)
|
63 |
+
return "Code ran succesfully"
|
64 |
+
except Exception as e:
|
65 |
+
return f"An error occurred during code execution phase: {e}"
|
66 |
+
|
67 |
+
class CodeChecker:
|
68 |
+
def __init__(self, solution, checker):
|
69 |
+
self.solution = solution
|
70 |
+
self.checker = checker
|
71 |
+
def check_n_refactor(self, iterations):
|
72 |
+
for i in range(iterations):
|
73 |
+
try:
|
74 |
+
success_status = check_code(self.solution)
|
75 |
+
except Exception as e:
|
76 |
+
success_status = f"An error occurred while checking the code: {e}"
|
77 |
+
print("Success status: " + success_status)
|
78 |
+
if success_status == "Code run succesfully":
|
79 |
+
return self.solution
|
80 |
+
else:
|
81 |
+
self.solution = self.checker.invoke({"code": self.solution.imports + "\n" + self.solution.code, "errors": success_status})
|
82 |
+
return self.solution
|
83 |
+
|
84 |
+
# Grader prompt
|
85 |
+
code_gen_prompt = ChatPromptTemplate.from_messages(
|
86 |
+
[
|
87 |
+
(
|
88 |
+
"system",
|
89 |
+
"""You are a coding assistant with expertise in python. Based on the following context (which can be code or revision suggestions): \n ------- \n {context} \n ------- \n Answer the user
|
90 |
+
question. Ensure any code you provide can be executed \n
|
91 |
+
with all required imports and variables defined. First, structure your answer with a description of the code solution. \n
|
92 |
+
Secondly list the imports. Thirdly list the functioning code block. Finally, describe potential errors one might encounter while executing the code. Here is the user question:""",
|
93 |
+
),
|
94 |
+
("placeholder", "{messages}"),
|
95 |
+
]
|
96 |
+
)
|
97 |
+
|
98 |
+
revisor_prompt = ChatPromptTemplate.from_messages(
|
99 |
+
[
|
100 |
+
(
|
101 |
+
"system",
|
102 |
+
"""You are a coding revisor with expertise in python. From the prefix, import, code and potential errors produced by a programmer, you should provide a thorough review with:
|
103 |
+
- First what would you improve in the imports
|
104 |
+
- Second what would you improve in the code block
|
105 |
+
- Third an overall evaluation of the whole code solution produced by the programmer. Here is the programmer solution you should revise:""",
|
106 |
+
),
|
107 |
+
("placeholder", "{messages}"),
|
108 |
+
]
|
109 |
+
)
|
110 |
+
|
111 |
+
modules_prompt = ChatPromptTemplate.from_messages(
|
112 |
+
[
|
113 |
+
(
|
114 |
+
"system",
|
115 |
+
"""Your job is to refactor code in a modularized way, and you have expertise in python. From the prefix, import, code and potential errors produced by a programmer, you should provide a refactored and modularized code with:
|
116 |
+
- A description of what you did
|
117 |
+
- The imports
|
118 |
+
- The refactored and modularized code.
|
119 |
+
Orient code generation on this context (which may be user's request or some revision suggestions):
|
120 |
+
\n\n-----------\n{context}\n-------------\n\n
|
121 |
+
Here is the programmer solution you should refactor and modularize:""",
|
122 |
+
),
|
123 |
+
("placeholder", "{messages}"),
|
124 |
+
]
|
125 |
+
)
|
126 |
+
|
127 |
+
checker_prompt = ChatPromptTemplate.from_messages(
|
128 |
+
[
|
129 |
+
(
|
130 |
+
"system",
|
131 |
+
"""Your job is to refactor code based on these errors:
|
132 |
+
|
133 |
+
----------
|
134 |
+
{errors}
|
135 |
+
----------
|
136 |
+
|
137 |
+
This is the code to refactor:
|
138 |
+
|
139 |
+
----------
|
140 |
+
{code}
|
141 |
+
----------
|
142 |
+
You should then reply with:
|
143 |
+
- A description of what you did
|
144 |
+
- The imports
|
145 |
+
- The refactored code""",
|
146 |
+
),
|
147 |
+
]
|
148 |
+
)
|
149 |
+
|
150 |
+
import time
|
151 |
+
|
152 |
+
def reply(message, history, api_key, context):
|
153 |
+
os.environ["OPENAI_API_KEY"] = api_key
|
154 |
+
expt_llm = "gpt-4o"
|
155 |
+
llm = ChatOpenAI(temperature=0, model=expt_llm)
|
156 |
+
code_gen_chain = code_gen_prompt | llm.with_structured_output(code)
|
157 |
+
code_revision_chain = revisor_prompt | llm.with_structured_output(revision)
|
158 |
+
aicodegenerator = CodeGenerator(code_gen_chain, code_revision_chain, 5)
|
159 |
+
solution = aicodegenerator.generate(prompt=message, context=context)
|
160 |
+
code_modules_chain = modules_prompt | llm.with_structured_output(modularized_code)
|
161 |
+
aicodemodularizer = CodeGenerator(code_modules_chain, code_revision_chain, 5)
|
162 |
+
modules_solution = aicodemodularizer.generate(prompt=coder_reply_to_string(solution), context=message)
|
163 |
+
code_checker_chain = checker_prompt | llm.with_structured_output(code)
|
164 |
+
aicodechecker = CodeChecker(modules_solution, code_checker_chain)
|
165 |
+
final_solution = aicodechecker.check_n_refactor(5)
|
166 |
+
response = "The final solution for your code is:\n\n```python" + final_solution.imports + "\n" + final_solution.code + "\n```"
|
167 |
+
this_hist = ""
|
168 |
+
for char in response:
|
169 |
+
this_hist+=char
|
170 |
+
time.sleep(0.001)
|
171 |
+
yield this_hist
|
172 |
+
|
173 |
+
api_key_user = gr.Textbox(label="OpenAI API key", type="password")
|
174 |
+
context_user = gr.Textbox(label="Context", info="Add some contextual instructions for the model to know how to generate code", value="def hello_world():\n\tprint('Hello world!')\n\nhello_world()")
|
175 |
+
|
176 |
+
chatbot = gr.Chatbot(height=400)
|
177 |
+
additional_accordion = gr.Accordion(label="Parameters to be set before you start chatting", open=True)
|
178 |
+
|
179 |
+
with gr.Blocks() as demo:
|
180 |
+
gr.HTML("<h1 align='center'>Self-Reviewing Coding Assistant🤖💻</h1>")
|
181 |
+
gr.Image('coding_assistant.png')
|
182 |
+
gr.ChatInterface(fn=reply, additional_inputs=[api_key_user, context_user], additional_inputs_accordion=additional_accordion, chatbot=chatbot)
|
183 |
+
|
184 |
+
demo.launch(server_name="0.0.0.0", server_port=7860)
|