ãã¡ãã®èšäºã¯ã MEDLEY Summer Tech Blog Relay ãã®18æ¥ç®ã®èšäºã§ãð ä»é±ã¯FY25æ°åãšã³ãžãã¢ã®4人ãé£ç¶ããŠèšäºããå±ãããŸãïŒ ã¯ããã« æ ªåŒäŒç€Ÿã¡ãã¬ãŒã« 2025 幎 4 æã«æ°åå
¥ç€Ÿãããå¹³æã§ãã å»çãã©ãããã©ãŒã ã®æ¯ç§èšºçæäºæ¥éšã§ãœãããŠã§ã¢ãšã³ãžãã¢ãããŠãããã¯ã©ãŠãæ¯ç§æ¥åæ¯æŽã·ã¹ãã ãDentisããéçºããŠããŸãã çããã¯ç
é¢ãæ¯ç§å»é¢ã§èšºå¯ãåããåŸãçªå£ã§æéãæ¯æã£ãŠãããšæããŸãããåãã®æ¹ãå€ããããããŸããããããã§æãæéã¯å»çæ©é¢ã®åå
¥ã®äžéšã«éããŸããã æ®ãã®èšºçå ±é
¬ã¯æ£è
ãå å
¥ããŠããä¿éºçµåïŒä¿éºè
ïŒããæ¯æãããããšã«ãªã£ãŠãããå»çæ©é¢ã¯æ¯ææ£è
ã«è¡ã£ã蚺çããŸãšããæžé¡ïŒèšºçå ±é
¬è«æ±æžãéç§°ã¬ã»ããïŒãäœæããŠæ¯æåºéïŒåœä¿ã®å Žåã¯åœæ°å¥åº·ä¿éºå£äœé£åäŒïŒã«è«æ±ããŸãã 以äžã¯ã瀟äŒä¿éºã«å å
¥ããŠããæ£è
ã®èšºçå ±é
¬è«æ±ã®æµãã§ãã æ¯æåºéã£ãŠã©ããªãšããïŒïœç€ŸäŒä¿éºèšºçå ±é
¬æ¯æåºé www.ssk.or.jp ãã®ã¬ã»ãããã³ã³ãã¥ãŒã¿ãŒã䜿ã£ãŠèªåã§äœæããŠãããã®ããã¬ã»ããã³ã³ãã¥ãŒã¿ãŒïŒã¬ã»ã³ã³ïŒã§ãã ä»åã¯ããã®ã¬ã»ããã«ã€ããŠåŠç¿ããããã«ãã¬ã»ãããã¥ãŒã¢ãäœã£ãŠã¿ãŸããã ãœãŒã¹ã³ãŒãã¯ä»¥äžã§å
¬éããŠããŸãã GitHub - avaice/dental-uke-reader Contribute to avaice/dental-uke-reader development by creating an account on GitHub. github.com é»åã¬ã»ããã«ã€ã㊠ã¬ã»ããã«ã¯ãçŽã¬ã»ãããšé»åã¬ã»ããã®2çš®é¡ããããŸããå
ã
ã¯çŽã¬ã»ããã®ã¿ã§ããããçŸåšã¯ãããããŒã¿åããé»åã¬ã»ãããäž»æµãšãªã£ãŠããŸãã é»åã¬ã»ããã¯CSVã©ã€ã¯ãªã«ã³ãåºåãã®ãã©ãŒããããšãªã£ãŠãããUKEãšããæ¡åŒµåã§ä¿åãããŸãã 以äžã¯ãäžè¬çãªé»åã¬ã»ããã®äŸã§ããâ»ããŒã¿ã¯æ¶ç©ºã®æ
å ±ã§ã UK,2,13,3,1234567,,ã¡ãã¬ãŒã¯ãªããã¯,202201,0117,00 IR,2,13,3,1234567,,202201,03-1234-5678,0117 RE,4,3318,202112,æ¯ç§ã倪é,1,19400808,,,20210609,1,,,29,,123456/8,,,,,,,,,,ã·ã«ã¿ããŠ, HO,39141320,,ïŒïŒïŒïŒïŒïŒïŒïŒ,2,1279,,,,,,,, JD,1,,,,,,,,1,,,,,,,,,,,,,,1,,,,,,,,, MF,00,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, HS,,,101700101500101400101300101200101100102100102200102300102400102500102600102700104800104500104400104300104200104100103100103200103300103400103500103700,5234009,,,,,,,, SS,12,1,301001610,,,CA062,,CA045,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,57,2,,,,,,,,1,,,,,,,,,,,,,,1,,,,,,,,, (...以äžçç¥) GO,116,155332,99 äžèŠããããããªãããŒã¿ã§ããã瀟äŒä¿éºèšºçå ±é
¬æ¯æåºéã®WebããŒãžã«ã¯ããªã³ã©ã€ã³åã¯å
ãã£ã¹ã¯çã«ãã è«æ±ã«ä¿ãèšé²æ¡ä»¶ä»æ§ïŒæ¯ç§çšïŒãïŒä»¥äžã仿§æžïŒãå
¬éãããŠããã®ã§ããããèŠãªããèªã¿é²ããŠãããŸãã é»åã¬ã»ããã®äœæïœç€ŸäŒä¿éºèšºçå ±é
¬æ¯æåºé www.ssk.or.jp 1åç®ã«ã¯ãUKããšæžããŠãããŸããããã¯ã¬ã³ãŒãè奿
å ±ã§ãã ã¬ã³ãŒãè奿
å ±ã®äžèЧã¯ã以äžã®ãšããã§ãã å€ ã¬ã³ãŒãã®çš®é¡ ããŒã¿ã®äžäŸ UK å仿
å ±ã¬ã³ãŒã å¯©æ»æ¯ææ©é¢ã»å»çæ©é¢ã³ãŒãã»éœéåºçãªã© IR å»çæ©é¢æ
å ±ã¬ã³ãŒã å»çæ©é¢ã³ãŒãã»é£çµ¡å
ã»è«æ±å¹Žæãªã© RE ã¬ã»ããå
±éã¬ã³ãŒã æ£è
ïŒè¢«ä¿éºè
ïŒã®ååã»æ§å¥ãªã© HO ä¿éºè
ã¬ã³ãŒã ä¿éºè
çªå·ã»åèšç¹æ°ãªã© KO å
¬è²»ã¬ã³ãŒã è² æ
è
çªå·å
¬è²»è² æ
è
çªå·ãªã© SN è³æ Œç¢ºèªã¬ã³ãŒã è² æ
è
çš®å¥ãå絊è
çªå·ãªã© JD å蚺æ¥çã¬ã³ãŒã æ¥å¥ã®å蚺çåºåãªã© MF çªå£è² æ
é¡ã¬ã³ãŒã é«é¡çé€è²»ã®æ±ããªã© HS å·ç
åéšäœã¬ã³ãŒã å·ç
åã³ãŒãã»éšäœã® æ¯åŒã³ãŒã ãªã© SS æ¯ç§èšºçè¡çºã¬ã³ãŒã 蚺çèå¥ã»æ¯ç§èšºçè¡çºã³ãŒããªã© SI 蚺çè¡çºã¬ã³ãŒã å»ç§èšºçè¡çºã³ãŒããªã© IY å»è¬åã¬ã³ãŒã 蚺çã§äœ¿çšããå»è¬åã»é¢å
ã§åŠæ¹ããå»è¬åãªã© TO ç¹å®åšæã¬ã³ãŒã ç¹å®åšæã³ãŒããªã© CO ã³ã¡ã³ãã¬ã³ãŒã 蚺çèå¥ã»ã³ã¡ã³ãã³ãŒããªã© SJ çç¶è©³èšã¬ã³ãŒã çç¶è©³èšïŒèšºçå
容ãæç¢ºã§ãªãå Žåãªã©ã«èšé²ããïŒãªã© GO 蚺çå ±é
¬è«æ±æžã¬ã³ãŒã ç·ä»¶æ°ãªã© ãã®å€ã«ãã£ãŠãã®è¡ãã©ããªæ
å ±ãå«ãã§ããã®ãå€å¥ããããšãã§ããŸãã ä»åã¯UKïŒå仿
å ±ã¬ã³ãŒãïŒã ãèŠãŠã¿ãŸãããã仿§æžãšç
§ããåããããšã以äžã®å
容ã§ããããšãåãããŸãã å€ èª¬æ åè 1 å¯©æ»æ¯ææ©é¢ 1: 瀟äŒä¿éºèšºçå ±é
¬æ¯æåºéã2: åœæ°å¥åº·ä¿éºå£äœé£åäŒ 13 éœéåºçã³ãŒã ç·åçãå®ããéœéåºçã³ãŒã( URL ) 16: å¯å±±ç 3 ç¹æ°è¡šçš®å¥ ç¹æ°è¡šçš®å¥ 3: æ¯ç§ ä»ã«ãã1: å»ç§, 4: 調å€ãªã© 1234567 å»çæ©é¢ã³ãŒã å»çæ©é¢ã³ãŒã (空æ¬) äºåãšãªã¢ ã¡ãã¬ãŒã¯ãªããã¯ å°æ¹åçïŒæ¯ïŒå±é·ã«å±ãåºãåç§° 20æåãè¶
ããå Žåã¯ã決ãŸã£ãŠããçç¥åç§°ã«ãªã 202201 è«æ±å¹Žæ ã¬ã»ãããè«æ±ããã幎æãäŸ: 2022幎1æ 0117 æœèšåºæºå±åºã³ãŒã 2æååºåãã§è§£éãããã01:è£ç®¡ïŒã¯ã©ãŠã³ã»ããªããžç¶æç®¡çæïŒ17:æ¯ç§å蚺æ 00 ãã«ãããªã¥ãŒã è奿
å ± ãããããŒãã£ã¹ã¯ãªã©å®¹éã®å°ãªãåªäœã䜿çšããéãã¬ã»ããæ
å ±ãè€æ°ã®ãã¡ã€ã«ã«åå²ãããŠããå Žåã«ããã®ãã¡ã€ã«ã®é çªã瀺ã ãã®ãããªåœ¢ã§åè¡ãèªãã§ãããšãé»åã¬ã»ããã瀺ããŠããå
容ãåãããŸãã ã¬ã»ããã®èªã¿æ¹ããªããšãªãåãã£ãã®ã§ã次ã¯å®éã«ãããèªã¿èŸŒãããã°ã©ã ãäœããŸãã CSVãèªã¿èŸŒãã§ããŒã¹ãã é»åã¬ã»ããã¯Shift-JISã§èšé²ãããŠããã®ã§ãæåã³ãŒããæå®ããŠèªã¿èŸŒã¿ãŸãã const loadFile = ( file ) => new Promise (( resolve , reject ) => { const reader = new FileReader (); reader . onload = ( e ) => { const text = e . target ?. result ; if ( typeof text !== "string" ) { reject ( new Error ( "Failed to load the file" )); return ; } resolve ( text ); }; reader . onerror = () => { reject ( new Error ( "Failed to read the file" )); }; reader . readAsText ( file , "shift-jis" ); }); èªã¿èŸŒãã ããšã¯ãUKEããŒã¿ãããŒã¹ããŸãã CSVã®ããŒã¹ã¯èæ
®ããããšãå€ããšã³ãžãã¢æ³£ããã§æåã§ãããUKEã®ä»æ§ã¯éåžžã«ã·ã³ãã«ãªã®ã§ç°¡åã«ããŒã¹ã§ããŸãã ïŒä»¥äžã¯ãäžéšæç²ã§ãïŒ ç¬Šå·åç§° å³åœ¢èšå· çšé ã³ã³ã , é
ç®ã®åºåãã衚çŸãã åŒçšç¬Š " 䜿çšããªã æ¹è¡ã³ãŒã \n ã¬ã³ãŒãã®åºåãã衚çŸãã const csv = await loadFile ( file ); const receipts = csv . trim () . split ( " \n " ) . map (( line ) => line . split ( "," )); é
ç®ã®èª¬æã衚瀺ãã è¡ããšã®ã¬ã³ãŒããšåçªå·ãæž¡ããšèª¬æãè¿ã£ãŠããããžãã¯ãäœããŸãã 説ææ
å ±ã¯ã瀟äŒä¿éºèšºçå ±é
¬æ¯æåºéã®WebããŒãžã«å
¬éãããŠãããé»åã¬ã»ããã®äœææåŒãããåèã«ããŸãã ãé»åã¬ã»ããã®äœææåŒããã¯PDFã§å
¬éãããŠããããŒã¿ã§ããã markitdown ã䜿ã£ãŠããŒã¯ããŠã³ã«å€æãäœæ¥ã¹ããŒã¹ã«çœ®ãããšã§ãCursorãClaude Codeãšãã£ãéçºæ¯æŽããŒã«ã掻çšããŠå¹ççã«å®è£
ãé²ããããšãã§ããŸããã GitHub - microsoft/markitdown: Python tool for converting files and office documents to Markdown. Python tool for converting files and office documents to Markdown. - microsoft/markitdown github.com export type RecordType = { index : number ; data : string []; }; export const explain = ( record : RecordType ) => { switch ( record . identification ) { case "UK" : return explainUK ( record ); case "IR" : return explainIR ( record ); // ...çç¥ default : return null ; } }; å€ã«ãã£ãŠèª¬æãå€ããå
容ãããã®ã§ãåçã«èª¬ææãäœããããã«ããŸããã const explainUK : ((( record : RecordType ) => string ) | string )[] = [ "ãã®è¡ãå仿
å ±ã¬ã³ãŒãã§ããããšã瀺ããŸã" , ( record ) => `å¯©æ»æ¯ææ©é¢ã瀺ããŸããå€ã ${ record . data [ record . index ] } ãã¯ã ${ getShiharaiKikan ( record . data [ record . index ]) } ãã§ã` , // ...çç¥ ]; ãã¹ã¿ãŒãã¡ã€ã«ããæ
å ±ãååŸãã UKEã®äžã«ã¯ãã®ãŸãŸè§£éã§ããå
容ã ãã§ãªãã蚺çè¡çºã³ãŒããå»è¬åã³ãŒãã®ãããªå¥ã®ããŒã¿ïŒãã¹ã¿ãŒãã¡ã€ã«ïŒãåç
§ããªããšå
容ãããããªããã®ããããŸãã ãã¹ã¿ãŒãã¡ã€ã«ã仿§ã¯ãåçåŽåçãWebã§å
¬éããŠãããŠããŸãã 蚺çå ±é
¾
å ±æäŸãµãŒãã¹ shinryohoshu.mhlw.go.jp ãã¹ã¿ãŒãã¡ã€ã«ã¯é»åã¬ã»ãããšä»æ§ã®éãCSVã§ã以äžã®ãããªä»æ§ã«ãªã£ãŠããŸãã é
ç®éã®åºåãæåã¯ã,ãïŒã«ã³ãïŒãšããã åé
ç®ã®å€ã¯ãã¢ãŒãïŒãæ°åãããè±æ°ãåã³ã挢åãïŒã«é¢ããããåŒçšç¬ŠãâãïŒããã«ã¯ã©ãŒããŒã·ã§ã³ïŒãååŸã«ä»ãã æå€§ãã€ãã¯åŒçšç¬Šãâããé€ãããã€ãæ°ã§ãããå°æ°éšãããå€ã¯ãå°æ°ç¹åã³å°æ°ä»¥éã®æ°åãå«ãã ïŒãã€ãã®æååïŒNullïŒã®å Žåã¯ãåŒçšç¬Šãâããç¶ããŠèšé²ããã å€ãããã«ã¯ã©ãŒããŒã·ã§ã³ã§å²ããšã®ããšãªã®ã§ãå€ã®äžã®ã«ã³ãã蚱容ãã仿§ã§ããå¯èœæ§ããããŸããæçŽã«1æåãã€åŠçããŸãã // const csv = çã®CSVããŒã¿; const lines = csv . split ( " \n " ); const records : Record < string , string >[] = []; const shobyomeiMasterHeaders = [ "倿Žåºå" , "ãã¹ã¿ãŒçš®å¥" , "å·ç
åã³ãŒã" , /** 以äžçç¥... */ ]; for ( const line of lines ) { const record : Record < string , string > = {}; let charIndex = 0 ; let columnIndex = 0 ; let inQuotes = false ; let buffer = "" ; while ( charIndex < line . length ) { const char = line [ charIndex ]; if ( char === '"' ) { inQuotes = ! inQuotes ; } else if ( char === ',' && ! inQuotes ) { // ã«ã³ãåºåãããã€åŒçšç¬Šã®å€ record [ shobyomeiMasterHeaders [ columnIndex ]] = buffer ; columnIndex ++; buffer = "" ; } else { // ãã以å€ã¯ãããã¡ã«è¿œå buffer += char ; } charIndex ++; } if ( buffer . length > 0 ) { record [ shobyomeiMasterHeaders [ columnIndex ]] = buffer ; } // ããŒã¿ããŒã¹ãžã®ä¿å await saveToDatabase ( "shobyomei" , record . å·ç
åã³ãŒã , [ record ]); } ãã¹ã¿ãŒãã¡ã€ã«ã¯å
šéšã§20MBçšåºŠãããæ¯ååŠçããŠãããæéãããã£ãŠããŸãã®ã§ãindexedDBã«å±éããŸããã ããã§ã蚺çè¡çºã³ãŒããå»è¬åã³ãŒããåºã«ãã¹ã¿ãŒã®å
容ãåç
§ã§ããããã«ãªããŸããã ããã§äžã€æ°ãã€ããªããã°ãããªãã®ã¯ãå»è¬åã³ãŒãã®æ
å ±ã«ã¯æå¹æéããããšããããšã§ãã 該åœããã¬ã³ãŒãã®èšºçæ¥ãã倿Žå¹Žææ¥ã廿¢å¹Žææ¥ã®éã§ããããšã確èªããå¿
èŠããããŸããäŸãã°2015幎ã®ã¬ã»ããããæ
å ±ãåŸããã®ã§ããã°ã2015幎æç¹ã®ãã¹ã¿ãŒãã¡ã€ã«ãåç
§ããå¿
èŠããããŸãã ãã®ãããæç³»åã«åã£ãè€æ°ããŒãžã§ã³ã®ãã¹ã¿ãŒãä¿æã§ããèšèšã«ããããã«ãããŒã«å¯ŸããŠããŒã¿ã¯é
åã§æã€ããã«ããŸããã 衚ãšããŠã¬ã³ããªã³ã°ãã UKEã®ããŒãµãŒãšæ
å ±ã®ååŸåŠçãæžããã®ã§ã衚ãšããŠã¬ã³ããªã³ã°ããŸãã type CellPosition = { x : number ; y : number }; const UKERenderer = ({ uke }: { uke : string [][] }) => { const [ activeCell , setActiveCell ] = useState < CellPosition | null >( null ); const handleClickCell = ( x : number , y : number ) => setActiveCell ({ x , y }); const isActiveCell = ( x : number , y : number ) => activeCell && activeCell . x === x && activeCell . y === y ; return uke . map (( row , y ) => ( < Row key = { `row- ${ y } ` } > { row . map (( value , x ) => ( < Cell key = { `cell- ${ x } ` } onClick = { () => handleClickCell ( x , y ) } active = { isActiveCell ( x , y ) } description = { explain ({ index: x , data: row }) } > { value } </ Cell > )) } </ Row > )); }; å®éã«éçºãããã® å®éã«éçºãããã®ã¯ãä»ãŸã§è§£èª¬ããã³ãŒããããŒã¹ã«æ©èœãåŠçãä»ãå ããŠããŸãã éçºããŠã¿ãР以åã¯ãããã¹ããšãã£ã¿ãŒã䜿ã£ãŠç®èŠã§ãã¹ã¿ãŒãã¡ã€ã«ã®å
容ãç
§ããåãããŠãã確èªäœæ¥ã倧å€ã§ããããä»åäœã£ãé»åã¬ã»ãããã¥ãŒã¢ã«ãã£ãŠãæ£ããã¬ã»ãããåºåãããŠãããã®ç¢ºèªãè¡ãããããªããŸããã ãŸããèªåèªèº«ãé»åã¬ã»ããã®ä»æ§ãåŠãã ããšã§ãæ¥åã§è¡ã£ãŠããããšãå°ããã€åããããã«ãªã£ãŠããŸããïŒ ãããã« ä»åã¯ãæ¯ç§ã®é»åã¬ã»ãããçè§£ããããã«ãé»åã¬ã»ãããã¥ãŒã¢ãéçºããŸããã ç§ãã¡ãœãããŠã§ã¢ãšã³ãžãã¢ã¯ãæ®æ®µå»çã«é¢ããã·ã¹ãã ã®è©±ãããŸãç®ã«ããããšã¯å°ãªãã§ãããæå€ãšä»æ§ãããŒã¿ãäžè¬ã«ãå
¬éãããŠãããæè»œã«è§ŠããŠã¿ãããšãã§ããŸãã ãã®èšäºãèªãã§ãå»çITã«èå³ãæã£ãŠãã ããæ¹ãããã°å¹žãã§ãïŒ æ¬¡ã¯ãæ°åãšã³ãžãã¢4人ç®ã®æ± ç°ããã§ãïŒã楜ãã¿ã«ïŒïŒ