import gradio as gr import sqlite3 import json import os from datetime import datetime import torch import nltk from transformers import AutoModelForSeq2SeqLM, AutoTokenizer, ElectraTokenizer, ElectraForTokenClassification import torch.nn as nn # Download NLTK data try: nltk.data.find('tokenizers/punkt') except LookupError: nltk.download('punkt') # Initialize SQLite database for storing submissions and exercises def init_database(): conn = sqlite3.connect('language_app.db') c = conn.cursor() # Users table c.execute('''CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, email TEXT UNIQUE NOT NULL, role TEXT NOT NULL, password_hash TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )''') # Tasks table c.execute('''CREATE TABLE IF NOT EXISTS tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, description TEXT NOT NULL, image_url TEXT, creator_id INTEGER, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )''') # Submissions table c.execute('''CREATE TABLE IF NOT EXISTS submissions ( id INTEGER PRIMARY KEY AUTOINCREMENT, task_id INTEGER, student_name TEXT NOT NULL, content TEXT NOT NULL, analysis_result TEXT, analysis_html TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )''') # Exercises table c.execute('''CREATE TABLE IF NOT EXISTS exercises ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, instructions TEXT NOT NULL, sentences TEXT NOT NULL, image_url TEXT, submission_id INTEGER, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )''') # Exercise attempts table c.execute('''CREATE TABLE IF NOT EXISTS exercise_attempts ( id INTEGER PRIMARY KEY AUTOINCREMENT, exercise_id INTEGER, student_name TEXT NOT NULL, responses TEXT NOT NULL, score REAL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )''') conn.commit() conn.close() # Neural Network Model (simplified version of your existing model) class SimpleGrammarChecker: def __init__(self): self.model_name = "Zlovoblachko/Realec-2step-ft-realec" self.ged_model_name = "Zlovoblachko/4tag-electra-grammar-error-detection" self.load_models() def load_models(self): try: # Load T5 model self.tokenizer = AutoTokenizer.from_pretrained(self.model_name) self.model = AutoModelForSeq2SeqLM.from_pretrained(self.model_name) # Load GED model self.ged_tokenizer = ElectraTokenizer.from_pretrained(self.ged_model_name) self.ged_model = ElectraForTokenClassification.from_pretrained(self.ged_model_name) print("Models loaded successfully!") except Exception as e: print(f"Error loading models: {e}") self.model = None self.ged_model = None def analyze_text(self, text): if not self.model or not text.strip(): return "Model not available or empty text", "" try: # Tokenize and generate correction inputs = self.tokenizer(text, return_tensors="pt", truncation=True, max_length=512) with torch.no_grad(): outputs = self.model.generate( input_ids=inputs.input_ids, attention_mask=inputs.attention_mask, max_length=512, num_beams=4, early_stopping=True ) corrected_text = self.tokenizer.decode(outputs[0], skip_special_tokens=True) # Get GED predictions if available error_spans = [] if self.ged_model: error_spans = self.get_error_spans(text) # Generate HTML output html_output = self.generate_html_analysis(text, corrected_text, error_spans) return corrected_text, html_output except Exception as e: return f"Error during analysis: {str(e)}", "" def get_error_spans(self, text): try: inputs = self.ged_tokenizer(text, return_tensors="pt", truncation=True, padding=True) with torch.no_grad(): outputs = self.ged_model(**inputs) predictions = torch.argmax(outputs.logits, dim=2) tokens = self.ged_tokenizer.convert_ids_to_tokens(inputs.input_ids[0]) token_predictions = predictions[0].cpu().numpy().tolist() error_spans = [] for i, (token, pred) in enumerate(zip(tokens, token_predictions)): if token.startswith("##") or token in ["[CLS]", "[SEP]", "[PAD]"]: continue if pred != 0: # 0 is correct, 1=R, 2=M, 3=U error_type = ["C", "R", "M", "U"][pred] error_spans.append({"token": token, "type": error_type, "position": i}) return error_spans except: return [] def generate_html_analysis(self, original, corrected, error_spans): html = f"""

Grammar Analysis Results

Original Text:

{original}

Corrected Text:

{corrected}

Error Analysis:

Found {len(error_spans)} potential errors

