-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathapp.py
More file actions
154 lines (129 loc) · 5.33 KB
/
Copy pathapp.py
File metadata and controls
154 lines (129 loc) · 5.33 KB
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
import streamlit as st
from dotenv import load_dotenv
from streamlit_ace import st_ace
from gpt_tools import generate_function_name, try_debug, write_scraper
from prompts import system_prompt, write_scraper_prompt
from search_for_sections import get_scraping_instructions
from utils import redact_test_output, run_code, write_to_disk
st.set_page_config(layout="wide")
st.title("Build Python Web Scrapers with GPT-4")
load_dotenv()
session_states = {"function_name", "final_scraper", "scraper", "scraping_instructions"}
for k in session_states:
if k not in st.session_state:
st.session_state[k] = None
def reset_session_state():
for k in session_states:
st.session_state[k] = None
url = st.text_input(
"Sample URL",
value="https://www.espn.com/nba/injuries",
on_change=reset_session_state,
)
task = st.text_area(
"Describe what you want to scrape from this page",
value="A list of every injured player on every team. Include their name, team, position, status, and the comment field",
on_change=reset_session_state,
)
if st.button("Get Started!") or st.session_state["function_name"] is not None:
if st.session_state["function_name"] is None:
st.session_state["function_name"] = generate_function_name(url, task)
st.session_state["function_name"] = st.text_input(
"Name of the function to generate:", st.session_state["function_name"]
)
@st.cache_data(persist=True)
def learn_to_scrape(url, task):
return get_scraping_instructions(url, task)
if st.session_state["function_name"] is not None:
if st.button("Build a scraper!"):
with st.spinner(
"Scannning the website to learn how to scrape it (this will take a minute)"
):
st.session_state["scraping_instructions"] = learn_to_scrape(url, task)
with st.spinner("Writing a scraper with those instructions"):
st.session_state["scraper"] = write_scraper(
url,
task,
st.session_state["function_name"],
st.session_state["scraping_instructions"],
)
if st.session_state["scraping_instructions"] is not None:
with st.expander("Scraping Instructions"):
st.write(st.session_state["scraping_instructions"])
if st.session_state["scraper"] is not None:
st.write(
"#### Here's a first draft of your scraper -- feel free to edit it, then you can automatically debug it below"
)
st.session_state["scraper"] = st_ace(
value=st.session_state["scraper"], language="python", theme="ambiance"
)
if st.session_state["scraper"] is not None:
st.header("Automatic Debugger")
st.write(
"When you're ready, have GPT-4 iteratively debug the above code to make sure it works"
)
num_rounds = st.slider("Maximum Debugging Rounds", 1, 50, 5, 1)
debug_model = st.selectbox(
"What model to use for debugging", ["gpt-4", "gpt-3.5-turbo"]
)
# maximum_output_length = st.slider('How many words do we allow in the output of a program (larger number make it likely that you will exceed token limits)', 100, 2000, 1500, 100)
creation_log = [
{"role": "system", "content": system_prompt()},
{
"role": "user",
"content": write_scraper_prompt(
url,
task,
st.session_state["function_name"],
st.session_state["scraping_instructions"],
),
},
{"role": "assistant", "content": f"```py\n{st.session_state['scraper']}\n```"},
]
if st.button("Start Debugging"):
write_to_disk(st.session_state["scraper"], st.session_state["function_name"])
working_code = st.session_state["scraper"]
for i in range(num_rounds):
st.subheader(f"Round {i+1}")
code_col, output_col = st.columns(2)
output, err, return_code = run_code(st.session_state["function_name"])
err = redact_test_output(err)
with code_col:
st_ace(
key=f"debug_round_{i}",
value=working_code,
language="python",
theme="ambiance",
readonly=True,
)
with output_col:
with st.expander("STDOUT:"):
st.code(output)
with st.expander("STDERR:"):
st.code(err)
if return_code == 0: # it worked!
st.session_state["final_scraper"] = working_code
break
else: # there was an error, debug
old_code = working_code
working_code, creation_log, response = try_debug(
working_code,
creation_log,
st.session_state["function_name"],
output,
err,
model=debug_model,
)
with output_col:
with st.expander("GPT's reasoning"):
st.write(response)
write_to_disk(working_code, st.session_state["function_name"])
if st.session_state["final_scraper"] is not None:
st.header("Final Code")
st_ace(
value=st.session_state["final_scraper"],
language="python",
theme="ambiance",
key="final_scraper",
readonly=True,
)