File size: 9,614 Bytes
f5fe108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43c3b55
 
f5fe108
 
 
 
 
 
43c3b55
 
 
 
 
 
 
 
 
 
 
 
 
f5fe108
 
 
 
 
 
43c3b55
 
 
 
 
 
 
 
 
f5fe108
 
 
 
43c3b55
 
f5fe108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43c3b55
f5fe108
 
43c3b55
 
 
 
f5fe108
 
 
 
 
43c3b55
 
f5fe108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43c3b55
f5fe108
43c3b55
 
 
 
 
f5fe108
43c3b55
 
 
f5fe108
 
 
 
 
 
 
43c3b55
f5fe108
 
43c3b55
 
 
 
 
f5fe108
 
 
 
 
43c3b55
 
 
 
 
f5fe108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43c3b55
f5fe108
 
43c3b55
 
 
 
f5fe108
 
 
 
43c3b55
 
 
 
 
f5fe108
 
 
 
 
 
 
 
 
 
 
 
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
from flask import Flask, jsonify, send_file, abort, make_response, request, Blueprint, 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 
import tempfile  # needed by validate-pronounce

app = Flask(__name__)
CORS(app)

# 👇 Add the helper right here
def _cohere_headers():
    api_key = current_app.config.get("COHERE_API_KEY") or COHERE_API_KEY
    return {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    }
    
@app.route('/')
def home():
    return "Welcome to the Flask app! The server is running."

# API configuration for AI-based question generation
COHERE_API_KEY = os.getenv("COHERE_API_KEY", "")
# (1) UPDATED URL: v2 endpoint on api.cohere.com
COHERE_API_URL = 'https://api.cohere.com/v2/chat'

# Dictionary to store user conversations
user_sessions = {}
# Endpoint to explain grammar topics
movie_bp = Blueprint("movie", __name__)

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 _cohere_generate(prompt: str, max_tokens: int = 1000, temperature: float = 0.7):
    api_key = current_app.config.get("COHERE_API_KEY") or COHERE_API_KEY
    if not api_key:
        return None, ("COHERE_API_KEY not set on the server", 500)

    headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
    # (2) UPDATED PAYLOAD: use messages instead of prompt
    payload = {
        "model": "command-r-08-2024",
        "messages": [
            {"role": "user", "content": prompt}
        ],
        "max_tokens": max_tokens,
        "temperature": temperature
    }
    try:
        r = requests.post(COHERE_API_URL, headers=headers, json=payload, timeout=30)
        if r.status_code != 200:
            return None, (f"Cohere API error: {r.text}", 502)
        # (3) UPDATED PARSING: read message.content[0].text
        text = _extract_text_v2(r.json())
        return text, None
    except Exception as e:
        current_app.logger.exception("Cohere request failed: %s", e)
        return None, ("Upstream request failed", 502)

@movie_bp.post("/explain-grammar")
def explain_grammar():
    try:
        data = request.get_json()
        print("Received Data:", data) 
        topic = data.get('topic', '').strip()
        session_id = data.get('session_id', str(uuid.uuid4()))  # Use provided session_id or create a new one

        if not topic:
            return jsonify({'error': 'Topic is required'}), 400

        # Retrieve previous conversation history
        conversation_history = user_sessions.get(session_id, [])

        # Keep the last 10 messages to maintain better context (adjustable)
        if len(conversation_history) > 10:
            conversation_history = conversation_history[-10:]

        # Generate a more **adaptive** prompt
        context = "\n".join(conversation_history) if conversation_history else ""

        prompt = f"""
        You are a highly skilled grammar assistant. Your job is to maintain a **dynamic conversation** and respond intelligently based on user input, If the user asks something **unrelated to grammar**, respond with: "Please send a grammar-related question..

        - Your answers must always **relate to the conversation history** and **extend naturally** based on what was previously asked.
        - Your answers must be **concise, clear, and to the point**
        - If the user asks for **examples**, explanations, or clarifications, **automatically infer** which topic they are referring to.
        - If the user's question is **vague**, determine the most **logical continuation** based on prior questions.
        - If the user asks something **unrelated to grammar**, respond with: "Please send a grammar-related question."

        **Conversation so far:**
        {context}

        **User's new question:** {topic}
        Please provide a **coherent and relevant answer** that continues the conversation naturally.
        """

        # Make the API call to Cohere
        headers = {
            'Authorization': f'Bearer {COHERE_API_KEY}',
            'Content-Type': 'application/json'
        }

        # (2) UPDATED PAYLOAD: messages array
        payload = {
            'model': 'command-r-08-2024',
            'messages': [
                {'role': 'user', 'content': prompt}
            ],
            'max_tokens': 1000
        }

        response = requests.post(COHERE_API_URL, headers=headers, json=payload)

        if response.status_code == 200:
            # (3) UPDATED PARSING
            ai_response = _extract_text_v2(response.json())

            # Store conversation history to maintain context
            conversation_history.append(f"User: {topic}\nAI: {ai_response}")
            user_sessions[session_id] = conversation_history  # Update session history

            return jsonify({'response': ai_response, 'session_id': session_id})
        else:
            return jsonify({'error': 'Failed to fetch data from Cohere API'}), 500

    except Exception as e:
        return jsonify({'error': str(e)}), 500