""" return html # Initialize components init_database() grammar_checker = SimpleGrammarChecker() # Gradio Interface Functions def analyze_student_writing(text, student_name, task_title="General Writing Task"): """Analyze student writing and store in database""" if not text.strip(): return "Please enter some text to analyze.", "" if not student_name.strip(): return "Please enter your name.", "" # Analyze text corrected_text, html_analysis = grammar_checker.analyze_text(text) # Store in database conn = sqlite3.connect('language_app.db') c = conn.cursor() # Insert task if not exists c.execute("INSERT OR IGNORE INTO tasks (title, description) VALUES (?, ?)", (task_title, f"Writing task: {task_title}")) c.execute("SELECT id FROM tasks WHERE title = ?", (task_title,)) task_id = c.fetchone()[0] # Insert submission analysis_data = { "corrected_text": corrected_text, "original_text": text, "html_output": html_analysis } c.execute("""INSERT INTO submissions (task_id, student_name, content, analysis_result, analysis_html) VALUES (?, ?, ?, ?, ?)""", (task_id, student_name, text, json.dumps(analysis_data), html_analysis)) submission_id = c.lastrowid conn.commit() conn.close() return corrected_text, html_analysis def create_exercise_from_text(text, exercise_title="Grammar Exercise"): """Create an exercise from text with errors""" if not text.strip(): return "Please enter text to create an exercise.", "" # Analyze text to find sentences with errors sentences = nltk.sent_tokenize(text) exercise_sentences = [] for sentence in sentences: corrected, _ = grammar_checker.analyze_text(sentence) if sentence.strip() != corrected.strip(): # Has errors exercise_sentences.append({ "original": sentence.strip(), "corrected": corrected.strip() }) if not exercise_sentences: return "No errors found in the text. Cannot create exercise.", "" # Store exercise in database conn = sqlite3.connect('language_app.db') c = conn.cursor() c.execute("""INSERT INTO exercises (title, instructions, sentences) VALUES (?, ?, ?)""", (exercise_title, "Correct the grammatical errors in the following sentences:", json.dumps(exercise_sentences))) exercise_id = c.lastrowid conn.commit() conn.close() # Generate exercise HTML exercise_html = f"""

{exercise_title}

Instructions: Correct the grammatical errors in the following sentences:

    """ for i, sentence_data in enumerate(exercise_sentences, 1): exercise_html += f"
  1. {sentence_data['original']}
  2. " exercise_html += "
" return f"Exercise created with {len(exercise_sentences)} sentences!", exercise_html def attempt_exercise(exercise_id, student_responses, student_name): """Submit exercise attempt and get score""" if not student_name.strip(): return "Please enter your name.", "" try: exercise_id = int(exercise_id) except: return "Please enter a valid exercise ID.", "" # Get exercise from database conn = sqlite3.connect('language_app.db') c = conn.cursor() c.execute("SELECT sentences FROM exercises WHERE id = ?", (exercise_id,)) result = c.fetchone() if not result: return "Exercise not found.", "" exercise_sentences = json.loads(result[0]) # Parse student responses responses = [r.strip() for r in student_responses.split('\n') if r.strip()] if len(responses) != len(exercise_sentences): return f"Please provide exactly {len(exercise_sentences)} responses (one per line).", "" # Calculate score correct_count = 0 feedback = [] for i, (sentence_data, response) in enumerate(zip(exercise_sentences, responses), 1): correct_answer = sentence_data['corrected'] is_correct = response.lower().strip() == correct_answer.lower().strip() if is_correct: correct_count += 1 feedback.append(f"✅ Sentence {i}: Correct!") else: feedback.append(f"❌ Sentence {i}: Your answer: '{response}' | Correct answer: '{correct_answer}'") score = (correct_count / len(exercise_sentences)) * 100 # Store attempt attempt_data = { "responses": responses, "score": score, "feedback": feedback } c.execute("""INSERT INTO exercise_attempts (exercise_id, student_name, responses, score) VALUES (?, ?, ?, ?)""", (exercise_id, student_name, json.dumps(attempt_data), score)) conn.commit() conn.close() feedback_html = f"""

Exercise Results

Score: {score:.1f}% ({correct_count}/{len(exercise_sentences)} correct)

