2021年1月28日木曜日

ワクチン関連業務、自衛隊の活用

世の中は現在、新形コロナウイルスと戦っています。
最近、ワクチンが開発され、これから予防接種が始まります。

ですが、日本の全住民に予防接種をうけさせることは、
簡単ではありません。
まず、医療スタッフは既に病気と戦っています。
保健所のスタッフも感染対応で追われています。
このような状況下、人員を確保して予防接種を行うのが、かなり難しいです。

ここで、自衛隊を活用すればと思わいます。
自衛隊の医療スタッフは既に民間病院などで支援をしています。
でも、一般隊員、まだまだいます。
隊員たちは診察など実際の予防接種はできませんが、
事務業務はできると思います。
受付作業、人の誘導、現場の消毒など、
人手がかかる所々で隊員を使うのができるでしょう。
今でも保健所の電話対応などができるはず。ちょっと事前勉強をさせたら。

新型コロナウイルスは国に対する脅威です。
まさか自衛隊の出所でしょう。

2021年1月16日土曜日

テルシス語翻訳スクリプトをパワーアップ

注:さらに進化したバージョンはこちら:
記事は英語しかなく。。。ごめんなさい。🙇‍♀️いつか日本語で書きます!

先日テルシス語(ヴァイオレット・エヴァーガーデン世界)翻訳Pythonスクリプトを書いたばかりですが、 テルシス語の解読しかできなく、性能は欠けていると思いました。

よって、休み時間を使って、パワーアップしました。
 
かなり増強しました。
解読だけではなく、テルシス語で書くこともできます。
解読する時、言語指定もできます。
バックエンドはGoogle Translateです。

とりあえず、v0.1をGitHubに載せました。
ここです。

コマンドラインからの実行例:
$ ./telsistrans.py -t "I love Major \Gilbert\ " -sl en
Nun posuk Gilbert ui gikapmarikon
$ ./telsistrans.py -t "Posuk \Gilbert\ nunki." -sl telsis
Thank you Major Gilbert.

インタラクティブモードもあります:
$ ./telsistrans.py -i
Source language: en
Input source text: I love you
Target language:       
In Tamil script: நான் உன்னை நேசிக்கிறேன்
Pronunciation: Nāṉ uṉṉai nēcikkiṟēṉ
In unaccented characters: Nan unnai necikkiren
In target language: Nun annui noyirrikon
Source language: telsis
Input source text: Nunki posuk
Target language: ja
In Tamil script: நன்றி மேஜர்
Pronunciation:
In unaccented characters: Nanri mejar
In target language: ありがとう少佐


Pythonスクリプト内でライブラリーとしても使用できます:
from telsistrans import telsis_translator
translator = telsis_translator()
srctext = "I love you"
srclang = 'en'
translator.lang2telsis(srctext, srclang)
print(translator.results['tgt_text'])  # Print out results of translation
srctext = "Nunki posuk"
tgtlang = 'ja'
translator.telsis2lang(srctext, tgtlang)
print(translator.results['tgt_text'])  # Print out results of translation

 
上記スクリプトを実行したアウトプット:
Nun annui noyirrikon
ありがとう少佐
 
テルシス語のフォントファイルを指定すれば、
このような出力もできます:
 「Dear Major Gilbert」(親愛なるギルベルト少佐)

 
 
 
「I love you」(君を愛しています)



 
この翻訳スクリプトを使用するため、以下のPythonライブラリーが必要です:
google_trans_new
unidecode
requests
Pillow
 
スクリプト(解読や翻訳の流れ)に関する説明もレポジトリーに載せましたが、
英語です。

テルシス語について、少し説明します。
ヴァイオレット・エヴァーガーデンの世界観設定を担当した鈴木貴昭さんがスタッフイベントで、
日本語原文を英語へ翻訳し、
英文をまた別の言語に翻訳し、
その結果のアルファベットを暗号化して、
最後にテルシス語の文字にする、と説明しました。
その別の言語は言及しませんでしたが、
すでに「タミル語」と特定した人々がいます。
ようするに、
テルシス語はタミル語を暗号化したものです。
その暗号は、英文字の置き換え(スワップ)です。 
ネット同志の努力で、
おそらく
A ⇔ U
C ⇔ Y 
E ⇔ O
G ⇔ V
H ⇔ T
K ⇔ R
M ⇔ P
で英文字を置き換えたと推測しました。
ネット同志は、S、Lについて少し悩んでいたみたいです。
個人的に、
J ⇔ S
L ⇔ Q
で置き換えられていたと思います。
確かではありませんが、この翻訳スクリプトではこのように置き換えます。