@app.route('/suggest-grammar-questions', methods=['POST'])
def suggest_grammar_questions():
    try:
        data = request.get_json()
        user_input = data.get('input', '').strip()  # User's partial input (e.g., "What is v")

        if not user_input:
            return jsonify({'error': 'Input is required'}), 400

        prompt = f"""
            You are a grammar expert. Given the user's input "{user_input}", generate **3 natural grammar-related questions** that people might ask.

            - The user's input is a **partial or full grammar-related query**.
            - AI must **infer the most likely grammar topic** based on the input.
            - AI must **ensure all suggestions are strictly related to English grammar**.
            - **If the input is incomplete, intelligently complete it** with the most likely grammar concept.
            - Ensure all **questions are fully formed and relevant**.

            **User input:** "{user_input}"
            Provide exactly 3 well-structured, grammar-related questions:
            """

        # Call Cohere API
        headers = {
            'Authorization': f'Bearer {COHERE_API_KEY}',
            'Content-Type': 'application/json'
        }

        # (2) UPDATED PAYLOAD: messages array
        payload = {
            'model': 'command-r-08-2024',
            'messages': [
                {'role': 'user', 'content': prompt}
            ],
            'max_tokens': 100,
            'temperature': 0.9
        }

        response = requests.post(COHERE_API_URL, headers=headers, json=payload)

        if response.status_code == 200:
            # (3) UPDATED PARSING
            text = _extract_text_v2(response.json())
            suggestions = [s for s in (text or "").split("\n") if s.strip()]
            return jsonify({'suggestions': suggestions[:3]})
            # keep exactly 3 if more lines present
        else:
            return jsonify({'error': 'Failed to fetch suggestions', 'details': response.text}), 500

    except Exception as e:
        return jsonify({'error': str(e)}), 500


def validate_topic(topic):
    validation_prompt = f"""
    You are an AI grammar expert. Your task is to determine if a given topic is related to **English grammar** or not.

    **Input:** "{topic}"

    ### **Rules:**
    - If the input is **in the form of a question** (e.g., it asks for an explanation or definition), return `"ask grammar topics"`, even if the topic is related to grammar.
    - If the topic is **related to English grammar concepts** such as **parts of speech**, **verb tenses**, **sentence structure**, etc., return `"Grammar"`.
    - If the topic is **not related to grammar**, such as general knowledge, science, math, history, or topics from other fields, return `"Not Grammar"`.
    - Your response must be based purely on whether the topic relates to grammar, and **not** based on specific words, phrases, or examples.

    **Your response must be exactly either "Grammar", "Not Grammar", or "ask grammar topics". No extra text.**
    """

    headers = {
        'Authorization': f'Bearer {COHERE_API_KEY}',
        'Content-Type': 'application/json'
    }

    # (2) UPDATED PAYLOAD: messages array
    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 PARSING
        validation_result = _extract_text_v2(response.json())

        # Ensure the response is strictly "Grammar" or "Not Grammar" or "ask grammar topics"
        if validation_result not in ["Grammar", "Not Grammar", "ask grammar topics"]:
            return "Not Grammar"  # Fallback to avoid incorrect responses

        return validation_result

    except Exception as e:
        return f"Error: {str(e)}"


if __name__ == '__main__':
    # app.run(debug=True)
    app.register_blueprint(movie_bp, url_prefix='')  # expose /explain-grammar locally
    app.run(host='0.0.0.0', port=5012, debug=True)