Spaces:
Runtime error
Runtime error
Owen Wang commited on
Commit ·
4b2c4ed
1
Parent(s): 034be72
get it working with ash prompt and chat
Browse files- app.py +32 -23
- requirements.txt +2 -1
app.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
| 1 |
-
from typing import List, Optional, TypedDict
|
| 2 |
import streamlit as st
|
| 3 |
import requests
|
| 4 |
import openai
|
| 5 |
import pinecone
|
| 6 |
import json
|
| 7 |
import re
|
|
|
|
| 8 |
|
| 9 |
PINECONE_API_KEY = st.secrets["PINECONE_API_KEY"]
|
| 10 |
# Set OpenAI API key from Streamlit Secrets
|
|
@@ -12,16 +12,11 @@ OPENAI_API_KEY = st.secrets["OPENAI_API_KEY"]
|
|
| 12 |
# Set maximum token length
|
| 13 |
MAX_TOKENS = 1024
|
| 14 |
# Set OpenAI model
|
| 15 |
-
MODEL = "
|
| 16 |
-
|
| 17 |
-
class Metadata(TypedDict):
|
| 18 |
-
title: str
|
| 19 |
-
description: str
|
| 20 |
-
slides: str
|
| 21 |
-
outcome: str
|
| 22 |
|
| 23 |
# Initialize OpenAI
|
| 24 |
openai.api_key = OPENAI_API_KEY
|
|
|
|
| 25 |
|
| 26 |
@st.cache_resource
|
| 27 |
def load_pinecone_index():
|
|
@@ -29,7 +24,7 @@ def load_pinecone_index():
|
|
| 29 |
index_name = "prequelworkshops"
|
| 30 |
return pinecone.Index(index_name)
|
| 31 |
|
| 32 |
-
def get_embeddings(texts
|
| 33 |
"""
|
| 34 |
Embed texts using OpenAI's ada model.
|
| 35 |
|
|
@@ -52,7 +47,8 @@ def get_embeddings(texts: List[str]) -> List[List[float]]:
|
|
| 52 |
return [result["embedding"] for result in data]
|
| 53 |
|
| 54 |
# Pinecone fetch function
|
| 55 |
-
|
|
|
|
| 56 |
vector = get_embeddings([query])[0]
|
| 57 |
|
| 58 |
return index.query(
|
|
@@ -66,18 +62,22 @@ def fetch_lesson(index, query: str):
|
|
| 66 |
)
|
| 67 |
|
| 68 |
# OpenAI prompt generation function
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
|
|
|
|
|
|
| 73 |
max_tokens=MAX_TOKENS,
|
| 74 |
n=1,
|
| 75 |
stop=None,
|
| 76 |
temperature=0.7,
|
|
|
|
| 77 |
)
|
| 78 |
-
|
|
|
|
| 79 |
|
| 80 |
-
def extract_arrays(s
|
| 81 |
# Find the starting and ending indices of the array
|
| 82 |
start = s.find('[')
|
| 83 |
end = s.find(']')
|
|
@@ -102,17 +102,23 @@ def extract_arrays(s: str) -> Optional[List[str]]:
|
|
| 102 |
else:
|
| 103 |
return None
|
| 104 |
|
| 105 |
-
def generate_curriculum(skills
|
| 106 |
prompt = f"You are a world-class middle and high school educator who develops project-based entrepreneurship curriculum catered to student interests. Create a curriculum of up to 5 lessons for a course based on the student's target skills to learn. Output the curriculum as a javascript array of strings, where each string is a description of the lesson. The output should just be the array and nothing else. Student's target skills: {skills}"
|
| 107 |
response = query_openai(prompt)
|
| 108 |
return extract_arrays(response)
|
| 109 |
|
| 110 |
-
def
|
| 111 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
response = query_openai(prompt)
|
| 113 |
return response
|
| 114 |
|
| 115 |
-
def format_metadata(metadata
|
| 116 |
print(metadata)
|
| 117 |
application = generate_application(metadata, interests)
|
| 118 |
return f"Title: [{metadata['title']}]({metadata['slides']})\n\n{application}"
|
|
@@ -140,15 +146,18 @@ if submit_button:
|
|
| 140 |
curriculum = generate_curriculum(skills)
|
| 141 |
|
| 142 |
if curriculum is not None:
|
| 143 |
-
status.text("Feeding the hamsters powering our servers...
|
| 144 |
index = load_pinecone_index()
|
| 145 |
lessons = [fetch_lesson(index, lesson) for lesson in curriculum]
|
| 146 |
lessons_metadata = filtered_metadatas(lessons)
|
| 147 |
|
| 148 |
-
status.text("
|
|
|
|
|
|
|
|
|
|
| 149 |
lesson_text = "\n\n".join([format_metadata(metadata, interests) for metadata in lessons_metadata])
|
| 150 |
status.empty()
|
| 151 |
st.markdown(f"\n\n## Your personalized learning playlist\n\n{lesson_text}")
|
| 152 |
else:
|
| 153 |
-
status.text("
|
| 154 |
|
|
|
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
import requests
|
| 3 |
import openai
|
| 4 |
import pinecone
|
| 5 |
import json
|
| 6 |
import re
|
| 7 |
+
from tenacity import retry, stop_after_attempt, wait_exponential
|
| 8 |
|
| 9 |
PINECONE_API_KEY = st.secrets["PINECONE_API_KEY"]
|
| 10 |
# Set OpenAI API key from Streamlit Secrets
|
|
|
|
| 12 |
# Set maximum token length
|
| 13 |
MAX_TOKENS = 1024
|
| 14 |
# Set OpenAI model
|
| 15 |
+
MODEL = "gpt-3.5-turbo"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
# Initialize OpenAI
|
| 18 |
openai.api_key = OPENAI_API_KEY
|
| 19 |
+
conversation = []
|
| 20 |
|
| 21 |
@st.cache_resource
|
| 22 |
def load_pinecone_index():
|
|
|
|
| 24 |
index_name = "prequelworkshops"
|
| 25 |
return pinecone.Index(index_name)
|
| 26 |
|
| 27 |
+
def get_embeddings(texts):
|
| 28 |
"""
|
| 29 |
Embed texts using OpenAI's ada model.
|
| 30 |
|
|
|
|
| 47 |
return [result["embedding"] for result in data]
|
| 48 |
|
| 49 |
# Pinecone fetch function
|
| 50 |
+
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=6))
|
| 51 |
+
def fetch_lesson(index, query):
|
| 52 |
vector = get_embeddings([query])[0]
|
| 53 |
|
| 54 |
return index.query(
|
|
|
|
| 62 |
)
|
| 63 |
|
| 64 |
# OpenAI prompt generation function
|
| 65 |
+
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=6))
|
| 66 |
+
def query_openai(prompt):
|
| 67 |
+
conversation.append({"role": "user", "content": prompt})
|
| 68 |
+
response = openai.ChatCompletion.create(
|
| 69 |
+
model=MODEL,
|
| 70 |
+
messages=conversation,
|
| 71 |
max_tokens=MAX_TOKENS,
|
| 72 |
n=1,
|
| 73 |
stop=None,
|
| 74 |
temperature=0.7,
|
| 75 |
+
frequency_penalty=2
|
| 76 |
)
|
| 77 |
+
conversation.append(response.choices[0].message)
|
| 78 |
+
return response.choices[0].message.content.strip()
|
| 79 |
|
| 80 |
+
def extract_arrays(s):
|
| 81 |
# Find the starting and ending indices of the array
|
| 82 |
start = s.find('[')
|
| 83 |
end = s.find(']')
|
|
|
|
| 102 |
else:
|
| 103 |
return None
|
| 104 |
|
| 105 |
+
def generate_curriculum(skills):
|
| 106 |
prompt = f"You are a world-class middle and high school educator who develops project-based entrepreneurship curriculum catered to student interests. Create a curriculum of up to 5 lessons for a course based on the student's target skills to learn. Output the curriculum as a javascript array of strings, where each string is a description of the lesson. The output should just be the array and nothing else. Student's target skills: {skills}"
|
| 107 |
response = query_openai(prompt)
|
| 108 |
return extract_arrays(response)
|
| 109 |
|
| 110 |
+
def generate_ideas(metadatas, interests):
|
| 111 |
+
summary = ".".join([f"Lesson {i} - title: {metadata['title']}, description: {metadata['description']}, learning outcome: {metadata['outcome']}" for i, metadata in enumerate(metadatas)])
|
| 112 |
+
prompt = f"We've created a curriculum for the student: {summary}. The student has an interest in \"{interests}\". What are some ambitious projects the student could do from what they'd learn from the curriculum?"
|
| 113 |
+
response = query_openai(prompt)
|
| 114 |
+
print(response)
|
| 115 |
+
|
| 116 |
+
def generate_application(metadata, interests):
|
| 117 |
+
prompt = f"For the lesson titled \"{metadata['title']}\" about \"{metadata['description']}\", first describe the lesson and its outcome in one sentence objectively. Next, explore possible personal growth outcomes that combine their interest in \"{interests}\" with this lesson in one concise sentence. Implicitly draw poetic connections between the interests and the lesson. Help them to feel inspired to connect with the lesson. Try to communicate this without using the words \"{interests}\". Instead, tie in one of the previously described ambitious projects. Don't repeat an example of a project if you've used it for a previous lesson. Help them to see how the knowledge they gain in this lesson will allow them to thrive in their interests."
|
| 118 |
response = query_openai(prompt)
|
| 119 |
return response
|
| 120 |
|
| 121 |
+
def format_metadata(metadata, interests):
|
| 122 |
print(metadata)
|
| 123 |
application = generate_application(metadata, interests)
|
| 124 |
return f"Title: [{metadata['title']}]({metadata['slides']})\n\n{application}"
|
|
|
|
| 146 |
curriculum = generate_curriculum(skills)
|
| 147 |
|
| 148 |
if curriculum is not None:
|
| 149 |
+
status.text("Feeding the hamsters powering our servers...")
|
| 150 |
index = load_pinecone_index()
|
| 151 |
lessons = [fetch_lesson(index, lesson) for lesson in curriculum]
|
| 152 |
lessons_metadata = filtered_metadatas(lessons)
|
| 153 |
|
| 154 |
+
status.text("Harvesting the seeds of wisdom...")
|
| 155 |
+
generate_ideas(lessons_metadata, interests)
|
| 156 |
+
|
| 157 |
+
status.text("Building a bridge from your dreams to reality... just one more moment!")
|
| 158 |
lesson_text = "\n\n".join([format_metadata(metadata, interests) for metadata in lessons_metadata])
|
| 159 |
status.empty()
|
| 160 |
st.markdown(f"\n\n## Your personalized learning playlist\n\n{lesson_text}")
|
| 161 |
else:
|
| 162 |
+
status.text("The Wheel of Education spun out of control! Care to give it another whirl? Click 'Generate curriculum' again")
|
| 163 |
|
requirements.txt
CHANGED
|
@@ -1,3 +1,4 @@
|
|
| 1 |
streamlit
|
| 2 |
openai
|
| 3 |
-
pinecone-client
|
|
|
|
|
|
| 1 |
streamlit
|
| 2 |
openai
|
| 3 |
+
pinecone-client
|
| 4 |
+
tenacity
|