分類
软件

在線翻譯

除了谷歌翻譯之外,DeepL 翻譯器(註:2021-07-03日發現無法直接訪問了)也是一個不錯的選擇。

但是我今天發現了另一個在線翻譯——LibreTranslate。下面是一些英文翻中文的測試:

English中文
I like you主席先生
Do you like me??
What a lovely day, I hope the good weather continues.我的那一天爱好一天,我希望那里的天气继续发生。
I have never used such a stupid translator!我从未使用这种流行病的变压器!

如你所見,用這個 LibreTranslate 翻中文現在就是純搞笑。希望有一天它能學會真正的翻譯吧。最後無論使用哪一款在線翻譯都不能掉以輕心,即使是大廠產品也經常會翻車。

本文更新於 2021/07/03。

分類
网站

使用 UpUp 讓網站離線可用

UpUp 是個很小(2.5 KB)的 Javascript 庫,但卻可以方便的實現網站的離線訪問。我之前有一個小項目,PHP 的後端和頁面,另外藉助 Apeche Cordova 用 HTML 實現了安卓的客戶端以供離線使用。最近用 Django 重新寫了,藉助 UpUp 的離線頁面,我不用爲了離線使用而再去生成一個安卓應用。

一般的網站,要使用 UpUp 是非常簡單的,只需要在網站的頂層文件夾引入對應的庫即可,但是 Django 的靜態文件一般是放在 static 下的,要想在項目根目錄下提供它們,可以這樣設置。

#項目的 url.py 文件
from django.urls import path
...
from . import views

urlpatterns = [
    ...
    path('upup.min.js', cache_page(60 * 60 * 48)(TemplateView.as_view(template_name="site/upup.min.js", 
  content_type='application/javascript', )), name='upup.min.js'),
    path('upup.sw.min.js', cache_page(60 * 60 * 48)(TemplateView.as_view(template_name="site/upup.sw.min.js", 
  content_type='application/javascript', )), name='upup.sw.min.js'),
]

然後將 upup.min.js 和 upup.sw.min.js 放在項目的模板目錄裏,比如 mysite/site/templates/site/ 中。

最後在 HTML 頁面中引用並設置需要離線的文件即可。

...
<script type="text/javascript" src="{% url 'upup.min.js' %}"></script>
<script type="text/javascript" src="{% static 'site/js/jquery-3.6.0.min.js' %}"></script>
<script>
UpUp.start({
  'content-url': '/site/',
  'assets': ['/static/site/js/jquery-3.6.0.min.js',
   '/static/site/js/site.js', '/static/site/css/site.css']

});
</script>

