Jupter의 확장 기능을 해봤어요.

개시하다


주피터를 자주 사용하지만 가끔'이런 기능이 있었으면 좋겠다'고 생각할 때가 있다.
"그럼 혼자 하면 되잖아요."그래서 Jupter의 확장 기능을 해 봤어요.
전방에서 서버 처리까지, Jupter의 확장 기능은 광범위하게 덮어쓸 수 있을 것 같지만, 이번에는 비교적 간단한 전방 처리만 했다.
설치에 관해서는 매우 참고 가치가 있다.

창설했어


은 셀 실행이 끝나면 사운드 알림을 보낼 수 있는 확장 기능입니다.
집행이 끝나는 시간이 너무 낭비돼 휴대전화를 보면서 다른 일을 하다 보니 어느새 실행이 끝나 슬프다.나는 그런 사람을 구하고 싶다.
물론입니다. ON/OFF, ON은 두 가지 모드가 있습니다.
  • 단일 단지 알림 모드
    칸이 실행되지 않을 때 단추를 누르면 이 모드는 ON이 되고 단추는 파란색이 됩니다.
    이 모드에서는 다음 칸의 처리가 끝난 후에 소리가 납니다.

  • 다중 단위 알림 모드
    여러 셀을 실행하는 동안 버튼을 누르면 모드는 ON, 버튼은 주황색으로 바뀝니다.이 모드에서는 현재 실행 중인 칸 처리가 끝났을 때 소리가 납니다.

    이미 발포되었기 때문에 아래 명령으로 설치할 수 있습니다.
  • pip install cell-executed-alert
    
    요구사항은 3.0이지만 만족해도 반영되지 않을 수도 있다.
    또한 Jupter notebook과colab notebook에는 반영되지 않았습니다.

    생성 방법


    typescript의 jupter 확장 기능 샘플가 공개돼 이를 바탕으로 제작됐다.jupyterlab>=3.0,node,npm,git,cookiecutter,jupyter_contrib_nbextensions 등이 필요하므로 사전 설치를 권장합니다.
    우선 cookiecutter로 확장 기능을 만드는 프로젝트입니다.
    cookiecutter https://github.com/jupyterlab/extension-cookiecutter-ts
    
    이때 다양한 입력이 필요합니다.labextensionname(확장자)만 채우면 나머지 Enter는 문제가 없습니다.
    를 입력하면 확장자 폴더가 생성됩니다.이 폴더에 확장자를 만듭니다.
    myextension
    ├─.github
    │  └─workflows
    ├─myextension
    ├─src
    └─style
    
    src 폴더에서 typescript를 스타일에 css를 기술하면 됩니다.
    이번에 다음 세 가지 문건을 변경했다.
    src/index.ts
    import {
      JupyterFrontEnd,
      JupyterFrontEndPlugin
    } from '@jupyterlab/application';
    
    import {INotebookTracker} from "@jupyterlab/notebook";
    
    // button.tsからButtonExtensionクラスをimport
    import {ButtonExtension}  from "./button";
    
    const plugin: JupyterFrontEndPlugin<void> = {
      id: 'cell-executed-alert:plugin',
      autoStart: true,
      activate: (app: JupyterFrontEnd, tracker: INotebookTracker) => {
        let buttonExtension = new ButtonExtension();
        app.docRegistry.addWidgetExtension('Notebook', buttonExtension);
      }
    };
    
    export default plugin;
    
    src/button.ts
    import {ToolbarButton} from "@jupyterlab/apputils";
    import {DocumentRegistry} from "@jupyterlab/docregistry";
    import {NotebookActions, INotebookModel, NotebookPanel} from "@jupyterlab/notebook";
    import {IDisposable} from "@lumino/disposable";
    
    export class ButtonExtension implements DocumentRegistry.IWidgetExtension<NotebookPanel, INotebookModel> {
        
      // 単一セル通知モードのフラグ
      public flag: boolean;
      // 複数セル通知モードのフラグ
      public all_flag: boolean;
    
      constructor() {
          this.flag = false;
          this.all_flag = false;
      }
    
      createNew(panel: NotebookPanel, context: DocumentRegistry.IContext<INotebookModel>): IDisposable {
        //base64コマンドで生成した音声ファイル。""の中に音声をエンコードした文字列が入るが長いので省略。
        const base64 = ""
    
        //Audioオブジェクトを生成
        const audio = new Audio("data:audio/wav;base64," + base64);
    
        const mybutton = new ToolbarButton({
            //label: 'Alert',
            className: 'alertButton',
            iconClass: 'fa fa-bell',
    	// クリック時の処理を記述
            onClick: () => {
    	    // アラートがOFFの場合
                if(this.flag==false && this.all_flag==false){
                  let cells = document!.querySelectorAll('.jp-InputArea-prompt');
                  let execution_count = 0;
                  for (const cell of cells) {
    	        // 現在実行中のセルの数をカウント
                    if(cell!.innerHTML == '[*]:'){
                      execution_count += 1;
                    }
                  }
    	      // 複数のセルが実行中の場合
    	      // CSSを変更(オレンジ)し,複数セル通知モードON
                  if(execution_count > 1){
                      document!.querySelector('.alertButton')!.classList!.replace('alertButton', 'alertButton-all-active');
                      this.all_flag = true;
                  }
    	      // 1つのセルが実行中,もしくは実行中のセルがない場合
    	      // CSSを変更(青色)し,単一セル通知モードON
                  else{
                      document!.querySelector('.alertButton')!.classList!.replace('alertButton', 'alertButton-active');
                      this.flag = true;
                  }
                 
    	     // セルの実行が終わった際に呼び出される関数
                  NotebookActions.executed.connect((_, action) => {
    	        // 単一セル通知モード:CSSを元に戻し,単一セル通知モードOFF
                    if(this.flag==true){
                        audio.play();
                        //alert('セルの実行が終了しました');
                        this.flag = false;
                        document!.querySelector('.alertButton-active')!.classList!.replace('alertButton-active', 'alertButton');
                    }
    		// 複数セル通知モード:実行中のセルがなければCSSを元に戻し,複数セル通知モードOFF
                    if(this.all_flag==true){
                        let cells = document!.querySelectorAll('.jp-InputArea-prompt');
                        let execution_count = 0;
                        for (const cell of cells) {
                          if(cell!.innerHTML == '[*]:'){
                            execution_count += 1;
                          }
                        }
                        if(execution_count == 0){
                          audio.play();
                          //alert('セルの実行が終了しました');
                          this.all_flag = false;
                          document!.querySelector('.alertButton-all-active')!.classList!.replace('alertButton-all-active', 'alertButton');
                        }
                    }
                  });
                }else{
    	      // アラートがONの場合にもう一度押すとOFFにする
                  if(this.flag){
                    this.flag = false;
                    document!.querySelector('.alertButton-active')!.classList!.replace('alertButton-active', 'alertButton');
                  }
                  if(this.all_flag){
                    this.all_flag = false;
                    document!.querySelector('.alertButton-all-active')!.classList!.replace('alertButton-all-active', 'alertButton');
                  }
                  NotebookActions.executed.connect((_, action) => {
                  });
                }
            },
            tooltip: 'Alert'
        });
    
        // ツールバーにボタンを追加
        panel.toolbar.insertItem(10, 'alertButton', mybutton);
    
        return mybutton;
      }
    }
    
    style/bace.css
    .alertButton.jp-Button.minimal .jp-Icon {
        color: gray;
    }
    .alertButton-active.jp-Button.minimal .jp-Icon {
        color: #39a9d6;
    }
    .alertButton-all-active.jp-Button.minimal .jp-Icon {
        color: #f37726;
    }
    
    파일의 기술에서 기존 라이브러리의 import을 추가할 때가 있습니다.
    확장 폴더에서 다음 명령을 실행해야 합니다.
    // 例)import {INotebookTracker} from "@jupyterlab/notebook";を記述した場合
    jlpm add @jupyterlab/notebook
    
    확장에 필요한 파일을 한 번 완성하면 확장을 build로 진행합니다.처음build은 다음 명령을 계속 실행합니다.
    // lockファイルの生成
    jlpm
    // 拡張機能のbuild
    jlpm build
    
    build 이후 확장을 다시 변경할 때 기존 라이브러리의 import을 추가하면 다시 실행합니다 jlpm.이때lock 파일을 미리 삭제합니다.
    import이 따로 추가되지 않은 경우 jlpm build만 실행하면 됩니다.
    순조롭게build에 성공하면 jupter lab에 확장 기능을 설치할 수 있습니다.
    jupyter labextension link .
    jupyter labextension develop --overwrite .
    
    이렇게 확장하면 기능이 완성됩니다.Jupter lab을 시작해서 확인해 보세요.
    또한 다음 명령으로 만든 확장자가 설치되어 있는지 확인할 수 있습니다.
    jupyter labextension list
    

    끝말


    주피터의 확장 기능을 만들어 보세요!그렇게 생각하지만 일본어의 문장은 전혀 참고 가치가 없고 공식 문서를 찾고 싶어도 정보를 정리하지 못했다는 인상을 준다.
    이렇게 말하지만 해보면 재밌어요. 확장기능 개발도 더 뜨거워야 한다고 생각해요.이것은 졸렬한 보도인데, 만약 도움을 줄 수 있다면 정말 좋겠다.
    이번에 전단에서 완결된 확장 기능을 제작했지만 이번 방법을 응용해 서버 측과 합작하여 처리할 수 있다.앞으로도 그거에 힘쓰고 싶어요.
    안녕히 계세요.

    좋은 웹페이지 즐겨찾기