Untitled
unknown
python
9 months ago
13 kB
4
Indexable
import streamlit as st import json,re from langchain_groq import ChatGroq from langchain.prompts import PromptTemplate from langchain.chains import LLMChain api_key = "??????" st.set_page_config(layout="wide") 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"], template=""" 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. """ try: 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] else: 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] else: 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}") processed_lesson['pages'].append(processed_page) processed_content['lessons'].append(processed_lesson) 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") st.write(expanded_content['text']) page["content"] = expanded_content['text'] st.success("Content expanded successfully!") else: 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") st.write(summarized_content['text']) 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(): st.markdown(""" <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> </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") st.markdown(""" <script> var button = document.querySelector('button[kind="secondary"]'); var container = document.getElementById('restart-button-container'); if (button && container) { container.appendChild(button); } </script> """, unsafe_allow_html=True) if restart_button: st.session_state.clear() st.rerun() 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..."): try: generated_content = generate_lesson_content( subject, number_lesson_titles, number_pages_per_lesson, number_subtitles_per_page, sentences_per_page ) 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.rerun() else: 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.") else: 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__": main()
Editor is loading...
Leave a Comment