離線站點調試的過程中遇到的另外一個問題是,離線站點必須是 HTTPS 類型的加密頁面,但是本地配置 HTTPS 又略嫌繁瑣,其實只要再 Chrome 裏添加例外(chrome://flags/#enable-site-per-process)即可。火狐我還不知道要怎麼添加,最近安卓火狐的一系列更新都不盡人意,實在是有些令人擔憂。

分類
软件

心臟異常檢測 Heart Anomaly Detection

藉助手機的麥克風來錄製心跳,然後使用 MananAgarwal 訓練的 Heartbeat-Classifier 模型來判斷心跳是否異常。經過測試,我和 Emanon 的心跳都是正常。我也有嘗試使用其他項目的實驗數據來測試這個模型,對於「二尖瓣迴流」和「主動脈狹窄」的異常心跳都成功的識別了出來。不過它畢竟只是一個人工智能模型,如果有不舒服,還是應該儘早去看醫生。

安裝 Heart Anomaly Detection

這是一個 python3 的 tensorflow 項目。項目本身並不大(9 MB)但依賴大概有 600MB ,所以推薦使用虛擬環境來安裝

#安裝依賴
pip install tensorflow keras librosa 
#下載項目
git clone https://github.com/MananAgarwal/Heartbeat-Classifier.git
#測試運行
cd Heartbeat-Classifier
python testing.py heartbeat-to-classify.wav
#稍等片刻應該會成功輸出
Normal heartbeat
confidence: 0.9638266

使用手機錄製心跳

由於我不是蘋果手機用戶,所以無法推薦和測試適合的錄音應用。但是該模型的訓練數據中有用到蘋果手機(用iStethoscope Pro)錄製的心跳音頻,所以蘋果手機應該也是沒問題的。我的安卓手機使用的是 Audio Recorder,一個開源免費又小巧的錄音軟件(5.6 MB)。設置裏只需要把編碼格式改爲「.wav」,其他的保持不變即可滿足我們的需要。

找到手機的麥克風位置,一般都在手機的底部。找一個相對安靜的地方,點擊開始錄音(爲了避免誤觸屏幕,可以按一下電源鍵把屏幕關閉),把手機的麥克風的位置貼近心臟的位置,按住15秒左右,然後打開手機,停止錄音。我的建議是手機直接接觸皮膚來錄音,可能會獲得更好的音質。但是我給 Emanon 錄音的時候是隔着 T 恤的,倒也沒有影響的測試結果。

錄好的聲音文件默認保存在 /sdcard/Android/data/com.github.axet.audiorecorder/files/recordings 中,可以通過 USB 線或 Material Files 文件管理器將文件傳輸到電腦上。

最後使用上面的測試命令進行檢測,即可得到預測的心率狀態:Normal(正常)或 Abnormal(不正常),以及預測的信心值 confidence。

關於這個預測模型

該模型由博拉理工学院(印度皮拉尼)的 Manan Agarwal 和 Ankita Chakravarty 根據 The Classifying Heart Sounds Challenge 2011的數據集訓練而來。模型的訓練準確度爲 89.73,測試準確率爲 84.04。下面的文字摘自他們的論文說明:

我們的目標是提供一個可靠,快速且低成本的系統,讓未經培訓的一線衛生工作者或任何具有互聯網訪問權限的人都可以使用,以幫助確定是否應該將受試者推薦給專家診斷,尤其是在訪問臨床醫生和專家比較困難的地區。這也將有助於早期診斷心血管疾病,並大大降低這些死亡的潛在危險因素。

分類
网站

使用 Plausible 統計用戶事件

中文繁簡轉換工具用上 Bootstrap 後漂亮多了,使用 JavaScript 來請求表格減少了頁面的跳轉,用起來也比較方便。於是產生一個新需求就是想統計下「轉換」按鈕被點擊了多少次。關於自定義事件目標的具體介紹,可以參考 Plausible 的官方文檔Custom event goals,我這裏只是羅列下具體步驟。

前端 html 中的修改

確保 Plausible 配置有下面的第二行

<script async defer data-domain="<yourdomain.com>" src="https://plausible.yourdomain.com/js/plausible.js"></script>
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>

在需要統計的地方執行這行 JavaScript

plausible('my_event');

Plausible 後臺的設置

打開 Plausible 後臺,在左上角的域名處選擇 Site Settings。在 Goals 區域點擊 + Add goal。然後 Goal trigger 選擇 Custom event,Event name 要輸入 JavaScritp 請求的參數,這裏就是「my_event」。最後點擊 Add goal 就完成了。

分類
程序

把媒體中地理位置標籤從 WGS-84 轉換成 GCJ-02

手機拍攝的照片地理位置默認是 WGS-84 系統,但是谷歌地圖使用的卻是 GCJ-02 系統,這就會出現偏移。爲了展示正確的位置,可以通過把照片的地理位置標籤轉換成 GCJ-02 來實現。需要用到 Phil Harvey開發的 ExifTool 和 Avatar sshuair 開發的 coord-convert。前者下載exiftool.exe 到本地即可,後者可以通過 pip 安裝。

# -*- coding: utf-8 -*-

#pip install coord-convert

#Usage:
#Drage a single photo or directory with photos to this script
# OR
#python wgs2gcj.py D:\my.JPG
#Results will be wrote to gps.log at the same dir with this script

from coord_convert.transform import wgs2gcj
import subprocess,json,sys,os,time,datetime
#You may set your exiftool file here
exiftool_path = "D:\\Program Files\\portable\\exiftool.exe"

work_dir = os.getcwd()
def log42(logFile,logText):
	ts = int(time.time())
	dt = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
	
	log_file = os.path.join(work_dir,logFile+".log")
	with open(log_file, "a") as myfile:
		myfile.write(dt+" "+logText+"\n")
		print(logText)
		
		
if (exiftool_path == ""):
	exiftool_path = os.path.join(work_dir,'exiftool.exe')
if not os.path.exists(exiftool_path):
	log42("gps","Error: exiftool.exe not found neither in script directory nor in the script setting \"exiftool_path\"")
	exit()
	
file_paths_input = sys.argv[1:]
file_paths = []

for file_path_input in file_paths_input:
	if os.path.isfile(file_path_input):
		file_paths.append(file_path_input)
	elif os.path.isdir(file_path_input):
		for root,ds,fs in os.walk(file_path_input):
			for ff in fs:
				full_path = os.path.join(root,ff)
				file_paths.append(full_path)

for f in file_paths:
	output = subprocess.check_output('"'+exiftool_path+'" -struct -j -a -n "-gps*" '+f, shell=True)
	data = json.loads(output)
	if 'GPSMapDatum' in data[0]:
		log42("gps",data[0]['SourceFile']+':'+str(data[0]['GPSMapDatum'])+' '+str(data[0]['GPSLatitude'])+' '+str(data[0]['GPSLongitude']))
		if(data[0]['GPSMapDatum']=='WGS-84'):
			gcj_lon, gcj_lat = wgs2gcj(data[0]['GPSLongitude'], data[0]['GPSLatitude'])
			log42("gps",str(gcj_lat)+' '+str(gcj_lon))
			if (gcj_lat==data[0]['GPSLatitude']):
				log42("gps",'not in China')
			else:
				output = subprocess.check_output('"'+exiftool_path+'" -overwrite_original -exif:gpsmapdatum=GCJ-02 -exif:gpslatitude='+str(gcj_lat)+' -exif:gpslongitude='+str(gcj_lon)+' '+f, shell=True)
				log42("gps",output.decode())
		else:			
			log42("gps","not a wgs84 location")
	else:
		log42("gps","no gps data found")
		
log42("gps","task finished")

另請參考:使用ExifTool處理文件元數據wgs-84-gcj-02-經緯度在線轉換

分類
网站

使用 datatables 展示表格

計算得出的中國城市飲用水中全氟辛烷磺酸(PFASs)的平均濃度(ng/L)

調查城市PFOAPFOS平均值18年人口 (万)所在省份
Anshan0.40.91.3341.8Liaoning
Atushi0.050.050.128.55Xinjiang
Baoding0.560.061.28935.93Hebei
Beijing3.290.9997.1922154.2Beijing
Benxi0.61.72.3146.1496Liaoning
Binzhou6.722.2534.7392.25Shandong
Changchun0.6420.3525.876751.3Jilin
Changsha0.9360.40616.616815.47Hunan
Changshu19.3272.852122.4106.8Jiangsu
Changzhou9.0552.65428.1472.3Jiangsu
Chaohu10.563.3359.8979.62Anhui
Chengdu0.7630.323119.4231633Sichuan
Chongqing2.5390.2193.2633101.79Chongqing
Dalian0.2760.6392.463595.2Liaoning
Dezhou1.4190.554.7581Shandong
Dongguan2.90424.22739.554839.22Guangdong
Dongying6.8682.18524.365217.21Shandong
Foshan45.55.0253.1790.57Guangdong
Fuzhou0.5330.4623.993774Fujian
Guangzhou5.4414.68120.2151490.44Guangdong
Guiyang0.5780.25817.135488.19Guizhou
Haining27.4122.4549.38685.85Zhejiang
Hangzhou49.9610.8874.145980.6Zhejiang
Harbin0.5580.1578.958951.5Heilongjiang
Hefei1.8530.29320.647808.7Anhui
Heihe0.020.010.54159.3Heilongjiang
Hohhot0.40.1913.663312.6Inner Mongolia
Hong Kong1.045.8688.068745.1Hong Kong
Huaian4.7380.43812.5492.5Jiangsu
Jinan9.6483.84730.564746.04Shandong
Jining1.0350.0452.9834.59Shandong
Jiujiang156.52.17175489.68Jiangxi
Kunming6.7381.11360.39685Yunnan
Lanzhou0.850.212.18374.16Gansu
Lhasa0.750.4514.8555.44Tibet
Lianyungang61.42186.17332.63452Jiangsu
Macao1.36.27.563.16Macao
Mudanjiang0.8201.97252.5Heilongjiang
Nanchang6.8080.9718.593554.55Jiangxi
Nanjing8.781.08327.824843.62Jiangsu
Nanning0.10.25364.093725.41Guangxi
Shanghai12.4512.34526.9132423.78Shanghai
Shenyang1.6410.8965.989831.6Liaoning
Shenzhen8.5489.95423.9021302.66Guangdong
Shijiazhuang17.6019.92145.7661095.16Hebei
Suzhou34.6462.09561.3131072.17Jiangsu
Taian1.3570.3927.2564Shandong
Taipei3.75.49.1262.6Taiwan
Taiyuan0.740.4930.697442.15Shanxi
Tianjin2.2321.0187.6041559.6Tianjin
Urumqi0.40.1959.64350.58Xinjiang
Wuhan1.8970.21213.7711108.1Hubei
Wuxi27.6986.85493.622657.45Zhejiang
Xiamen2.60.763.36411Fujian
Xi'an0.3820.4969.5621000.37Shaanxi
Xining0.4450.21511.39237.11Qinghai
Xuzhou6.8330.87512.5880.2Jiangsu
Yangzhou7.6510.97112.5453.1Jiangsu
Yinchuan0.040.46828.036225.06Ningxia
Zhengzhou0.5160.18315.4761013.6Henan
Zhenjiang4.6741.6816319.64Jiangsu
Zhongshan0.60.61.2331Guangdong
Zhuhai0.7651.312.075189.11Guangdong
Zhuzhou2.110.335.54402.08Hunan
Zibo15.892.1141.01470.2Shandong
Zigong467.9551.606502.926292Sichuan

不同國家和美國各州發布的飲用水中 PFAS 準則

DateAuthorityAgency指導值(ng/L)Guideline TypeReference
2006GermanyGerman Ministry of HealthPFOA+PFOS: 300Health-based guide valuehttps://www.umweltbundesamt.de/sites/default/files/medien/pdfs/pft-in-drinking-water.pdf
2006GermanyGerman Ministry of HealthPFOA+PFOS: 100Health-based precautionary valuehttps://www.umweltbundesamt.de/sites/default/files/medien/pdfs/pft-in-drinking-water.pdf
2014ItalyNational Institute of HealthPFOA: 500; PFOS: 30Health-based levelhttp://www.euro.who.int/__data/assets/pdf_file/0018/340704/FINAL_pfas-report-20170530-h1200.pdf
2015DenmarkDanish Environmental Protection AgencyPFOS: 100; PFOA: 100Quality Criteriahttp://mst.dk/service/publikationer/publikationsarkiv/2015/apr/perfluoroalkylated-substances-pfoa-pfos-and-pfosa/
2016AustraliaDepartment of HealthPFOA: 560; PFOS+PFHxS: 70Health-based guidancehttp://www.health.gov.au/internet/main/publishing.nsf/content/ohp-pfas-hbgv.htm
2016USAUSEPAPFOS+PFOA: 70Lifetime Health Advisoryhttps://www.epa.gov/sites/production/files/2016-05/documents/pfos_health_advisory_final_508.pdf
2016ConnecticutDepartment of Public HealthPFOA+PFOS+PFHxS+PFNA+PFHpA: 70Action Levelhttp://portal.ct.gov/DPH/Search-Results?SearchKeyword=PFAS
2018European UnionEuropean CommissionIndividual PFASs: 100Proposed Drinking Water Directiveec.europa.eu/environment/water/water-drink/review_en.html
2018European UnionEuropean CommissionSum of PFASs: 500Proposed Drinking Water Directiveec.europa.eu/environment/water/water-drink/review_en.html
2018CanadaHealth CanadaPFOA: 200; PFOS: 600Drinking Water Screening Valuehttps://www.canada.ca/en/services/health/publications/healthy-living/water-talk-drinking-water-screening-values-perfluoroalkylated-substances.html
2019MinnesotaDepartment of HealthPFOA: 35; PFOS: 15; PFHxS: 47; PFBA: 7000; PFBS: 2000Health Based Guidance for Waterhttps://www.health.state.mn.us/communities/environment/hazardous/topics/pfcs.html#safelevels
2019California Water Resources Control BoardPFOA: 5.1; PFOS: 6.5Notification Levelshttps://www.ecos.org/news-and-updates/california-lowers-pfas-notification-levels-initiates-regulatory-process/
2019VermontDepartment of Environmental ConservationPFOA+PFOS+PFHxS+PFHpA+PFNA: 20Maximum Contaminant Levelshttps://dec.vermont.gov/water/drinking-water/water-quality-monitoring/pfas
2020MichiganDepartment of Environment, Great Lakes, and EnergyPFOA: 8; PFNA: 6; PFHxA: 400000; PFOS: 16; PFHxS: 51; PFBS: 420; HFPO-DA: 370Maximum Contaminant Levelshttps://www.michigan.gov/egle/0,9429,7-135--534660--,00.html
2020New YorkDepartment of HealthPFOA: 10; PFOS: 10Maximum Contaminant Levelshttps://www.wamc.org/post/nys-adopts-drinking-water-standards-three-emerging-contaminants
2020New HampshireDepartment of Environmental Services PFOA: 12; PFOS: 15; PFHxS: 18; PFNA: 11 Maximum Contaminant Levelshttps://www4.des.state.nh.us/nh-pfas-investigation/?p=1185
2020New JerseyDepartment of Environmental ProtectionPFOA: 13; PFOS: 14Maximum Contaminant Levelshttps://www.penn-er.com/2020/06/08/new-jersey-establishes-mcls-ground-water-and-remediation-standards-for-pfoa-pfos/
2020MassachusettsDepartment of Environmental ProtectionPFOA+PFOS+PFHxS+PFNA+PFHpA+PFDA: 20Maximum Contaminant Levelshttps://www.mass.gov/lists/development-of-a-pfas-drinking-water-standard-mcl
2020SwedenSwedish Food AgencyPFOA+PFOS+PFHxS+PFNA+PFHpA+PFDA+PFBS+6:2FTS+PFBA+PFPeA+PFHxA: 90Action Levelhttps://www.livsmedelsverket.se/en/food-and-content/oonskade-amnen/miljogifter/pfas-in-drinking-water-fish-risk-management

數據來源及完整論文請參閱:Per- and polyfluoroalkyl substances (PFASs) in Chinese drinking water: risk assessment and geographical distribution。Liu, L., Qu, Y., Huang, J. et al. Per- and polyfluoroalkyl substances (PFASs) in Chinese drinking water: risk assessment and geographical distribution. Environ Sci Eur 33, 6 (2021). https://doi.org/10.1186/s12302-020-00425-3

如何在 WordPress 中展示上面的數據圖表

這裏使用了開源的js插件 DataTables 來展示上面的圖表。安裝方法可以參考官方安裝文檔,非常簡單。考慮到文件裏推薦的 CDN 方法在中國可能水土不服,所以我使用本地的安裝方法。在下載頁面勾選需要的組件(我只選了必須的 css 和 js,由於 WordPress 已自帶 jquery,所以不用選jquery)然後下載到一個 zip 包。我是將其上傳到 WordPress 的 wp-content/uploads/share/js 目錄中,然後解壓並修改文件所有者爲nginx( chown nginx:nginx -R DataTables ),就可以使用了。文章裏用到的代碼如下:

<link rel="stylesheet" type="text/css" href="/wp-content/uploads/share/js/datatables.min.css"/>
<script type="text/javascript" src="/wp-content/uploads/share/js/datatables.min.js"></script>

<table id="table_id" class="display">
    <thead>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Row 1 Data 1</td>
            <td>Row 1 Data 2</td>
        </tr>
        <tr>
            <td>Row 2 Data 1</td>
            <td>Row 2 Data 2</td>
        </tr>
    </tbody>
</table>

<script>
jQuery(document).ready(function($) {
    $('#table_id').DataTable();
} );
</script>
分類
方法

使用谷歌位置記錄來給照片增加位置標籤

Emanon 有一些多年前旅行時拍攝的自然觀察的照片,但是現在很難回憶起照片的具體拍攝位置。好在當年手機打開了谷歌的位置記錄,現在我只要把照片的拍攝時間和谷歌位置記錄裏的時間相關聯即可。需要用到兩個工具: Scarygami 開發的 Python 腳本 Location History JSON Converter 和一個強大的開源影音管理軟件digiKam

首先要從谷歌獲取自己的位置記錄,打開 Google Takeout,按提示下載 json 格式的文件即可。然後把 location_history_json_converter.py 文件保存的本地,用來把谷歌的文件轉換成 digiKam 可用的格式,即 gpxtracks 格式。

#從定位記錄中轉換出指定範圍的數據
python location_history_json_converter.py "/home/fred/Documents/Takeout/定位記錄/定位記錄.json" 2019.gpx -f gpxtracks -s 2019-03-01 -e 2019-10-31

有了 gpx 文件後,即可參考简单使用影音管理軟件 digiKam 來給照片加上地理位置標籤了。

幾個小撇步:一、匹配位置的時候請留意「相機時區」,gpx文件中的都是 UTC,所以要選對照片拍攝的時區才準確。二、如果對位置精度要求不高,可適當增加「最大時間間隔」以提高匹配成功率。三、最後如果個別照片還是匹配不到,還可以根據前後照片的位置來手動指定其位置。