{'
'.join(feedback)}
""" return f"Score: {score:.1f}%", feedback_html def get_student_progress(student_name): """Get student's submission and exercise history""" if not student_name.strip(): return "Please enter a student name." conn = sqlite3.connect('language_app.db') c = conn.cursor() # Get submissions c.execute("""SELECT s.id, s.content, s.created_at, t.title FROM submissions s JOIN tasks t ON s.task_id = t.id WHERE s.student_name = ? ORDER BY s.created_at DESC""", (student_name,)) submissions = c.fetchall() # Get exercise attempts c.execute("""SELECT ea.score, ea.created_at, e.title FROM exercise_attempts ea JOIN exercises e ON ea.exercise_id = e.id WHERE ea.student_name = ? ORDER BY ea.created_at DESC""", (student_name,)) attempts = c.fetchall() conn.close() progress_html = f"""

Progress for {student_name}

Writing Submissions ({len(submissions)})

Exercise Attempts ({len(attempts)})

" return progress_html # Create Gradio Interface with gr.Blocks(title="Language Learning App - Grammar Checker", theme=gr.themes.Soft()) as app: gr.Markdown("# 🎓 Language Learning Application") gr.Markdown("### AI-Powered Grammar Checking and Exercise Generation") with gr.Tabs(): # Student Writing Analysis Tab with gr.TabItem("📝 Writing Analysis"): gr.Markdown("## Submit Your Writing for Analysis") with gr.Row(): with gr.Column(): student_name_input = gr.Textbox(label="Your Name", placeholder="Enter your name") task_title_input = gr.Textbox(label="Assignment Title", value="General Writing Task") writing_input = gr.Textbox( label="Your Writing", lines=8, placeholder="Paste your writing here for grammar analysis..." ) analyze_btn = gr.Button("Analyze Writing", variant="primary") with gr.Column(): corrected_output = gr.Textbox(label="Corrected Text", lines=6) analysis_output = gr.HTML(label="Detailed Analysis") analyze_btn.click( analyze_student_writing, inputs=[writing_input, student_name_input, task_title_input], outputs=[corrected_output, analysis_output] ) # Exercise Creation Tab with gr.TabItem("🏋️ Exercise Creation"): gr.Markdown("## Create Grammar Exercises") with gr.Row(): with gr.Column(): exercise_title_input = gr.Textbox(label="Exercise Title", value="Grammar Exercise") exercise_text_input = gr.Textbox( label="Text with Errors", lines=6, placeholder="Enter text containing grammatical errors to create an exercise..." ) create_exercise_btn = gr.Button("Create Exercise", variant="primary") with gr.Column(): exercise_result = gr.Textbox(label="Result") exercise_display = gr.HTML(label="Generated Exercise") create_exercise_btn.click( create_exercise_from_text, inputs=[exercise_text_input, exercise_title_input], outputs=[exercise_result, exercise_display] ) # Exercise Attempt Tab with gr.TabItem("✏️ Exercise Practice"): gr.Markdown("## Practice Grammar Exercises") with gr.Row(): with gr.Column(): exercise_id_input = gr.Textbox(label="Exercise ID", placeholder="Enter exercise ID") student_name_exercise = gr.Textbox(label="Your Name", placeholder="Enter your name") responses_input = gr.Textbox( label="Your Answers", lines=6, placeholder="Enter your corrected sentences (one per line)..." ) submit_exercise_btn = gr.Button("Submit Answers", variant="primary") with gr.Column(): score_output = gr.Textbox(label="Your Score") feedback_output = gr.HTML(label="Detailed Feedback") submit_exercise_btn.click( attempt_exercise, inputs=[exercise_id_input, responses_input, student_name_exercise], outputs=[score_output, feedback_output] ) # Progress Tracking Tab with gr.TabItem("📊 Student Progress"): gr.Markdown("## View Student Progress") with gr.Row(): with gr.Column(scale=1): progress_student_name = gr.Textbox(label="Student Name", placeholder="Enter student name") get_progress_btn = gr.Button("Get Progress", variant="primary") with gr.Column(scale=2): progress_output = gr.HTML(label="Student Progress") get_progress_btn.click( get_student_progress, inputs=[progress_student_name], outputs=[progress_output] ) gr.Markdown(""" --- ### How to Use: 1. **Writing Analysis**: Submit your writing to get grammar corrections and detailed error analysis 2. **Exercise Creation**: Teachers can create exercises from text containing errors 3. **Exercise Practice**: Students can practice with generated exercises and get scored feedback 4. **Progress Tracking**: View student progress across submissions and exercises *Powered by advanced neural networks for grammar error detection and correction* """) if __name__ == "__main__": app.launch()