Spaces:
Sleeping
Sleeping
File size: 14,480 Bytes
ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 34771bf ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 34771bf ce7ee25 34771bf ce7ee25 34771bf ce7ee25 34771bf ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 fc01712 ce7ee25 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
# from flask import Flask, Blueprint, jsonify, send_file, abort, make_response, request
from flask import Flask, Blueprint, jsonify, send_file, abort, make_response, request, current_app
from flask_cors import CORS
import os
print(f"GOOGLE_APPLICATION_CREDENTIALS: {os.getenv('GOOGLE_APPLICATION_CREDENTIALS')}")
import io
import uuid
import requests
import re
questions_bp = Blueprint("questions", __name__)
app = Flask(__name__)
CORS(app)
@app.route('/')
def home():
return "Welcome to the Flask app! The server is running."
# read from env as a fallback (works for local .env and HF Secrets)
COHERE_API_KEY = os.getenv("COHERE_API_KEY", "")
def _cohere_headers():
"""
Prefer a key set on the Flask app (e.g., in verification.py: app.config["COHERE_API_KEY"]),
otherwise fall back to the environment variable COHERE_API_KEY.
"""
api_key = current_app.config.get("COHERE_API_KEY") or COHERE_API_KEY
if not api_key:
return None
return {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
}
# (1) UPDATED: Cohere v2 Chat endpoint
COHERE_API_URL = 'https://api.cohere.com/v2/chat'
def _extract_text_v2(resp_json: dict) -> str:
"""
v2 /chat returns:
{ "message": { "content": [ { "type": "text", "text": "..." } ] } }
"""
msg = resp_json.get("message", {})
content = msg.get("content", [])
if isinstance(content, list) and content:
block = content[0]
if isinstance(block, dict):
return (block.get("text") or "").strip()
return ""
def validate_topic(topic):
validation_prompt = f"""
ou are a highly knowledgeable AI grammar expert. Your task is to evaluate whether the given topic relates to **English grammar** or not.
**Input Topic:** "{topic}"
### **Instructions:**
- If the input **exactly refers to** grammar concepts (such as **parts of speech**, **verb tenses**, **sentence structure**, **grammar rules**, etc.), respond with `"Grammar"`.
- If the input **seems to be a general question or concept** that is **not directly related to grammar**, such as general knowledge, science, history, or unrelated fields, respond with `"Not Grammar"`.
- If the input is in the form of a **question** (e.g., "What is subject-verb agreement?"), respond with `"ask grammar topics"`.
- If the topic refers to a **specific grammar concept** (e.g., **noun**, **verb**, **preposition**, **past tense**, etc.), always classify it as `"Grammar"`.
- **Do not include any explanations or examples**. Your answer must only be `"Grammar"`, `"Not Grammar"`, or `"ask grammar topics"`, depending on whether the topic is relevant to grammar.
- If the input is **unclear**, err on the side of classifying it as `"Not Grammar"` rather than `"Grammar"`.
Your response must only be one of these three options:
- `"Grammar"`
- `"Not Grammar"`
- `"ask grammar topics"`
No extra text or explanation.
"""
headers = _cohere_headers()
if not headers:
return "Error: COHERE_API_KEY not set"
# (2) UPDATED: messages payload
payload = {
'model': 'command-r-08-2024',
'messages': [
{'role': 'user', 'content': validation_prompt}
],
'max_tokens': 5
}
try:
response = requests.post(COHERE_API_URL, json=payload, headers=headers)
# (3) UPDATED: v2 parsing
validation_result = _extract_text_v2(response.json())
if validation_result not in ["Grammar", "Not Grammar", "ask grammar topics"]:
return "Not Grammar"
return validation_result
except Exception as e:
return f"Error: {str(e)}"
@questions_bp.post('/generate-questions')
def generate_questions_test():
try:
data = request.get_json()
topic = data.get('topic', '').strip()
validation_result = validate_topic(topic)
if validation_result != "Grammar":
return jsonify({"message": "Please enter a valid **grammar topic**, not a general word or unrelated question."}), 400
difficulty = data.get('difficulty', 'basic')
print(f"Generating {difficulty} questions for topic: {topic}")
if difficulty == 'basic':
prompt = f"""
Generate five **completely new and unique** very basic-level fill-in-the-blank grammar questions **every time** on the topic '{topic}'.
### Rules:
- Generate five unique fill-in-the-blank grammar questions based on the topic '{topic}'.
- Each question must have exactly one blank represented by '_______' (not two blanks or underscores inside the sentence).
- Each question must have a different theme for variety.
- Use different sentence structures; avoid predictable patterns.
- Avoid long words or abstract concepts.
- Focus on the topic '{topic}', and ensure the blank is the key part of speech.
- Each question must include the correct answer in parentheses at the end.
- Do not include any explanations or instructions—only the five questions.
"""
elif difficulty == 'intermediate':
prompt = f"""
Generate five **completely new and unique** intermediate-level fill-in-the-blank grammar questions **every time** on the topic '{topic}'.
### Rules:
- Generate five unique fill-in-the-blank grammar questions based on the topic '{topic}'.
- Each question must have exactly one blank represented by '_______'.
- Slightly more challenging than basic-level; use a wider range of sentence structures and vocabulary.
- Each question must have a different theme.
- Sentences should be longer and include more detail.
- Focus on the topic '{topic}', and ensure the blank is the key part of speech.
- Each question must include the correct answer in parentheses at the end.
- Do not include any explanations or instructions—only the five questions.
"""
elif difficulty == 'expert':
prompt = f"""
Generate five **completely new and unique** advanced-level (C1) fill-in-the-blank grammar questions **every time** on the topic '{topic}'.
### Rules:
- Generate five unique fill-in-the-blank grammar questions based on the topic '{topic}'.
- Each question must have exactly one blank represented by '_______'.
- More challenging than intermediate (C1); require expert-level mastery of grammar and context.
- Ensure varied and sophisticated vocabulary; avoid basic words.
- Each question should require nuanced comprehension; test advanced grammar patterns.
- The blank must be the key part of the sentence (not an obvious answer).
- Each question must include the correct answer in parentheses at the end.
- Do not include any explanations or instructions—only the five questions.
"""
else:
return jsonify({"error": "Invalid difficulty level"}), 400
headers = _cohere_headers()
if not headers:
return jsonify({"error": "COHERE_API_KEY not set on the server"}), 500
# (2) UPDATED: messages payload
payload = {
'model': 'command-r-08-2024',
'messages': [
{'role': 'user', 'content': prompt}
],
'max_tokens': 1000
}
response = requests.post(COHERE_API_URL, json=payload, headers=headers)
print("Response status code:", response.status_code)
print("Response content:", response.text)
if response.status_code == 200:
# (3) UPDATED: v2 parsing
text = _extract_text_v2(response.json())
# Return same style as before but adapted (text content)
return jsonify({"text": text})
else:
return jsonify({"error": "Failed to fetch questions", "details": response.text}), 500
except Exception as e:
return jsonify({"error": str(e)}), 500
@questions_bp.post('/validate-answer')
def validate_answer():
try:
data = request.get_json()
topic = data.get('topic', '')
question = data.get('question', '')
user_answer = data.get('user_answer', '')
if not question or not user_answer or not topic:
return jsonify({'error': 'Topic, question, and user answer are required'}), 400
prompt = f"""
You are a highly knowledgeable grammar assistant. Validate whether the user's answer to the following question is correct or not based on {topic}. If the answer is incorrect, provide a helpful hint.
Topic: {topic}
Question: "{question}"
User's Answer: "{user_answer}"
Is the answer correct? If not, please explain why and give a hint.
"""
headers = _cohere_headers()
if not headers:
return jsonify({"error": "COHERE_API_KEY not set on the server"}), 500
# (2) UPDATED: messages payload
payload = {
'model': 'command-r-08-2024',
'messages': [
{'role': 'user', 'content': prompt}
],
'max_tokens': 100,
'temperature': 0.7
}
response = requests.post(COHERE_API_URL, headers=headers, json=payload)
print(f"Status Code: {response.status_code}")
print(f"Response Body: {response.text}")
if response.status_code == 200:
# (3) UPDATED: v2 parsing
text = _extract_text_v2(response.json())
return jsonify({"text": text})
else:
return jsonify({'error': 'Failed to fetch data from Cohere API'}), 500
except Exception as e:
return jsonify({'error': str(e)}), 500
# Function to validate an individual answer using Cohere API
def validate_answer_with_ai(topic, question, user_answer):
try:
prompt = f"""
You are a highly knowledgeable grammar assistant. Validate whether the user's answer to the following question is correct or not based on {topic}. If the answer is incorrect, provide a helpful hint.
Topic: {topic}
Question: "{question}"
User's Answer: "{user_answer}"
Is the answer correct? If not, please explain why and give a hint.
"""
headers = _cohere_headers()
if not headers:
return "Error: COHERE_API_KEY not set"
# (2) UPDATED: messages payload
payload = {
'model': 'command-r-08-2024',
'messages': [
{'role': 'user', 'content': prompt}
],
'max_tokens': 200,
'temperature': 0.7
}
# (1) UPDATED URL used here too
response = requests.post(COHERE_API_URL, headers=headers, json=payload)
if response.status_code == 200:
# (3) UPDATED: v2 parsing
return _extract_text_v2(response.json())
else:
return f"Error: {response.status_code} - {response.text}"
except Exception as e:
return f"An error occurred: {str(e)}"
@questions_bp.post('/validate-all-answers')
def validate_all_answers():
try:
data = request.get_json()
questions = data.get('questions', [])
if not questions:
return jsonify({'error': 'No questions provided'}), 400
validation_results = []
for item in questions:
topic = item.get('topic', '')
question = item.get('question', '')
user_answer = item.get('user_answer', '')
if not topic or not question or not user_answer:
validation_results.append({
'question': question,
'error': 'Missing required fields (topic, question, or answer).'
})
continue
validation_response = validate_answer_with_ai(topic, question, user_answer)
hint = None
if isinstance(validation_response, str) and (
"incorrect" in validation_response.lower() or "not correct" in validation_response.lower()
):
hint = generate_hint(topic, question, user_answer)
validation_results.append({
'question': question,
'user_answer': user_answer,
'validation_response': validation_response,
'hint': hint
})
return jsonify({'results': validation_results})
except Exception as e:
return jsonify({'error': str(e)}), 500
def generate_hint(topic, question, user_answer):
try:
prompt = f"""
You are a highly skilled grammar assistant. Your task is to generate a helpful hint for the user to improve their answer based on the following question.
Topic: {topic}
Question: "{question}"
User's Answer: "{user_answer}"
If the user's answer is incorrect, provide a specific, actionable hint to help the user correct their answer.
The hint should include:
- Explanation of the error made by the user.
- A hint on the correct grammatical structure or word form.
- A hint on how to structure the sentence correctly **without revealing the exact answer**.
Please make sure the hint is **clear** and **helpful** for the user, **without revealing the correct answer**.
"""
headers = _cohere_headers()
if not headers:
return "Error: COHERE_API_KEY not set"
# (2) UPDATED: messages payload
payload = {
'model': 'command-r-08-2024',
'messages': [
{'role': 'user', 'content': prompt}
],
'max_tokens': 250,
'temperature': 0.7
}
response = requests.post(COHERE_API_URL, headers=headers, json=payload)
if response.status_code == 200:
# (3) UPDATED: v2 parsing
return _extract_text_v2(response.json())
else:
return f"Error: {response.status_code} - {response.text}"
except Exception as e:
return f"An error occurred: {str(e)}"
if __name__ == '__main__':
app.register_blueprint(questions_bp, url_prefix='') # local exposure
app.run(host='0.0.0.0', port=5012, debug=True)
|