Coverage for app/routes/suggestions.py: 60%
96 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-05-02 02:49 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-05-02 02:49 +0000
1from flask import Blueprint, request
2from app.services.suggestion_service import getAvailableModels, getSuggestion, generate_hint_from_gemini, generate_explanation_from_gemini, check_code_correctness, get_suggestion_by_id, generate_refined_prompt
3from app.models.response import *
4from app.models.status_codes import StatusCodes
5from flasgger import swag_from
7suggestions_bp = Blueprint('suggestions', __name__)
9@suggestions_bp.route('/suggestion', methods=['POST'])
10@swag_from({
11 'tags': ['Suggestions'],
12 'summary': 'Generate a suggestion using the AI model',
13 'description': 'Sends a prompt to the locally running Ollama model with an optional model name and correctness flag, returning the generated suggestion.',
14 'consumes': ['application/json'],
15 'produces': ['application/json'],
16 'parameters': [
17 {
18 'name': 'body',
19 'in': 'body',
20 'required': True,
21 'schema': {
22 'type': 'object',
23 'properties': {
24 'prompt': {
25 'type': 'string',
26 'example': 'def add(a, b):'
27 },
28 'vendor': {
29 'type': 'string',
30 'example': "ollama"
31 },
32 'model': {
33 'type': 'string',
34 'example': 'codellama:7b',
35 'description': 'The AI model to use for generating the suggestion.'
36 },
37 'parameters': {
38 'type': 'object',
39 'example': {
40 "top_k": 0.2
41 },
42 'description': 'A flag indicating whether the suggestion should be correct.'
43 }
44 },
45 'required': ['prompt']
46 }
47 }
48 ],
49 'responses': {
50 '200': {
51 'description': 'Successfully generated suggestion',
52 'schema': {
53 'type': 'object',
54 'properties': {
55 'suggestions': {
56 'type': 'array',
57 'items': {'type': 'string'},
58 'example': ["return a + b"]
59 }
60 }
61 }
62 },
63 '400': {
64 'description': 'Bad Request - No prompt provided',
65 'schema': {
66 'type': 'object',
67 'properties': {
68 'error': {'type': 'string', 'example': 'No prompt provided'}
69 }
70 }
71 },
72 '500': {
73 'description': 'Internal Server Error - Failed to generate response',
74 'schema': {
75 'type': 'object',
76 'properties': {
77 'error': {'type': 'string', 'example': 'Connection error'}
78 }
79 }
80 }
81 }
82})
83def generate_suggestion_route():
84 """
85 Generate a suggestion based on the provided prompt.
86 See Swagger docs for more information.
87 """
88 data = request.json
89 prompt = data.get("prompt", "")
90 vendor_name = data.get("vendor")
91 model_name = data.get("model")
92 model_params = data.get("parameters")
94 if not prompt:
95 return error_response(
96 "No prompt provided",
97 None,
98 StatusCodes.BAD_REQUEST
99 )
101 try:
102 # Call getSuggestion with all parameters, it will decide which model to use
103 response = getSuggestion(
104 prompt=prompt,
105 vendor=vendor_name,
106 model_name=model_name,
107 )
109 print(f"Response from model: {response}")
111 return success_response(
112 "AI Suggestions",
113 {"response": response if isinstance(response, list) else []},
114 StatusCodes.OK
115 )
117 except Exception as e:
118 print(e)
119 return error_response(
120 str(e),
121 None,
122 StatusCodes.SERVER_ERROR
123 )
125@suggestions_bp.route('/suggestion/refine', methods=['POST'])
126def refine_prompt():
127 """
128 Generate a refined prompt for code completion.
129 """
130 data = request.json
131 raw_prompt = data.get("rawPrompt", "")
133 if not raw_prompt:
134 return error_response(
135 "Missing required field: rawPrompt",
136 None,
137 StatusCodes.BAD_REQUEST
138 )
140 try:
141 refined = generate_refined_prompt(raw_prompt)
143 print(f"Refined prompt: {refined}")
145 return success_response(
146 "Prompt refined",
147 {"refinedPrompt": refined},
148 StatusCodes.OK
149 )
151 except Exception as e:
152 return error_response(
153 str(e),
154 None,
155 StatusCodes.SERVER_ERROR
156 )
158@suggestions_bp.route('/suggestion/hint', methods=['POST'])
159def generate_hint():
160 """
161 Generate a hint explaining the difference between code versions.
162 """
163 data = request.json
164 prompt = data.get("prompt", "")
165 wrong_code = data.get("wrongCode", "")
166 right_code = data.get("rightCode", "")
168 if not all([prompt, wrong_code, right_code]):
169 return error_response(
170 "Missing required fields (prompt, wrongCode, rightCode)",
171 None,
172 StatusCodes.BAD_REQUEST
173 )
175 try:
176 hint = generate_hint_from_gemini(prompt, wrong_code, right_code)
178 return success_response(
179 "Hint generated",
180 {"hint": hint},
181 StatusCodes.OK
182 )
184 except Exception as e:
185 return error_response(
186 str(e),
187 None,
188 StatusCodes.SERVER_ERROR
189 )
191@suggestions_bp.route('/suggestion/explanation', methods=['POST'])
192def generate_explanation():
193 """
194 Generate a explanation telling the user what is wrong with the 'bad code'.
195 """
196 data = request.json
197 prompt = data.get("prompt", "")
198 wrong_code = data.get("wrongCode", "")
199 right_code = data.get("rightCode", "")
201 if not all([prompt, wrong_code, right_code]):
202 return error_response(
203 "Missing required fields (prompt, wrongCode, rightCode)",
204 None,
205 StatusCodes.BAD_REQUEST
206 )
208 try:
209 explanation = generate_explanation_from_gemini(prompt, wrong_code, right_code)
211 return success_response(
212 "Explanation generated",
213 {"explanation": explanation},
214 StatusCodes.OK
215 )
217 except Exception as e:
218 return error_response(
219 str(e),
220 None,
221 StatusCodes.SERVER_ERROR
222 )
224@suggestions_bp.route('/suggestion/answer', methods=['POST'])
225def validate_fix():
226 """
227 Validate the user's fixed code using an AI model.
228 """
229 data = request.json
230 prompt = data.get("prompt", "")
231 wrong_code = data.get("wrongCode", "")
232 fixed_code = data.get("fixedCode", "")
234 if not all([prompt, wrong_code, fixed_code]):
235 return error_response(
236 "Missing required fields (prompt, wrongCode, fixedCode)",
237 None,
238 StatusCodes.BAD_REQUEST
239 )
241 try:
242 is_correct = check_code_correctness(prompt, wrong_code, fixed_code)
244 print(f"Is the fixed code correct? {is_correct}")
246 return success_response(
247 "Code validation result",
248 {"isCorrect": is_correct},
249 StatusCodes.OK
250 )
252 except Exception as e:
253 return error_response(
254 str(e),
255 None,
256 StatusCodes.SERVER_ERROR
257 )
260@suggestions_bp.route('/models', methods=['GET'])
261@swag_from({
262 'tags': ['Suggestions'],
263 'summary': 'Get all models available from a vendor',
264 'description': 'Lists all models available from the selected vendor',
265 'produces': ['application/json'],
266 'parameters': [
267 {
268 'name': 'vendor',
269 'in': 'query', # Change from 'body' to 'query'
270 'required': True,
271 'type': 'string',
272 'example': "openai",
273 }
274 ],
275 'responses': {
276 '200': {
277 'description': 'List of models from the vendor',
278 'schema': {
279 'type': 'object',
280 'properties': {
281 'models': {
282 'type': 'array',
283 'items': {'type': 'string'}
284 }
285 }
286 }
287 },
288 '400': {
289 'description': 'Bad Request, missing vendor',
290 },
291 '500': {
292 'description': 'Internal server error',
293 }
294 }
295})
296def list_models_route():
297 vendor = request.args.get('vendor') # Get vendor from query string
299 if not vendor:
300 return error_response(
301 "Vendor not included in request",
302 None,
303 StatusCodes.BAD_REQUEST
304 )
306 try:
307 models = getAvailableModels(vendor) # Pass vendor to function
308 return success_response(
309 "Models List",
310 {"models": models}
311 )
313 except Exception as e:
314 return error_response(
315 str(e),
316 None,
317 StatusCodes.SERVER_ERROR
318 )
320@suggestions_bp.route('/suggestion/<suggestion_id>', methods=['GET'])
321@swag_from({
322 'tags': ['Suggestions'],
323 'summary': 'Get a suggestion by ID',
324 'description': 'Retrieves a specific suggestion using its unique identifier.',
325 'parameters': [
326 {
327 'name': 'suggestion_id',
328 'in': 'path',
329 'required': True,
330 'type': 'string',
331 'example': 'abc123'
332 }
333 ],
334 'responses': {
335 '200': {
336 'description': 'Suggestion retrieved successfully',
337 'schema': {
338 'type': 'object',
339 'properties': {
340 'id': {'type': 'string'},
341 'prompt': {'type': 'string'},
342 'suggestion': {'type': 'string'},
343 'user_id': {'type': 'string'},
344 'created_at': {'type': 'string', 'format': 'date-time'},
345 # Add other fields if needed
346 }
347 }
348 },
349 '404': {
350 'description': 'Suggestion not found',
351 'schema': {
352 'type': 'object',
353 'properties': {
354 'error': {'type': 'string'}
355 }
356 }
357 }
358 }
359})
360def get_suggestion_details(suggestion_id):
361 try:
362 suggestion = get_suggestion_by_id(suggestion_id)
364 if not suggestion:
365 return error_response(
366 f"No suggestion found for id {suggestion_id}",
367 None,
368 StatusCodes.NOT_FOUND
369 )
371 return success_response(
372 f"Suggestion retrieved for id {suggestion_id}",
373 suggestion.to_json(),
374 StatusCodes.OK
375 )
377 except Exception as e:
378 return error_response(
379 f"Error fetching suggestion {suggestion_id}: {e}",
380 None,
381 StatusCodes.SERVER_ERROR
382 )