Spaces:
Sleeping
Sleeping
import gradio as gr | |
import os | |
from langchain_openai import ChatOpenAI | |
from langchain.agents import AgentExecutor, create_tool_calling_agent | |
from langchain_community.tools.tavily_search import TavilySearchResults | |
from langchain_core.prompts import ChatPromptTemplate | |
from datetime import datetime, timedelta | |
# Set up API keys | |
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") | |
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY") | |
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY | |
os.environ["TAVILY_API_KEY"] = TAVILY_API_KEY | |
# Initialize the LLM | |
llm = ChatOpenAI(model="gpt-4o-mini") | |
# Set Up the Tavily Search Tool | |
tools = [TavilySearchResults(max_results=3)] | |
# CEFR levels and their descriptions | |
CEFR_LEVELS = { | |
"Pre-A1": "Foundation", | |
"A1": "Elementary", | |
"A2": "Pre-intermediate", | |
"B1": "Intermediate", | |
"B2": "Upper Intermediate", | |
"C1": "Advanced", | |
"C2": "Proficiency" | |
} | |
# Create a Chat Prompt Template | |
prompt = ChatPromptTemplate.from_messages([ | |
("system", "You are a helpful assistant for ESL learners. Use the tavily_search_results_json tool to find current news information about the students' interests."), | |
("human", "{input}"), | |
("placeholder", "{agent_scratchpad}"), | |
]) | |
# Construct the Tools agent | |
agent = create_tool_calling_agent(llm, tools, prompt) | |
# Create an agent executor | |
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) | |
def get_news_content(topic): | |
current_date = datetime.now().strftime("%Y-%m-%d") | |
week_ago = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d") | |
query = f"Summarize the latest news about {topic} from {week_ago} to {current_date}" | |
result = agent_executor.invoke({"input": query}) | |
return result['output'], result.get('intermediate_steps', []) | |
def generate_article(topic, content, urls, level, learning_objective=None): | |
objective_text = f"Focus on the following learning objective: {learning_objective}. " if learning_objective else "" | |
prompt = f""" | |
Write a news article about {topic} suitable for a {level} ({CEFR_LEVELS[level]}) English language learner. | |
{objective_text} | |
Select from the following content to write an interesting article: {content} | |
The article should be engaging, informative, and appropriate for the specified language level. | |
Include a 'Sources' section at the end of the article with the following URLs: {urls} | |
""" | |
result = agent_executor.invoke({"input": prompt}) | |
return result['output'] | |
def extract_language_elements(article, level, learning_objective=None): | |
objective_text = f"Additionally, focus on the following learning objective: {learning_objective}. " if learning_objective else "" | |
prompt = f""" | |
Analyze the following article for a {level} ({CEFR_LEVELS[level]}) English language learner: | |
Extract and categorize the following language elements: | |
1. Vocabulary: Important or challenging words with their definitions | |
2. Grammar: Key grammar structures or patterns used in the article | |
3. Conjugation: Notable verb conjugations present in the article | |
4. Expressions: Idiomatic expressions or phrasal verbs | |
5. Sentence structures: Complex or notable sentence structures | |
Ensure that the extracted elements are appropriate and relevant for a {level} learner. | |
{objective_text} | |
Return the results in a structured format. | |
Article: {article} | |
""" | |
result = agent_executor.invoke({"input": prompt}) | |
return result['output'] | |
def generate_feedback_and_takeaway(article, level, language_elements, learning_objective=None): | |
objective_text = f"Additionally, focus on the following learning objective: {learning_objective}. " if learning_objective else "" | |
prompt = f""" | |
Based on the following article for a {level} ({CEFR_LEVELS[level]}) English language learner and the extracted language elements: | |
Create a takeaway section about key language learning points including: | |
- A list of important vocabulary words with their definitions | |
- A list of important grammar rules or patterns used in the article | |
- A list of notable conjugations | |
- A list of idiomatic expressions or phrasal verbs | |
- Examples of complex or notable sentence structures | |
Use the provided language elements as a basis, but feel free to expand or adjust as needed. | |
{objective_text} | |
Article: {article} | |
Language Elements: {language_elements} | |
""" | |
result = agent_executor.invoke({"input": prompt}) | |
return result['output'] | |
def generate_response(user_input, context, level, learning_objective=None): | |
objective_text = f"Additionally, focus on the following learning objective: {learning_objective}. " if learning_objective else "" | |
prompt = f""" | |
#Role | |
You are an ESL teacher | |
You answer students' questions about an article, helping them understand it, with a focus on language elements. | |
You also ask the student questions aligned with relevant language elemnts to check their understanding. | |
#Instructions | |
1. If the student asks a question: Based on the following article for a {level} ({CEFR_LEVELS[level]}) English language learner, respond to the user's input in a helpful manner. | |
2. When the user is ready, ask relevant questions to check for their understanding of the article, but also to practice the relevant language elements. | |
Ensure questions are challenging but appropriate for the {level} level. | |
Avoid questions with obvious answers. | |
Types of questions should include: | |
- Multiple-choice questions | |
- True/false questions | |
- Fill-in-the-blank questions | |
- Questions to apply the elements of language learned in new contexts | |
- Open-ended questions | |
Questions should become increasingly difficult as the student succeeds, and easier if they struggle. | |
When the student fails, provide a hint. If they fail again, provide the answer and an explanation. | |
{objective_text} | |
Article: {context['article']} | |
Language Elements: {context['language_elements']} | |
User Input: {user_input} | |
""" | |
result = agent_executor.invoke({"input": prompt}) | |
return result['output'] | |
def main(topic, level, learning_objective=None): | |
try: | |
news_content, intermediate_steps = get_news_content(topic) | |
if news_content: | |
urls = [step[1].get('url', '') for step in intermediate_steps if isinstance(step[1], dict)] | |
article = generate_article(topic, news_content, urls, level, learning_objective) | |
language_elements = extract_language_elements(article, level, learning_objective) | |
feedback_and_takeaway = generate_feedback_and_takeaway(article, level, language_elements, learning_objective) | |
context = { | |
'article': article, | |
'language_elements': language_elements, | |
'feedback_and_takeaway': feedback_and_takeaway | |
} | |
return article, feedback_and_takeaway, context | |
else: | |
return "No relevant news content found. Please try a different topic.", "", None | |
except Exception as e: | |
return f"An error occurred: {str(e)}", "", None | |
def chat(user_input, context): | |
response = generate_response(user_input, context) | |
return response | |
# Gradio Interface | |
with gr.Blocks() as demo: | |
topic_input = gr.Textbox(label="Enter your topic of interest") | |
level_input = gr.Dropdown(label="Select your English proficiency level", choices=list(CEFR_LEVELS.keys())) | |
objective_input = gr.Textbox(label="Enter a specific learning objective (optional)") | |
generate_btn = gr.Button("Generate Article") | |
article_output = gr.Markdown() | |
feedback_output = gr.Markdown() | |
chat_input = gr.Textbox(label="Ask questions about the article or English language here") | |
chat_output = gr.Chatbot() | |
context = gr.State() | |
def on_generate(topic, level, learning_objective): | |
article, feedback, ctx = main(topic, level, learning_objective) | |
context.set(ctx) | |
return article, feedback | |
generate_btn.click(on_generate, inputs=[topic_input, level_input, objective_input], outputs=[article_output, feedback_output]) | |
def on_chat(user_input): | |
if context.get() is not None: | |
response = chat(user_input, context.get()) | |
return response | |
else: | |
return "Please generate an article first." | |
chat_input.submit(on_chat, inputs=[chat_input], outputs=[chat_output]) | |
demo.launch() | |