Skip to content

Commit 25e9a13

Browse files
author
Sébastien Fichot
committed
feat(main.py): refactor code to improve readability and error handling
feat(main.py): integrate streamlit for better UI and logging for better debugging feat(main.py): add argparse for command line arguments feat(main.py): change file extensions from .txt to .md for better readability feat(main.py): add new prompts and results directories for better organization feat(main.py): add .gitignore to ignore .venv directory feat(main.py): add openai_apikey.md and problems.md for storing API key and problems respectively The code in main.py has been refactored to improve readability and error handling. Streamlit has been integrated to provide a better user interface and logging has been added for better debugging. Argparse has been added to handle command line arguments. The file extensions have been changed from .txt to .md for better readability in text editors that support markdown. New directories for prompts and results have been added for better organization of files. A .gitignore file has been added to ignore the .venv directory which contains virtual environment files. The openai_apikey.md and problems.md files have been added to store the OpenAI API key and problems respectively.
1 parent adafd1c commit 25e9a13

13 files changed

+232
-108
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.venv
2+
results/*.md
3+
solution_*.md
4+
debug.txt

main.py

Lines changed: 196 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,86 @@
11
import openai
22
import os
3-
import requests
4-
import re
5-
from time import sleep
63
import time
4+
import logging
5+
import argparse
6+
import streamlit as st
7+
8+
# Set up logging
9+
logging.basicConfig(level=logging.INFO)
710

811
# Define a function to open a file and return its contents as a string
9-
def open_file (filepath) :
10-
with open (filepath, 'r', encoding='utf-8') as infile:
11-
return infile.read ()
12+
def open_file(filepath):
13+
try:
14+
with open(filepath, 'r', encoding='utf-8') as infile:
15+
return infile.read()
16+
except IOError as e:
17+
logging.error(f'Error opening file {filepath}: {e}')
18+
raise e
19+
20+
# Define a function to save content to a file
21+
def save_file(filepath, content, mode='w'):
22+
try:
23+
with open(filepath, mode, encoding='utf-8') as outfile:
24+
outfile.write(content)
25+
except IOError as e:
26+
logging.error(f'Error writing to file {filepath}: {e}')
27+
28+
def save_debug(content):
29+
try:
30+
save_file('debug.txt', content, 'a')
31+
except IOError as e:
32+
logging.error(f'Error writing to file {filepath}: {e}')
1233

13-
#Define a function to save content to a file
14-
def save_file (filepath, content):
15-
with open (filepath, 'w', encoding='utf-8') as outfile:
16-
outfile.write (content)
1734

1835
# Set the OpenAI API keys by reading them from files
19-
api_key = open_file ('openai apikey2.txt')
36+
api_key = open_file('openai_apikey.md')
37+
38+
page_title = '# Chain Prompt + Tree of Thoughts 🎈'
39+
40+
st.set_page_config(page_title=page_title, page_icon=None, layout="wide", initial_sidebar_state="auto", menu_items=None)
41+
42+
st.markdown(page_title)
43+
44+
col1, col2 = st.columns([1, 4])
45+
col1.subheader("Auto")
46+
col2.subheader("Result")
47+
bar = col2.progress(0)
2048

2149
class ScriptRunner:
22-
def __init__ (self):
50+
def __init__(self, loop_count):
2351
self.current_progress = 0
52+
self.loop_count = loop_count
53+
self.conversation = []
54+
self.problem = ""
55+
self.evidea2 = ""
2456

25-
def update progress (self, value);
57+
def update_progress(self, value):
2658
self.current_progress = value
59+
bar.progress(value)
2760

28-
def get_solution (self):
61+
def get_solution(self):
2962
if self.conversation:
3063
assistant_messages = ""
3164
for msg in self.conversation:
32-
if msg ['role'] = 'assistant':
65+
if msg['role'] == 'assistant':
3366
assistant_messages += msg['content'] + "\n"
3467
return assistant_messages.strip()
3568
return 'Solution not yet available.'
3669

37-
def get_chain_results (self):
70+
def get_chain_results(self):
3871
chain_results = {}
39-
for i in range (1, 8):
40-
if os. path.exists (f'chain{i}.txt');
41-
chain_results [f'chain{i}'] = open_file(f'chain{i}.txt')
42-
return chain_results
72+
for i in range(1, 8):
73+
if os.path.exists(f'chain{i}.md'):
74+
chain_results[f'chain{i}'] = open_file(f'chain{i}.md')
75+
return chain_results
4376

4477
def get_chat_response (self):
45-
eturn self.chat_response
78+
return self.chat_response
4679

4780
def get_conversation_history (self):
4881
return "\n".join([f"{message['role'].capitalize()}: {message['content']}" for message in self.conversation])
4982

83+
5084
def chatgpt(self, api_key, conversation, chatbot, user_input, temperature=0.7, frequency_penalty=0.2, presence_penalty=0, max_retry=5):
5185
# Set the API key
5286
openai.api_key = api_key
@@ -62,6 +96,9 @@ def chatgpt(self, api_key, conversation, chatbot, user_input, temperature=0.7, f
6296
retry = 0
6397
while True:
6498
try:
99+
save_debug(f'retry: {retry}\n')
100+
save_debug(f'messages_input: {messages_input}\n')
101+
65102
# Make an API call to the Chat Completion endpoint with the updated messages
66103
completion = openai.ChatCompletion.create(
67104
model="gpt-4",
@@ -74,108 +111,159 @@ def chatgpt(self, api_key, conversation, chatbot, user_input, temperature=0.7, f
74111
# Extract the assistant's message and add it to the conversation
75112
message = completion['choices'][0]['message']['content']
76113
conversation.append({"role": "assistant", "content": message})
114+
save_debug(f'message: {message}\n')
115+
save_debug('----\n')
77116
return message
78-
except openai.api_resources.completion.ChatCompletion.CreateError as e:
117+
118+
except openai.error.RateLimitError as e:
79119
if e.error['message'] == 'Rate limit exceeded' and retry < max_retry:
80-
time.sleep(1) # Sleep for 1 second before retrying
120+
retry_time = e.retry_after if hasattr(e, 'retry_after') else 3
121+
print(f'Rate limit exceeded. Sleeping for {retry_time} seconds...')
122+
time.sleep(retry_time)
81123
retry += 1
82124
else:
83125
raise e
84-
time.sleep(1) # Sleep for 1 second before retrying
126+
127+
except openai.error.ServiceUnavailableError as e:
128+
retry_time = 10 # Adjust the retry time as needed
129+
print(f'Service is unavailable. Retrying in {retry_time} seconds...')
130+
time.sleep(retry_time)
131+
retry += 1
132+
133+
except openai.error.APIError as e:
134+
retry_time = e.retry_after if hasattr(e, 'retry_after') else 10
135+
print(f'API error occurred. Retrying in {retry_time} seconds...')
136+
time.sleep(retry_time)
137+
retry += 1
138+
139+
except OSError as e:
140+
retry_time = 5 # Adjust the retry time as needed
141+
print(f'Connection error occurred: {e}. Retrying in {retry_time} seconds...')
142+
time.sleep(retry_time)
143+
retry += 1
144+
145+
def chain_process(self, prompt_file, save_file_name, replacements, api_key, conversation, chatbot):
146+
prompt = open_file(prompt_file)
147+
for placeholder, value in replacements.items():
148+
prompt = prompt.replace(placeholder, value)
149+
150+
col1.markdown(f'- {prompt_file}')
151+
152+
result = self.chatgpt(api_key, conversation, chatbot, prompt)
153+
save_file(save_file_name, result)
154+
155+
with col2.expander(save_file_name):
156+
st.markdown(f'Prompt: {prompt_file}')
157+
st.markdown(f'File: {save_file_name}')
158+
st.markdown(result)
159+
160+
return result
85161

86162
def run_loop(self):
87-
for i in range (3): # change the number here to adjust the number of iterations
163+
for i in range(self.loop_count):
88164
# Create a new conversation list for each iteration
89165
conversation_iteration = []
90-
166+
91167
# Summary Chain 3
92-
win1 = open_file('prompt3.txt').replace('<<WINNINGIDEA>>', self.evidea2)
93-
print(win1)
94-
win2 = self.chatgpt (api_key, conversation_iteration, "Assistant", win1)
95-
save_file('winning1_{}.txt'.format(i), win2)
96-
print (win2)
168+
replacements = {'<<WINNINGIDEA>>': self.evidea2}
169+
win2 = self.chain_process('prompts/discriminate.md', f'results/loop_{i}_discriminated.md', replacements, api_key, conversation_iteration, "Assistant")
97170
self.update_progress(20 + 20 * i)
98171

99172
# Summary Chain 4
100-
loopidea = open_file('prompt1-5.txt').replace('<<PROBLEM>>', self.problem).replace('<<WINNING2>>', win2)
101-
print(loopidea)
102-
loopidea2 = self.chatgpt(api_key, conversation_iteration, "Assistant", loopidea)
103-
save_file('winningloop_{}.txt'.format(i), loopidea2)
104-
print (loopidea2)
173+
replacements = {'<<PROBLEM>>': self.problem, '<<WINNING2>>': win2}
174+
loopidea2 = self.chain_process('prompts/brainstorm.md', f'results/loop_{i}_brained.md', replacements, api_key, conversation_iteration, "Assistant")
105175
self.update_progress(40 + 20 * i)
106176

107177
# Summary Chain 5
108-
loopidea3 = open_file('prompt2-5.txt').replace('<<WLOOP>>', loopidea2)
109-
print (loopidea3)
110-
loopidea4 = self.chatgpt (api_key, conversation_iteration, "Assistant", loopidea3)
111-
save_file('winningloop2_().txt'.format (i), loopidea4)
112-
print (loopidea4)
178+
replacements = {'<<WLOOP>>': loopidea2}
179+
loopidea4 = self.chain_process('prompts/evaluate.md', f'results/loop_{i}_evaluated.md', replacements, api_key, conversation_iteration, "Assistant")
113180
self.update_progress(60 + 20 * i)
114181

115-
def run_script(self):
116-
self.conversation = []
117-
self.problem = open_file('problems.txt')
118-
# Create a new conversation list
119-
conversation = []
120-
121-
# Summary Chain 1
122-
idea = open_file('prompt1.txt').replace('<<PROBLEM>>', self.problem)
123-
print(idea)
124-
idea2 = self.chatgpt(api_key, conversation, "Assistant", idea)
125-
save_file('ideas1.txt', idea2)
126-
print (idea2)
127-
self.update_progress(5)
128-
129-
# Summary Chain 2
130-
evidea = open_file('prompt2.txt').replace('<<3IDEAS>>', idea2)
131-
print(evidea)
132-
self.evidea2 = self.chatgpt(api_key, conversation, "Asaistant", evidea)
133-
save_file('evideas1.txt', self.evidea2)
134-
print (self.evidea2)
135-
self.update_progress(10)
136-
137-
# Summary Chain 3
138-
win1 = open_file('prompt3.txt').replace('<<WINNINGIDEA>>', self.evidea2)
139-
print(win1)
140-
win2 = self.chatgpt(api_key, conversation, "Assistant", win1)
141-
save_file('winning1.txt', win2)
142-
print(win2)
143-
self.update_progress(20)
144-
145-
# Summary Chain 4
146-
loopidea = open_file('prompt1-5.txt').replace('<<PROBLEM>>', self.problem).replace('<<WINNING2>>', win2)
147-
print(loopidea)
148-
loopidea2 = self.chatgpt (api_key, conversation, "Assistant", loopidea)
149-
save_file('winningloop.txt', loopidea2)
150-
print(loopidea2)
151-
self.update_progress(30)
152-
153-
# Summary Chain 5
154-
loopidea3 = open_file('prompt2-5.txt').replace('<<WLOOP>>', loopidea2)
155-
print(loopidea3)
156-
loopidea4 = self.chatgpt (api_key, conversation, "Assistant", loopidea3)
157-
save_file('winningloop2.txt', loopidea4)
158-
print(loopidea4)
159-
self.run_loop()
160-
self.update_progress(60)
161-
162-
# Summary Chain 6
163-
winner = open_file('winning1_3.txt')
164-
winner2 = open_file('winnerprompt.txt').replace('<<WINNER>>', winner)
165-
print(winner2)
166-
winner3 = self.chatgpt(api_key, conversation, "Assistant", winner2)
167-
save_file('winnerdeep.txt', winner3)
168-
print(winner3)
169-
self.update_progress(80)
170-
171-
# Summary Chain 7
172-
winner4 = open_file('finalprompt.txt').replace('<<WINNER2>>', winner3) # 184 --
173-
print(winner4)
174-
winner5 = self.chatgpt(api_key, conversation, "Assistant", winner4)
175-
save_file('winnerfinal.txt', winner5)
176-
print(winner5)
177-
self.update_progress(100)
178-
179-
# Print out the results of each chain
180-
for chain, result in self.get_chain_results().items():
181-
print(f"{chain}: {result}")
182+
def run_script(self):
183+
self.problem = open_file('problems.md')
184+
185+
col2.markdown("Problems")
186+
col2.markdown(self.problem)
187+
188+
conversation = []
189+
190+
# Summary Chain 1
191+
replacements = {'<<PROBLEM>>': self.problem}
192+
idea2 = self.chain_process('prompts/brainstorm-initial.md', 'results/brainstormed.md', replacements, api_key, conversation, "Assistant")
193+
self.update_progress(5)
194+
195+
# Summary Chain 2
196+
replacements = {'<<3IDEAS>>': idea2}
197+
self.evidea2 = self.chain_process('prompts/evaluate-initial.md', 'results/evaluated.md', replacements, api_key, conversation, "Assistant")
198+
self.update_progress(10)
199+
200+
# Summary Chain 3
201+
replacements = {'<<WINNINGIDEA>>': self.evidea2}
202+
win2 = self.chain_process('prompts/discriminate.md', 'results/discriminated.md', replacements, api_key, conversation, "Assistant")
203+
self.update_progress(20)
204+
205+
# Summary Chain 4
206+
replacements = {'<<PROBLEM>>': self.problem, '<<WINNING2>>': win2}
207+
loopidea2 = self.chain_process('prompts/brainstorm.md', 'results/brainstormed-2.md', replacements, api_key, conversation, "Assistant")
208+
self.update_progress(30)
209+
210+
# Summary Chain 5
211+
replacements = {'<<WLOOP>>': loopidea2}
212+
loopidea4 = self.chain_process('prompts/evaluate.md', 'results/evaluated-2.md', replacements, api_key, conversation, "Assistant")
213+
self.update_progress(60)
214+
215+
self.run_loop()
216+
217+
# Summary Chain 6
218+
winner = open_file(f'results/loop_{self.loop_count - 1}_evaluated.md')
219+
replacements = {'<<WINNER>>': winner}
220+
winner3 = self.chain_process('prompts/deepen-win.md', 'results/win-deepened.md', replacements, api_key, conversation, "Assistant")
221+
self.update_progress(80)
222+
223+
# Summary Chain 7
224+
replacements = {'<<WINNER2>>': winner3}
225+
winner5 = self.chain_process('prompts/justify-win.md', 'results/win-justified.md', replacements, api_key, conversation, "Assistant")
226+
self.update_progress(95)
227+
228+
# Create a solution.md
229+
timestr = time.strftime("%Y-%m-%d_%H-%M-%S")
230+
solution_file_name = f'solution_{timestr}.md'
231+
save_file(solution_file_name, '# SOLUTIONS\n\n', 'w')
232+
save_file(solution_file_name, '## Stated problems\n\n', 'a')
233+
save_file(solution_file_name, self.problem, 'a')
234+
save_file(solution_file_name, '\n\n', 'a')
235+
save_file(solution_file_name, '## Initial brainstorm\n\n', 'a')
236+
save_file(solution_file_name, self.evidea2, 'a')
237+
save_file(solution_file_name, '\n\n', 'a')
238+
save_file(solution_file_name, '## Second brainstorm\n\n', 'a')
239+
save_file(solution_file_name, loopidea2, 'a')
240+
save_file(solution_file_name, '\n\n', 'a')
241+
save_file(solution_file_name, '## Second brainstorm\n\n', 'a')
242+
save_file(solution_file_name, loopidea2, 'a')
243+
save_file(solution_file_name, '\n\n', 'a')
244+
save_file(solution_file_name, f'## Solution\n', 'a')
245+
save_file(solution_file_name, f'After {self.loop_count} iterations, we deepened the thoughts on the solution.\n\n', 'a')
246+
save_file(solution_file_name, winner3, 'a')
247+
save_file(solution_file_name, '\n\n', 'a')
248+
save_file(solution_file_name, f'## Final thoughts on the solution\n\n', 'a')
249+
save_file(solution_file_name, winner5, 'a')
250+
self.update_progress(100)
251+
252+
# Print out the results of each chain
253+
for chain, result in self.get_chain_results().items():
254+
logging.info(f'{chain}: {result}')
255+
with st.sidebar:
256+
st.divider()
257+
st.markdown(chain)
258+
st.divider()
259+
st.markdown(result)
260+
st.divider()
261+
262+
263+
if __name__ == "__main__":
264+
parser = argparse.ArgumentParser(description='Run the script with a specific number of loops.')
265+
parser.add_argument('--loops', type=int, default=3, help='The number of loops to run.')
266+
args = parser.parse_args()
267+
268+
runner = ScriptRunner(loop_count=args.loops)
269+
runner.run_script()

problems.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
I am a new Tech Lead in a company which operates over the Spotify organization model (Squads, Chapters, and Matrices). I will operate within a team of Tech Leads. What should I focus on for the first 30 days?

prompts/brainstorm-initial.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Here is the problem : <<PROBLEM>>
2+
3+
Could you brainstorm 3 creative distinct solutions? Please consider the 3 factors that has the most impact on the outcome.

prompts/brainstorm.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Here is the problem:
2+
3+
<<PROBLEM>>
4+
5+
Could you brainstorm 2 new creative distinct solutions and include the following idea <<WINNING2>> so we now have 3 ideas. Please consider the 3 factors that has the most impact on the outcome.

prompts/deepen-win.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
For the winning solution, deepen the thought process. Generate potential scenarios, strategies for implementation, any necessary partnerships or resources, and how potential obstacles might be overcome. Also, consider any potential unexpected outcomes and how they might be handled.
2+
Winning solution:
3+
<<WINNER>>

prompts/discriminate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Here are the ideas:
2+
3+
<<WINNINGIDEA>>
4+
5+
Remove to 2 lowest rated Ideas and keep and rewrite a compressed summary of ONLY the higest rated idea including the probability score.

0 commit comments

Comments
 (0)