owned this note
owned this note
Published
Linked with GitHub
# 具有整合協力合作之開放式人工智慧病理分析平台
## 簡介
如下圖之病理影像,一片組織切片可包含數萬個需要分析的區塊,在傳統方法利用特殊染色及醫師肉眼觀察,不僅耗時耗力,且即使醫師耗費長時間的心力,面對數以萬計的區域,難以有客觀的定量觀察結果,只能依賴醫師經驗以半定量判斷之。這些難題都造成精準診斷、精準治療之阻礙。
近年因為人工智慧發展,國內外團隊已逐漸將人工智慧的技術帶入了醫療影像輔助分析,以輔助結果定量分析。本計畫在國科會推動支持下,連結國內多家研究單位、醫院,及國家高速網路中心,針對數位病理影像分析之挑戰,發展對應之人工智慧訓練及分析技術,並建立研發團隊資料共享平台,連結國內外的AI病理團隊,協力合作,共同發展病理分析技術及資源,為人類更精準的疾病診斷治療而努力,期許未來更精確的治療方式能裨益人類。
在此前景之努力下,我們為了符合研究暨醫學倫理與病人隱私保護機制,本團隊建立此平台,利用線上的方式向病人說明研究目的以及未來展望,藉此獲得病人提供病理影像之同意書,結合優良醫師團隊確認是否符合資格,以及病理影像去識別化與去連結後上傳國網儲存保護,唯有參與研究計畫團隊成員與醫師方能獲取此病理影像作為研究。

