134 lines
3.9 KiB
Python
134 lines
3.9 KiB
Python
import openai
|
|
import os
|
|
import json
|
|
import genanki
|
|
from logging_config import setup_logging
|
|
from constants import API_KEY_ENV, CHAT_MODEL
|
|
|
|
|
|
setup_logging()
|
|
|
|
|
|
API_KEY = os.environ.get(API_KEY_ENV)
|
|
if not API_KEY:
|
|
raise ValueError("Please set the OPENAI_API_KEY environment variable.")
|
|
|
|
openai.api_key = API_KEY
|
|
|
|
PROMPT_TEMPLATE = """
|
|
Please craft a title for the deck and generate a comprehensive set of index cards based on the provided text. Follow these guidelines:
|
|
|
|
1. Every card should have a title, a question on the front, and an answer on the back.
|
|
2. Each answer must contain at least one concrete fact that is not evident from its corresponding question.
|
|
3. Ensure inclusion of numbers, data, or intricate details that would be challenging for individuals to remember.
|
|
4. The goal is to enable someone who learns this set to competently convey both the overarching themes and intricate details of the text to another person.
|
|
5. Create one index card for every 2-4 sentences of the content. The exact number depends on the density of the information. Aim for completeness over brevity.
|
|
6. Each index card should home in on answering a distinct question.
|
|
7. Limit each index card answer to no more than three sentences for brevity and clarity.
|
|
|
|
Structure your output as:
|
|
```
|
|
Deck Title: [Title of the Deck]
|
|
Cards:
|
|
- Title: [Card Title 1]
|
|
Front: [Question 1]
|
|
Back: [Answer 1]
|
|
- Title: [Card Title 2]
|
|
Front: [Question 2]
|
|
Back: [Answer 2]
|
|
... continue in this pattern
|
|
```
|
|
|
|
Content for reference:
|
|
{content}
|
|
"""
|
|
|
|
|
|
def prompt_for_card_content(text_content):
|
|
# Prepare the prompt
|
|
prompt = PROMPT_TEMPLATE.format(content=text_content)
|
|
|
|
# Get completion from the OpenAI ChatGPT API
|
|
response = openai.ChatCompletion.create(
|
|
model=CHAT_MODEL,
|
|
messages=[
|
|
{"role": "user", "content": prompt}
|
|
],
|
|
temperature=0,
|
|
)
|
|
|
|
# Extract content from response and save to a new file
|
|
return response.choices[0]['message']['content']
|
|
|
|
|
|
def response_to_json(response_text):
|
|
lines = [line.strip() for line in response_text.split("\n") if line.strip()]
|
|
|
|
deck_title = None
|
|
cards = []
|
|
current_card = {}
|
|
|
|
for line in lines:
|
|
if "Deck Title:" in line and not deck_title:
|
|
deck_title = line.split("Deck Title:", 1)[1].strip()
|
|
elif "Title:" in line:
|
|
if current_card: # If there's a card being processed, add it to cards
|
|
cards.append(current_card)
|
|
current_card = {}
|
|
current_card["Title"] = line.split("Title:", 1)[1].strip()
|
|
elif "Front:" in line:
|
|
current_card["Question"] = line.split("Front:", 1)[1].strip()
|
|
elif "Back:" in line:
|
|
current_card["Answer"] = line.split("Back:", 1)[1].strip()
|
|
|
|
if current_card: # Add the last card if it exists
|
|
cards.append(current_card)
|
|
|
|
return {
|
|
"DeckTitle": deck_title,
|
|
"Cards": cards
|
|
}
|
|
|
|
|
|
# Create a new model for our cards. This is necessary for genanki.
|
|
MY_MODEL = genanki.Model(
|
|
1607372319,
|
|
"Simple Model",
|
|
fields=[
|
|
{"name": "Title"},
|
|
{"name": "Question"},
|
|
{"name": "Answer"},
|
|
],
|
|
templates=[
|
|
{
|
|
"name": "{{Title}}",
|
|
"qfmt": "{{Question}}",
|
|
"afmt": "{{FrontSide}}<hr id='answer'>{{Answer}}",
|
|
},
|
|
])
|
|
|
|
def json_file_to_package(json_path):
|
|
with open(json_path, 'r', encoding='utf-8') as f:
|
|
json_data = json.load(f)
|
|
package = to_package(json_data)
|
|
|
|
return package
|
|
|
|
def to_package(deck_json):
|
|
deck_title = deck_json["DeckTitle"]
|
|
deck = genanki.Deck(1607372319, deck_title)
|
|
|
|
for card_json in deck_json["Cards"]:
|
|
title = card_json["Title"]
|
|
question = card_json["Question"]
|
|
answer = card_json["Answer"]
|
|
|
|
note = genanki.Note(
|
|
model=MY_MODEL,
|
|
fields=[title, question, answer]
|
|
)
|
|
|
|
deck.add_note(note)
|
|
|
|
return genanki.Package(deck)
|