作ったばかりで、まだ完全にテストしたものではありません。
でも、出力は合っていると思います。😅
コンソルでの使用ですが、少し慣れていない方には難しいかもしれません。。。🙇‍♀️
将来的にTkで簡単なGUIを作ろうとは思いますが。。。
GUIを作るのが大嫌いで、おそらくなかなかできはしないでしょう。 

英語ブログにもこのスクリプトについて書きました。)

2020年1月23日更新:GUIを作りました。
Kivyを使用したGUI:

PySimpleGUIを使用したGUI:

テルシス語のフォントも作りました。

2020年1月25日更新:GUI使い方のビデオをアップしました。


2021年1月14日木曜日

テルシス語(ヴァイオレット・エヴァーガーデン世界)翻訳Pythonスクリプト

2021年1月16日更新:パワーアップしたスクリプトについてはこちらへ
 
ヴァイオレット・エヴァーガーデン世界で使用されているテルシス語を英語へ翻訳するPythonスクリプトがあります。

それを少し改造して、日本語へ翻訳できるようにしました。
英語ブログから流用しました。)

使用するにはgoogle_trans_newライブラリーが必要です。
pip3 install google_trans_new

Google翻訳APIサービスは有料ですが、
google_trans_newは無料で使わせてくれるみたいです。
でも、商用では使えません。ご注意ください。

現在、ターゲット言語を日本語に設定しました。例えば、英語にしたい場合、
target_language = 'ja'
を以下のように書き換えてください。
target_language = 'en'
 
スクリプトの実行
python3 nunkish_translator_2.py

スクリプト(ファイルネーム:nunkish_translator_2.py)
-----------------
from google_trans_new import google_translator  
import requests
 
translator = google_translator()  

alphabet = {
    'a': 'u',
    'b': '',
    'c': 'y',
    'd': '',
    'e': 'o',
    'f': '',
    'g': 'v',
    'h': 't',
    'i': 'i',
    'j': '',
    'k': 'r',
    'l': 'i',
    'm': 'p',
    'n': 'n',
    'o': 'e',
    'p': 'm',
    'q': 'l',
    'r': 'k',
    's': 'y',
    't': 'h',
    'u': 'a',
    'v': 'g',
    'w': '',
    'x': '',
    'y': 'c',
    'z': '',
    'A': 'U',
    'B': '',
    'C': 'Y',
    'D': '',
    'E': 'O',
    'F': '',
    'G': 'V',
    'H': 'T',
    'I': 'I',
    'J': '',
    'K': 'R',
    'L': 'I',
    'M': 'P',
    'N': 'N',
    'O': 'E',
    'P': 'M',
    'Q': 'L',
    'R': 'K',
    'S': 'Y',
    'T': 'H',
    'U': 'A',
    'V': 'G',
    'W': '',
    'X': '',
    'Y': 'C',
    'Z': '',
    ' ': ' ',
    '0': '0',
    '1': '1',
    '2': '2',
    '3': '3',
    '4': '4',
    '5': '5',
    '6': '6',
    '7': '7',
    '8': '8',
    '9': '9',
}

tamil_script_url = 'https://inputtools.google.com/request?text={text}&itc=ta-t-i0-und'

source_language = 'ta'
target_language = 'ja'

def trans(nunkish):
    tamil = ""
    for char in nunkish:
        if char not in alphabet:
            tamil += char
        else:
            tchar = alphabet[char]
        if tchar:
            tamil += tchar
        else:
            tamil += "?"
    
    print(f"Converted to tamil: {tamil}")
    
    tamil_res = requests.get(tamil_script_url.format(text=tamil), headers={
        'Content-Type': 'application/json'
    }).json()
    
    if (tamil_res[0] == 'SUCCESS'):
        tamil_script = tamil_res[1][0][1][0]
    print(f"In Tamil script: {tamil_script}")
    return translator.translate(f'{tamil_script}', lang_src=
source_language, lang_tgt=target_language)

while True:
    nunkish = input("Input nunkish: ")
    print(f"You entered: {nunkish}")
    print(trans(nunkish.replace('\n', ' ').replace('\r', '')))
---------------------

M5Stick CでWiFiのRSSI表示

