AutoHSK / app.py
Luigi
Update app.py
a88cae5 verified
import os
import gradio as gr
from weasyprint import HTML # Use WeasyPrint for HTML to PDF
from huggingface_hub import InferenceClient
from huggingface_hub.utils import HfHubHTTPError
import requests
# --- Configuration ---
HF_TOKEN = os.getenv("HF_TOKEN")
if not HF_TOKEN:
raise ValueError("The HF_TOKEN environment variable must be set.")
MODEL_NAME = "meta-llama/Llama-3.1-8B-Instruct"
MAX_INPUT_LENGTH = 4096 # Maximum characters for lesson content
# --- Hugging Face Inference Client ---
client = InferenceClient(model=MODEL_NAME, token=HF_TOKEN) # Corrected: Use model and token
def call_hf_api(lesson_text: str) -> str:
"""
Calls the Hugging Face Inference API, generating exercises in SPANISH.
"""
if not lesson_text.strip():
return "Please provide lesson content."
if len(lesson_text) > MAX_INPUT_LENGTH:
return f"Error: Lesson content is too long (>{MAX_INPUT_LENGTH} characters). Please shorten it."
prompt = f"""
You are a helpful assistant that generates structured HSK exercises in HTML format.
Use ONLY the following lesson content to create the exercises. Do NOT hallucinate any content.
The generated exercises, including all instructions within each exercise, section titles,
and questions, MUST be in SPANISH.
USER INPUT Lesson Content YOU MUST USE FOR CUSTOMIZING THE EXERCICES OF THE HTML TEMPLATE:
{lesson_text}
Generate exactly 12 exercise sections in HTML, as shown in the example below.
The exercises MUST use the vocabulary and grammar points from the lesson content provided above.
Do not include an answer key.
Example HTML Output Structure (use this EXACT structure, adapt exercise TYPES and content, and generate content in SPANISH, ACCORDING TO THE INPUT):
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>CHINOTOTAL - Lección [Número de Lección]</title>
<style>
body {{ font-family: Arial, sans-serif; margin: 0 auto; max-width: 800px; line-height: 1.5; }}
h1, h2, h3 {{ text-align: center; }}
hr {{ margin: 30px 0; }}
.exercise-title {{ color: #007BFF; font-weight: bold; }}
.instructions {{ font-style: italic; margin-bottom: 10px; }}
ol, ul {{ margin-bottom: 20px; }}
</style>
</head>
<body>
<h1>CHINOTOTAL - Lección [Número de Lección]</h1>
<h2>Ejercicios Completos</h2>
<p style="text-align:center; margin:20px 0;">Total de 12 Secciones - La última es escritura.</p>
<hr>
<!-- SECCIÓN 1: Fill in the Blanks -->
<h3>Sección 1: Completa los Espacios en Blanco</h3>
<p class="instructions">Completa las siguientes oraciones con la palabra correcta del recuadro.</p>
<p>[Palabras del recuadro: (Palabras relevantes de la lección)]</p>
<ol>
<li>El ______ está en la mesa. (libro, silla, comida)</li>
<li>Me gusta ______ música. (escuchar, hablar, comer)</li>
</ol>
<hr>
<!-- SECCIÓN 2: Sentence Ordering -->
<h3>Sección 2: Ordena las Oraciones</h3>
<p class="instructions">Ordena las siguientes palabras para formar oraciones coherentes.</p>
<ol>
<li>/ libro / el / es / dónde /</li>
<li>/ gusta / me / mucho / este / restaurante /</li>
</ol>
<hr>
<!-- SECCIÓN 3: Multiple Choice -->
<h3>Sección 3: Opción Múltiple</h3>
<p class="instructions">Elige la opción correcta para completar cada oración.</p>
<ol>
<li>Voy ______ la biblioteca. (a, en, de)</li>
<li>______ es tu nombre? (Cómo, Qué, Quién)</li>
</ol>
<hr>
<!-- SECCIÓN 4: Translation -->
<h3>Sección 4: Traducción</h3>
<p class="instructions">Traduce las siguientes frases al chino.</p>
<ol>
<li>I like to read books.</li>
<li>Where is the bathroom?</li>
</ol>
<hr>
<!-- SECCIÓN 5: Matching -->
<h3>Sección 5: Emparejar</h3>
<p class="instructions">Empareja las palabras de la columna A con sus significados en la columna B.</p>
<ol>
<li>[Palabra 1] A. [Significado A]</li>
<li>[Palabra 2] B. [Significado B]</li>
</ol>
<hr>
<!-- SECCIÓN 6: Character Writing -->
<h3>Sección 6: Escritura de Caracteres</h3>
<p class="instructions">Escribe los siguientes caracteres en los recuadros.</p>
<ol>
<li>[Caracter 1] [Recuadro para escribir]</li>
<li>[Caracter 2] [Recuadro para escribir]</li>
</ol>
<hr>
<!-- SECCIÓN 7: Dialogue Completion -->
<h3>Sección 7: Completa el Diálogo</h3>
<p class="instructions">Completa el siguiente diálogo con las frases apropiadas.</p>
<p>A: ______<br>B: Me llamo Li Hua.</p>
<ol>
<li>¿Cómo te llamas?</li>
<li>¿De dónde eres?</li>
</ol>
<hr>
<!-- SECCIÓN 8: Short Answer -->
<h3>Sección 8: Respuesta Corta</h3>
<p class="instructions">Responde las siguientes preguntas en español.</p>
<ol>
<li>¿Qué te gusta hacer en tu tiempo libre?</li>
<li>¿Cuál es tu comida favorita?</li>
</ol>
<hr>
<!-- SECCIÓN 9: True/False -->
<h3>Sección 9: Verdadero/Falso</h3>
<p class="instructions">Indica si las siguientes afirmaciones son verdaderas (V) o falsas (F).</p>
<ol>
<li>[Afirmación 1] (V/F)</li>
<li>[Afirmación 2] (V/F)</li>
</ol>
<hr>
<!-- SECCIÓN 10: Picture Description -->
<h3>Sección 10: Descripción de Imagen</h3>
<p class="instructions">Describe la siguiente imagen en una oración.</p>
<p>[Espacio para la imagen, o una descripción si no se puede incluir la imagen]</p>
<p>[ ]</p>
<hr>
<!-- SECCIÓN 11: Error Correction -->
<h3>Sección 11: Corrección de Errores</h3>
<p class="instructions">Corrige los errores en las siguientes oraciones.</p>
<ol>
<li>Yo gusta leer libro.</li>
<li>El dónde es el baño.</li>
</ol>
<hr>
<!-- SECCIÓN 12: Writing Prompt -->
<h3>Sección 12: Ejercicio de Escritura</h3>
<p class="instructions">Escribe un párrafo corto (aproximadamente 50-80 palabras) en chino sobre un tema relacionado con la lección. Usa el vocabulario y las estructuras gramaticales que has aprendido.</p>
<p>[Espacio para escribir]</p>
<hr>
<p style="text-align:center; margin: 30px 0;">— Fin de la Hoja de Ejercicios —</p>
</body>
</html>
Do NOT include any other text outside of the HTML. Output ONLY the HTML. The HTML MUST be different and adapted to the content provided in the `lesson_text` variable. The example serves as a template of the STRUCTURE and TYPES OF EXERCISES. The content MUST be in SPANISH, and related to lesson_text
"""
messages = [
{
"role": "user",
"content": prompt,
}
]
try:
# Corrected: Use the text-generation task and pass messages directly
generated_text = client.text_generation(
prompt=prompt,
max_new_tokens=2000,
temperature=0.7,
top_p=0.9,
stop_sequences=["```"],
)
# HTML Cleanup:
if "```html" in generated_text:
generated_text = generated_text.split("```html")[1]
if "```" in generated_text:
generated_text = generated_text.split("```")[0]
return generated_text
except HfHubHTTPError as e:
return f"Error from Hugging Face Hub: {e}"
except requests.exceptions.RequestException as e:
return f"Network or API error: {e}"
except Exception as e:
return f"An unexpected error occurred: {e}"
def generate_exercises(lesson_text: str) -> str:
"""Generates exercises in HTML format."""
return call_hf_api(lesson_text)
def create_pdf(exercises_text: str) -> str:
"""Creates a PDF from the generated HTML exercises."""
if not exercises_text.strip():
return None
try:
output_filename = "hsk_exercises.pdf"
HTML(string=exercises_text).write_pdf(output_filename)
return output_filename
except Exception as e:
return f"Error during PDF generation: {e}"
def copy_text(exercises_text: str) -> str:
"""Copies the generated HTML to the clipboard (for display purposes)."""
if not exercises_text.strip():
return "No text to copy!"
return exercises_text
# --- Gradio Interface ---
with gr.Blocks(title="HSK Exercise Generator", theme=gr.themes.Soft()) as demo:
gr.Markdown("# HSK Exercise Generator")
gr.Markdown("Paste your lesson content and generate structured HSK exercises.")
with gr.Row():
lesson_input = gr.Textbox(
lines=10,
label="Lesson Content",
placeholder=f"Paste lesson content here (max {MAX_INPUT_LENGTH} characters)...",
)
generate_btn = gr.Button("Generate Exercises")
output_html = gr.HTML(label="Generated Exercises") # Use gr.HTML for HTML output
with gr.Row():
download_btn = gr.Button("Download as PDF")
copy_btn = gr.Button("Copy Text")
copy_notice = gr.Textbox(
label="Copy/Status",
placeholder="Shows copied text or status here.",
interactive=False,
)
generate_btn.click(generate_exercises, inputs=lesson_input, outputs=output_html)
download_btn.click(create_pdf, inputs=output_html, outputs=gr.File())
copy_btn.click(copy_text, inputs=output_html, outputs=copy_notice)
gr.Markdown(
"""
Usage:
1. Set your Hugging Face token: `export HF_TOKEN=hf_yourRealToken`
2. Install required packages: `pip install gradio huggingface_hub requests weasyprint`
3. Run the script: `python exercise_generator.py`
4. Open the provided local URL in your browser.
5. Paste your lesson content (make sure it's not too long).
6. Click "Generate Exercises".
7. The generated exercises (in Spanish) will appear in the output area.
8. You can then download them as a PDF or copy the text.
"""
)
if __name__ == "__main__":
demo.launch()