Skip to content

Commit

Permalink
add file monitoring with marshmallow/swagger
Browse files Browse the repository at this point in the history
  • Loading branch information
RogerioLS committed Sep 4, 2024
1 parent 9aeafb4 commit cfba88e
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -1,49 +1,84 @@
from flask import Flask, request, jsonify, render_template
from flask import Flask, request, jsonify, render_template, send_from_directory
import pickle
import pandas as pd
from marshmallow import Schema, fields, ValidationError
from flask_swagger_ui import get_swaggerui_blueprint
from flask_wtf.csrf import CSRFProtect
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

app = Flask(__name__)

# Configuração da proteção CSRF
csrf = CSRFProtect(app)

# Configuração de rate limiting
limiter = Limiter(
get_remote_address,
app=app,
default_limits=["200 per day", "50 per hour"]
)

# Swagger setup http://localhost:5000/swagger
SWAGGER_URL = '/swagger'
API_URL = '/static_swagger/swagger.json'
swaggerui_blueprint = get_swaggerui_blueprint(SWAGGER_URL, API_URL, config={'app_name': "Real Estate Price Prediction API"})
app.register_blueprint(swaggerui_blueprint, url_prefix=SWAGGER_URL)

# Adicionar uma rota para servir o arquivo swagger.json
@app.route('/static_swagger/<path:filename>')
def serve_static(filename):
return send_from_directory('static_swagger', filename)

# Carregar o modelo treinado
model = pickle.load(open('../model_trained/model_regression_immobile.pkl', 'rb'))

# Carregar a base de dados
#data = pd.read_csv('../data/arquivo.csv')
# Definição do schema de validação usando marshmallow
class InputSchema(Schema):
MedInc = fields.Float(required=True)
HouseAge = fields.Float(required=True)
AveRooms = fields.Float(required=True)
AveBedrms = fields.Float(required=True)
Population = fields.Int(required=True)
AveOccup = fields.Float(required=True)
RoomDensity = fields.Float(required=True)
Latitude = fields.Float(required=True)
Longitude = fields.Float(required=True)

@app.route('/')
def index():
return render_template('index.html')

@app.route('/predict', methods=['POST'])
@limiter.limit("10 per minute") # Limite de 10 requisições por minuto para este endpoint
@csrf.exempt # Exemplo: desabilitar CSRF para a rota de API (opcional, com cuidado)
def predict():
# Receber dados do cliente
req_data = request.get_json()

# Verificar se todos os campos necessários estão presentes
required_fields = ['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup', 'Latitude', 'Longitude']
if not all(field in req_data for field in required_fields):
return jsonify({'error': 'Missing required fields'}), 400

# Criar DataFrame a partir dos dados recebidos
input_data = {
'MedInc': req_data['MedInc'],
'HouseAge': req_data['HouseAge'],
'AveRooms': req_data['AveRooms'],
'AveBedrms': req_data['AveBedrms'],
'Population': req_data['Population'],
'AveOccup': req_data['AveOccup'],
'Latitude': req_data['Latitude'],
'Longitude': req_data['Longitude']
}

input_df = pd.DataFrame([input_data])

try:
# Receber dados do cliente
req_data = request.get_json()

# Validar entrada
schema = InputSchema()
validated_data = schema.load(req_data)

# Criar DataFrame a partir dos dados validados
input_df = pd.DataFrame([validated_data])

# Prever usando o modelo carregado
prediction = model.predict(input_df)
return jsonify({'prediction': prediction[0]})
except ValidationError as err:
# Erros de validação do input
return jsonify({'error': 'Validation Error', 'messages': err.messages}), 400
except KeyError as err:
# Se algum campo esperado não estiver presente
return jsonify({'error': f'Missing required field: {err}'}), 400
except ValueError as err:
# Erros relacionados ao valor dos dados de entrada
return jsonify({'error': f'Invalid input: {err}'}), 400
except Exception as e:
return jsonify({'error': str(e)}), 400
# Erro geral
return jsonify({'error': 'An error occurred', 'message': str(e)}), 500

