Spaces:
Sleeping
Sleeping
Minimal HTML GUI.
Browse filesSession is stored in db
Mocked chatGpt calls, to test async loading.
Works local and docker.
- eval_code.py +77 -0
- main.py +269 -125
- requirements.txt +1 -0
- test/test_dbops.py +27 -0
- test/test_eval_code.py +28 -0
eval_code.py
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import time
|
3 |
+
|
4 |
+
"""
|
5 |
+
We will handle here the code evaluation phase.
|
6 |
+
|
7 |
+
"""
|
8 |
+
import json
|
9 |
+
|
10 |
+
def clean_prompt_answer(answer):
|
11 |
+
"""
|
12 |
+
Chatgpt4 is ok, does not pollute the code but 3.5 encloses it in ```
|
13 |
+
|
14 |
+
:param answer:
|
15 |
+
:return:
|
16 |
+
"""
|
17 |
+
cleaned = []
|
18 |
+
for l in answer.split("\n"):
|
19 |
+
if l.startswith("```"):
|
20 |
+
continue
|
21 |
+
else:
|
22 |
+
cleaned.append(l)
|
23 |
+
return "\n".join(cleaned)
|
24 |
+
|
25 |
+
def parse_chatgpt_answer(ans_text):
|
26 |
+
try:
|
27 |
+
js_answer = json.loads(ans_text)
|
28 |
+
except:
|
29 |
+
# for now we dump the error in console
|
30 |
+
import traceback
|
31 |
+
exception = traceback.format_exc()
|
32 |
+
print(exception)
|
33 |
+
return {"error":exception}
|
34 |
+
return js_answer
|
35 |
+
|
36 |
+
def eval_code_by_chatgpt(openai_client, ccode):
|
37 |
+
"""
|
38 |
+
Will evaluate a piece of code using our heavily tuned prompt!
|
39 |
+
|
40 |
+
:param openai_client:
|
41 |
+
:param ccode:
|
42 |
+
:return:
|
43 |
+
"""
|
44 |
+
time.sleep(3)
|
45 |
+
try:
|
46 |
+
return """[
|
47 |
+
{
|
48 |
+
"criteria": "DRY",
|
49 |
+
"explanation": "The memory allocation and initialization for ``p1``, ``p2``, and ``p3`` are repetitive. Consider creating a function like ``allocateAndInitializeMemory``."
|
50 |
+
},
|
51 |
+
{
|
52 |
+
"criteria": "SRP",
|
53 |
+
"explanation": "The ``main`` function handles memory allocation, initialization, and printing. You should separate these responsibilities into different functions like ``allocateMemory``, ``initializeData``, and ``printData``."
|
54 |
+
},
|
55 |
+
{
|
56 |
+
"criteria": "NAME",
|
57 |
+
"explanation": "``x1`` should be called ``title``, ``y1`` should be called ``author``, ``z1`` should be called ``year``, ``p1`` should be called ``titlePtr``, ``p2`` should be called ``authorPtr``, ``p3`` should be called ``yearPtr``."
|
58 |
+
}
|
59 |
+
]"""
|
60 |
+
assert openai_client is not None
|
61 |
+
except:
|
62 |
+
import traceback
|
63 |
+
traceback.print_exc()
|
64 |
+
return {"error":"There was an error while parsing the answer. Maybe ChatGPT is overloaded?"}
|
65 |
+
|
66 |
+
def eval_the_piece_of_c_code(openai_client, ccode):
|
67 |
+
"""
|
68 |
+
Main entrypoint to this module. Will be called from backend
|
69 |
+
|
70 |
+
:param ccode:
|
71 |
+
:return:
|
72 |
+
"""
|
73 |
+
chatgpt_ans = eval_code_by_chatgpt(openai_client, ccode)
|
74 |
+
chatgpt_js = parse_chatgpt_answer(chatgpt_ans)
|
75 |
+
return chatgpt_js
|
76 |
+
|
77 |
+
|
main.py
CHANGED
@@ -1,6 +1,13 @@
|
|
|
|
|
|
|
|
1 |
from fasthtml.common import *
|
2 |
import os
|
3 |
-
import
|
|
|
|
|
|
|
|
|
4 |
|
5 |
OAUTH_CLIENT_ID = os.environ.get('OAUTH_CLIENT_ID')
|
6 |
OAUTH_SCOPES = os.environ.get('OAUTH_SCOPES')
|
@@ -8,130 +15,267 @@ OAUTH_CLIENT_SECRET = os.environ.get('OAUTH_CLIENT_SECRET')
|
|
8 |
OPENID_PROVIDER_URL = os.environ.get('OPENID_PROVIDER_URL')
|
9 |
SPACE_HOST = os.environ.get('SPACE_HOST')
|
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 |
serve()
|
|
|
1 |
+
import json
|
2 |
+
import uuid
|
3 |
+
|
4 |
from fasthtml.common import *
|
5 |
import os
|
6 |
+
import eval_code
|
7 |
+
from datetime import datetime
|
8 |
+
from sqlite_minutils.db import Database
|
9 |
+
|
10 |
+
# the secrets. Will be loaded from HF, or for docker --env-file or from IDE
|
11 |
|
12 |
OAUTH_CLIENT_ID = os.environ.get('OAUTH_CLIENT_ID')
|
13 |
OAUTH_SCOPES = os.environ.get('OAUTH_SCOPES')
|
|
|
15 |
OPENID_PROVIDER_URL = os.environ.get('OPENID_PROVIDER_URL')
|
16 |
SPACE_HOST = os.environ.get('SPACE_HOST')
|
17 |
|
18 |
+
# The database. In memory bc it is efemerial on HF anyway.
|
19 |
+
|
20 |
+
global_database = Database(memory=True, memory_name="mem_db_name")
|
21 |
+
global_database_tables = global_database.t
|
22 |
+
session_state_table = global_database_tables.session_state
|
23 |
+
if session_state_table not in global_database_tables:
|
24 |
+
# session_id stored in cookies
|
25 |
+
# see EVAL_STATUS_x below for state
|
26 |
+
session_state_table.create(id=int, session_id=str, state=int, submitted=datetime, completed=datetime, answer=str, pk='id')
|
27 |
+
Session_State_cls = session_state_table.dataclass()
|
28 |
+
|
29 |
+
EVAL_STATE_NEW=0
|
30 |
+
EVAL_STATE_QUERY=1
|
31 |
+
EVAL_STATE_TIMEDOUT=2
|
32 |
+
EVAL_STATE_ANSWER=3
|
33 |
+
EVAL_STATE_ERROR=4
|
34 |
+
|
35 |
+
|
36 |
+
if "localhost" in SPACE_HOST:
|
37 |
+
# Are we hacking locally?
|
38 |
+
print("Localhost detected in SPACE_HOST. App started in debug+live mode!")
|
39 |
+
app, rt = fast_app(debug=True, live=True)
|
40 |
+
else:
|
41 |
+
app, rt = fast_app(debug=False, live=False)
|
42 |
+
|
43 |
+
|
44 |
+
CODE_AUGMENTATIONS=[
|
45 |
+
("DRY", "Don't repeat yourself."),
|
46 |
+
("SRP", "Single object[function] responsability"),
|
47 |
+
("MC", "Magic constants."),
|
48 |
+
("NAME", "Meaningful names in the code."),
|
49 |
+
]
|
50 |
+
|
51 |
+
def format_code_review(code_js, html_id=""):
|
52 |
+
list_of_citerias = []
|
53 |
+
for caug_code, caug_txt in CODE_AUGMENTATIONS:
|
54 |
+
crit_tag = [H3(caug_code), P(caug_txt)]
|
55 |
+
list_of_citerias.extend(crit_tag)
|
56 |
+
# yeah, I know . . .
|
57 |
+
criteria_found = False
|
58 |
+
for eval_line in code_js:
|
59 |
+
if caug_code == eval_line["criteria"]:
|
60 |
+
eval_txt = Pre(eval_line["explanation"])
|
61 |
+
list_of_citerias.append(eval_txt)
|
62 |
+
criteria_found = True
|
63 |
+
if criteria_found is False:
|
64 |
+
list_of_citerias.append(P("Not infringed"))
|
65 |
+
return Div(*list_of_citerias, _id=html_id)
|
66 |
+
|
67 |
+
def generate_default_eval_section(html_id=""):
|
68 |
+
return Div(P("This is where criterias will show up once the code is evaluated"), _id=html_id)
|
69 |
+
|
70 |
+
def generate_working_eval_section(html_id=""):
|
71 |
+
return Div(P("Working . . ."), _id=html_id,
|
72 |
+
hx_get=f"/render_answer",
|
73 |
+
hx_trigger = "every 2s",
|
74 |
+
hx_swap = "outerHTML",
|
75 |
+
)
|
76 |
+
|
77 |
+
# How can I timeout? Well ... TBD.
|
78 |
+
@threaded
|
79 |
+
def call_gpt_and_store_result(pkid, code_to_check):
|
80 |
+
# print("evaluatign code")
|
81 |
+
try:
|
82 |
+
# Pesky way to get a new cursor, in a thread safe way, into the db. This code runs in another thread.
|
83 |
+
# Can we do better?
|
84 |
+
local_database = Database(memory=True, memory_name="mem_db_name")
|
85 |
+
local_cursor = local_database.t.session_state
|
86 |
+
Session_State_cls = local_cursor.dataclass()
|
87 |
+
local_sess_obj_lst = local_cursor(limit=1, where=f"id == {pkid}")
|
88 |
+
local_sess_obj = local_sess_obj_lst[0]
|
89 |
+
gpt_js_eval = eval_code.eval_the_piece_of_c_code(openai_client=None, ccode=code_to_check)
|
90 |
+
# print("done eval with ", gpt_js_eval)
|
91 |
+
# new_sess_obj = Session_State_cls(session_obj)
|
92 |
+
if "error" in gpt_js_eval:
|
93 |
+
local_sess_obj.state = EVAL_STATE_ERROR
|
94 |
+
local_sess_obj.answer = gpt_js_eval["error"]
|
95 |
+
local_sess_obj.completed = datetime.utcnow()
|
96 |
+
else:
|
97 |
+
local_sess_obj.state = EVAL_STATE_ANSWER
|
98 |
+
local_sess_obj.answer = json.dumps(gpt_js_eval)
|
99 |
+
local_sess_obj.completed = datetime.utcnow()
|
100 |
+
local_cursor.update(local_sess_obj)
|
101 |
+
except:
|
102 |
+
import traceback
|
103 |
+
traceback.print_exc()
|
104 |
+
|
105 |
+
def get_rendered_answer(session_id):
|
106 |
+
state_rows = session_state_table(limit=1, where=f"session_id == '{session_id}'", order_by="id DESC")
|
107 |
+
# print(state_rows)
|
108 |
+
if len(state_rows) <= 0:
|
109 |
+
return generate_default_eval_section(html_id="prompt_response")
|
110 |
+
state = state_rows[0]
|
111 |
+
if state.state == EVAL_STATE_ANSWER:
|
112 |
+
gpt_js_eval = json.loads(state.answer)
|
113 |
+
return format_code_review(gpt_js_eval, html_id="prompt_response")
|
114 |
+
if state.state == EVAL_STATE_QUERY:
|
115 |
+
return generate_working_eval_section(html_id="prompt_response")
|
116 |
+
return Div(P("There was an error:", P(state.answer)), _id="prompt_response")
|
117 |
+
|
118 |
+
|
119 |
+
@rt("/render_answer")
|
120 |
+
def get(session):
|
121 |
+
if 'session_id' not in session: return "No session ID"
|
122 |
+
session_id = session["session_id"]
|
123 |
+
return get_rendered_answer(session_id)
|
124 |
+
|
125 |
+
@rt("/")
|
126 |
+
def get(session):
|
127 |
+
if 'session_id' not in session:
|
128 |
+
session['session_id'] = str(uuid.uuid4())
|
129 |
+
inp = Textarea(id="ccodetoeval", name="ccodetoeval", placeholder="Enter a piece of C code", rows=20)
|
130 |
+
# eval_area = Pre("", id="prompt_response")
|
131 |
+
# eval_area = format_code_review([], html_id="prompt_response")
|
132 |
+
eval_area = generate_default_eval_section(html_id="prompt_response")
|
133 |
+
add = Form(Group(inp, Button("Generate")), hx_post="/submit_to_eval", hx_swap="outerHTML", target_id='prompt_response')
|
134 |
+
return Title('Image Generation Demo'), Main(H1('Magic Image Generation'), add, eval_area, cls='container')
|
135 |
+
|
136 |
+
|
137 |
+
@rt("/submit_to_eval", methods="post")
|
138 |
+
def post(ccodetoeval:str, session):
|
139 |
+
if 'session_id' not in session: return P("Bad call. No session ID")
|
140 |
+
session_id = session["session_id"]
|
141 |
+
session_obj = Session_State_cls(
|
142 |
+
session_id=session_id,
|
143 |
+
state=EVAL_STATE_QUERY,
|
144 |
+
submitted=datetime.utcnow(),
|
145 |
+
answer=""
|
146 |
+
)
|
147 |
+
# we insert and we get the new primary key
|
148 |
+
session_obj = session_state_table.insert(session_obj)
|
149 |
+
# will be executed in another thread with magic @threaded
|
150 |
+
call_gpt_and_store_result(session_obj.id, ccodetoeval)
|
151 |
+
return get_rendered_answer(session_id)
|
152 |
+
|
153 |
+
|
154 |
+
## This code is for reference, for OAuth. BIG PITA, will be added later.
|
155 |
+
|
156 |
+
#
|
157 |
+
# js_hf_imports = \
|
158 |
+
# """
|
159 |
+
# {
|
160 |
+
# "imports": {
|
161 |
+
# "@huggingface/hub": "https://cdn.jsdelivr.net/npm/@huggingface/hub@0.13.0/+esm"
|
162 |
+
# }
|
163 |
+
# }
|
164 |
+
# """
|
165 |
+
#
|
166 |
+
# js_block_hf_auth = \
|
167 |
+
# """
|
168 |
+
# import { oauthLoginUrl, oauthHandleRedirectIfPresent } from "@huggingface/hub";
|
169 |
+
# console.log("huggingface env", window.huggingface);
|
170 |
+
# let oauthResult = localStorage.getItem("oauth");
|
171 |
+
# if (oauthResult) {
|
172 |
+
# try {
|
173 |
+
# oauthResult = JSON.parse(oauthResult);
|
174 |
+
# } catch {
|
175 |
+
# oauthResult = null;
|
176 |
+
# }
|
177 |
+
# }
|
178 |
+
#
|
179 |
+
# oauthResult ||= await oauthHandleRedirectIfPresent();
|
180 |
+
# if (oauthResult) {
|
181 |
+
# document.querySelector("pre").textContent = JSON.stringify(oauthResult, null, 2);
|
182 |
+
# localStorage.setItem("oauth", JSON.stringify(oauthResult));
|
183 |
+
# document.getElementById("signout").style.removeProperty("display");
|
184 |
+
# document.getElementById("signout").onclick = async function() {
|
185 |
+
# localStorage.removeItem("oauth");
|
186 |
+
# window.location.href = window.location.href.replace(/\?.*$/, '');
|
187 |
+
# window.location.reload();
|
188 |
+
# }
|
189 |
+
# } else {
|
190 |
+
# document.getElementById("signin").style.removeProperty("display");
|
191 |
+
# document.getElementById("signin").onclick = async function() {
|
192 |
+
# // prompt=consent to re-trigger the consent screen instead of silently redirecting
|
193 |
+
# window.location.href = (await oauthLoginUrl({scopes: window.huggingface.variables.OAUTH_SCOPES})) + "&prompt=consent";
|
194 |
+
# }
|
195 |
+
# }
|
196 |
+
# """
|
197 |
+
#
|
198 |
+
# js_block_hf_auth2 = \
|
199 |
+
# """
|
200 |
+
# import { oauthLoginUrl, oauthHandleRedirectIfPresent } from "@huggingface/hub";
|
201 |
+
# let oauthResult = localStorage.getItem("oauth");
|
202 |
+
# if (oauthResult) {
|
203 |
+
# try {
|
204 |
+
# oauthResult = JSON.parse(oauthResult);
|
205 |
+
# } catch {
|
206 |
+
# oauthResult = null;
|
207 |
+
# }
|
208 |
+
# }
|
209 |
+
#
|
210 |
+
# console.log("OAuth result", oauthResult);
|
211 |
+
# oauthResult ||= await oauthHandleRedirectIfPresent();
|
212 |
+
#
|
213 |
+
# if (oauthResult) {
|
214 |
+
# document.querySelector("pre").textContent = JSON.stringify(oauthResult, null, 2);
|
215 |
+
# localStorage.setItem("oauth", JSON.stringify(oauthResult));
|
216 |
+
# console.log("There is an oauth result", oauthResult);
|
217 |
+
# document.getElementById("signout").style.removeProperty("display");
|
218 |
+
# document.getElementById("signout").onclick = async function() {
|
219 |
+
# localStorage.removeItem("oauth");
|
220 |
+
# window.location.href = window.location.href.replace(/\?.*$/, '');
|
221 |
+
# window.location.reload();
|
222 |
+
# }
|
223 |
+
#
|
224 |
+
# } else {
|
225 |
+
# console.log("No OAuth result. Setting the loging button event");
|
226 |
+
# document.getElementById("signin").style.removeProperty("display");
|
227 |
+
# document.getElementById("signin").onclick = async function() {
|
228 |
+
# // prompt=consent to re-trigger the consent screen instead of silently redirecting
|
229 |
+
# window.location.href = window.hf_redirect_url;
|
230 |
+
# }
|
231 |
+
# }
|
232 |
+
# """
|
233 |
+
#
|
234 |
+
#
|
235 |
+
# def get_hf_user_data():
|
236 |
+
# pass
|
237 |
+
|
238 |
+
|
239 |
+
# @rt('/', methods="get")
|
240 |
+
# def get():
|
241 |
+
# global SPACE_HOST
|
242 |
+
# if "localhost" in SPACE_HOST:
|
243 |
+
# space_host = f"htpp://{SPACE_HOST}/"
|
244 |
+
# else:
|
245 |
+
# space_host = f"https://{SPACE_HOST}/"
|
246 |
+
# hf_redirect_url_func = (
|
247 |
+
# f"import {{ oauthLoginUrl, }} from '@huggingface/hub'; \n"
|
248 |
+
# f"window.hf_redirect_url = await oauthLoginUrl({{clientId:'{OAUTH_CLIENT_ID}',redirectUrl:'{space_host}',"
|
249 |
+
# f"scopes:'{OAUTH_SCOPES}'}}) + '&prompt=consent';\n"
|
250 |
+
# f"console.log(window.hf_redirect_url);")
|
251 |
+
#
|
252 |
+
# header = Head(Title("C code reviewing"),
|
253 |
+
# Script(src="https://unpkg.com/es-module-shims@1.7.0/dist/es-module-shims.js"),
|
254 |
+
# Script(js_hf_imports, type="importmap"),
|
255 |
+
# )
|
256 |
+
# content = Body(Div(P("Some content!")),
|
257 |
+
# A(f"Space host: {space_host}", href=space_host),
|
258 |
+
# Pre(""),
|
259 |
+
# Script(hf_redirect_url_func, type="module"),
|
260 |
+
# Img(src="https://huggingface.co/datasets/huggingface/badges/resolve/main/sign-in-with-huggingface-xl-dark.svg",
|
261 |
+
# alt="Sign in with Hugging Face",
|
262 |
+
# style="cursor: pointer; display: none;",
|
263 |
+
# _id="signin", name=None),
|
264 |
+
# Button("Sign out", _id="signout", style="display: none", name=None),
|
265 |
+
# A("Authenticate!", href="authorized"),
|
266 |
+
# Script(js_block_hf_auth2, type="module"))
|
267 |
+
# full_page = Html(header, content)
|
268 |
+
# return full_page
|
269 |
+
|
270 |
+
|
271 |
+
# @rt('/change')
|
272 |
+
# def get(): return P('Nice to be here!')
|
273 |
+
|
274 |
+
|
275 |
+
# @rt('/authorized', methods="get")
|
276 |
+
# def authorized():
|
277 |
+
# content = Body(P("Do we have authenticated user?"))
|
278 |
+
# return content
|
279 |
|
280 |
|
281 |
serve()
|
requirements.txt
CHANGED
@@ -1 +1,2 @@
|
|
1 |
python-fasthtml
|
|
|
|
1 |
python-fasthtml
|
2 |
+
fastsql==1.0.1
|
test/test_dbops.py
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fasthtml.common import *
|
2 |
+
from sqlite_minutils.db import Database
|
3 |
+
def test_some_sqldb_inmem():
|
4 |
+
|
5 |
+
db = Database(memory=True)
|
6 |
+
assert db is not None
|
7 |
+
db_tables = db.t
|
8 |
+
session_states = db_tables.session_states
|
9 |
+
if session_states not in db.t:
|
10 |
+
session_states.create(prompt=str, session_id=str, id=int, folder=str, pk='id')
|
11 |
+
Session_state = session_states.dataclass()
|
12 |
+
sess = Session_state(prompt="Some prompt", folder="Somewhere")
|
13 |
+
session_states.insert(sess)
|
14 |
+
session_states.insert(sess)
|
15 |
+
session_states.insert(sess)
|
16 |
+
sess2 = Session_state(prompt="Some prompt", folder="Somewhere new")
|
17 |
+
# insert AND get the newly inserted ID
|
18 |
+
g = session_states.insert(sess2)
|
19 |
+
assert g.id > 3
|
20 |
+
g.prompt = "New prompt"
|
21 |
+
# Update and check if it can be retrieved
|
22 |
+
session_states.update(g)
|
23 |
+
# retrieval
|
24 |
+
newg = session_states(where=f"id={g.id}")
|
25 |
+
assert len(newg) == 1
|
26 |
+
assert newg[0].prompt == "New prompt"
|
27 |
+
|
test/test_eval_code.py
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pytest
|
2 |
+
import eval_code
|
3 |
+
|
4 |
+
TYPICAL_ANSWER = """[
|
5 |
+
{
|
6 |
+
"criteria": "DRY",
|
7 |
+
"explanation": "The memory allocation and initialization for ``p1``, ``p2``, and ``p3`` are repetitive. Consider creating a function like ``allocateAndInitializeMemory``."
|
8 |
+
},
|
9 |
+
{
|
10 |
+
"criteria": "SRP",
|
11 |
+
"explanation": "The ``main`` function handles memory allocation, initialization, and printing. You should separate these responsibilities into different functions like ``allocateMemory``, ``initializeData``, and ``printData``."
|
12 |
+
},
|
13 |
+
{
|
14 |
+
"criteria": "NAME",
|
15 |
+
"explanation": "``x1`` should be called ``title``, ``y1`` should be called ``author``, ``z1`` should be called ``year``, ``p1`` should be called ``titlePtr``, ``p2`` should be called ``authorPtr``, ``p3`` should be called ``yearPtr``."
|
16 |
+
}
|
17 |
+
]"""
|
18 |
+
|
19 |
+
|
20 |
+
def test_parse_chatgpt_answer():
|
21 |
+
ans = eval_code.parse_chatgpt_answer(TYPICAL_ANSWER)
|
22 |
+
assert ans is not None
|
23 |
+
assert len(ans) > 0
|
24 |
+
an_eval = ans[0]
|
25 |
+
assert "criteria" in an_eval.keys()
|
26 |
+
assert "explanation" in an_eval.keys()
|
27 |
+
|
28 |
+
|