[網站位置 smile lab](http://smilelab.ee.ncku.edu.tw:8087/)
#### 檔案位置
[Github 最新版本V3.0](https://github.com/s07362022/smile_web/releases/tag/v3.0.0)
## 系統核心

:::spoiler Files Tree
```
app.py
│ consent.pdf
│ form.py
│ form3.py
│ formcheck.py
│ formcheckAcc.py
│ formDocCheck.py
│ formDoctor.py
│ formDownload.py
│ formPatInfo.py
│ model.py
│ model2.py
│ modelAnony.py
│ modelDocInfo.py
│ modelEmail.py
├─static
│ │ taglist.js
│ │
│ ├─css
│ │ .DS_Store
│ │ bbt.css
│ │
│ ├─image
│ │ ALOVAS.png
│ │ box1.JPG
│ │ box1.PNG
│ │ box1_.jpg
│ │ box1_.png
│ │ Chao-Jyun .png
│ │ Chu-Song.png
│ │ Chun-Rong.png
│ │ Chun-Shien.png
│ │ Fu-Chang.png
│ │ futrue.png
│ │ lg.png
│ │ Meng-Ru .png
│ │ one.jpg
│ │ one1.png
│ │ tgr.png
│ │ two.png
│ │ Wei-Ta.png
│ │
│ └─lib
│ .DS_Store
│ howler.min.js
│
├─templates
│ aix.html
│ checkAcc.html
│ checkAcc2.html
│ checkDoc.html
│ dd.html
│ docReg.html
│ downPage.html
│ hardem.html
│ hmoe2.html
│ home.html
│ index copy.html
│ index.html
│ index2 copy.html
│ index2.html
│ pag1.html
│ page2.html
│ page3.html
│ page4.html
│ pub.html
│ pub2.html
│ pubdelete.html
│ publish.html
│ pubRevise.html
│ upload0 copy.html
│ upload0.html
```
:::
#### Software Develope From :
(python 80%, html 20%)
- MySQL (SQL server)
- Flask (Web framwork)
- SMTP (Email server)
- CSRF (Information Security)
## 系統架構

## 技術與方法
[後端框架 [基礎教學] — Flask](https://medium.com/@harden004/flask-%E5%AD%B8%E7%BF%92%E6%97%A5%E8%A8%98-day01-jinja2-76cc67821086)
- :::spoiler ### **FLASK** (Version 2.0.0)
http://IP/
```
@app.route('/', methods=['GET', 'POST'])
def home():
return render_template('home.html')
```

http://IP/page1
```
@app.route('/page1', methods=['GET', 'POST'])
def page1():
pic1 = web_img(img_local_path)
pic2 = web_img(img_local_path2 )
return render_template('pag1.html',pic1=pic1,pic2=pic2) #將圖片傳至pag1.html
```

http://IP/page2
```
@app.route('/page2', methods=['GET', 'POST'])
def page2():
return render_template('page2.html')
```

http://IP/page4
```
@app.route('/page4', methods=['GET', 'POST'])
def page4():
pic3 = web_img(img_local_path3)
return render_template('page4.html',pic3=pic3) #將圖片傳至page4.html
```

http://IP/projects
```
@csrf.exempt
@app.route('/projects', methods=['GET', 'POST'])
def projects():
return render_template('aix.html')
```

http://IP/Pubcontent
```
@csrf.exempt
@app.route('/Pubcontent', methods=['GET', 'POST'])
def Pubcontent():
data = get_publish() #取得公告資料表內的所有內容
return render_template('Pub.html', data=data)
```

http://IP/check
```
@app.route('/check', methods=['GET', 'POST'])
def check():
if formCheck.validate_on_submit(): #按下驗證身分鍵後檢查帳號密碼
hashed_password = get_doc_info1(account=acc) #抓出此醫生帳號的雜湊密碼
check_password = bcrypt.check_password_hash(hashed_password, pwd) #對比輸入密碼與雜湊密碼是否一致
if check_password:
return redirect(url_for('Pubdelete', acc=acc)) #驗證通過後跳轉至管理頁面
return render_template('checkAcc2.html', formcheck=formCheck)
```

http://IP/Pubdelete/<string:acc>
```
@csrf.exempt
@app.route('/Pubdelete', methods=['GET', 'POST'])
def Pubdelete():
data = get_delpublish(acc) #抓取此帳號發布過的公告內容
sum = get_sumpublish(acc) #抓取此帳號發布過的公告數
return render_template('Pubdelete.html', data=data, sum=sum, acc= acc, acc2=acc)
```

http://IP/publish
```
#/publish2/<string:acc2>在新增公佈欄點擊發布消息後,對公佈欄內容儲存
@app.route('/publish', methods=['POST'])
def publish():
db.session.add(pub)
db.session.commit()
return redirect(url_for('Pubcontent'))
```
http://IP/publish2/<string:acc2>
```
@app.route('/publish2/<string:acc2>', methods=['GET', 'POST'])
def publish2(acc2):
return render_template('publish.html', acc2=acc2)
```

http://IP/upload2
```
@app.route('/upload2')
def index():
#增加下載同意書在html
return render_template('upload0.html')
```

http://IP/upload
```
@app.route('/upload', methods=['POST'])
def upload():
#/upload點下上傳同意書後,做同意書的儲存及處理
file.save('./ncku_web-main/document/' + num + '/' + file.filename)
db.session.add(user)
db.session.add(email_info)
return redirect(url_for('home'))
```
http://IP/out
```
@csrf.exempt
@app.route('/out', methods=['GET', 'POST'])
def out():
if form.validate_on_submit():
db.session.add(user) #新增病患資料進病患資料表
db.session.add(email_info) #新增郵件進郵件資料表
db.session.commit()
smtp3(get_pat_applyid(form.email.data)) #寄送病患意願郵件通知醫生
return redirect(url_for('home')) #結束後返回首頁
return render_template('index.html', form=form)
```

http://IP/docReg
```
@app.route('/docReg', methods=['GET', 'POST'])
def docReg():
if formDoctor.validate_on_submit():
db.session.add(doctor) #新增醫生資料進醫生資料表
db.session.commit()
return redirect(url_for('checkAcc')) #申請完成後返回醫生認證畫面
return render_template('docReg.html', formDoctor=formDoctor)
```

http://IP/checkAcc
```
@app.route('/checkAcc', methods=['GET', 'POST'])
def checkAcc():
if formCheck.validate_on_submit():
hashed_password = get_doc_info1(account=acc) #抓出此醫生帳號的雜湊密碼
check_password = bcrypt.check_password_hash(hashed_password, pwd) #對比輸入密碼與雜湊密碼是否一致
if check_password:
return redirect(url_for('docDown', acc=acc, applyid=applyid)) #驗證通過進入醫生確認頁面
return render_template('checkAcc.html', formcheckAcc=formCheck)
```

http://IP/docDown
```
@csrf.exempt
@app.route('/docDown', methods=['GET', 'POST'])
def docDown():
if formDownload.validate_on_submit():
db.session.add(ann) #新增病患匿名資料至匿名資料表
#從病患資料表找出此病患資料並設為待刪除
delete = db.session.query(UserReister).filter_by(formid=applyid).first()
delete.shield = 1
db.session.commit()
#以匿名ID作為檔名儲存此病患病理影像ID
file = open("./ncku_web-main/patimg/" + ann.anonyid + ".txt", 'w', encoding='utf-8')
file.write(consent)
file.close()
smtp2(get_doc_info(acc, ann.anonyid),file, ann.anonyid) #寄送病患匿名資料郵件通知助理
return redirect(url_for('home')) #結束後返回首頁
return render_template('downPage.html', formDownload=formDownload, applyid=applyid, patInfo=patInfo) #將病患資料渲染到downPage.html
```
:::
[SQL[基礎操作與指令] — MySQL](https://medium.com/@harden004/sql-%E5%9F%BA%E7%A4%8E%E6%93%8D%E4%BD%9C-mysql-1b54723f897)
- :::spoiler ### **MySQL** (Shell 8.0.26)
- #### *DataBase* :+1:
ncku_w
- #### *Table* :+1:
==ncku_w== (存於病患表單資訊)
1. username、id、hpname、email : 儲存使用者填寫的姓名、身分證後四碼等個人資料
2. time : 送出資料的時間
3. airesearch、preeval :勾選此研究則為1,無勾選則為0
4. agree : 同意參與研究則為1,退出為0
5. filePath : 存放使用者同意書檔案位置
6. formid : 系統自動生成申請ID區別病患
7. shield : 若從空值變為1則表示此資料待刪除,並在十天內完成刪除動作
```
CREATE TABLE `ncku_w`(
`index` INT AUTO_INCREMENT,
`username` VARCHAR(20) NOT NULL,
`id` VARCHAR(100) NOT NULL,
`hpname` VARCHAR(20) NOT NULL,
`time_` VARCHAR(1000) NOT NULL,
`email` VARCHAR(100) ,
`airesearch` Boolean,
`preeval` Boolean,
`agree` INT,
`filePath` VARCHAR(100) ,
`formid` VARCHAR(36) ,
`shield` TINYINT(1) ,
PRIMARY KEY(`index`)
);
```
==publish_content== (公佈欄訊息)
1. title : 公告標題
2. content : 公告內容
3. acc : 公告者帳號
4. time : 公告時間(日期-西元)
```
CREATE TABLE `publish_content`(
`index` INT AUTO_INCREMENT,
`title` VARCHAR(100) NOT NULL,
`content` VARCHAR(500) NOT NULL,
`acc` VARCHAR(100) NOT NULL,
`time` VARCHAR(1000) NOT NULL,
PRIMARY KEY(`index`)
);
```
==doctor_info== (醫師資訊)
1. acc : 存放醫師輸入帳號
2. pwd : 存放經由加密處理後醫師輸入密碼
3. doctorname : 存放醫師姓名
4. hpname : 存放醫師所屬醫院
5. email : 存放醫師email
```
CREATE TABLE `doctor_info`(
acc VARCHAR(100) NOT NULL,
pwd VARCHAR(100) NOT NULL,
doctorname VARCHAR(30) NOT NULL,
hpname VARCHAR(30) NOT NULL,
email VARCHAR(50) NOT NULL,
PRIMARY KEY(`acc`)
);
```
==anony_info== (存匿名ID)
1. anonyid : 病患的匿名ID
2. doctorid : 儲存負責醫生的ID
3. applyid : 病患的真實ID
4. patimg : 此病患的病理影像編號
```
CREATE TABLE `anony_info`(
`index` INT AUTO_INCREMENT,
`anonyid` VARCHAR(100) NOT NULL,
`doctorid` VARCHAR(36) NOT NULL,
`applyid` VARCHAR(100) NOT NULL,
`patimg` VARCHAR(100) ,
PRIMARY KEY(`index`)
);
```
==email_table== (病患信箱)
1. email : 存放使用者email
2. agree : 若同意研究則為1,退出為0
```
CREATE TABLE `email_table`(
`index` INT AUTO_INCREMENT,
`email` VARCHAR(100) NOT NULL,
`agree` VARCHAR(100) ,
PRIMARY KEY(`index`)
);
```
- MySQL連接Flask方式
第一種
```python
# 連接MySQL與FLASK
app.config['SQLALCHEMY_DATABASE_URI'] =\
"mysql+pymysql://root:0000@localhost:3306/ncku_w"
```
第二種
```python
import mysql.connector
connection = mysql.connector.connect(host='localhost',
port='3306',
user='root',
password='0000',
database='ncku_w')
cursor = connection.cursor()
```
- :::spoiler ### **Function** (Python==3.8.9)
:::
## 設備與軟體
| 開發工具/伺服器 | 軟體套件 |
| :--: | :--: |
|  VS Code |  Flask |
|  MySQL|  Apache |
|  WSGI |  SMTP |
|  ubuntu |  html/css |