if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)
app.run(host='0.0.0.0', port=5000)
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
"swagger": "2.0",
"info": {
"description": "API para prever preços de imóveis",
"version": "1.0.0",
"title": "Real Estate Price Prediction API"
},
"host": "localhost:5000",
"basePath": "/",
"schemes": [
"http"
],
"paths": {
"/predict": {
"post": {
"tags": ["prediction"],
"summary": "Obter previsão de preço",
"description": "Envia dados de entrada e obtém a previsão de preço do imóvel.",
"consumes": ["application/json"],
"produces": ["application/json"],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Dados de entrada",
"required": true,
"schema": {
"$ref": "#/definitions/InputData"
}
}
],
"responses": {
"200": {
"description": "Previsão obtida com sucesso",
"schema": {
"type": "object",
"properties": {
"prediction": {
"type": "number",
"example": 150000.0
}
}
}
},
"400": {
"description": "Erro de validação de entrada"
},
"500": {
"description": "Erro interno do servidor"
}
}
}
}
},
"definitions": {
"InputData": {
"type": "object",
"required": [
"MedInc",
"HouseAge",
"AveRooms",
"AveBedrms",
"Population",
"AveOccup",
"RoomDensity",
"Latitude",
"Longitude"
],
"properties": {
"MedInc": {"type": "number", "example": 8.3252},
"HouseAge": {"type": "number", "example": 41.0},
"AveRooms": {"type": "number", "example": 6.9841},
"AveBedrms": {"type": "number", "example": 1.0238},
"Population": {"type": "integer", "example": 322},
"AveOccup": {"type": "number", "example": 2.5556},
"Latitude": {"type": "number", "example": 37.88},
"Longitude": {"type": "number", "example": -122.23},
"RoomDensity": {"type": "number", "example": -122.23}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,31 @@
<h1>Real Estate Price Prediction</h1>
<form id="prediction-form">
<label for="MedInc">Median Income:</label>
<input type="number" id="MedInc" name="MedInc" step="0.1" required><br>
<input type="number" id="MedInc" name="MedInc" step="0.1" value="3.5" required><br>

<label for="HouseAge">House Age:</label>
<input type="number" id="HouseAge" name="HouseAge" required><br>
<input type="number" id="HouseAge" name="HouseAge" value="20" required><br>

<label for="AveRooms">Average Rooms:</label>
<input type="number" id="AveRooms" name="AveRooms" step="0.1" required><br>
<input type="number" id="AveRooms" name="AveRooms" step="0.1" value="5.0" required><br>

<label for="AveBedrms">Average Bedrooms:</label>
<input type="number" id="AveBedrms" name="AveBedrms" step="0.1" required><br>
<input type="number" id="AveBedrms" name="AveBedrms" step="0.1" value="1.0" required><br>

<label for="Population">Population:</label>
<input type="number" id="Population" name="Population" required><br>
<input type="number" id="Population" name="Population" value="5000" required><br>

<label for="AveOccup">Average Occupancy:</label>
<input type="number" id="AveOccup" name="AveOccup" step="0.1" required><br>

<input type="number" id="AveOccup" name="AveOccup" step="0.1" value="2.5" required><br>

<label for="RoomDensity">Room Density:</label>
<input type="number" id="RoomDensity" name="RoomDensity" step="0.1" value="0.1" required><br>

<label for="Latitude">Latitude:</label>
<input type="number" id="Latitude" name="Latitude" step="0.1" required><br>
<input type="number" id="Latitude" name="Latitude" step="0.1" value="34.0" required><br>

<label for="Longitude">Longitude:</label>
<input type="number" id="Longitude" name="Longitude" step="0.1" required><br>
<input type="number" id="Longitude" name="Longitude" step="0.1" value="-118.0" required><br>

<button type="button" onclick="predict()">Predict</button>
</form>
Expand All @@ -41,17 +44,37 @@ <h1>Real Estate Price Prediction</h1>
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());

const response = await fetch('/predict', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
// Convert data to appropriate types
data.MedInc = parseFloat(data.MedInc);
data.HouseAge = parseInt(data.HouseAge);
data.AveRooms = parseFloat(data.AveRooms);
data.AveBedrms = parseFloat(data.AveBedrms);
data.Population = parseInt(data.Population);
data.AveOccup = parseFloat(data.AveOccup);
data.RoomDensity = parseFloat(data.RoomDensity);
data.Latitude = parseFloat(data.Latitude);
data.Longitude = parseFloat(data.Longitude);

try {
const response = await fetch('/predict', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});

const result = await response.json();

const result = await response.json();
document.getElementById('result').innerText = `Prediction: ${result.prediction}`;
if (response.ok) {
document.getElementById('result').innerText = `Prediction: ${result.prediction}`;
} else {
document.getElementById('result').innerText = `Error: ${result.error}`;
}
} catch (error) {
document.getElementById('result').innerText = `Error: ${error.message}`;
}
}
</script>
</body>
</html>
</html>

0 comments on commit cfba88e

Please sign in to comment.