先日、WiFi信号の強度が知りたくて、
M5Stick Cを使ってWiFi受信RSSIを表示するスケッチを作りました。
元はこのスケッチです。
元のスケッチは時間と日付を表示するスケッチで、
それを少し改造して、
RSSIも表示するようにしました。
また、OTAアップデートもできるようにしました。

WiFiのSSIDとパスワード、タイムゾーンを入力をconfig.hファイルに以下のように記入しました。
#define TIMEZONE     9
#define WIFI_SSID   "your_wifi_ssid"
#define WIFI_PASSWORD   "your_wifi_password"


ボタンA(M5と書いてあるボタン)を押せば表示のオン・オフが切り替えられます。
ボタンB(上の小さいボタン)を2秒以上長押しすれば時間シンクロが行われます。
 
実際のスケッチは以下です。改造した結果、timeToDoという関数は必要なくなりましたが、そのまま残しました。
-----------------------------------------------------
#include <Arduino.h>
#include <M5StickC.h>
#include <ESPmDNS.h>
#include <WiFi.h>
#include "time.h"
#include "config.h"
#include <ArduinoOTA.h>

// default hostname if not defined in config.h
#ifndef HOSTNAME
  #define HOSTNAME "m5stickc"
#endif

// use the WiFi settings in config.h file
char* ssid       = WIFI_SSID;
char* password   = WIFI_PASSWORD;

// define the NTP server to use
char* ntpServer =  "ntp.nict.jp";

// define what timezone you are in
int timeZone = TIMEZONE * 3600;

// delay workarround
int tcount = 0;

// LCD Status
bool LCD = true;

RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;

//delays stopping usualy everything using this workarround
bool timeToDo(int tbase) {
  tcount++;
  if (tcount == tbase) {
    tcount = 0;
    return true;    
  } else {
    return false;
  }  
}

// Syncing time from NTP Server
void timeSync() {
    M5.Lcd.setTextSize(1);
    Serial.println("Syncing Time");
    Serial.printf("Connecting to %s ", ssid);
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(20, 15);
    M5.Lcd.println("connecting WiFi");
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
    Serial.println(" CONNECTED");
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(20, 15);
    M5.Lcd.println("Connected");
    // Set ntp time to local
    configTime(timeZone, 0, ntpServer);

    // Get local time
    struct tm timeInfo;
    if (getLocalTime(&timeInfo)) {
      // Set RTC time
      RTC_TimeTypeDef TimeStruct;
      TimeStruct.Hours   = timeInfo.tm_hour;
      TimeStruct.Minutes = timeInfo.tm_min;
      TimeStruct.Seconds = timeInfo.tm_sec;
      M5.Rtc.SetTime(&TimeStruct);

      RTC_DateTypeDef DateStruct;
      DateStruct.WeekDay = timeInfo.tm_wday;
      DateStruct.Month = timeInfo.tm_mon + 1;
      DateStruct.Date = timeInfo.tm_mday;
      DateStruct.Year = timeInfo.tm_year + 1900;
      M5.Rtc.SetData(&DateStruct);
      Serial.println("Time now matching NTP");
      M5.Lcd.fillScreen(BLACK);
      M5.Lcd.setCursor(20, 15);
      M5.Lcd.println("S Y N C");
      delay(500);
      M5.Lcd.fillScreen(BLACK);
    }
}

void buttons_code() {
  // Button A control the LCD (ON/OFF)
  if (M5.BtnA.wasPressed()) {
    if (LCD) {
      M5.Lcd.writecommand(ST7735_DISPOFF);
      M5.Axp.ScreenBreath(0);
      LCD = !LCD;
    } else {
      M5.Lcd.writecommand(ST7735_DISPON);
      M5.Axp.ScreenBreath(255);
      LCD = !LCD;
    }
  }
  // Button B doing a time resync if pressed for 2 sec
  if (M5.BtnB.pressedFor(2000)) {
    timeSync();
  }
}

