Spaces:
Running
Running
| import os | |
| import openai | |
| import random | |
| from flask import Flask, Blueprint, request, jsonify, current_app | |
| from flask_cors import CORS | |
| # --- Blueprint --- | |
| writting_bp = Blueprint("writting", __name__) | |
| app = Flask(__name__) | |
| CORS(app) | |
| # openai.api_key = "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" | |
| # ---- API key from env/config (no hard-coded key) ---- | |
| _OPENAI_API_KEY_FALLBACK = os.getenv("OPENAI_API_KEY", "") | |
| def _ensure_openai_key(): | |
| """Set openai.api_key from app config or env before each API call.""" | |
| api_key = (current_app.config.get("OPENAI_API_KEY") if current_app else None) or _OPENAI_API_KEY_FALLBACK | |
| if api_key: | |
| openai.api_key = api_key | |
| previous_topics = set() | |
| def is_similar(new_topic): | |
| """Check if the new topic is too similar to previously generated ones.""" | |
| for topic in previous_topics: | |
| if new_topic.lower() in topic.lower() or topic.lower() in new_topic.lower(): | |
| return True | |
| return False | |
| # ---- Routes converted to Blueprint (paths unchanged) ---- | |
| # @app.route('/generate-writing-topics', methods=['POST']) | |
| def generate_writing_topics(): | |
| global previous_topics | |
| try: | |
| data = request.json | |
| grade_level = data.get("grade_level", "lower").lower() | |
| valid_levels = {"lower", "middle", "upper"} | |
| if grade_level not in valid_levels: | |
| return jsonify({"error": "Invalid grade level."}), 400 | |
| prompt = f""" | |
| Generate a completely **random and unpredictable** writing topic for a {grade_level}-grade student. | |
| The topic should: | |
| - Be age-appropriate for {grade_level}-grade students. | |
| - Be something **new and unexpected**. | |
| - Avoid overused or common writing prompts. | |
| - Be **appropriate in complexity based on the grade level**: | |
| - **For younger students**, make topics more **imaginative and storytelling-driven**. | |
| - **For middle-level students**, introduce **more structured thinking, problem-solving, or decision-making elements**. Avoid relying only on fantasy—ensure topics also include **real-world ethical dilemmas, debates, and problem-solving challenges**. | |
| - **For upper-level students**, push for **analytical, ethical, or futuristic discussions requiring critical thinking**. | |
| - Follow no specific structure or category. | |
| - Be **one sentence long**. | |
| - **Format the output as:** "Writing topic: <your topic here>" | |
| """ | |
| # Generate topic with full randomness | |
| max_retries = 7 | |
| retries = 0 | |
| while retries < max_retries: | |
| response = openai.chat.completions.create( | |
| model="gpt-4-turbo", | |
| messages=[{"role": "user", "content": prompt}], | |
| max_tokens=50, | |
| temperature=1.8, # High randomness for maximum diversity | |
| top_p=0.95 # Allows broader AI output | |
| ) | |
| new_topic = response.choices[0].message.content.strip() | |
| # Ensure AI follows correct format | |
| if "Writing topic:" in new_topic: | |
| new_topic = new_topic.replace("Writing topic:", "").strip() | |
| # Check uniqueness before returning | |
| if not is_similar(new_topic) and new_topic not in previous_topics: | |
| previous_topics.add(new_topic) | |
| return jsonify({"topic": new_topic}), 200 | |
| retries += 1 | |
| return jsonify({"error": "Failed to generate a unique topic"}), 500 | |
| except Exception as e: | |
| print(f"Error: {e}") | |
| return jsonify({"error": "An error occurred"}), 500 | |
| # @app.route('/validate-response', methods=['POST']) | |
| def validate_response(): | |
| """ | |
| Validate user response against the provided topic using GPT. | |
| """ | |
| try: | |
| data = request.json | |
| topic = data.get("topic") | |
| response_text = data.get("response") | |
| if not topic or not response_text: | |
| return jsonify({"error": "Both 'topic' and 'response' fields are required."}), 400 | |
| # Define the prompt for GPT to evaluate the response | |
| validation_prompt = ( | |
| f"You are a strict writing teacher. " | |
| f"Score: <number>/10\n\n" | |
| f"Check the student's response for grammar, spelling, punctuation, and sentence structure. " | |
| f"Give feedback in simple, clear English that a 10-year-old can understand. " | |
| f"Keep the feedback neat and easy to read. " | |
| f"Use this exact format:\n\n" | |
| f"What is good:\n" | |
| f"- <two short points about strengths>\n" | |
| f"Needs fixing:\n" | |
| f"- <two short points about mistakes>\n" | |
| f"How to improve:\n" | |
| f"- <one short, clear tip or rewrite>\n" | |
| f"Topic: '{topic}'. Response: '{response_text}'." | |
| ) | |
| messages = [ | |
| {"role": "system", "content": "You are a helpful writing teacher."}, | |
| {"role": "user", "content": validation_prompt} | |
| ] | |
| # Call GPT for validation using OpenAI's ChatCompletion API | |
| result = openai.chat.completions.create( | |
| model="gpt-4-turbo", | |
| messages=messages, | |
| max_tokens=1500, | |
| temperature=0.7 | |
| ) | |
| feedback = result.choices[0].message.content.strip() | |
| return jsonify({"feedback": feedback}), 200 | |
| except Exception as e: | |
| print(f"Error validating response: {e}") | |
| return jsonify({"error": "An error occurred while validating the response."}), 500 | |
| # if __name__ == '__main__': | |
| # app.run(host='0.0.0.0', port=8000, debug=True) | |
| # --- Optional: standalone run (local testing) --- | |
| if __name__ == '__main__': | |
| app = Flask(__name__) | |
| CORS(app) | |
| app.config["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY", "") | |
| app.register_blueprint(writting_bp, url_prefix='') | |
| app.run(host='0.0.0.0', port=8000, debug=True) | |