Skip to content

Commit

Permalink
EYFS activity plan (#8)
Browse files Browse the repository at this point in the history
* feat: EYFS activity plan

* feat: Add prompt selection

* feat: Add prompts

* feat: Use openai api

* feat: Add more requirements

* chore: Get api key

* chore: Remove verbose

* feat: Enchancements based on feedback

* feat: Update prompt

* feat: Modify the prompt

* chore: Temporarily remove the prompt selector

* feat: Update readme

* feat: Add prompts

* feat: Refactor app and activity planner

* chore: Remove langchain prompts

* chore: Remove one of the todos

* chore: Update setup instructions

* feat: Create Dockerfile and update readme

* feat: Update docstrings and app text
  • Loading branch information
kstathou committed Jul 27, 2023
1 parent b344f91 commit 96b767d
Show file tree
Hide file tree
Showing 15 changed files with 522 additions and 15 deletions.
34 changes: 34 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Use an official Python runtime as a parent image
FROM python:3.9.17-slim

# Set environment varibles
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# Install system dependencies
RUN apt-get update \
&& apt-get install -y --no-install-recommends gcc

# Install poetry
RUN pip install "poetry==1.5.1"

# Set the working directory in the Docker image
WORKDIR /app

# Copy only requirements to cache them in docker layer
COPY pyproject.toml poetry.lock ./
COPY src/genai /app/src/genai
COPY README.md /app/README.md
COPY app.py /app/app.py

# Don't push the image to dockerhub
COPY .env /app/.env
COPY .streamlit /app/.streamlit

# Project initialization:
RUN poetry config virtualenvs.create false \
&& poetry install --no-interaction --no-ansi

EXPOSE 8501
# Specify the command to run your application
CMD ["streamlit", "run", "app.py"]
100 changes: 99 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,104 @@

Collection of generative AI prototypes, mainly using LLMs.

- [Generative AI prototypes](#generative-ai-prototypes)
- [Setup](#setup)
- [Generic setup for working with `pyenv` and `poetry`](#generic-setup-for-working-with-pyenv-and-poetry)
- [How to install this project](#how-to-install-this-project)
- [TODO](#todo)

## Setup


### Generic setup for working with `pyenv` and `poetry`
Assuming you work on a Mac, you can use the following commands to setup your environment from scratch with `pyenv` and `poetry`. Please deactivate any anaconda environments you might have activated before the setup.

1. [Install brew](https://brew.sh/). Confirm you've installed it correctly by running:

```bash
brew --version
``````

2. Install `pyenv`
```bash
brew install pyenv
```

At the end of the installation, `pyenv` will advise you to add the following lines to your `.bash_profile` (or `.zshrc` if you use `zsh`). Do that, save the file and restart your terminal.

```bash
export PYENV_ROOT="$HOME/.pyenv"
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
```

3. Install Python

Install/update a few dependencies

```
brew install openssl readline sqlite3 xz zlib
```

Install Python 3.9.17

```bash
pyenv install 3.9.17
```

Confirm you've installed it correctly by running:
```bash
pyenv versions
```
Run the following commands to set the global Python version to 3.9.17.
```bash
pyenv global 3.9.17
```
Close and reopen your terminal so that the changed take effect.
4. Install `poetry`
You can use the [official installer](https://python-poetry.org/docs/master/#installing-with-the-official-installer):
```bash
curl -sSL https://install.python-poetry.org | python3 -
```
Add poetry to your PATH. **Recommended:** Add the following lines to your `.bash_profile` (or `.zshrc` if you use `zsh`). Save the file and restart your terminal.
```bash
export PATH="/Users/<MYUSERNAME>/.local/bin:$PATH"
```
Confirm your poetry installation:
```bash
poetry --version
```
### How to install this project
1. Assuming you have installed `pyenv` and `poetry` as described above, you can now install this project:
```bash
make init
```
2. Activate the virtual environment:
```bash
source .venv/bin/activate
```
3. Add the secrets to the environment.
1. Add your OpenAI API key to the `.env` file. See `.env.example` for an example.
2. The streamlit app is password-protected. You can either remove the password requirement from `app.py` or create a `.streamlit/secrets.toml` file and add `password='<MYPASSWORD>'`.
## TODO
- Write setup instructions
- Streaming
- Async calls
- Parse more than one messages
95 changes: 89 additions & 6 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
"""Streamlit app for the Generative AI prototypes."""

import os

import openai
import streamlit as st

from dotenv import load_dotenv
from streamlit_option_menu import option_menu

from genai.eli3 import TextGenerator
from genai.eyfs.eyfs import ActivityGenerator
from genai.utils import read_json


load_dotenv()


APP_TITLE = "Nesta Discovery: Generative AI Prototypes"


def main() -> None:
"""Run app."""
"""Run the app."""
with st.sidebar:
selected = option_menu("Prototypes", ["Home page", "ELI3", "Dummy"], default_index=0)
selected = option_menu("Prototypes", ["Home page", "ELI3", "EYFS-based activity plan"], default_index=0)
if selected == "Home page":
st.title(APP_TITLE)
st.write("Welcome to the Nesta Discovery Generative AI prototypes.")
st.write("Welcome to the Nesta Discovery Generative AI prototypes. Please select a prototype from the menu.")
elif selected == "ELI3":
eli3()
elif selected == "Dummy":
st.title("Dummy prototype")
elif selected == "EYFS-based activity plan":
early_year_activity_plan()


def check_password() -> bool:
Expand Down Expand Up @@ -78,7 +87,7 @@ def eli3() -> None:
question = st.text_input(
label="**Question**",
value="How can whales breath in water?",
help="Ask the LLM a question.",
help="Ask the large language model a question.",
)

# Generate the answer
Expand All @@ -87,5 +96,79 @@ def eli3() -> None:
st.write(answer)


def early_year_activity_plan() -> None:
"""Come up with activities for children."""
st.title("Generating activity plans grounded in EY foundation stages")
auth_openai()
areas_of_learning_desc = read_json("src/genai/eyfs/areas_of_learning.json")
aol = list(areas_of_learning_desc.keys())

with st.sidebar:
# Select a model, temperature and number of results
selected_model = st.radio(label="**OpenAI model**", options=["gpt-3.5-turbo", "gpt-4"], index=1)
description = "<THIS IS WHERE THE GENERATOR WILL SHOW THE RESULTS>"
n_results = 10
temperature = st.slider(label="**Temperature**", min_value=0.0, max_value=1.0, value=0.6, step=0.1)

# Select the areas of learning
areas_of_learning = st.multiselect(label="**Areas of learning**", options=aol, default=aol)
areas_of_learning_text = [v for k, v in areas_of_learning_desc.items() if k in areas_of_learning]

# Describe each Area of Learning in an expanding window
with st.expander("**Areas of Learning Description**"):
for k, v in areas_of_learning_desc.items():
if k in areas_of_learning:
st.write(f"#### {k}")
st.write(v.split("##")[-1])

areas_of_learning_text = "\n\n".join(areas_of_learning_text)
location = st.selectbox(label="**Location**", options=["Indoor", "Outdoor", "Indoor or Outdoor"], index=2)

# Create the messages
paths = [
"src/genai/eyfs/prompts/system.json",
"src/genai/eyfs/prompts/context_and_task.json",
"src/genai/eyfs/prompts/constraints.json",
"src/genai/eyfs/prompts/situation.json",
]

messages = [read_json(path) for path in paths]

# Get the user input
description = st.text_input(
label="**What's the topic you want activities for?**",
value="Let's create activities educating children on how whales breath",
help="Prompt the large language model with a some text and it will generate an activity plan for you.",
)

# Generate the answer
if st.button(label="**Generate**", help="Generate an answer."):
with st.spinner("Generating activities..."):
messages_placeholders = {
"description": description,
"areas_of_learning": areas_of_learning,
"n_results": n_results,
"location": location,
"areas_of_learning_text": areas_of_learning_text,
}

r = ActivityGenerator.generate(
model=selected_model,
temperature=temperature,
messages=messages,
message_kwargs=messages_placeholders,
)

st.write(r["choices"][0]["message"]["content"])


def auth_openai() -> None:
"""Authenticate with OpenAI."""
try:
openai.api_key = os.environ["OPENAI_API_KEY"]
except Exception:
openai.api_key = st.secrets["OPENAI_API_KEY"]


if check_password():
main()
Loading

0 comments on commit 96b767d

Please sign in to comment.