// Printing WiFi RSSI and time to LCD
void doTime() {
  //if (timeToDo(1000)) {
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    M5.Lcd.setCursor(10, 10);
    M5.Lcd.setTextSize(1);
    M5.Lcd.printf("%s: ", WiFi.SSID());
    long strength = WiFi.RSSI();
    if(strength < -70) M5.Lcd.setTextColor(RED, BLACK);
    else if(strength < -60) M5.Lcd.setTextColor(YELLOW, BLACK);
    else M5.Lcd.setTextColor(GREEN, BLACK);
    M5.Lcd.printf("%02d\n", strength);
    M5.Lcd.setTextSize(3);
    M5.Lcd.setTextColor(WHITE, BLACK);
    M5.Rtc.GetTime(&RTC_TimeStruct);
    M5.Rtc.GetData(&RTC_DateStruct);
    M5.Lcd.setCursor(10, 25);
    M5.Lcd.printf("%02d:%02d:%02d\n", RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes, RTC_TimeStruct.Seconds);
    M5.Lcd.setCursor(15, 60);
    M5.Lcd.setTextSize(1);
    M5.Lcd.setTextColor(WHITE, BLACK);
    M5.Lcd.printf("Date: %04d-%02d-%02d\n", RTC_DateStruct.Year, RTC_DateStruct.Month, RTC_DateStruct.Date);
  //}
}

void setup() {
  M5.begin();

  M5.Lcd.setRotation(1);
  M5.Lcd.fillScreen(BLACK);

  M5.Lcd.setTextSize(1);
  M5.Lcd.setTextColor(WHITE,BLACK);
  timeSync(); //uncomment if you want to have a timesync everytime you turn device on (if no WIFI is avail mostly bad)

  // Port defaults to 3232
  // ArduinoOTA.setPort(3232);

  // Hostname defaults to esp3232-[MAC]
  ArduinoOTA.setHostname(HOSTNAME);

  // No authentication by default
  // ArduinoOTA.setPassword("admin");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

  ArduinoOTA
    .onStart([]() {
      String type;
      if (ArduinoOTA.getCommand() == U_FLASH)
        type = "sketch";
      else // U_SPIFFS
        type = "filesystem";

      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
      Serial.println("Start updating " + type);
    })
    .onEnd([]() {
      Serial.println("\nEnd");
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .onError([](ota_error_t error) {
      Serial.printf("Error[%u]: ", error);
      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
      else if (error == OTA_END_ERROR) Serial.println("End Failed");
    });

  ArduinoOTA.begin();
}

void loop() {
  M5.update();
  buttons_code();
  doTime();
  ArduinoOTA.handle();
}
------------------------------------------------------------

2021年1月13日水曜日

新しい生活様式は緊急事態宣言下のみではない

新型コロナウイルス感染症拡大を防止するため、3密を避けることが重要と言われています。
3密とは、
1.密閉空間(換気の悪い密閉空間である)
2.密集場所(多くの人が密集している)
3.密接場面(互いに手を伸ばしたら届く距離での会話や発声が行われる)
のことです。

今の緊急事態宣言は効果あるのか?
 
テレワークへの移行は3密を減らすでしょう。
しかし、テレワークができない業種や会社もあります。
その場合、時間差出勤を推進する必要があります。
 
飲食店の時短営業は確かに夜8時以降の3密を減らしますが、それ以外の時間帯ではさらなる取り組みや工夫が必要です。
例えば、店内の客数制限や、お客様グループの人数制限など。
そうしない限り、同じ密閉空間に多人数が集会し密接することが続きます。
そもそも、人々が大人数で集まらなければの話です。
少人数で時間差をもって飲食店へ行く、食事中も十分な距離をとる。
こうすれば、飲食店も営業し続けられるでしょう。
 
イベントや他の娯楽(スポーツ観戦や映画など)も同じでしょう。
同じ場所に多人数がいるとしても、
しっかりした換気と十分な距離をとることで密閉と密接を防ぐことができます。
換気は場所によって難しい場合もありますが、
距離をとることは主催者や運営者の意志があればできるでしょう。
 
現時点、学校は通常通りです。
同じ場所に数十人が集い、共通な作業(勉強)を行う。
3密を避けるのが難しいと思っても、
まずは換気から始めましょう。
 
そして、一番重要なポイントです。
感染症に勝つためには常に一歩前に歩かなければなりません。
これらの取り組みは、緊急事態宣言が解除されても、ワクチンが普及しない限り、続くべきだと思います。
これが新しい生活様式です。
緊急事態宣言が解除され、また昔のように戻れば、感染は再び広げます。
今まで我慢したこと、努力したこと、意味がなくなります。
そうならないため、解除しても距離をとることが重要です。
個人も企業も、責任を持って距離をとらなければ、
同じことの繰り返しになるだけです。
皆の自覚ある行動で感染症を乗り越えましょう!