Skip to content

Commit

Permalink
Merge pull request #3 from edx/ashultz0/card-csv-from-cms
Browse files Browse the repository at this point in the history
pull card content, route to openai
  • Loading branch information
ashultz0 authored Oct 24, 2023
2 parents 30a7b55 + 16406c4 commit f591aaf
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 0 deletions.
Empty file.
67 changes: 67 additions & 0 deletions flashcards/apps/cards/cardgen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import openai
from django.conf import settings
from edx_rest_api_client import client as rest_client

from flashcards.apps.cards.prompt import anki_prompt
from flashcards.settings.private import OPENAI_API_KEY # pylint: disable=import-error,no-name-in-module

openai.api_key = OPENAI_API_KEY

# provision a user in devstack provision-ida-user.sh flashcards flashcards 3000


def get_client(oauth_base_url=settings.LMS_ROOT_URL):
"""
Returns an authenticated edX REST API client.
"""
client = rest_client.OAuthAPIClient(
oauth_base_url,
settings.BACKEND_SERVICE_EDX_OAUTH2_KEY,
settings.BACKEND_SERVICE_EDX_OAUTH2_SECRET,
)
client._ensure_authentication() # pylint: disable=protected-access
if not client.auth.token: # pragma: no cover
raise Exception('No Auth Token') # pylint: disable=broad-exception-raised
return client


def block_content_for_cards(course_id, block_id, source='lms'):
block_id = block_id.replace(":", "$:")
lms_url = f'{settings.LMS_ROOT_URL}/courses/{course_id}/xblock/aside-usage-v2:{block_id}::extractor_aside/handler/extract_handler' # noqa
# currently sourcing via the CMS doesn't work by auth and if auth is disabled walking
# the handler in the CMS context poisons the cache and obliterates those blocks in the course
# cms_url = f'{settings.CMS_ROOT_URL}/xblock/aside-usage-v2:{block_id}::extractor_aside/handler/extract_handler'

handler_url = lms_url

client = get_client()
response = client.get(handler_url)

if response.status_code < 200 or response.status_code > 300:
response.raise_for_status()

content = response.json()
joined_content = '\n\n'.join(content['content'])
return joined_content


def cards_from_openai(content):
messages = [
{"role": "system", "content": anki_prompt},
{"role": "system", "content": content},
]

result = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=messages,
temperature=1.0,
)

maybe_csv = result['choices'][0]['message']['content']
return maybe_csv


def cards_from_block_id(course_id, block_id):
content = block_content_for_cards(course_id, block_id)
cards = cards_from_openai(content)
return cards
26 changes: 26 additions & 0 deletions flashcards/apps/cards/prompt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# The prompt to ask ChatGPT to make anki cards.
anki_prompt = """
I want you to act as a professional Anki card creator, able to create Anki cards from the text I provide.
Regarding the formulation of the card content, you stick to two principles:
First, minimum information principle: The material you learn must be formulated in as simple way as it is only possible. Simplicity does not have to imply losing information and skipping the difficult part.
Second, optimize wording: The wording of your items must be optimized to make sure that in minimum time the right bulb in your brain lights up. This will reduce error rates, increase specificity, reduce response time, and help your concentration.
Please output these cards you create in a .csv format, with the questions and answers separated by commas.
The following is a model card-create template for you to study.
Text: The characteristics of the Dead Sea: Salt lake located on the border between Israel and Jordan. Its shoreline is the lowest point on the Earth's surface, averaging 396 m below sea level. It is 74 km long. It is seven times as salty (30% by volume) as the ocean. Its density keeps swimmers afloat. Only simple organisms can live in its saline waters
Where is the Dead Sea located?,On the border between Israel and Jordan
What is the lowest point on the Earth's surface?,The Dead Sea shoreline
What is the average level on which the Dead Sea is located?,400 meters (below sea level)
How long is the Dead Sea?,70 km
How much saltier is the Dead Sea as compared with the oceans?,7 times
What is the volume content of salt in the Dead Sea?,30%
Why can the Dead Sea keep swimmers afloat?,Due to high salt content
Why is the Dead Sea called Dead?,Because only simple organisms can live in it
Why only simple organisms can live in the Dead Sea?,Because of high salt content
""" # noqa
3 changes: 3 additions & 0 deletions flashcards/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,6 @@ def root(*path_fragments):

# OpenAI API key, to be specified in the private settings file
OPENAI_API_KEY = ''

CMS_ROOT_URL = None
LMS_ROOT_URL = None
5 changes: 5 additions & 0 deletions flashcards/settings/devstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,8 @@
'SECRET_KEY': 'lms-secret',
}],
})

CMS_ROOT_URL = 'http://edx.devstack.cms:18010'
LMS_ROOT_URL = 'http://edx.devstack.lms:18000'
BACKEND_SERVICE_EDX_OAUTH2_KEY = 'flashcards-backend-service-key'
BACKEND_SERVICE_EDX_OAUTH2_SECRET = 'flashcards-backend-service-secret'
5 changes: 5 additions & 0 deletions flashcards/settings/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,8 @@
# Lastly, see if the developer has any local overrides.
if os.path.isfile(join(dirname(abspath(__file__)), 'private.py')):
from .private import * # pylint: disable=import-error,wildcard-import

CMS_ROOT_URL = 'http://localhost:18010'
LMS_ROOT_URL = 'http://localhost:18000'
BACKEND_SERVICE_EDX_OAUTH2_KEY = 'flashcards-backend-service-key'
BACKEND_SERVICE_EDX_OAUTH2_SECRET = 'flashcards-backend-service-secret'

0 comments on commit f591aaf

Please sign in to comment.