mail@pastecode.io avatar
11 days ago
13 kB
from pathlib import Path
import streamlit as st
import json,re
from langchain_groq import ChatGroq
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain

from auth.auth_works import load_config,create_authenticator,handle_login,handle_user_registration,handle_logout

api_key = "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"
llm = ChatGroq(api_key=api_key)

def generate_lesson_content(subject, number_lesson_titles, number_pages_per_lesson, number_subtitles_per_page, sentences_per_page):
    prompt_template = PromptTemplate(
        input_variables=["subject", "number_lesson_titles", "number_pages_per_lesson", "number_subtitles_per_page", "sentences_per_page"],
        Create a detailed lesson plan on the subject of {subject}. 
        Provide EXACTLY the following:
        1. {number_lesson_titles} lesson titles
        2. For each lesson, EXACTLY {number_pages_per_lesson} page titles
        3. For each page, EXACTLY {number_subtitles_per_page} subtitles
        4. For each page, a content summary of EXACTLY {sentences_per_page} sentences

        Format your response as a JSON structure with the following format:
        "subject": "{subject}",
        "lessons": [
                "title": "Lesson Title",
                "pages": [
                        "title": "Page Title",
                        "subtitles": ["Subtitle 1", "Subtitle 2", ...],
                        "content": "Detailed content for the page (EXACTLY {sentences_per_page} sentences)"

        Ensure the content is informative, relevant to the subject of {subject}, and follows this exact JSON structure. 
        Do not use any backslashes in the JSON keys.
        IMPORTANT: Strictly adhere to the numbers provided: {number_lesson_titles} lessons, {number_pages_per_lesson} pages per lesson, {number_subtitles_per_page} subtitles per page, and {sentences_per_page} sentences per page.
    chain = LLMChain(llm=llm, prompt=prompt_template)
    result = chain.invoke({
        "subject": subject,
        "number_lesson_titles": number_lesson_titles,
        "number_pages_per_lesson": number_pages_per_lesson,
        "number_subtitles_per_page": number_subtitles_per_page,
        "sentences_per_page": sentences_per_page
    It creates the exact number of lessons requested.
    For each lesson, it creates the exact number of pages requested.
    For each page, it ensures the exact number of subtitles and sentences.
    If the generated content is short, it fills in with placeholder data.
    If the generated content is too long, it trims it to the requested size.
        content = json.loads(result['text'])
        # print(content["lessons"][0]["pages"][0]["content"])
        # Post-process the content to ensure it matches the requested structure
        processed_content = {
            "subject": subject,
            "lessons": []
        for i in range(number_lesson_titles):
            if i < len(content['lessons']):
                lesson = content['lessons'][i]
                lesson = {"title": f"Lesson {i+1}", "pages": []}
            processed_lesson = {
                "title": lesson['title'],
                "pages": []
            for j in range(number_pages_per_lesson):
                if j < len(lesson.get('pages', [])):
                    page = lesson['pages'][j]
                    page = {"title": f"Page {j+1}", "subtitles": [], "content": ""}
                processed_page = {
                    "title": page['title'],
                    "subtitles": page.get('subtitles', [])[:number_subtitles_per_page],
                    "content": '. '.join(page.get('content', '').split('.')[:sentences_per_page]) + '.'
                # Ensure correct number of subtitles
                while len(processed_page['subtitles']) < number_subtitles_per_page:
                    processed_page['subtitles'].append(f"Subtitle {len(processed_page['subtitles'])+1}")
        return json.dumps(processed_content, indent=2)
    except json.JSONDecodeError:
        st.error("The generated content is not valid JSON. Please try again.")
        return None
    except Exception as e:
        st.error(f"An error occurred while processing the content: {str(e)}")
        return None

def handle_user_input(json_content):
    if not json_content.get("lessons"):
        st.warning("No lessons available. Please generate content first.")
        return json_content

    st.header("Lesson Content Editor")

    col1, col2 = st.columns(2)
    with col1:
        lesson_titles = [lesson.get("title", f"Lesson {i+1}") for i, lesson in enumerate(json_content["lessons"])]
        lesson_title = st.selectbox("📚 Select a lesson", lesson_titles)
        lesson_index = lesson_titles.index(lesson_title)
        lesson = json_content["lessons"][lesson_index]

    with col2:
        if not lesson.get("pages"):
            st.warning(f"No pages available for lesson: {lesson_title}")
            return json_content

        page_titles = [page.get("title", f"Page {i+1}") for i, page in enumerate(lesson["pages"])]
        page_title = st.selectbox("📄 Select a page", page_titles)
        page_index = page_titles.index(page_title)
        page = lesson["pages"][page_index]

    st.subheader(f"📝 Content: {page_title}")
    with st.expander("View original content", expanded=True):
        st.write(page.get("content", "No content available."))

    with st.expander("View subtitles"):
        for subtitle in page.get("subtitles", []):
            st.write(f"• {subtitle}")

    st.subheader("🛠️ Edit Content")
    action = st.radio("What would you like to do with the content?", ["Accept", "Expand", "Summarize"])

    if action == "Accept":
        st.success("Content accepted without changes.")
    elif action == "Expand":
        subtitles = page.get("subtitles", [])
        if subtitles:
            subtitle = st.selectbox("Select a subtitle to expand", subtitles)
            if st.button("Expand Content"):
                with st.spinner("Expanding content..."):
                    prompt = PromptTemplate(
                    input_variables=["subtitle", "page_title", "content"],
                    template="Expand on '{subtitle}' in the context of {page_title}. Original content: {content}")
                    chain = LLMChain(llm=llm, prompt=prompt)
                    expanded_content = chain.invoke({
                        "subtitle": subtitle,
                        "page_title": page_title,
                        "content": page.get("content", "")
                    st.subheader("Expanded Content")
                    page["content"] = expanded_content['text']
                    st.success("Content expanded successfully!")
            st.warning("No subtitles available for expansion.")
    elif action == "Summarize":
        summary_length = st.select_slider("Select summary length", options=["Short", "Medium", "Long"])
        if st.button("Summarize Content"):
            with st.spinner("Summarizing content..."):
                prompt = PromptTemplate( input_variables=["page_title", "summary_length", "content"],
                template="Summarize the content about {page_title} in a {summary_length} summary. Original content: {content}")
                chain = LLMChain(llm=llm, prompt=prompt)
                summarized_content = chain.invoke({
                    "page_title": page_title,
                    "summary_length": summary_length.lower(),
                    "content": page.get("content", "")
                st.subheader("Summarized Content")
                page["content"] = summarized_content['text']
                st.success("Content summarized successfully!")

    return json_content

def preprocess_json_string(json_string):
    # Remove any leading/trailing whitespace
    json_string = json_string.strip()
    # Remove any potential Unicode characters
    json_string = json_string.encode('ascii', 'ignore').decode('ascii')
    # Replace any single backslashes that aren't part of a valid escape sequence
    json_string = re.sub(r'(?<!\\)\\(?!["\\/bfnrt]|u[0-9a-fA-F]{4})', r'', json_string)
    # Fix potential issues with unescaped quotes within strings
    json_string = re.sub(r'(?<!\\)"(?=(?:(?!(?<!\\)").)*$)', r'\"', json_string)
    # Remove any trailing commas before closing brackets or braces
    json_string = re.sub(r',\s*([\]}])', r'\1', json_string)
    return json_string

def main():
    <div style="display: flex; justify-content: space-between; align-items: center;">
        <h1 style="margin: 0;">Interactive Lesson Content Editor</h1>
        <div id="restart-button-container"></div>
    """, unsafe_allow_html=True)

    # Add a restart button, visible only if content has been generated
    if 'content_generated' in st.session_state and st.session_state.content_generated:
        restart_button = st.button("Restart and selected a new subject")
            var button = document.querySelector('button[kind="secondary"]');
            var container = document.getElementById('restart-button-container');
            if (button && container) {
        """, unsafe_allow_html=True)
        if restart_button:
    if 'json_content' not in st.session_state:
        st.session_state.json_content = {
            "subject": "",
            "lessons": []
    if 'content_generated' not in st.session_state:
        st.session_state.content_generated = False

    if not st.session_state.content_generated:
        subject = st.text_input("Enter the subject for the lesson content:")

        col1, col2 = st.columns(2)

        with col1:
            number_lesson_titles = st.number_input("Number of lesson titles:", min_value=1, value=2, step=1)
            number_pages_per_lesson = st.number_input("Pages per lesson:", min_value=1, value=2, step=1)

        with col2:
            number_subtitles_per_page = st.number_input("Subtitles per page:", min_value=1, value=3, step=1)
            sentences_per_page = st.number_input("Sentences per page:", min_value=1, value=3, step=1)

        if subject and subject != st.session_state.json_content.get("subject", ""):
            if st.button("Generate Content"):
                with st.spinner("Generating lesson content..."):
                        generated_content = generate_lesson_content(
                        if generated_content:
                            processed_content = json.loads(generated_content)
                            st.session_state.json_content = processed_content
                            st.session_state.content_generated = True
                            st.success("Lesson content generated successfully!")
                            st.error("Failed to generate content. Please try again.")
                    except json.JSONDecodeError:
                        st.error("The generated content is not valid JSON. Please try again.")
                    except Exception as e:
                        st.error(f"An error occurred: {str(e)}. Please try again.")

        if st.session_state.json_content.get("lessons"):
            st.session_state.json_content = handle_user_input(st.session_state.json_content)

            if st.button("Save Changes"):
                with open(f'{st.session_state.json_content["subject"].replace(" ", "_").lower()}_lesson_content.json', 'w') as f:
                    json.dump(st.session_state.json_content, f, indent=2)
                st.success(f"Changes saved successfully to {st.session_state.json_content['subject'].replace(' ', '_').lower()}_lesson_content.json!")
if __name__ == "__main__":
Leave a Comment