From 691c91c4b5f17e5a3fc824d76a5b6cdec6b7ca6c Mon Sep 17 00:00:00 2001 From: dw927 <dw927@drexel.edu> Date: Sun, 26 Feb 2023 21:19:50 +0000 Subject: [PATCH] Removed test hardcoding from images. Images are now populated from api... --- diagnosis_service/svc/database_connection.py | 18 +++ diagnosis_service/svc/run.py | 18 +-- front_end/dpath.py | 30 +++-- front_end/static/js/popup.js | 40 +++++++ front_end/static/styles/style.css | 109 ++++++++++++++++++ front_end/templates/home.html | 11 +- front_end/templates/includes/imageList.html | 12 ++ front_end/templates/includes/imagePopup.html | 3 + front_end/templates/includes/navbar.html | 4 +- .../templates/includes/reportDetail.html | 60 +++++----- front_end/templates/includes/reports.html | 16 +-- front_end/templates/includes/scriptsload.html | 1 + front_end/templates/reportDetail.html | 10 +- front_end/templates/reports.html | 2 +- upload_service/app.py | 33 ++++-- upload_service/diagnosis_provider.py | 40 +++++++ 16 files changed, 335 insertions(+), 72 deletions(-) create mode 100644 front_end/static/js/popup.js create mode 100644 front_end/templates/includes/imageList.html create mode 100644 front_end/templates/includes/imagePopup.html create mode 100644 front_end/templates/includes/scriptsload.html create mode 100644 upload_service/diagnosis_provider.py diff --git a/diagnosis_service/svc/database_connection.py b/diagnosis_service/svc/database_connection.py index 4b64b94..d35f338 100644 --- a/diagnosis_service/svc/database_connection.py +++ b/diagnosis_service/svc/database_connection.py @@ -143,3 +143,21 @@ class DigpathDatabase: } return results + + def get_requests(self): + cursor = self._db.cursor().execute('SELECT * FROM requests') + results = [] + for i in cursor.fetchall(): + item = { + 'request_id': i[0], + 'file': i[1], + 'diagnosis': i[2], + 'total_chips': i[3], + 'mild': i[4], + 'moderate': i[5], + 'severe': i[6], + 'status': i[7], + 'timestamp': i[8] + } + results.append(item) + return results diff --git a/diagnosis_service/svc/run.py b/diagnosis_service/svc/run.py index af895e4..6c9a168 100644 --- a/diagnosis_service/svc/run.py +++ b/diagnosis_service/svc/run.py @@ -2,7 +2,6 @@ import json import uuid import boto3 -import mysql.connector from flask import Flask, request, jsonify from database_connection import DigpathDatabase @@ -40,7 +39,7 @@ def get_slice_percentage(slice_num): return start, stop -@app.route('/diagnose') +@app.route('/diagnose', methods=['POST']) def diagnoseEndpoint(): request_id = str(uuid.uuid4()) @@ -73,14 +72,15 @@ def diagnoseEndpoint(): } return jsonify(response) -@app.route('/request_info') -def getDiagnosisEndpoint(): - - content = request.json - print(f"Getting info for: {content}") +@app.route('/request_info/<string:request_id>') +def getDiagnosisEndpoint(request_id): + request_info = DIGPATH_DB.get_request_info(request_id) + return jsonify(request_info) - request_info = DIGPATH_DB.get_request_info(content['request_id']) +@app.route('/request_info') +def getDiagnoses(): + request_info = DIGPATH_DB.get_requests() return jsonify(request_info) if __name__ == '__main__': - app.run(host='0.0.0.0') + app.run(host='0.0.0.0', debug=True) diff --git a/front_end/dpath.py b/front_end/dpath.py index d3957ea..86907dd 100644 --- a/front_end/dpath.py +++ b/front_end/dpath.py @@ -1,4 +1,4 @@ -from flask import Flask, render_template, url_for, flash, redirect, request +from flask import Flask, render_template, url_for, flash, redirect, request, send_file import requests from werkzeug.utils import secure_filename @@ -6,7 +6,7 @@ from werkzeug.utils import secure_filename app = Flask(__name__) UPLOAD_FOLDER = 'static/uploads/' -REPORTS_SERVICE_URL = 'http://127.0.0.1:5000' +REPORTS_SERVICE_URL = 'http://127.0.0.1:5001' app.secret_key = "secret key" app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER @@ -16,10 +16,6 @@ ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif', 'tif']) BASE_URL = 'dpath' -def allowed_file(filename): - return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS - - @app.route(f'/{BASE_URL}/') def home(): return render_template('home.html') @@ -34,13 +30,14 @@ def term2(): @app.route(f'/{BASE_URL}/reports') def reports(): reports = requests.get(f'{REPORTS_SERVICE_URL}/dpath/report').json() + print(reports) return render_template('reports.html', reports=reports) @app.route(f'/{BASE_URL}/reports/<string:report_id>') def get_report(report_id): report = requests.get(f'{REPORTS_SERVICE_URL}/dpath/report/{report_id}').json() - return render_template('reportDetail.html', report=report) - + images = requests.get(f'{REPORTS_SERVICE_URL}/dpath/report/{report_id}/images').json() + return render_template('reportDetail.html', report=report, images=images, image_name=image_name, upload_service_url=upload_service_url) @app.route('/', methods=['GET', "POST"]) def upload_image(): @@ -54,17 +51,28 @@ def upload_image(): if file and allowed_file(file.filename): filename = secure_filename(file.filename) report = post_file(request) - return render_template('reportDetail.html', report=report) + return get_report(report['request_id']) else: flash('Allowed image types are - png, jpg, jpeg, gif, tif') return redirect(request.url) - @app.route('/display/<filename>') def display_image(filename): return redirect(url_for('static', filename='uploads/' + filename), code=301) +def allowed_file(filename): + return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS + + def post_file(request) : response = requests.post(f'{REPORTS_SERVICE_URL}/{BASE_URL}/report/image', files=request.files).json() - return response \ No newline at end of file + return response + +def image_name(image_url) : + image_name = image_url.split('/')[-1] + return image_name + +def upload_service_url(image_url) : + return image_url.replace('..', REPORTS_SERVICE_URL) + \ No newline at end of file diff --git a/front_end/static/js/popup.js b/front_end/static/js/popup.js new file mode 100644 index 0000000..a372452 --- /dev/null +++ b/front_end/static/js/popup.js @@ -0,0 +1,40 @@ +function showImage(imageUrl) { + dialog = document.getElementById("imageDialog"); + image = createImage(imageUrl); + dialog.appendChild(image); + buttonWrapper = document.createElement("div"); + buttonWrapper.classList.add('dialog-button-wrapper'); + buttonWrapper.appendChild(createCloseButton()); + buttonWrapper.appendChild(createNewTabLink(imageUrl)); + dialog.appendChild(buttonWrapper); + dialog.showModal(); +} + +function createImage(imageUrl) { + image = document.createElement('img'); + image.src = imageUrl; + return image +} + +function createCloseButton() { + closeButton = document.createElement('button'); + closeButton.classList.add("dialog-button"); + closeButton.onclick = function() { + dialog.close(); + while (dialog.hasChildNodes()) { + dialog.removeChild(dialog.firstChild); + } + } + closeButton.textContent = 'Close'; + return closeButton; +} + +function createNewTabLink(imageUrl) { + button = document.createElement('button'); + button.onclick = function() { + window.open(imageUrl); + } + button.textContent = 'View in New Tab'; + button.classList.add('dialog-button'); + return button; +} \ No newline at end of file diff --git a/front_end/static/styles/style.css b/front_end/static/styles/style.css index 5bc2f3b..0dbd5e3 100644 --- a/front_end/static/styles/style.css +++ b/front_end/static/styles/style.css @@ -1,10 +1,42 @@ body { width: 100%; + background-color: #FAF9F6; +} + +title { + display: block; +} + +.title-wrapper { + width: 100%; + text-align: center; + display:block; } .container { width: 100%; text-align: center; + margin-top: 20px; + display: flex; +} + +.nav-link { + color: white; + font-weight: bold; +} + +.navbar-brand { + color: white; + font-weight: bold; +} + +.bg-primary { + color: white; +} + +.navbar { + background-color: #e3f2fd; + padding-left: 10px; } .report-table { @@ -17,10 +49,15 @@ th { background-color: lightskyblue; } +tr { + transition-duration: .2s; +} + tr:hover { background-color: lightgray; } + td { padding-left: 5px; padding-right: 5px; @@ -32,4 +69,76 @@ td { .right { text-align: right; +} + +.table-link { + text-decoration: none; +} + +#imageDisplay { + width: 100%; + height: 100%; + position: absolute; + background-color: blue; + text-align: center; + top: 0; +} + +img { + max-width: 100%; + max-height: 100%; +} + +.hidden { + display: none; +} + +.dialog-button { + border: 2px solid white; + border-color: white; + border-radius: 15px; + box-shadow: none; + background-color: #0d6efd; + color: white; + font-weight: bold; + padding: 10px; +} + +.dialog-button-wrapper { + width: 100%; + margin-top: 20px; + display: flex; + text-align: center; +} + +dialog { + text-align: center; + margin-left: auto; + margin-right: auto; + border-radius: 15px; + border-color: lightgray; +} + +.left-panel { + width: 40%; +} + +.right-panel { + width: 60%; +} + +.image-table { + margin-left: 30px; +} + +.report-detail-table { + width: 100%; +} + +.detail-left { + width: 30%; +} + +.detail-right { + width: 70%; } \ No newline at end of file diff --git a/front_end/templates/home.html b/front_end/templates/home.html index e40bed6..3c1259c 100644 --- a/front_end/templates/home.html +++ b/front_end/templates/home.html @@ -1,14 +1,16 @@ <!doctype html> <html lang="en"> -<center> + <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Slide Analyzer</title> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous"> + {% include 'includes/stylesload.html' %} </head> +<center> <body> {% include 'includes/navbar.html' %} + <div class=""> <h1>Welcome to the Digital Pathology Slide Analyzer.</h1> <br> <h2>Please select a file to upload.</h2> @@ -32,7 +34,7 @@ <button type="submit" class="btn btn-primary">Submit</button> </div> </form> - <br> + <!-- <br> <h2> Sample id: c1471950-71a5-11ed-9ddb-1267f16e00ed </h2> @@ -46,8 +48,9 @@ Chip Predictions: Mild: 806 Severe: 846 - </h2> + </h2> --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script> + </div> </body> </center> </html> \ No newline at end of file diff --git a/front_end/templates/includes/imageList.html b/front_end/templates/includes/imageList.html new file mode 100644 index 0000000..0f5dac2 --- /dev/null +++ b/front_end/templates/includes/imageList.html @@ -0,0 +1,12 @@ +<div> + <table class="image-table"> + <th class="left bg-primary">Chips</th> + {% for image in images %} + <tr> + <td class="left"> + <a class="table-link" href="javascript:showImage('{{ upload_service_url(image) }}')" name="{{ image }}">{{ image_name(image) }}</a> + </td> + </tr> + {% endfor %} + </table> +</div> \ No newline at end of file diff --git a/front_end/templates/includes/imagePopup.html b/front_end/templates/includes/imagePopup.html new file mode 100644 index 0000000..eeefd35 --- /dev/null +++ b/front_end/templates/includes/imagePopup.html @@ -0,0 +1,3 @@ +<div id="imageDisplay" class="hidden"> + <img src="http://127.0.0.1:5001/dpath/report/1939b367-0c4d-4689-8f39-8fdad55226c4/image/reportimage123.png"> +</div> \ No newline at end of file diff --git a/front_end/templates/includes/navbar.html b/front_end/templates/includes/navbar.html index a9474cc..08f0526 100644 --- a/front_end/templates/includes/navbar.html +++ b/front_end/templates/includes/navbar.html @@ -1,8 +1,8 @@ -<nav class="navbar navbar-expand-lg navbar-light bg-light"> +<nav class="navbar navbar-expand-lg bg-primary"> <a class="navbar-brand" href="#">Digital Pathology</a> <ul class="navbar-nav mr-auto"> <li class="nav-item"> - <a class="nav-link" href="{{ url_for('home')}}">Home</a> + <a class="nav-link" href="{{ url_for('home')}}">Upload</a> </li> <li class="nav-item"> <a class="nav-link" href="{{ url_for('reports')}}">Reports</a> diff --git a/front_end/templates/includes/reportDetail.html b/front_end/templates/includes/reportDetail.html index a1e0ffb..99b2467 100644 --- a/front_end/templates/includes/reportDetail.html +++ b/front_end/templates/includes/reportDetail.html @@ -1,28 +1,36 @@ {% block content %} -<table class="report-detail-table"> - <th class="left">Details</th> - <tr> - <td>Id</td> - <td>{{ report.id }}</td> - </tr> - <tr> - <td>Report Date</td> - <td>{{ report.report.runDate }}</td> - </tr> - <tr> - <td>Report Status</td> - <td>Todo</td> - </tr> - <tr> - <td>Diagnosis</td> - <td>{{ report.report.diagnosis }}</td> - </tr> - <tr> - <td>Mild Chips</td> - <td>{{ report.report.chipPredictions.mild}}</td> - </tr> - <tr> - <td>Severe Chips</td> - <td>{{ report.report.chipPredictions.severe}}</td> - </tr> +<div class="panel panel-default"> + <table class="report-detail-table "> + <th class="left bg-primary detail-left">Details</th> + <th class="left bg-primary detail-right"></th> + <tr> + <td>Id</td> + <td>{{ report.request_id }}</td> + </tr> + <tr> + <td>Report Date</td> + <td>{{ report.timestamp }}</td> + </tr> + <tr> + <td>Report Status</td> + <td>{{ report.status }}</td> + </tr> + <tr> + <td>Diagnosis</td> + <td>{{ report.diagnosis }}</td> + </tr> + <tr> + <td>Mild Chips</td> + <td>{{ report.mild}}</td> + </tr> + <tr> + <td>Moderate Chips</td> + <td>{{ report.moderate}}</td> + </tr> + <tr> + <td>Severe Chips</td> + <td>{{ report.severe}}</td> + </tr> + </table> +</div> {% endblock %} \ No newline at end of file diff --git a/front_end/templates/includes/reports.html b/front_end/templates/includes/reports.html index 2186ea1..7a798f3 100644 --- a/front_end/templates/includes/reports.html +++ b/front_end/templates/includes/reports.html @@ -1,17 +1,19 @@ {% block content %} -<h1>{% block title %} Reports {% endblock %}</h1> +<!-- <div class="title-wrapper"> + <h1>Reports</h1> +</div> --> <table class="report-table"> - <th class="left">Id</th> - <th class="left">Status</th> - <th class="right">Run Date</th> + <th class="left bg-primary">Id</th> + <th class="left bg-primary">Status</th> + <th class="right bg-primary">Run Date</th> {% for report in reports %} <tr> <td class="left"> - <a href="{{ url_for('get_report', report_id=report.id)}}">{{ report.id }}</a> + <a class="table-link" href="{{ url_for('get_report', report_id=report.request_id)}}">{{ report.request_id }}</a> </td> - <td class="left">Completed</td> - <td class="right">{{ report.report.runDate }}</td> + <td class="left">{{ report.status }}</td> + <td class="right">{{ report.timestamp }}</td> </tr> {% endfor %} </table> diff --git a/front_end/templates/includes/scriptsload.html b/front_end/templates/includes/scriptsload.html new file mode 100644 index 0000000..830e21f --- /dev/null +++ b/front_end/templates/includes/scriptsload.html @@ -0,0 +1 @@ +<script src="{{ url_for('static', filename='js/popup.js') }}"></script> \ No newline at end of file diff --git a/front_end/templates/reportDetail.html b/front_end/templates/reportDetail.html index cbe840b..c3cad10 100644 --- a/front_end/templates/reportDetail.html +++ b/front_end/templates/reportDetail.html @@ -5,9 +5,17 @@ {% include 'includes/stylesload.html' %} </head> +{% include 'includes/scriptsload.html' %} + <body> {% include 'includes/navbar.html' %} <div class="container"> - {% include 'includes/reportDetail.html' %} + <div class="left-panel"> + {% include 'includes/reportDetail.html' %} + </div> + <div class="right-panel"> + {% include 'includes/imageList.html' %} + </div> + <dialog id="imageDialog"></dialog> </div> </body> \ No newline at end of file diff --git a/front_end/templates/reports.html b/front_end/templates/reports.html index b579b6b..d45f0a3 100644 --- a/front_end/templates/reports.html +++ b/front_end/templates/reports.html @@ -3,7 +3,7 @@ <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Reports</title> + <title>Reports</title> {% include 'includes/stylesload.html' %} </head> diff --git a/upload_service/app.py b/upload_service/app.py index c1e3521..136f07f 100644 --- a/upload_service/app.py +++ b/upload_service/app.py @@ -1,8 +1,9 @@ from flask import Flask from flask import jsonify from flask import request +from flask import send_file # from s3_provider import Provider -from test_report_provider import Provider +from diagnosis_provider import Provider from fake_model import LearningModel as Model import uuid @@ -30,19 +31,32 @@ def get_reports() : response.status_code = 200 return response +@app.route(f'/{PREFIX}/report/<string:report_id>/images', methods=['GET']) +def get_images(report_id) : + provider = Provider() + response = jsonify(provider.get_images(report_id)) + response.status_code = 200 + return response + +@app.route(f'/{PREFIX}/report/<string:report_id>/image/<string:file_name>', methods=['GET']) +def get_image(report_id, file_name) : + provider = Provider() + path = provider.get_image_path(file_name) + return send_file( + path, + download_name=file_name, + mimetype='image/png' + ) + @app.route(f'/{PREFIX}/report/image', methods=['POST']) def upload_image(): - print("reached") response = validate_request(request) if response.status_code == 400: return response provider = Provider() id = uuid.uuid1() - response = jsonify(provider.create_report("")) - # response = jsonify(Model(id).start()) - response.status_code = 201 - return response + return jsonify(provider.save_binary(request.files['file'])) def validate_request(request): response = jsonify({'message' : 'File successfully uploaded'}) @@ -52,12 +66,9 @@ def validate_request(request): response = jsonify({'message' : 'No file part in the request'}) response.status_code = 400 return response + + file = request.files['file'] - file = file = request.files['file'] - # if invalid_extension(file.filename.rsplit('.', 1)[1].lower()): - # response = jsonify({'message' : 'Allowed file types are png, tiff'}) - # response.status_code = 400 - # return response if invalid_filename(file): response = jsonify({'message' : 'No file selected for uploading'}) response.status_code = 400 diff --git a/upload_service/diagnosis_provider.py b/upload_service/diagnosis_provider.py new file mode 100644 index 0000000..2c37d44 --- /dev/null +++ b/upload_service/diagnosis_provider.py @@ -0,0 +1,40 @@ +import requests +from PIL import Image +import os +from base64 import b64encode + +BASE_URL = 'http://127.0.0.1:5000' +SAVE_DIRECTORY = 'C:\\Users\\Dave\\OneDrive\\Documents\\Capstone\\data\\' + + +class Provider: + + def save_binary(self, data): + url = BASE_URL + '/diagnose' + file_name = self.__save_local_file(data) + request = {'file': file_name} + return requests.post(url, json=request).json() + + def get_report(self, id): + url = BASE_URL + '/request_info/' + id + return requests.get(url).json() + + def get_reports(self): + url = BASE_URL + '/request_info' + return requests.get(url).json() + + def get_images(self, report_id): + response = [] + for _ in range(50) : + response.append(f'../dpath/report/{report_id}/image/reportimage123.png') + return response + + def get_image_path(self, image_name): + return SAVE_DIRECTORY + image_name + + def __save_local_file(self, file): + file_name = 'reportimage123.png' + new_file = open(SAVE_DIRECTORY + file_name, 'wb') + new_file.write(file.stream.read()) + new_file.close() + return file_name \ No newline at end of file -- GitLab