Open cometbus opened 1 year ago
I don't know how to do pull requests, but I fixed it.
book.py import openai from tqdm import tqdm import prompts import tiktoken import json
enc = tiktoken.get_encoding("cl100k_base")
class Book: def init(self, **kwargs):
self.arguments = '; '.join([f'{key}: {value}' for key, value in kwargs.items() if key != 'tolerance'])
# Get 'tolerance' attribute from kwargs
self.tolerance = kwargs.get('tolerance', 0.9)
# Assign a status variable
self.status = 0
# Setting up the base prompt
self.base_prompt = [
self.get_message('system', prompts.INITIAL_INSTRUCTIONS),
self.get_message('user', self.arguments),
self.get_message('assistant', 'Ready')
]
# Setting up the title prompt
self.title_prompt = [
self.get_message('system', prompts.TITLE_INSTRUCTIONS),
self.get_message('assistant', 'Ready'),
self.get_message('user', self.arguments)
]
# Setting up the structure prompt
self.structure_prompt = [
self.get_message('system', prompts.STRUCTURE_INSTRUCTIONS),
self.get_message('assistant', 'Ready'),
]
# Initialize the title attribute
self.title = None
self.output('Prompts set up. Ready to generate book.')
def get_title(self):
if not self.title:
self.title = Book.get_response(prompt=self.title_prompt, tokens_needed=20)
return self.title
def get_structure(self):
if not hasattr(self, 'title'):
self.output('Title not generated. Please generate title first.')
return
else:
structure_arguments = self.arguments + f'; title: {self.title}'
self.structure_prompt.append(self.get_message('user', structure_arguments))
self.structure = self.get_response(self.structure_prompt)
self.chapters = self.convert_structure(self.structure)
self.paragraph_amounts = self.get_paragraph_amounts(self.chapters)
self.paragraph_words = self.get_paragraph_words(self.chapters)
return self.structure, self.chapters
def finish_base(self):
if not hasattr(self, 'title'):
self.output('Title not generated. Please generate title first.')
return
elif not hasattr(self, 'structure'):
self.output('Structure not generated. Please generate structure first.')
return
else:
self.base_prompt.append(self.get_message('user', '!t'))
self.base_prompt.append(self.get_message('assistant', self.title))
self.base_prompt.append(self.get_message('user', '!s'))
self.base_prompt.append(self.get_message('assistant', self.structure))
return self.base_prompt
def calculate_max_status(self):
if not hasattr(self, 'chapters'):
self.output('Structure not generated. Please generate structure first.')
return
else:
self.max_status = sum(self.get_paragraph_amounts(self.chapters))
return self.max_status
def get_content(self):
chapters = []
for i in tqdm(range(len(self.chapters))):
prompt = self.base_prompt.copy()
chapter = self.get_chapter(i, prompt.copy())
chapters.append(chapter)
self.content = chapters
return self.content
def save_book(self):
# Save the book in md format
with open(f'book.md', 'w') as file:
file.write(f'# {self.title}\n\n')
for chapter in self.content:
file.write(f'## {self.chapters[self.content.index(chapter)]["title"]}\n\n')
for paragraph in chapter:
file.write(
f'### {self.chapters[self.content.index(chapter)]["paragraphs"][chapter.index(paragraph)]["title"]}\n\n')
file.write(paragraph + '\n\n')
file.write('\n\n')
def get_chapter(self, chapter_index, prompt):
if len(self.base_prompt) == 3:
self.finish_base()
paragraphs = []
for i in range(self.paragraph_amounts[chapter_index]):
paragraph = self.get_paragraph(prompt.copy(), chapter_index, i)
prompt.append(self.get_message('user', f'!w {chapter_index + 1} {i + 1}'))
prompt.append(self.get_message('assistant', paragraph))
self.status += 1
paragraphs.append(paragraph)
return paragraphs
def get_paragraph(self, prompt, chapter_index, paragraph_index):
prompt.append(self.get_message('user', f'!w {chapter_index + 1} {paragraph_index + 1}'))
paragraph = ""
response = ""
available_tokens = 4096 - len(enc.encode(json.dumps(prompt))) - 100
while len(paragraph.split(' ')) < int(self.paragraph_words[chapter_index][paragraph_index] * self.tolerance) and available_tokens > 0:
try:
response = Book.get_response(prompt)
paragraph += response
prompt.append(self.get_message('assistant', response))
prompt.append(self.get_message('system', '!c'))
available_tokens -= len(enc.encode(response))
except ValueError:
response = None
break
return paragraph
@staticmethod
def get_message(role, content):
return {"role": role, "content": content}
@staticmethod
def convert_structure(structure):
chapters = structure.split("Chapter")
chapters = [x for x in chapters if x != '']
chapter_information = []
for chapter in chapters:
for line in chapter.split("\n"):
if 'paragraphs' in line.lower():
split_line = line.split('): ')
if len(split_line) > 1:
chapter_information.append({'title': split_line[1], 'paragraphs': []})
elif 'paragraph' in line.lower():
chapter_information[-1]['paragraphs'].append(
{'title': line.split('): ')[1], 'words': line.split('(')[1].split(')')[0].split(' ')[0]})
chapter_information[-1]['paragraph_amount'] = len(chapter_information[-1]['paragraphs'])
return chapter_information
@staticmethod
def get_paragraph_amounts(structure):
amounts = []
for chapter in structure:
amounts.append(chapter['paragraph_amount'])
return amounts
@staticmethod
def get_paragraph_words(structure):
words = []
for chapter in structure:
words.append([int(x['words']) for x in chapter['paragraphs']])
return words
@staticmethod
def get_response(prompt, tokens_needed=None):
enc = tiktoken.encoding_for_model("gpt-3.5-turbo")
token_count = len(enc.encode(json.dumps(prompt)))
print(f"Token count for the prompt: {token_count}")
max_tokens = 4096
if token_count >= max_tokens:
raise ValueError("The total token count in the prompt exceeds the model's limit of 4096 tokens.")
safety_margin = 100
available_tokens = max_tokens - token_count - safety_margin
print(f"Available tokens for the response: {available_tokens}")
if available_tokens <= 0:
raise ValueError("There are not enough tokens available for the response.")
if tokens_needed and tokens_needed < available_tokens:
response_length = tokens_needed
else:
response_length = available_tokens
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0301",
messages=prompt,
max_tokens=response_length
)["choices"][0]["message"]["content"]
return response
@staticmethod
def output(message):
print(message)
askopenai.js const askOpenAI = async function (prompt, role, modelChoice = 'gpt-3.5-turbo', tokens=5000, temp=0.65) { let now = new Date(); // let model = 'gpt-3.5-turbo' // //gpt-4-0314 let roleContent = "You are an ChatGPT-powered chat bot."
if (role == 'machine') {
roleContent = "You are a computer program attempting to comply with the user's wishes."
}
if (role == 'writer') {
roleContent = "You are a professional fiction writer who is a best-selling author. You use all of the rhetorical devices you know to write a compelling book."
}
return new Promise(function(resolve, reject) {
fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
'headers': {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.API_KEY}`,
},
'body': JSON.stringify({
'model': modelChoice,
"messages": [
{"role": "system", "content": roleContent},
{"role": "user", "content": prompt},
],
"max_tokens": tokens,
"temperature": temp,
})
}).then(response => response.json()).then(data => {
try {
let elapsed = new Date() - now;
console.log('\nOpenAI response time: ' + elapsed + 'ms\n')
resolve (data)
} catch(e) {
console.log(e);
resolve (e);
}
})
});
}
exports.askOpenAI = askOpenAI;
Running into the same issue here. But can't really implement your changes, @cometbus. Do you think you could submit the code in a code box? Or in any more intuitive format for someone with very little programming background?
Thanks!
@fdtory changing book.py to the following should work
import openai
from tqdm import tqdm
import prompts
import tiktoken
import json
enc = tiktoken.get_encoding("cl100k_base")
class Book:
def __init__(self, **kwargs):
# Joining the keyword arguments into a single string
self.arguments = '; '.join([f'{key}: {value}' for key, value in kwargs.items() if key != 'tolerance'])
# Get 'tolerance' attribute from kwargs
self.tolerance = kwargs.get('tolerance', 0.9)
# Assign a status variable
self.status = 0
# Setting up the base prompt
self.base_prompt = [
self.get_message('system', prompts.INITIAL_INSTRUCTIONS),
self.get_message('user', self.arguments),
self.get_message('assistant', 'Ready')
]
# Setting up the title prompt
self.title_prompt = [
self.get_message('system', prompts.TITLE_INSTRUCTIONS),
self.get_message('assistant', 'Ready'),
self.get_message('user', self.arguments)
]
# Setting up the structure prompt
self.structure_prompt = [
self.get_message('system', prompts.STRUCTURE_INSTRUCTIONS),
self.get_message('assistant', 'Ready'),
]
# Initialize the title attribute
self.title = None
self.output('Prompts set up. Ready to generate book.')
def get_title(self):
if not self.title:
self.title = Book.get_response(prompt=self.title_prompt, tokens_needed=20)
return self.title
def get_structure(self):
if not hasattr(self, 'title'):
self.output('Title not generated. Please generate title first.')
return
else:
structure_arguments = self.arguments + f'; title: {self.title}'
self.structure_prompt.append(self.get_message('user', structure_arguments))
self.structure = self.get_response(self.structure_prompt)
self.chapters = self.convert_structure(self.structure)
self.paragraph_amounts = self.get_paragraph_amounts(self.chapters)
self.paragraph_words = self.get_paragraph_words(self.chapters)
return self.structure, self.chapters
def finish_base(self):
if not hasattr(self, 'title'):
self.output('Title not generated. Please generate title first.')
return
elif not hasattr(self, 'structure'):
self.output('Structure not generated. Please generate structure first.')
return
else:
self.base_prompt.append(self.get_message('user', '!t'))
self.base_prompt.append(self.get_message('assistant', self.title))
self.base_prompt.append(self.get_message('user', '!s'))
self.base_prompt.append(self.get_message('assistant', self.structure))
return self.base_prompt
def calculate_max_status(self):
if not hasattr(self, 'chapters'):
self.output('Structure not generated. Please generate structure first.')
return
else:
self.max_status = sum(self.get_paragraph_amounts(self.chapters))
return self.max_status
def get_content(self):
chapters = []
for i in tqdm(range(len(self.chapters))):
prompt = self.base_prompt.copy()
chapter = self.get_chapter(i, prompt.copy())
chapters.append(chapter)
self.content = chapters
return self.content
def save_book(self):
# Save the book in md format
with open(f'book.md', 'w') as file:
file.write(f'# {self.title}\n\n')
for chapter in self.content:
file.write(f'## {self.chapters[self.content.index(chapter)]["title"]}\n\n')
for paragraph in chapter:
file.write(
f'### {self.chapters[self.content.index(chapter)]["paragraphs"][chapter.index(paragraph)]["title"]}\n\n')
file.write(paragraph + '\n\n')
file.write('\n\n')
def get_chapter(self, chapter_index, prompt):
if len(self.base_prompt) == 3:
self.finish_base()
paragraphs = []
for i in range(self.paragraph_amounts[chapter_index]):
paragraph = self.get_paragraph(prompt.copy(), chapter_index, i)
prompt.append(self.get_message('user', f'!w {chapter_index + 1} {i + 1}'))
prompt.append(self.get_message('assistant', paragraph))
self.status += 1
paragraphs.append(paragraph)
return paragraphs
def get_paragraph(self, prompt, chapter_index, paragraph_index):
prompt.append(self.get_message('user', f'!w {chapter_index + 1} {paragraph_index + 1}'))
paragraph = ""
response = ""
available_tokens = 4096 - len(enc.encode(json.dumps(prompt))) - 100
while len(paragraph.split(' ')) < int(self.paragraph_words[chapter_index][paragraph_index] * self.tolerance) and available_tokens > 0:
try:
response = Book.get_response(prompt)
paragraph += response
prompt.append(self.get_message('assistant', response))
prompt.append(self.get_message('system', '!c'))
available_tokens -= len(enc.encode(response))
except ValueError:
response = None
break
return paragraph
@staticmethod
def get_message(role, content):
return {"role": role, "content": content}
@staticmethod
def convert_structure(structure):
chapters = structure.split("Chapter")
chapters = [x for x in chapters if x != '']
chapter_information = []
for chapter in chapters:
for line in chapter.split("\n"):
if 'paragraphs' in line.lower():
split_line = line.split('): ')
if len(split_line) > 1:
chapter_information.append({'title': split_line[1], 'paragraphs': []})
elif 'paragraph' in line.lower():
chapter_information[-1]['paragraphs'].append(
{'title': line.split('): ')[1], 'words': line.split('(')[1].split(')')[0].split(' ')[0]})
chapter_information[-1]['paragraph_amount'] = len(chapter_information[-1]['paragraphs'])
return chapter_information
@staticmethod
def get_paragraph_amounts(structure):
amounts = []
for chapter in structure:
amounts.append(chapter['paragraph_amount'])
return amounts
@staticmethod
def get_paragraph_words(structure):
words = []
for chapter in structure:
words.append([int(x['words']) for x in chapter['paragraphs']])
return words
@staticmethod
def get_response(prompt, tokens_needed=None):
enc = tiktoken.encoding_for_model("gpt-3.5-turbo")
token_count = len(enc.encode(json.dumps(prompt)))
print(f"Token count for the prompt: {token_count}")
max_tokens = 4096
if token_count >= max_tokens:
raise ValueError("The total token count in the prompt exceeds the model's limit of 4096 tokens.")
safety_margin = 100
available_tokens = max_tokens - token_count - safety_margin
print(f"Available tokens for the response: {available_tokens}")
if available_tokens <= 0:
raise ValueError("There are not enough tokens available for the response.")
if tokens_needed and tokens_needed < available_tokens:
response_length = tokens_needed
else:
response_length = available_tokens
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0301",
messages=prompt,
max_tokens=response_length
)["choices"][0]["message"]["content"]
return response
@staticmethod
def output(message):
print(message)
@gursheyss @cometbus Thank you both! The last print statement had 3 extra characters that also needed to be removed. I also had to add tiktoken to the requirements.txt file and ran the "pip install -r requirements.txt" command again. Everything worked as expected after that.
This model's maximum context length is 4097 tokens. However, your messages resulted in 4113 tokens. Please reduce the length of the messages.
every time I try to run it