Help
RSS
API
Feed
Maltego
Contact
Domain > taro.hatenablog.jp
×
More information on this domain is in
AlienVault OTX
Is this malicious?
Yes
No
DNS Resolutions
Date
IP Address
2015-01-19
54.64.13.59
(
ClassC
)
2026-02-05
3.175.34.33
(
ClassC
)
Port 80
HTTP/1.1 301 Moved PermanentlyServer: CloudFrontDate: Thu, 05 Feb 2026 19:55:29 GMTContent-Type: text/htmlContent-Length: 167Connection: keep-aliveLocation: https://taro.hatenablog.jp/X-Cache: Redirect from cloudfrontVia: 1.1 0f2e998c974188ba76236f3dadfba890.cloudfront.net (CloudFront)X-Amz-Cf-Pop: HIO52-P3X-Amz-Cf-Id: ymZYh0y-7eGnXPoTS4oyfrrWyE5kv5XMVxE2dApwLeMfQRi-dp58Eg html>head>title>301 Moved Permanently/title>/head>body>center>h1>301 Moved Permanently/h1>/center>hr>center>CloudFront/center>/body>/html>
Port 443
HTTP/1.1 200 OKContent-Type: text/html; charsetutf-8Transfer-Encoding: chunkedConnection: keep-aliveServer: nginxDate: Thu, 05 Feb 2026 19:55:29 GMTCache-Control: privateX-Proxy-Revision: f9947fdf1627a1d1b3c8c87a6a5233f9cd465c93Vary: Accept-EncodingVary: X-Epic-Device-Type,X-Epic-Flag-Variants,Accept-EncodingAccess-Control-Allow-Origin: *Content-Security-Policy: frame-ancestors none; upgrade-insecure-requestsContent-Security-Policy-Report-Only: block-all-mixed-content; report-uri https://blog.hatena.ne.jp/api/csp_reportP3P: CPOTI CUR OUR BUS STAX-Cache-Only-Varnish: 1X-Content-Type-Options: nosniffX-Dispatch: Hatena::Epic::Web::Blogs::Index#indexX-Frame-Options: DENYX-Revision: f9947fdf1627a1d1b3c8c87a6a5233X-XSS-Protection: 1X-Runtime: 0.139120X-Varnish: 23274737 342611Via: 1.1 ip-10-1-13-194.ap-northeast-1.compute.internal (Varnish/7.6), 1.1 807ba99de77a37a6a53c93279fb231fe.cloudfront.net (CloudFront)Strict-Transport-Security: max-age2592000;X-Cache: Miss from cloudfrontX-Amz-Cf-Pop: HIO52-P3X-Amz-Cf-Id: vp2fWRhVzS_k2-JTi57ixPS_WzFVBsMz3Vbi6KifII185YbOe61qigAge: 3427 !DOCTYPE html>html langjadata-admin-domain//blog.hatena.ne.jpdata-admin-originhttps://blog.hatena.ne.jpdata-authorngsw_tarodata-avail-langsja endata-blogtaro.hatenablog.jpdata-blog-hosttaro.hatenablog.jpdata-blog-is-public1data-blog-name算譜王におれはなる!!!!data-blog-ownerngsw_tarodata-blog-show-ads1data-blog-show-sleeping-adsdata-blog-urihttps://taro.hatenablog.jp/data-blog-uuid13208692334729901135data-blogs-uri-basehttps://taro.hatenablog.jpdata-brandhatenablogdata-data-layer{"hatenablog":{"admin":{},"analytics":{"brand_property_id":"","measurement_id":"","non_sampling_property_id":"","property_id":"","separated_property_id":"UA-29716941-21"},"blog":{"blog_id":"13208692334729901135","content_seems_japanese":"true","disable_ads":"","enable_ads":"true","enable_keyword_link":"true","entry_show_footer_related_entries":"true","force_pc_view":"false","is_public":"true","is_responsive_view":"false","is_sleeping":"false","lang":"ja","name":"\u7b97\u8b5c\u738b\u306b\u304a\u308c\u306f\u306a\u308b!!!!","owner_name":"ngsw_taro","uri":"https://taro.hatenablog.jp/"},"brand":"hatenablog","page_id":"index","permalink_entry":null,"pro":"free","router_type":"blogs"}}data-devicepcdata-dont-recommend-profalsedata-global-domainhttps://hatena.blogdata-globalheader-colorbdata-globalheader-typepcdata-has-touch-view1data-help-urlhttps://help.hatenablog.comdata-pageindexdata-parts-domainhttps://hatenablog-parts.comdata-plus-availabledata-profalsedata-router-typeblogsdata-sentry-dsnhttps://03a33e4781a24cf2885099fed222b56d@sentry.io/1195218data-sentry-environmentproductiondata-sentry-sample-rate0.1data-static-domainhttps://cdn.blog.st-hatena.comdata-versionf9947fdf1627a1d1b3c8c87a6a5233 data-initial-state{} > head prefixog: http://ogp.me/ns# fb: http://ogp.me/ns/fb#> meta nameviewport contentwidthdevice-width, initial-scale1.0 /> meta namerobots contentmax-image-preview:large /> meta charsetutf-8/> meta http-equivX-UA-Compatible contentIE7; IE9; IE10; IE11 /> title>算譜王におれはなる!!!!/title> link relcanonical hrefhttps://taro.hatenablog.jp//> meta itempropname content算譜王におれはなる!!!!/> meta itempropimage contenthttps://cdn.blog.st-hatena.com/images/theme/og-image-1500.png/> meta propertyog:title content算譜王におれはなる!!!!/>meta propertyog:type contentblog/> meta propertyog:url contenthttps://taro.hatenablog.jp//> meta propertyog:image contenthttps://cdn.blog.st-hatena.com/images/theme/og-image-1500.png/>meta propertyog:image:alt content算譜王におれはなる!!!!/> meta propertyog:description content偏りはあると思うけど情報技術全般についてマイペースに書くよ。 />meta propertyog:site_name content算譜王におれはなる!!!!/> meta nametwitter:card contentsummary_large_image /> meta nametwitter:image contenthttps://cdn.blog.st-hatena.com/images/theme/og-image-1500.png /> meta nametwitter:title content算譜王におれはなる!!!! /> meta nametwitter:description content偏りはあると思うけど情報技術全般についてマイペースに書くよ。 /> meta nametwitter:app:name:iphone contentはてなブログアプリ /> meta nametwitter:app:id:iphone content583299321 /> meta nametwitter:app:url:iphone contenthatenablog:///open?urihttps%3A%2F%2Ftaro.hatenablog.jp%2F /> meta nametwitter:site content@ngsw_taro /> meta namekeywords contentKotlin /> script idembed-gtm-data-layer-loader data-data-layer-page-specific>(function() { function loadDataLayer(elem, attrName) { if (!elem) { return {}; } var json elem.getAttribute(attrName); if (!json) { return {}; } return JSON.parse(json); } var globalVariables loadDataLayer( document.documentElement, data-data-layer ); var pageSpecificVariables loadDataLayer( document.getElementById(embed-gtm-data-layer-loader), data-data-layer-page-specific ); var variables globalVariables, pageSpecificVariables; if (!window.dataLayer) { window.dataLayer ; } for (var i 0; i variables.length; i++) { window.dataLayer.push(variablesi); }})();/script>!-- Google Tag Manager -->script>(function(w,d,s,l,i){wlwl||;wl.push({gtm.start:new Date().getTime(),event:gtm.js});var fd.getElementsByTagName(s)0,jd.createElement(s),dll!dataLayer?&l+l:;j.asynctrue;j.srchttps://www.googletagmanager.com/gtm.js?id+i+dl;f.parentNode.insertBefore(j,f);})(window,document,script,dataLayer,GTM-P4CXTW);/script>!-- End Google Tag Manager --> link relshortcut icon hrefhttps://taro.hatenablog.jp/icon/favicon>link relapple-touch-icon hrefhttps://taro.hatenablog.jp/icon/touch>link relicon sizes192x192 hrefhttps://taro.hatenablog.jp/icon/link> link relalternate typeapplication/atom+xml titleAtom hrefhttps://taro.hatenablog.jp/feed/>link relalternate typeapplication/rss+xml titleRSS2.0 hrefhttps://taro.hatenablog.jp/rss/> link relauthor hrefhttp://www.hatena.ne.jp/ngsw_taro/> link relstylesheet typetext/css hrefhttps://cdn.blog.st-hatena.com/css/blog.css?versionf9947fdf1627a1d1b3c8c87a6a5233/> link relstylesheet typetext/css hrefhttps://usercss.blog.st-hatena.com/blog_style/13208692334729901135/0a4dae50ecd0ed3b656649ea731ee445b661ab5b/> script> /script> style> div#google_afc_user, div.google-afc-user-container, div.google_afc_image, div.google_afc_blocklink { display: block !important; }/style> script srchttps://cdn.pool.st-hatena.com/valve/valve.js async>/script>script idtest-valve-definition> var valve window.valve || ; valve.push(function(v) { v.config({ service: blog, content: { result: adtrust, documentIds: blog:entry:17179246901335132652,blog:entry:6802418398312577694,blog:entry:26006613762769542,blog:entry:26006613710632877 } }); v.defineDFPSlot({lazy:1,sizes:{mappings:320,568,336,280,300,250,fluid,0,0,300,250},slotId:ad-in-entry,unit:/4374287/blog_pc_entry_sleep_in-article}); v.defineDFPSlot({lazy:,sizes:300,250,336,280,468,60,fluid,slotId:google_afc_user_container_0,unit:/4374287/blog_user}); v.defineDFPSlot({lazy:,sizes:300,250,336,280,468,60,fluid,slotId:google_afc_user_container_1,unit:/4374287/blog_user_2nd}); v.defineDFPSlot({lazy:,sizes:300,250,336,280,468,60,fluid,slotId:google_afc_user_container_2,unit:/4374287/blog_user_2nd}); v.defineDFPSlot({lazy:1,sizes:300,250,336,280,468,60,fluid,slotId:google_afc_user_container_3,unit:/4374287/blog_user_2nd}); v.sealDFPSlots(); });/script> script typeapplication/ld+json>{@context:https://schema.org,@type:WebSite,name:算譜王におれはなる!!!!,url:https://taro.hatenablog.jp/}/script> /head> body classpage-index globalheader-ng-enabled> div idglobalheader-container data-brandhatenablog > iframe idglobalheader height37 frameborder0 allowTransparencytrue>/iframe>/div> nav class blog-controlls > div classblog-controlls-blog-icon> a hrefhttps://taro.hatenablog.jp/> img srchttps://cdn.blog.st-hatena.com/images/admin/blog-icon-noimage.png alt算譜王におれはなる!!!!/> /a> /div> div classblog-controlls-title> a hrefhttps://taro.hatenablog.jp/>算譜王におれはなる!!!!/a> /div> a hrefhttps://blog.hatena.ne.jp/ngsw_taro/taro.hatenablog.jp/subscribe?utm_mediumbutton&utm_sourceblogs_topright_button&utm_campaignsubscribe_blog classblog-controlls-subscribe-btn test-blog-header-controlls-subscribe> 読者になる /a> /nav> div idcontainer> div idcontainer-inner> header idblog-title data-brandhatenablog> div idblog-title-inner > div idblog-title-content> h1 idtitle>a hrefhttps://taro.hatenablog.jp/>算譜王におれはなる!!!!/a>/h1> h2 idblog-description>偏りはあると思うけど情報技術全般についてマイペースに書くよ。/h2> /div> /div>/header> div idcontent classhfeed > div idcontent-inner> div idwrapper> div idmain> div idmain-inner> !-- google_ad_section_start --> !-- rakuten_ad_target_begin --> article classentry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-3600 words-100 mode-markdown entry-odd identry-17179246901335132652 data-keyword-campaign data-uuid17179246901335132652 data-publication-typeentry> div classentry-inner> header classentry-header> div classdate entry-date first> a hrefhttps://taro.hatenablog.jp/archive/2025/12/24 relnofollow> time datetime2025-12-24T00:37:32Z title2025-12-24T00:37:32Z> span classdate-year>2025/span>span classhyphen>-/span>span classdate-month>12/span>span classhyphen>-/span>span classdate-day>24/span> /time> /a> /div> h1 classentry-title> a hrefhttps://taro.hatenablog.jp/entry/2025/12/24/093732 classentry-title-link bookmark>AIボイスレコーダー作った【M5Stack Atom Echo × Supabase × Gemini】/a>/h1> div classentry-categories categories> a hrefhttps://taro.hatenablog.jp/archive/category/%E7%94%9F%E6%88%90AI classentry-category-link category-生成AI>生成AI/a> /div> /header> div classentry-content hatenablog-entry> p>a hrefhttps://jp.plaud.ai/>Plaud/a>っていうAIa classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%DC%A5%A4%A5%B9%A5%EC%A5%B3%A1%BC%A5%C0%A1%BC>ボイスレコーダー/a>、社内の一部のメンバーが使っているのだけど、私は使ったことがないんですよね。ちょっと羨ましい。ぶっちゃけa classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%B9%A5%DE%A5%DB>スマホ/a>でええやんって思うんですが、やっぱ専用デa classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%D0%A5%A4%A5%B9>バイス/a>でボタンをぽちっとすればすぐに録音が始まるのは便利ですよね。特に録音なんてものは、サッとできてこそ。ということでAIa classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%DC%A5%A4%A5%B9%A5%EC%A5%B3%A1%BC%A5%C0%A1%BC>ボイスレコーダー/a>(a classkeyword hrefhttps://d.hatena.ne.jp/keyword/%CC%BF%CC%BE>命名/a> Taroud)を作ったので、その話を書きます。/p>p>a hrefhttps://adventar.org/calendars/12070>Ubieテックアドベントカレンダー/a>の24日目のエントリーですが、アドカレというよりもa classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%CF%A5%C3%A5%AB%A5%BD%A5%F3>ハッカソン/a>的なノリの内容で strong>ネタ枠/strong> です。/p>h2 id構成全体像>構成・全体像/h2>p>a classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%B9%A5%DE%A5%DB>スマホ/a>とは別の独立したデa classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%D0%A5%A4%A5%B9>バイス/a>を使おうということで、M5Stackのa hrefhttps://docs.m5stack.com/ja/atom/atomecho>Atom Echo/a>というIoTa classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%DE%A5%A4%A5%B3%A5%F3>マイコン/a>を使います。a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Atom>Atom/a> Echoの理由は、たまたま持っていたからです(オフィスに常設されている銅鑼が鳴らされたことを検知するために、以前、a classkeyword hrefhttps://d.hatena.ne.jp/keyword/%BD%A9%CD%D5%B8%B6>秋葉原/a>で3,000円くらいで買ったものです)。a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Atom>Atom/a> Echoは、ボタン、LED1個、マイク、スピーカーを持っており、a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Wifi>Wifi/a>接続が可能です。/p>p>figure stylewidth: 400px classfigure-image figure-image-fotolife titleAtom Echo, 小さくてかわいい>span itemscope itemtypehttp://schema.org/Photograph>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20251221/20251221142434.png width1200 height901 loadinglazy title classhatena-fotolife itempropimage>/span>figcaption>a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Atom>Atom/a> Echo, 小さくてかわいい/figcaption>/figure>/p>p>実現したい体験は次のとおり。/p>ol>li>a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Atom>Atom/a> Echoのボタンを押す/li>li>話す/li>li>a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Atom>Atom/a> Echoのボタンを押す/li>li>a classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%B9%A5%DE%A5%DB>スマホ/a>で会話の要約を見る/li>/ol>p>シンプルですね。サッと録音を開始して、終了できる。終了したら勝手に要約が生成されるのもいいですね。/p>p>strong>その他の登場人物/strong>/p>ul>li>Supabaseul>li>Database: 録音のa classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%E1%A5%BF%A5%C7%A1%BC%A5%BF>メタデータ/a>を保存/li>li>Storage: 録音そのもの(wav)を保存/li>li>Edge Functions: Geminiを叩いてSlackに通知する/li>/ul>/li>li>Gemini: 音声ファイルから要約を得る/li>li>Slack: 要約完了の通知と、要約を見るためのインタフェース/li>/ul>p>最初は画面を作る気満々でしたが、バックグラウンドからの通知を実装するのが面倒だと思ったのでSlackをまるっと使うことにして、画面の作成を省略しました。/p>p>実現したい体験を絡めた、各登場人物のインタラクションは次のようになります。/p>p>figure stylewidth: 400px classfigure-image figure-image-fotolife titleこういうところはアナログ派>span itemscope itemtypehttp://schema.org/Photograph>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20251221/20251221142701.png width1200 height901 loadinglazy title classhatena-fotolife itempropimage>/span>figcaption>こういうところはアナログ派/figcaption>/figure>/p>p>記事を書くに際して、この絵をGeminiに投げて、シーケンス図を表現するMermaidを出力してもらいました(少し手を加えています)。/p>p>span itemscope itemtypehttp://schema.org/Photograph>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20251221/20251221142818.png width1200 height676 loadinglazy title classhatena-fotolife itempropimage>/span>/p>h2 idAtom-Echo>a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Atom>Atom/a> Echo/h2>p>2回目のボタン押下、すなわち会話・録音の終了の前に、WAV書き込みを行っています。この図では一度きりに見えますが、頻度高く何度も行います。これはa classkeyword hrefhttps://d.hatena.ne.jp/keyword/Atom>Atom/a> EchoのRAMの小ささからそのようにしています。/p>p>RAMやストレージが十分に大きければ、録音をたっぷり溜め込んだあと、一度だけアップロードすればOKです。しかし、実際にはそうはできません。a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Atom>Atom/a> EchoのRAMは520KB、ストレージは4MB(プログラム領域を考慮するとWAVが保存できる領域はもっと少ない)。なので、録音したデータをa classkeyword hrefhttps://d.hatena.ne.jp/keyword/Atom>Atom/a> Echoに長く留めておくわけにはいかないのです。/p>p>今回の実装では、RAMに音声(8kHz。昔の固定電話と同じ)を保存しておき、2.9秒ごとにアップロードしています(3秒だと失敗することが多かった)。/p>p>最初、この高頻度のアップロードで、その度にconnect(a classkeyword hrefhttps://d.hatena.ne.jp/keyword/SSL>SSL/a>ハンドシェイク等)が発生し、そのオーバーヘッドが録音の品質に悪影響を与えていました。とても聴けた音じゃない。ここは大いにハマりました。普段のプログラミングで意識することがありませんからね。1度確立したconnectionを再利用するようにしたら、言葉を識別できるレベルの音声になりました。/p>h2 idBackend>Backend/h2>p>さくっとサーバーレスということでSupabaseを使うことにしました。Firebaseのa classkeyword hrefhttps://d.hatena.ne.jp/keyword/REST%20API>REST API/a>を直叩きするのは、a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Atom>Atom/a> Echoの素朴な環境で(あと慣れない言語で)使うにはちょっと大変そうだなと。/p>p>Backend as a Serviceをライトに使うだけなので、特筆することはないんですが、やってることを少しだけ説明します。/p>p>録音ステータスはDatabaseで管理し、実際の音声データ(細切れのWAV)はStorageに保存します。録音が終わると(2回目のボタン押下)録音ステータスをfinishedに書き換えます。すると、それをトリガーにEdge Functionsが呼び出されます。Edge Functionsでは、細切れのWAVを繋げて、1つのWAVにします。これを音声ファイルのまま(実際にはa classkeyword hrefhttps://d.hatena.ne.jp/keyword/base64>base64/a>)Geminiに投げて(今回はgemini-2.5-a classkeyword hrefhttps://d.hatena.ne.jp/keyword/flash>flash/a>を利用)要約テキストを取得します。これをWebhookを使って、Slackに投稿する、という流れです。/p>p>figure stylewidth: 400px classfigure-image figure-image-fotolife titleたくさんの細切れwavとmerged.wav>span itemscope itemtypehttp://schema.org/Photograph>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20251221/20251221143056.png width1133 height572 loadinglazy title classhatena-fotolife itempropimage>/span>figcaption>たくさんの細切れwavとmerged.wav/figcaption>/figure>/p>p>細切れWAVを繋げて、1つのWAVにまとめる操作をバックエンドで行うのであれば、それを前提として、細切れWAVをヘッダー情報を持たないPCMにするということも検討しました。a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Atom>Atom/a> EchoのRAM節約にもなると思い、少し期待したのですが、一瞬で却下しました。細切れWAV(一時的に溜めている音声データ)のサイズは46,400bytesなので、そのうちの44bytesを節約しても無視できるほどの効果です。また、Storageにアップロードされた音声ファイルの品質をチェックするために、SupabaseのWebUI上で再生して確認するには、PCMではなくヘッダー情報を正しく持ったWAVである必要があったからです。/p>h2 idできたもの>できたもの/h2>p>a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Atom>Atom/a> Echoはバッテリーを持っていないので、モバイルバッテリーなどと繋いで給電してやる必要があります。いざ、接続!/p>p>figure stylewidth: 400px classfigure-image figure-image-fotolife titleLEDが光るとテンション上がるよね>span itemscope itemtypehttp://schema.org/Photograph>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20251221/20251221143234.png width1200 height901 loadinglazy title classhatena-fotolife itempropimage>/span>figcaption>LEDが光るとテンション上がるよね/figcaption>/figure>/p>p>起動すると、a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Wifi>Wifi/a>に接続して、待機中である旨を示すLEDが青色に点灯します。ボタンを押すとLEDが赤色に変わり、録音が始まったことがわかります。5歳の娘とちょっとした雑談をしてボタンを押すと、再び待機中としてLEDが青に戻ります。数秒後、a classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%B9%A5%DE%A5%DB>スマホ/a>にSlack通知が届き、要約が完成したことを知らせてくれます。/p>p>figure stylewidth: 400px classfigure-image figure-image-fotolife titleあまり会話が弾まなかった…>span itemscope itemtypehttp://schema.org/Photograph>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20251221/20251221142341.png width658 height1200 loadinglazy title classhatena-fotolife itempropimage>/span>figcaption>あまり会話が弾まなかった…/figcaption>/figure>/p>h2 idあとがき>あとがき/h2>p>strong>実用性はない。/strong>/p>p>と思ったが、a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Atom>Atom/a> Echoが3,000円で、Supabaseが無料で、Geminiが従量課金で駄菓子程度の費用ということを考えると、Plaudほどスマートな体験にはならないとはいえ、その代替としては検討しうるか。/p>p>ガチるならa classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%B9%A5%DE%A5%DB>スマホ/a>アプリを作った方が断然いいですね。カメラアプリのシャッターを切るa classkeyword hrefhttps://d.hatena.ne.jp/keyword/bluetooth>bluetooth/a>ボタン(電池入り)を使ってみると面白そう。500円くらいで手に入ります。シャッターを切る操作=音量上げキー押下なのでそれをバックグラウンドにいながらリッスンできたら、物理ボタンから一瞬で録音をスタートできて、やりたかったことに近づけます。/p>h2 idということでAndroidアプリも作った>ということでa classkeyword hrefhttps://d.hatena.ne.jp/keyword/Android>Android/a>アプリも作った/h2>p>ボタンひとつで録音が開始するのが、やはり体験として最高だったので、どうしても実用的なものが欲しくなりました。/p>p>a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Android>Android/a>であれば、 code>AccessibilityService/code> を使ってボタン押下をグローバルに取得できます。本来はその名のとおり、a classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%A2%A5%AF%A5%BB%A5%B7%A5%D3%A5%EA%A5%C6%A5%A3>アクセシビリティ/a>を目的としたもので、アプリに対して強い権限を与えるので、目的外の使用ということでアプリストアで配布することはできないでしょう。なので、あくまで自分用。/p>p>figure stylewidth:400px classfigure-image figure-image-fotolife titleポチッとすれば録音開始>span itemscope itemtypehttp://schema.org/Photograph>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20251223/20251223100842.png width1200 height711 loadinglazy title classhatena-fotolife itempropimage>/span>figcaption>ポチッとすれば録音開始/figcaption>/figure>/p>p>右手に持っているのが、カメラのシャッターを切るa classkeyword hrefhttps://d.hatena.ne.jp/keyword/bluetooth>bluetooth/a>ボタンです。これを押すと、どんなアプリが開いていようと、あるいは画面が閉じていようと、自分のアプリがそのイベントをキャッチしてくれます(そうなるように実装したということです)。結果、録音がスタートします。画面上部に録音のnotificationが出現しているのがわかると思います。/p>p>話し終えた後、もう一度ボタンを押せば録音が停止します。a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Wifi>Wifi/a>環境下では、録音を停止したあとに自動的に要約処理が走るようにしました。モバイルネットワークではギガを節約するために何もしません(手動でも要約リクエストを投げられるようにしている)。/p>p>figure stylewidth:400pxclassfigure-image figure-image-fotolife title要約結果>span itemscope itemtypehttp://schema.org/Photograph>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20251223/20251223101332.png width1200 height736 loadinglazy title classhatena-fotolife itempropimage>/span>figcaption>要約結果/figcaption>/figure>/p>p>要約処理が完了すると通知されます。通知をタップすると、その内容が確認できます。/p>p>なお、カメラのシャッターを切るa classkeyword hrefhttps://d.hatena.ne.jp/keyword/bluetooth>bluetooth/a>ボタンは、一定時間(数分くらい?)ボタンが押されないとa classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%B9%A5%DE%A5%DB>スマホ/a>から切断されます。接続するにはボタンの長押しが必要です。そのため、a classkeyword hrefhttps://d.hatena.ne.jp/keyword/bluetooth>bluetooth/a>ボタンでサッと録音するのはあまり現実的ではないかも。それでも、a classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%B9%A5%DE%A5%DB>スマホ/a>の音量を上げる物理ボタンを押すこととイベントとしては同義なので、a classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%B9%A5%DE%A5%DB>スマホ/a>のボタンをポチッとするだけという手軽さはあります。/p> /div> footer classentry-footer> div classentry-tags-wrapper> div classentry-tags> span classentry-tag> a hrefhttps://d.hatena.ne.jp/keyword/%E7%94%9F%E6%88%90%20AI classentry-tag-link> span classentry-tag-icon>#/span>span classentry-tag-label>生成 AI/span> /a> /span> span classentry-tag> a hrefhttps://d.hatena.ne.jp/keyword/LLM classentry-tag-link> span classentry-tag-icon>#/span>span classentry-tag-label>LLM/span> /a> /span> span classentry-tag> a hrefhttps://d.hatena.ne.jp/keyword/Internet%20of%20Things%20(IoT) classentry-tag-link> span classentry-tag-icon>#/span>span classentry-tag-label>Internet of Things (IoT)/span> /a> /span> /div>/div> p classentry-footer-section track-inview-by-gtm data-gtm-track-json{"area": "finish_reading"}> span classauthor vcard>span classfn data-load-nickname1 data-user-namengsw_taro >ngsw_taro/span>/span> span classentry-footer-time>a hrefhttps://taro.hatenablog.jp/entry/2025/12/24/093732>time data-relative datetime2025-12-24T00:37:32Z title2025-12-24T00:37:32Z classupdated>2025-12-24 09:37/time>/a>/span> span class entry-footer-subscribe data-test-blog-controlls-subscribe> a hrefhttps://blog.hatena.ne.jp/ngsw_taro/taro.hatenablog.jp/subscribe?utm_campaignsubscribe_blog&utm_sourceblogs_entry_footer&utm_mediumbutton> 読者になる /a> /span> /p> div classhatena-star-container data-hatena-star-container data-hatena-star-urlhttps://taro.hatenablog.jp/entry/2025/12/24/093732 data-hatena-star-titleAIボイスレコーダー作った【M5Stack Atom Echo × Supabase × Gemini】 data-hatena-star-variantprofile-icon data-hatena-star-profile-url-templatehttps://blog.hatena.ne.jp/{username}/ >/div> div classsocial-buttons> div classsocial-button-item> a hrefhttps://b.hatena.ne.jp/entry/s/taro.hatenablog.jp/entry/2025/12/24/093732 classhatena-bookmark-button data-hatena-bookmark-urlhttps://taro.hatenablog.jp/entry/2025/12/24/093732 data-hatena-bookmark-layoutvertical-balloon data-hatena-bookmark-langja titleこの記事をはてなブックマークに追加>img srchttps://b.st-hatena.com/images/entry-button/button-only.gif altこの記事をはてなブックマークに追加 width20 height20 styleborder: none; />/a> /div> div classsocial-button-item> div classfb-share-button data-layoutbox_count data-hrefhttps://taro.hatenablog.jp/entry/2025/12/24/093732>/div> /div> div classsocial-button-item> a classentry-share-button entry-share-button-twitter test-share-button-twitter hrefhttps://x.com/intent/tweet?hashtags%E7%94%9F%E6%88%90_AI&hashtagsLLM&hashtagsInternet_of_Things_(IoT)&textAI%E3%83%9C%E3%82%A4%E3%82%B9%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%80%E3%83%BC%E4%BD%9C%E3%81%A3%E3%81%9F%E3%80%90M5Stack+Atom+Echo+%C3%97+Supabase+%C3%97+Gemini%E3%80%91+-+%E7%AE%97%E8%AD%9C%E7%8E%8B%E3%81%AB%E3%81%8A%E3%82%8C%E3%81%AF%E3%81%AA%E3%82%8B!!!!&urlhttps%3A%2F%2Ftaro.hatenablog.jp%2Fentry%2F2025%2F12%2F24%2F093732 titleX(Twitter)で投稿する >/a> /div> div classsocial-button-item> a hrefhttp://www.tumblr.com/share data-hatenablog-tumblr-share-button data-share-urlhttps://taro.hatenablog.jp/entry/2025/12/24/093732 data-share-titleAIボイスレコーダー作った【M5Stack Atom Echo × Supabase × Gemini】 - 算譜王におれはなる!!!! titleShare on Tumblr styledisplay:inline-block; text-indent:-9999px; overflow:hidden; width:81px; height:20px; background:url(https://platform.tumblr.com/v1/share_1.png) top left no-repeat transparent; vertical-align: top;>Share on Tumblr/a> /div> span> div classline-it-button styledisplay: none; data-typeshare-e data-langja >/div> script src//scdn.line-apps.com/n/line_it/thirdparty/loader.min.js asyncasync deferdefer >/script> /span> /div> div classgoogle-afc-image test-google-rectangle-ads> div idgoogle_afc_user_container_0 classgoogle-afc-user-container google_afc_blocklink2_5 google_afc_boder data-test-unit/4374287/blog_user>/div> a hrefhttp://blog.hatena.ne.jp/guide/pro classopen-pro-modal data-guide-pro-modal-ad-urlhttps://hatena.blog/guide/pro/modal/ad>広告を非表示にする/a> /div> div classcustomized-footer> /div> div classcomment-box js-comment-box> ul classcomment js-comment> li classread-more-comments styledisplay: none;>a>もっと読む/a>/li> /ul> a classleave-comment-title js-leave-comment-title>コメントを書く/a> /div> /footer> /div>/article> article classentry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-2800 words-400 mode-markdown entry-even identry-6802418398312577694 data-keyword-campaign data-uuid6802418398312577694 data-publication-typeentry> div classentry-inner> header classentry-header> div classdate entry-date first> a hrefhttps://taro.hatenablog.jp/archive/2024/12/18 relnofollow> time datetime2024-12-18T06:32:45Z title2024-12-18T06:32:45Z> span classdate-year>2024/span>span classhyphen>-/span>span classdate-month>12/span>span classhyphen>-/span>span classdate-day>18/span> /time> /a> /div> h1 classentry-title> a hrefhttps://taro.hatenablog.jp/entry/2024/12/18/153245 classentry-title-link bookmark>Gemini 2.0の空間認識をJavaScriptで試す/a>/h1> div classentry-categories categories> a hrefhttps://taro.hatenablog.jp/archive/category/%E7%94%9F%E6%88%90AI classentry-category-link category-生成AI>生成AI/a> a hrefhttps://taro.hatenablog.jp/archive/category/JavaScript classentry-category-link category-JavaScript>JavaScript/a> a hrefhttps://taro.hatenablog.jp/archive/category/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0 classentry-category-link category-プログラミング>プログラミング/a> /div> /header> div classentry-content hatenablog-entry> p>a hrefhttps://blog.google/intl/ja-jp/company-news/technology/google-gemini-ai-update-december-2024/>Gemini 2.0 Flashのプレビュー/a>が出ましたね。a hrefhttps://ai.google.dev/gemini-api/docs/models/gemini-v2>APIドキュメント/a>を見て、興味を惹かれたのはBounding box detection。かねてより、画像から対象の座標を取れたら面白いことできそうだな〜と思っていました。a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Google>Google/a> AI Studioで試すことができます。/p>p>span itemscope itemtypehttp://schema.org/Photograph>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20241218/20241218141303.png width1200 height769 loadinglazy title classhatena-fotolife itempropimage>/span>span itemscope itemtypehttp://schema.org/Photograph>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20241218/20241218141342.png width1200 height768 loadinglazy title classhatena-fotolife itempropimage>/span>/p>p>a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Google>Google/a> AI Studioが発行しているプロンプトを確認すると/p>pre classcode data-lang data-unlink>Detect 料理, with no more than 20 items. Output a json list where each entry contains the 2D bounding box in "box_2d" and a text label in "label"./pre>p>って感じで、a classkeyword hrefhttps://d.hatena.ne.jp/keyword/%BC%AB%C1%B3%B8%C0%B8%EC>自然言語/a>でa classkeyword hrefhttps://d.hatena.ne.jp/keyword/JSON>JSON/a>の形式を指定しているんですね。OpenAIのstructured_outputに慣れているとちょっと驚き。実際に、どういうレスポンスが来るのかは後述します。/p>p>この空間認識・a classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%D0%A5%A6%A5%F3%A5%C7%A5%A3>バウンディ/a>ング検出は、既存のa classkeyword hrefhttps://d.hatena.ne.jp/keyword/JavaScript>JavaScript/a>向けa classkeyword hrefhttps://d.hatena.ne.jp/keyword/SDK>SDK/a>でも利用可能であるのが、すぐ試すには手軽でよいです。新しいa classkeyword hrefhttps://d.hatena.ne.jp/keyword/SDK>SDK/a>は、a classkeyword hrefhttps://d.hatena.ne.jp/keyword/JavaScript>JavaScript/a>向けの提供がまだ始まっていないようなので。/p>pre classcode lang-typescript data-langtypescript data-unlink>span classsynIdentifier>const/span> model vertexai.getGenerativeModel(span classsynIdentifier>{/span> span classsynStatement>model/span>: span classsynConstant>"gemini-2.0-flash-exp"/span>,span classsynIdentifier>}/span>);/pre>p>素直に、新しいモデル名を指定するだけで使えるみたいです。あとは、いつも通りに code>generateContent/code> を呼び出してテキストを生成するだけです。先述のようにa classkeyword hrefhttps://d.hatena.ne.jp/keyword/%A5%D0%A5%A6%A5%F3%A5%C7%A5%A3>バウンディ/a>ングを検出したい旨をプロンプトに含めることで、決まった書式のa classkeyword hrefhttps://d.hatena.ne.jp/keyword/JSON>JSON/a>っぽいものが返されます。/p>p>まずは2Dから実装。プロンプトはa classkeyword hrefhttps://d.hatena.ne.jp/keyword/Google>Google/a> AI Studioのものを、ちょこっといじってこんな感じにしてみます。/p>pre classcode lang-typescript data-langtypescript data-unlink>span classsynConstant>`Detect /span>span classsynStatement>${/span>targetspan classsynStatement>}/span>span classsynConstant>, with no more than 20 items. Output a json list where each entry contains the 2D bounding box in "box_2d" and name in "label".`/span>/pre>p>これでgenerateContentすると、次のようなテキストが生成されます。/p>pre>```a classkeyword hrefhttps://d.hatena.ne.jp/keyword/json>json/a> {box_2d: 13, 432, 457, 879, label: 料理}, {box_2d: 309, 0, 892, 509, label: 料理}, {box_2d: 535, 390, 892, 773, label: 料理}```/pre>p>純粋なa classkeyword hrefhttps://d.hatena.ne.jp/keyword/JSON>JSON/a>ではなくて、a classkeyword hrefhttps://d.hatena.ne.jp/keyword/JSON>JSON/a>を含むa classkeyword hrefhttps://d.hatena.ne.jp/keyword/Markdown>Markdown/a>であることに注意が必要です。中身のa classkeyword hrefhttps://d.hatena.ne.jp/keyword/JSON>JSON/a>だけ取り出して扱いましょう。整数の配列の意味はa hrefhttps://github.com/google-gemini/cookbook/blob/main/gemini-2/spatial_understanding_3d.ipynb>この資料/a>に書かれています。画像 左上の座標を (0, 0) とし、右下の座標を (1000, 1000) としたときの、ボックスの左上、右下の座標を表しています。y座標が先で、x座標が後なことに注意。つまり code>13, 432, 457, 879/code> は、左上 x432, y13 右下 x879, y457 です。/p>p>実際にブラウザ上にただ表示するのは簡単です。a classkeyword hrefhttps://d.hatena.ne.jp/keyword/CSS>CSS/a>でabsoluteしてtop, left, width, heightを%指定するだけですね。/p>p>span itemscope itemtypehttp://schema.org/Photograph>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20241218/20241218144657.png width1098 height773 loadinglazy title classhatena-fotolife itempropimage>/span>/p>p>3Dも大体同じではあります。a classkeyword hrefhttps://d.hatena.ne.jp/keyword/Google>Google/a> AI Studioのプロンプトをいじって、こうしてみました。/p>pre classcode lang-typescript data-langtypescript data-unlink>span classsynConstant>`Detect the 3D bounding boxes of /span>span classsynStatement>${/span>targetspan classsynStatement>}/span>span classsynConstant> , output no more than 10 items. Output a json list where each entry contains the object name in "label" and its 3D bounding box in "box_3d".`/span>/pre>p>生成されるテキストはこんな感じです。/p>pre>```a classkeyword hrefhttps://d.hatena.ne.jp/keyword/json>json/a> {label: 料理, box_3d: 0.41,1.54,0.22,0.71,0.74,0.87,-34,-13,10}, {label: 料理, box_3d: -0.31,1.55,-0.1,0.71,0.5,0.76,-34,-12,9}, {label: 料理, box_3d: 0.06,1.54,-0.4,0.46,0.36,0.37,-33,-2,2}```/pre>p>それぞれの数値の意味は/p>ul>li>最初の3つ: x_center, y_center, z_center/li>li>真ん中の3つ: x_size, y_size, z_size/li>li>最後の3つ: x軸の回転、y軸の回転, z軸の回転(度数法)/li>/ul>p>で、ドキュメント曰く x_center とか x_size はメートル単位の長さっぽいです。なので、画面に描画したあとはズームイン/ズームアウトを行って、元画像との重なりを調節しなきゃいけないと思います、たぶん。/p>p>今回はReactでThree.jsするa hrefhttps://r3f.docs.pmnd.rs/>React Three Fiber/a>を使いました。/p>p>ちなみに、Next.js 15系でReact Three Fiber 8.17.10だと、上手く動きませんでした。a hrefhttps://github.com/vercel/next.js/issues/71836>このissue/a>を参考に、9.0.0-rc.1 のReact Three Fiberを使ったら上手く行きました。/p>p>もう一つ厄介、というか誤解の種として、Three.jsの座標系とGeminiが返すそれは異なるので注意が必要です。Three.jsは、画面に対して垂直方向がy軸で、奥行きがz軸。Geminiは、垂直方向がz軸で、奥行きがy軸っぽいです。/p>p>そこを気をつけてReact Three Fiberで箱型の辺を組めば、期待通りに3Dを描画できます。/p>p>span itemscope itemtypehttp://schema.org/Photograph>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20241218/20241218152928.png width1137 height792 loadinglazy title classhatena-fotolife itempropimage>/span>/p>p>なお、3Dの方はまだ実験段階にあり、精度は高くないようです。/p>p>ところで、全然関係ないですが、使用している写真はa hrefhttps://tsukemen-tsujita.com/>つじ田/a>、お気に入りのつけ麺屋さんの一つです。/p> /div> footer classentry-footer> div classentry-tags-wrapper> div classentry-tags> /div>/div> p classentry-footer-section track-inview-by-gtm data-gtm-track-json{"area": "finish_reading"}> span classauthor vcard>span classfn data-load-nickname1 data-user-namengsw_taro >ngsw_taro/span>/span> span classentry-footer-time>a hrefhttps://taro.hatenablog.jp/entry/2024/12/18/153245>time data-relative datetime2024-12-18T06:32:45Z title2024-12-18T06:32:45Z classupdated>2024-12-18 15:32/time>/a>/span> span class entry-footer-subscribe data-test-blog-controlls-subscribe> a hrefhttps://blog.hatena.ne.jp/ngsw_taro/taro.hatenablog.jp/subscribe?utm_mediumbutton&utm_sourceblogs_entry_footer&utm_campaignsubscribe_blog> 読者になる /a> /span> /p> div classhatena-star-container data-hatena-star-container data-hatena-star-urlhttps://taro.hatenablog.jp/entry/2024/12/18/153245 data-hatena-star-titleGemini 2.0の空間認識をJavaScriptで試す data-hatena-star-variantprofile-icon data-hatena-star-profile-url-templatehttps://blog.hatena.ne.jp/{username}/ >/div> div classsocial-buttons> div classsocial-button-item> a hrefhttps://b.hatena.ne.jp/entry/s/taro.hatenablog.jp/entry/2024/12/18/153245 classhatena-bookmark-button data-hatena-bookmark-urlhttps://taro.hatenablog.jp/entry/2024/12/18/153245 data-hatena-bookmark-layoutvertical-balloon data-hatena-bookmark-langja titleこの記事をはてなブックマークに追加>img srchttps://b.st-hatena.com/images/entry-button/button-only.gif altこの記事をはてなブックマークに追加 width20 height20 styleborder: none; />/a> /div> div classsocial-button-item> div classfb-share-button data-layoutbox_count data-hrefhttps://taro.hatenablog.jp/entry/2024/12/18/153245>/div> /div> div classsocial-button-item> a classentry-share-button entry-share-button-twitter test-share-button-twitter hrefhttps://x.com/intent/tweet?textGemini+2.0%E3%81%AE%E7%A9%BA%E9%96%93%E8%AA%8D%E8%AD%98%E3%82%92JavaScript%E3%81%A7%E8%A9%A6%E3%81%99+-+%E7%AE%97%E8%AD%9C%E7%8E%8B%E3%81%AB%E3%81%8A%E3%82%8C%E3%81%AF%E3%81%AA%E3%82%8B!!!!&urlhttps%3A%2F%2Ftaro.hatenablog.jp%2Fentry%2F2024%2F12%2F18%2F153245 titleX(Twitter)で投稿する >/a> /div> div classsocial-button-item> a hrefhttp://www.tumblr.com/share data-hatenablog-tumblr-share-button data-share-urlhttps://taro.hatenablog.jp/entry/2024/12/18/153245 data-share-titleGemini 2.0の空間認識をJavaScriptで試す - 算譜王におれはなる!!!! titleShare on Tumblr styledisplay:inline-block; text-indent:-9999px; overflow:hidden; width:81px; height:20px; background:url(https://platform.tumblr.com/v1/share_1.png) top left no-repeat transparent; vertical-align: top;>Share on Tumblr/a> /div> span> div classline-it-button styledisplay: none; data-typeshare-e data-langja >/div> script src//scdn.line-apps.com/n/line_it/thirdparty/loader.min.js asyncasync deferdefer >/script> /span> /div> div classgoogle-afc-image test-google-rectangle-ads> div idgoogle_afc_user_container_1 classgoogle-afc-user-container google_afc_blocklink2_5 google_afc_boder data-test-unit/4374287/blog_user_2nd>/div> a hrefhttp://blog.hatena.ne.jp/guide/pro classopen-pro-modal data-guide-pro-modal-ad-urlhttps://hatena.blog/guide/pro/modal/ad>広告を非表示にする/a> /div> div classcustomized-footer> /div> div classcomment-box js-comment-box> ul classcomment js-comment> li classread-more-comments styledisplay: none;>a>もっと読む/a>/li> /ul> a classleave-comment-title js-leave-comment-title>コメントを書く/a> /div> /footer> /div>/article> article classentry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-400 words-100 mode-markdown entry-odd identry-26006613762769542 data-keyword-campaign data-uuid26006613762769542 data-publication-typeentry> div classentry-inner> header classentry-header> div classdate entry-date first> a hrefhttps://taro.hatenablog.jp/archive/2021/05/13 relnofollow> time datetime2021-05-13T01:11:14Z title2021-05-13T01:11:14Z> span classdate-year>2021/span>span classhyphen>-/span>span classdate-month>05/span>span classhyphen>-/span>span classdate-day>13/span> /time> /a> /div> h1 classentry-title> a hrefhttps://taro.hatenablog.jp/entry/2021/05/13/101114 classentry-title-link bookmark>Ubieだからこそプロダクト開発を全力で楽しめている/a>/h1> div classentry-categories categories> a hrefhttps://taro.hatenablog.jp/archive/category/%E5%80%8B%E4%BA%BA%E7%9A%84%E3%81%AA%E8%A9%B1 classentry-category-link category-個人的な話>個人的な話/a> a hrefhttps://taro.hatenablog.jp/archive/category/%E3%82%AD%E3%83%A3%E3%83%AA%E3%82%A2 classentry-category-link category-キャリア>キャリア/a> /div> /header> div classentry-content hatenablog-entry> p>span itemscope itemtypehttp://schema.org/Photograph>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20210512/20210512132408.png altf:id:ngsw_taro:20210512132408p:plain title classhatena-fotolife itempropimage>/span>この4月にUbie入社4年目を迎えました。入社当初5, 6人しかいなかったメンバーも今では100人を超えました。プロダクトも成長し、顧客も増えました。入社から3年間で状況は様変わりしましたが、Ubie Discoverya href#f-df594273 namefn-df594273 titleUbieという会社は現時点でUbie DiscoveryとUbie Customer Scienceの2大組織で構成されており、僕やエンジニアなどが所属する組織がUbie Discoveryです。詳しくは「スタートアップで、カルチャーが全く違う2つの組織を作った話」をご覧ください。>*1/a>で働く本質的な楽しさは変わらないどころか、なんなら今が一番楽しいと思っています。本エントリでは、この「strong>楽しい/strong>」に集中できる理由と、そうしておけばstrong>万事良し/strong>の理由について話します。/p>div classfootnote>p classfootnote>a href#fn-df594273 namef-df594273 classfootnote-number>*1/a>span classfootnote-delimiter>:/span>span classfootnote-text>Ubieという会社は現時点でUbie DiscoveryとUbie Customer Scienceの2大組織で構成されており、僕やエンジニアなどが所属する組織がUbie Discoveryです。詳しくは「a hrefhttps://note.com/ubie/n/n192cef30c5eb>スタートアップで、カルチャーが全く違う2つの組織を作った話/a>」をご覧ください。/span>/p>/div> a classentry-see-more hrefhttps://taro.hatenablog.jp/entry/2021/05/13/101114>続きを読む/a> /div> footer classentry-footer> div classentry-tags-wrapper> div classentry-tags> span classentry-tag> a hrefhttps://d.hatena.ne.jp/keyword/%E3%82%AD%E3%83%A3%E3%83%AA%E3%82%A2 classentry-tag-link> span classentry-tag-icon>#/span>span classentry-tag-label>キャリア/span> /a> /span> span classentry-tag> a hrefhttps://d.hatena.ne.jp/keyword/%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%88%E3%82%A2%E3%83%83%E3%83%97 classentry-tag-link> span classentry-tag-icon>#/span>span classentry-tag-label>スタートアップ/span> /a> /span> span classentry-tag> a hrefhttps://d.hatena.ne.jp/keyword/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E classentry-tag-link> span classentry-tag-icon>#/span>span classentry-tag-label>プログラマ/span> /a> /span> /div>/div> p classentry-footer-section track-inview-by-gtm data-gtm-track-json{"area": "finish_reading"}> span classauthor vcard>span classfn data-load-nickname1 data-user-namengsw_taro >ngsw_taro/span>/span> span classentry-footer-time>a hrefhttps://taro.hatenablog.jp/entry/2021/05/13/101114>time data-relative datetime2021-05-13T01:11:14Z title2021-05-13T01:11:14Z classupdated>2021-05-13 10:11/time>/a>/span> span class entry-footer-subscribe data-test-blog-controlls-subscribe> a hrefhttps://blog.hatena.ne.jp/ngsw_taro/taro.hatenablog.jp/subscribe?utm_mediumbutton&utm_sourceblogs_entry_footer&utm_campaignsubscribe_blog> 読者になる /a> /span> /p> div classhatena-star-container data-hatena-star-container data-hatena-star-urlhttps://taro.hatenablog.jp/entry/2021/05/13/101114 data-hatena-star-titleUbieだからこそプロダクト開発を全力で楽しめている data-hatena-star-variantprofile-icon data-hatena-star-profile-url-templatehttps://blog.hatena.ne.jp/{username}/ >/div> div classsocial-buttons> div classsocial-button-item> a hrefhttps://b.hatena.ne.jp/entry/s/taro.hatenablog.jp/entry/2021/05/13/101114 classhatena-bookmark-button data-hatena-bookmark-urlhttps://taro.hatenablog.jp/entry/2021/05/13/101114 data-hatena-bookmark-layoutvertical-balloon data-hatena-bookmark-langja titleこの記事をはてなブックマークに追加>img srchttps://b.st-hatena.com/images/entry-button/button-only.gif altこの記事をはてなブックマークに追加 width20 height20 styleborder: none; />/a> /div> div classsocial-button-item> div classfb-share-button data-layoutbox_count data-hrefhttps://taro.hatenablog.jp/entry/2021/05/13/101114>/div> /div> div classsocial-button-item> a classentry-share-button entry-share-button-twitter test-share-button-twitter hrefhttps://x.com/intent/tweet?hashtags%E3%82%AD%E3%83%A3%E3%83%AA%E3%82%A2&hashtags%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%88%E3%82%A2%E3%83%83%E3%83%97&hashtags%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E&textUbie%E3%81%A0%E3%81%8B%E3%82%89%E3%81%93%E3%81%9D%E3%83%97%E3%83%AD%E3%83%80%E3%82%AF%E3%83%88%E9%96%8B%E7%99%BA%E3%82%92%E5%85%A8%E5%8A%9B%E3%81%A7%E6%A5%BD%E3%81%97%E3%82%81%E3%81%A6%E3%81%84%E3%82%8B+-+%E7%AE%97%E8%AD%9C%E7%8E%8B%E3%81%AB%E3%81%8A%E3%82%8C%E3%81%AF%E3%81%AA%E3%82%8B!!!!&urlhttps%3A%2F%2Ftaro.hatenablog.jp%2Fentry%2F2021%2F05%2F13%2F101114 titleX(Twitter)で投稿する >/a> /div> div classsocial-button-item> a hrefhttp://www.tumblr.com/share data-hatenablog-tumblr-share-button data-share-urlhttps://taro.hatenablog.jp/entry/2021/05/13/101114 data-share-titleUbieだからこそプロダクト開発を全力で楽しめている - 算譜王におれはなる!!!! titleShare on Tumblr styledisplay:inline-block; text-indent:-9999px; overflow:hidden; width:81px; height:20px; background:url(https://platform.tumblr.com/v1/share_1.png) top left no-repeat transparent; vertical-align: top;>Share on Tumblr/a> /div> span> div classline-it-button styledisplay: none; data-typeshare-e data-langja >/div> script src//scdn.line-apps.com/n/line_it/thirdparty/loader.min.js asyncasync deferdefer >/script> /span> /div> div classgoogle-afc-image test-google-rectangle-ads> div idgoogle_afc_user_container_2 classgoogle-afc-user-container google_afc_blocklink2_5 google_afc_boder data-test-unit/4374287/blog_user_2nd>/div> a hrefhttp://blog.hatena.ne.jp/guide/pro classopen-pro-modal data-guide-pro-modal-ad-urlhttps://hatena.blog/guide/pro/modal/ad>広告を非表示にする/a> /div> div classcustomized-footer> /div> div classcomment-box js-comment-box> ul classcomment js-comment> li classread-more-comments styledisplay: none;>a>もっと読む/a>/li> /ul> a classleave-comment-title js-leave-comment-title>コメントを書く/a> /div> /footer> /div>/article> article classentry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-800 words-100 mode-markdown entry-even identry-26006613710632877 data-keyword-campaign data-uuid26006613710632877 data-publication-typeentry> div classentry-inner> header classentry-header> div classdate entry-date first> a hrefhttps://taro.hatenablog.jp/archive/2021/03/31 relnofollow> time datetime2021-03-31T07:49:22Z title2021-03-31T07:49:22Z> span classdate-year>2021/span>span classhyphen>-/span>span classdate-month>03/span>span classhyphen>-/span>span classdate-day>31/span> /time> /a> /div> h1 classentry-title> a hrefhttps://taro.hatenablog.jp/entry/2021/03/31/164922 classentry-title-link bookmark>いまさらだけどContentEditableをいじって、キャレットの扱いがしんどいということがわかったよ/a>/h1> div classentry-categories categories> a hrefhttps://taro.hatenablog.jp/archive/category/Web classentry-category-link category-Web>Web/a> a hrefhttps://taro.hatenablog.jp/archive/category/JavaScript classentry-category-link category-JavaScript>JavaScript/a> /div> /header> div classentry-content hatenablog-entry> p>a classkeyword hrefhttp://d.hatena.ne.jp/keyword/WYSIWYG>WYSIWYG/a>エディタに憧れてa hrefhttps://developer.mozilla.org/ja/docs/Web/HTML/Global_attributes/contenteditable>ContentEditable/a>をいじってみると、けっこうな底無し沼だと。気づいたときにはどっぷり浸かってるやつ。ググればそれなりに知見が見つかるし、良い感じのライブラリもある。けど僕がやりたかったことは、自分でコードを書いて実現するのが早いんじゃないかなーと思って、沼にダイブした。/p>p>やりたいことは、a classkeyword hrefhttp://d.hatena.ne.jp/keyword/%A5%EF%A1%BC%A5%D7%A5%ED>ワープロ/a>ソフトみたいなやつというよりも、編集しているテキストのスタイルがリアルタイムに変化するa classkeyword hrefhttp://d.hatena.ne.jp/keyword/Markdown>Markdown/a>エディタっぽいやつ。つまりユーザがスタイルを当てるんじゃなくて、ユーザが入力したテキストに応じてスタイルを当てたい。より正確には、テキストの見た目をおしゃれにするだけではなくて、もっと高度な何か、Reactのa classkeyword hrefhttp://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8>コンポーネント/a>とか、を埋め込むとかしたかった。/p>p>span itemscope itemtypehttp://schema.org/Photograph>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20210331/20210331161758.gif altf:id:ngsw_taro:20210331161758g:plain title classhatena-fotolife itempropimage>/span>/p>p>a hrefhttps://draftjs.org/>Draft.js/a>やa hrefhttps://editorjs.io/>Editor.js/a>のような、ContentEditableを扱いやすくしてくれるライブラリも検討した。Reactのa classkeyword hrefhttp://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8>コンポーネント/a>を埋め込むのも簡単そうだった。ただ、ContentEditableの内容を入力のたびに再構築するような方法を採ると、キャレット(エディタ内にあるテキストが挿入される箇所を示す code>|/code> これ)が編集箇所とは無関係に先頭とかに飛んでしまう現象があった。パフォーマンス上の懸念はありつつも、ContentEditableの内容を再構築する方法は、ユーザの入力内容を解析してUIに反映する上で一番楽な方法だと思ったので、これを譲りたくなかった。/p>p>かくしてdel>やめときゃいいのに/del>素のContentEditableをいじることとなった。/p> a classentry-see-more hrefhttps://taro.hatenablog.jp/entry/2021/03/31/164922>続きを読む/a> /div> footer classentry-footer> div classentry-tags-wrapper> div classentry-tags> /div>/div> p classentry-footer-section track-inview-by-gtm data-gtm-track-json{"area": "finish_reading"}> span classauthor vcard>span classfn data-load-nickname1 data-user-namengsw_taro >ngsw_taro/span>/span> span classentry-footer-time>a hrefhttps://taro.hatenablog.jp/entry/2021/03/31/164922>time data-relative datetime2021-03-31T07:49:22Z title2021-03-31T07:49:22Z classupdated>2021-03-31 16:49/time>/a>/span> span class entry-footer-subscribe data-test-blog-controlls-subscribe> a hrefhttps://blog.hatena.ne.jp/ngsw_taro/taro.hatenablog.jp/subscribe?utm_mediumbutton&utm_sourceblogs_entry_footer&utm_campaignsubscribe_blog> 読者になる /a> /span> /p> div classhatena-star-container data-hatena-star-container data-hatena-star-urlhttps://taro.hatenablog.jp/entry/2021/03/31/164922 data-hatena-star-titleいまさらだけどContentEditableをいじって、キャレットの扱いがしんどいということがわかったよ data-hatena-star-variantprofile-icon data-hatena-star-profile-url-templatehttps://blog.hatena.ne.jp/{username}/ >/div> div classsocial-buttons> div classsocial-button-item> a hrefhttps://b.hatena.ne.jp/entry/s/taro.hatenablog.jp/entry/2021/03/31/164922 classhatena-bookmark-button data-hatena-bookmark-urlhttps://taro.hatenablog.jp/entry/2021/03/31/164922 data-hatena-bookmark-layoutvertical-balloon data-hatena-bookmark-langja titleこの記事をはてなブックマークに追加>img srchttps://b.st-hatena.com/images/entry-button/button-only.gif altこの記事をはてなブックマークに追加 width20 height20 styleborder: none; />/a> /div> div classsocial-button-item> div classfb-share-button data-layoutbox_count data-hrefhttps://taro.hatenablog.jp/entry/2021/03/31/164922>/div> /div> div classsocial-button-item> a classentry-share-button entry-share-button-twitter test-share-button-twitter hrefhttps://x.com/intent/tweet?text%E3%81%84%E3%81%BE%E3%81%95%E3%82%89%E3%81%A0%E3%81%91%E3%81%A9ContentEditable%E3%82%92%E3%81%84%E3%81%98%E3%81%A3%E3%81%A6%E3%80%81%E3%82%AD%E3%83%A3%E3%83%AC%E3%83%83%E3%83%88%E3%81%AE%E6%89%B1%E3%81%84%E3%81%8C%E3%81%97%E3%82%93%E3%81%A9%E3%81%84%E3%81%A8%E3%81%84%E3%81%86%E3%81%93%E3%81%A8%E3%81%8C%E3%82%8F%E3%81%8B%E3%81%A3%E3%81%9F%E3%82%88+-+%E7%AE%97%E8%AD%9C%E7%8E%8B%E3%81%AB%E3%81%8A%E3%82%8C%E3%81%AF%E3%81%AA%E3%82%8B!!!!&urlhttps%3A%2F%2Ftaro.hatenablog.jp%2Fentry%2F2021%2F03%2F31%2F164922 titleX(Twitter)で投稿する >/a> /div> div classsocial-button-item> a hrefhttp://www.tumblr.com/share data-hatenablog-tumblr-share-button data-share-urlhttps://taro.hatenablog.jp/entry/2021/03/31/164922 data-share-titleいまさらだけどContentEditableをいじって、キャレットの扱いがしんどいということがわかったよ - 算譜王におれはなる!!!! titleShare on Tumblr styledisplay:inline-block; text-indent:-9999px; overflow:hidden; width:81px; height:20px; background:url(https://platform.tumblr.com/v1/share_1.png) top left no-repeat transparent; vertical-align: top;>Share on Tumblr/a> /div> span> div classline-it-button styledisplay: none; data-typeshare-e data-langja >/div> script src//scdn.line-apps.com/n/line_it/thirdparty/loader.min.js asyncasync deferdefer >/script> /span> /div> div classgoogle-afc-image test-google-rectangle-ads> script> (valve window.valve || ).push(function(v) { v.displayDFPSlot(google_afc_user_container_3); }); /script> div idgoogle_afc_user_container_3 classgoogle-afc-user-container google_afc_blocklink2_5 google_afc_boder data-test-unit/4374287/blog_user_2nd>/div> a hrefhttp://blog.hatena.ne.jp/guide/pro classopen-pro-modal data-guide-pro-modal-ad-urlhttps://hatena.blog/guide/pro/modal/ad>広告を非表示にする/a> /div> div classcustomized-footer> /div> div classcomment-box js-comment-box> ul classcomment js-comment> li classread-more-comments styledisplay: none;>a>もっと読む/a>/li> /ul> a classleave-comment-title js-leave-comment-title>コメントを書く/a> /div> /footer> /div>/article> !-- rakuten_ad_target_end --> !-- google_ad_section_end --> div classpager autopagerize_insert_before> span classpager-next> a hrefhttps://taro.hatenablog.jp/?page1617176962 relnext>次のページ/a> /span> /div> /div> /div> aside idbox1> div idbox1-inner> /div>/aside> /div>!-- #wrapper --> aside idbox2> div idbox2-inner> div classhatena-module hatena-module-profile> div classhatena-module-title> プロフィール /div> div classhatena-module-body> a hrefhttps://taro.hatenablog.jp/about classprofile-icon-link> img srchttps://cdn.profile-image.st-hatena.com/users/ngsw_taro/profile.png?1573693748 altid:ngsw_taro classprofile-icon /> /a> span classid> a hrefhttps://taro.hatenablog.jp/about classhatena-id-link>span data-load-nickname1 data-user-namengsw_taro>id:ngsw_taro/span>/a> /span> div classprofile-description> p>プログラマー🍺br />Ubie株式会社 Ubie Discovery が現職。br />日本Kotlinユーザグループ代表。/p> /div> div classhatena-follow-button-box btn-subscribe js-hatena-follow-button-box > a href# classhatena-follow-button js-hatena-follow-button> span classsubscribing> span classforeground>読者です/span> span classbackground>読者をやめる/span> /span> span classunsubscribing data-track-nameprofile-widget-subscribe-button data-track-once> span classforeground>読者になる/span> span classbackground>読者になる/span> /span> /a> div classsubscription-count-box js-subscription-count-box> i>/i> u>/u> span classsubscription-count js-subscription-count> /span> /div>/div> div classhatena-follow-button-box> a hrefhttps://twitter.com/ngsw_taro titleX(Twitter)アカウント classbtn-twitter data-langja> img srchttps://cdn.blog.st-hatena.com/images/theme/plofile-socialize-x.svg?versionf9947fdf1627a1d1b3c8c87a6a5233 altX> span> @ngsw_taroをフォロー /span> /a> /div> div classprofile-about> a hrefhttps://taro.hatenablog.jp/about>このブログについて/a> /div> /div>/div> div classhatena-module hatena-module-html> div classhatena-module-title>Ubie株式会社/div> div classhatena-module-body> a hrefhttps://ubie.life/ target_blank>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20180619/20180619101539.png alt20180619101539>img srchttps://cdn-ak.f.st-hatena.com/images/fotolife/n/ngsw_taro/20180619/20180619101939.jpg alt20180619101939>/a> /div>/div> div classhatena-module hatena-module-search-box> div classhatena-module-title> 検索 /div> div classhatena-module-body> form classsearch-form rolesearch actionhttps://taro.hatenablog.jp/search methodget> input typetext nameq classsearch-module-input value placeholder記事を検索 required> input typesubmit value検索 classsearch-module-button />/form> /div>/div> div classhatena-module hatena-module-recent-entries > div classhatena-module-title> a hrefhttps://taro.hatenablog.jp/archive> 最新記事 /a> /div> div classhatena-module-body> ul classrecent-entries hatena-urllist > li classurllist-item recent-entries-item> div classurllist-item-inner recent-entries-item-inner> a hrefhttps://taro.hatenablog.jp/entry/2025/12/24/093732 classurllist-title-link recent-entries-title-link urllist-title recent-entries-title>AIボイスレコーダー作った【M5Stack Atom Echo × Supabase × Gemini】/a> /div> /li> li classurllist-item recent-entries-item> div classurllist-item-inner recent-entries-item-inner> a hrefhttps://taro.hatenablog.jp/entry/2024/12/18/153245 classurllist-title-link recent-entries-title-link urllist-title recent-entries-title>Gemini 2.0の空間認識をJavaScriptで試す/a> /div> /li> li classurllist-item recent-entries-item> div classurllist-item-inner recent-entries-item-inner> a hrefhttps://taro.hatenablog.jp/entry/2021/05/13/101114 classurllist-title-link recent-entries-title-link urllist-title recent-entries-title>Ubieだからこそプロダクト開発を全力で楽しめている/a> /div> /li> li classurllist-item recent-entries-item> div classurllist-item-inner recent-entries-item-inner> a hrefhttps://taro.hatenablog.jp/entry/2021/03/31/164922 classurllist-title-link recent-entries-title-link urllist-title recent-entries-title>いまさらだけどContentEditableをいじって、キャレットの扱いがしんどいということがわかったよ/a> /div> /li> li classurllist-item recent-entries-item> div classurllist-item-inner recent-entries-item-inner> a hrefhttps://taro.hatenablog.jp/entry/2020/12/11/154113 classurllist-title-link recent-entries-title-link urllist-title recent-entries-title>KotlinのCompose for Desktopを味見してみたよ〜/a> /div> /li> /ul> /div>/div> div classhatena-module hatena-module-category> div classhatena-module-title> カテゴリー /div> div classhatena-module-body> ul classhatena-urllist> li> a hrefhttps://taro.hatenablog.jp/archive/category/Android classcategory-Android> Android (25) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/AndroidWear classcategory-AndroidWear> AndroidWear (2) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/Google classcategory-Google> Google (4) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/Groovy classcategory-Groovy> Groovy (2) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/HTML5%EF%BC%8FCSS3 classcategory-HTML5/CSS3> HTML5/CSS3 (1) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/IDE classcategory-IDE> IDE (1) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/Java classcategory-Java> Java (6) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/JavaScript classcategory-JavaScript> JavaScript (3) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/Kotlin classcategory-Kotlin> Kotlin (92) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/Ktor classcategory-Ktor> Ktor (2) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/Ruby classcategory-Ruby> Ruby (1) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/Scala classcategory-Scala> Scala (1) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/Spring classcategory-Spring> Spring (1) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/Twitter classcategory-Twitter> Twitter (4) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/Web classcategory-Web> Web (2) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/Web%20API classcategory-Web-API> Web API (4) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/Web%E3%82%A2%E3%83%97%E3%83%AA classcategory-Webアプリ> Webアプリ (4) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/%E3%81%9D%E3%81%AE%E4%BB%96 classcategory-その他> その他 (6) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%EF%BC%8F%E3%82%AB%E3%83%B3%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9 classcategory-イベント/カンファレンス> イベント/カンファレンス (34) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/%E3%82%AD%E3%83%A3%E3%83%AA%E3%82%A2 classcategory-キャリア> キャリア (4) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/%E3%83%84%E3%83%BC%E3%83%AB classcategory-ツール> ツール (1) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/%E3%83%96%E3%83%AD%E3%82%B0%E3%81%8A%E7%9F%A5%E3%82%89%E3%81%9B classcategory-ブログお知らせ> ブログお知らせ (1) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0 classcategory-プログラミング> プログラミング (27) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/%E3%83%A1%E3%83%A2 classcategory-メモ> メモ (11) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA classcategory-ライブラリ> ライブラリ (1) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/%E5%80%8B%E4%BA%BA%E7%9A%84%E3%81%AA%E8%A9%B1 classcategory-個人的な話> 個人的な話 (14) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/%E6%9B%B8%E8%A9%95%EF%BC%8F%E6%9C%AC%E3%81%AE%E6%84%9F%E6%83%B3 classcategory-書評/本の感想> 書評/本の感想 (3) /a> /li> li> a hrefhttps://taro.hatenablog.jp/archive/category/%E7%94%9F%E6%88%90AI classcategory-生成AI> 生成AI (2) /a> /li> /ul> /div>/div> div classhatena-module hatena-module-archive data-archive-typedefault data-archive-urlhttps://taro.hatenablog.jp/archive> div classhatena-module-title> a hrefhttps://taro.hatenablog.jp/archive>月別アーカイブ/a> /div> div classhatena-module-body> ul classhatena-urllist> li classarchive-module-year archive-module-year-hidden data-year2025> div classarchive-module-button> span classarchive-module-hide-button>▼/span> span classarchive-module-show-button>▶/span> /div> a hrefhttps://taro.hatenablog.jp/archive/2025 classarchive-module-year-title archive-module-year-2025> 2025 /a> ul classarchive-module-months> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2025/12 classarchive-module-month-title archive-module-month-2025-12> 2025 / 12 /a> /li> /ul> /li> li classarchive-module-year archive-module-year-hidden data-year2024> div classarchive-module-button> span classarchive-module-hide-button>▼/span> span classarchive-module-show-button>▶/span> /div> a hrefhttps://taro.hatenablog.jp/archive/2024 classarchive-module-year-title archive-module-year-2024> 2024 /a> ul classarchive-module-months> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2024/12 classarchive-module-month-title archive-module-month-2024-12> 2024 / 12 /a> /li> /ul> /li> li classarchive-module-year archive-module-year-hidden data-year2021> div classarchive-module-button> span classarchive-module-hide-button>▼/span> span classarchive-module-show-button>▶/span> /div> a hrefhttps://taro.hatenablog.jp/archive/2021 classarchive-module-year-title archive-module-year-2021> 2021 /a> ul classarchive-module-months> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2021/05 classarchive-module-month-title archive-module-month-2021-5> 2021 / 5 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2021/03 classarchive-module-month-title archive-module-month-2021-3> 2021 / 3 /a> /li> /ul> /li> li classarchive-module-year archive-module-year-hidden data-year2020> div classarchive-module-button> span classarchive-module-hide-button>▼/span> span classarchive-module-show-button>▶/span> /div> a hrefhttps://taro.hatenablog.jp/archive/2020 classarchive-module-year-title archive-module-year-2020> 2020 /a> ul classarchive-module-months> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2020/12 classarchive-module-month-title archive-module-month-2020-12> 2020 / 12 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2020/11 classarchive-module-month-title archive-module-month-2020-11> 2020 / 11 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2020/04 classarchive-module-month-title archive-module-month-2020-4> 2020 / 4 /a> /li> /ul> /li> li classarchive-module-year archive-module-year-hidden data-year2019> div classarchive-module-button> span classarchive-module-hide-button>▼/span> span classarchive-module-show-button>▶/span> /div> a hrefhttps://taro.hatenablog.jp/archive/2019 classarchive-module-year-title archive-module-year-2019> 2019 /a> ul classarchive-module-months> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2019/12 classarchive-module-month-title archive-module-month-2019-12> 2019 / 12 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2019/06 classarchive-module-month-title archive-module-month-2019-6> 2019 / 6 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2019/05 classarchive-module-month-title archive-module-month-2019-5> 2019 / 5 /a> /li> /ul> /li> li classarchive-module-year archive-module-year-hidden data-year2018> div classarchive-module-button> span classarchive-module-hide-button>▼/span> span classarchive-module-show-button>▶/span> /div> a hrefhttps://taro.hatenablog.jp/archive/2018 classarchive-module-year-title archive-module-year-2018> 2018 /a> ul classarchive-module-months> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2018/08 classarchive-module-month-title archive-module-month-2018-8> 2018 / 8 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2018/07 classarchive-module-month-title archive-module-month-2018-7> 2018 / 7 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2018/05 classarchive-module-month-title archive-module-month-2018-5> 2018 / 5 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2018/04 classarchive-module-month-title archive-module-month-2018-4> 2018 / 4 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2018/02 classarchive-module-month-title archive-module-month-2018-2> 2018 / 2 /a> /li> /ul> /li> li classarchive-module-year archive-module-year-hidden data-year2017> div classarchive-module-button> span classarchive-module-hide-button>▼/span> span classarchive-module-show-button>▶/span> /div> a hrefhttps://taro.hatenablog.jp/archive/2017 classarchive-module-year-title archive-module-year-2017> 2017 /a> ul classarchive-module-months> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2017/12 classarchive-module-month-title archive-module-month-2017-12> 2017 / 12 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2017/11 classarchive-module-month-title archive-module-month-2017-11> 2017 / 11 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2017/08 classarchive-module-month-title archive-module-month-2017-8> 2017 / 8 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2017/06 classarchive-module-month-title archive-module-month-2017-6> 2017 / 6 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2017/05 classarchive-module-month-title archive-module-month-2017-5> 2017 / 5 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2017/03 classarchive-module-month-title archive-module-month-2017-3> 2017 / 3 /a> /li> /ul> /li> li classarchive-module-year archive-module-year-hidden data-year2016> div classarchive-module-button> span classarchive-module-hide-button>▼/span> span classarchive-module-show-button>▶/span> /div> a hrefhttps://taro.hatenablog.jp/archive/2016 classarchive-module-year-title archive-module-year-2016> 2016 /a> ul classarchive-module-months> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2016/12 classarchive-module-month-title archive-module-month-2016-12> 2016 / 12 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2016/10 classarchive-module-month-title archive-module-month-2016-10> 2016 / 10 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2016/06 classarchive-module-month-title archive-module-month-2016-6> 2016 / 6 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2016/04 classarchive-module-month-title archive-module-month-2016-4> 2016 / 4 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2016/02 classarchive-module-month-title archive-module-month-2016-2> 2016 / 2 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2016/01 classarchive-module-month-title archive-module-month-2016-1> 2016 / 1 /a> /li> /ul> /li> li classarchive-module-year archive-module-year-hidden data-year2015> div classarchive-module-button> span classarchive-module-hide-button>▼/span> span classarchive-module-show-button>▶/span> /div> a hrefhttps://taro.hatenablog.jp/archive/2015 classarchive-module-year-title archive-module-year-2015> 2015 /a> ul classarchive-module-months> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2015/12 classarchive-module-month-title archive-module-month-2015-12> 2015 / 12 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2015/10 classarchive-module-month-title archive-module-month-2015-10> 2015 / 10 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2015/09 classarchive-module-month-title archive-module-month-2015-9> 2015 / 9 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2015/06 classarchive-module-month-title archive-module-month-2015-6> 2015 / 6 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2015/05 classarchive-module-month-title archive-module-month-2015-5> 2015 / 5 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2015/04 classarchive-module-month-title archive-module-month-2015-4> 2015 / 4 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2015/03 classarchive-module-month-title archive-module-month-2015-3> 2015 / 3 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2015/02 classarchive-module-month-title archive-module-month-2015-2> 2015 / 2 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2015/01 classarchive-module-month-title archive-module-month-2015-1> 2015 / 1 /a> /li> /ul> /li> li classarchive-module-year archive-module-year-hidden data-year2014> div classarchive-module-button> span classarchive-module-hide-button>▼/span> span classarchive-module-show-button>▶/span> /div> a hrefhttps://taro.hatenablog.jp/archive/2014 classarchive-module-year-title archive-module-year-2014> 2014 /a> ul classarchive-module-months> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2014/12 classarchive-module-month-title archive-module-month-2014-12> 2014 / 12 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2014/10 classarchive-module-month-title archive-module-month-2014-10> 2014 / 10 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2014/09 classarchive-module-month-title archive-module-month-2014-9> 2014 / 9 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2014/07 classarchive-module-month-title archive-module-month-2014-7> 2014 / 7 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2014/06 classarchive-module-month-title archive-module-month-2014-6> 2014 / 6 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2014/04 classarchive-module-month-title archive-module-month-2014-4> 2014 / 4 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2014/03 classarchive-module-month-title archive-module-month-2014-3> 2014 / 3 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2014/01 classarchive-module-month-title archive-module-month-2014-1> 2014 / 1 /a> /li> /ul> /li> li classarchive-module-year archive-module-year-hidden data-year2013> div classarchive-module-button> span classarchive-module-hide-button>▼/span> span classarchive-module-show-button>▶/span> /div> a hrefhttps://taro.hatenablog.jp/archive/2013 classarchive-module-year-title archive-module-year-2013> 2013 /a> ul classarchive-module-months> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2013/12 classarchive-module-month-title archive-module-month-2013-12> 2013 / 12 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2013/11 classarchive-module-month-title archive-module-month-2013-11> 2013 / 11 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2013/10 classarchive-module-month-title archive-module-month-2013-10> 2013 / 10 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2013/09 classarchive-module-month-title archive-module-month-2013-9> 2013 / 9 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2013/08 classarchive-module-month-title archive-module-month-2013-8> 2013 / 8 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2013/07 classarchive-module-month-title archive-module-month-2013-7> 2013 / 7 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2013/06 classarchive-module-month-title archive-module-month-2013-6> 2013 / 6 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2013/04 classarchive-module-month-title archive-module-month-2013-4> 2013 / 4 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2013/03 classarchive-module-month-title archive-module-month-2013-3> 2013 / 3 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2013/01 classarchive-module-month-title archive-module-month-2013-1> 2013 / 1 /a> /li> /ul> /li> li classarchive-module-year archive-module-year-hidden data-year2012> div classarchive-module-button> span classarchive-module-hide-button>▼/span> span classarchive-module-show-button>▶/span> /div> a hrefhttps://taro.hatenablog.jp/archive/2012 classarchive-module-year-title archive-module-year-2012> 2012 /a> ul classarchive-module-months> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2012/12 classarchive-module-month-title archive-module-month-2012-12> 2012 / 12 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2012/09 classarchive-module-month-title archive-module-month-2012-9> 2012 / 9 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2012/08 classarchive-module-month-title archive-module-month-2012-8> 2012 / 8 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2012/04 classarchive-module-month-title archive-module-month-2012-4> 2012 / 4 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2012/03 classarchive-module-month-title archive-module-month-2012-3> 2012 / 3 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2012/02 classarchive-module-month-title archive-module-month-2012-2> 2012 / 2 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2012/01 classarchive-module-month-title archive-module-month-2012-1> 2012 / 1 /a> /li> /ul> /li> li classarchive-module-year archive-module-year-hidden data-year2011> div classarchive-module-button> span classarchive-module-hide-button>▼/span> span classarchive-module-show-button>▶/span> /div> a hrefhttps://taro.hatenablog.jp/archive/2011 classarchive-module-year-title archive-module-year-2011> 2011 /a> ul classarchive-module-months> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2011/12 classarchive-module-month-title archive-module-month-2011-12> 2011 / 12 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2011/11 classarchive-module-month-title archive-module-month-2011-11> 2011 / 11 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2011/10 classarchive-module-month-title archive-module-month-2011-10> 2011 / 10 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2011/09 classarchive-module-month-title archive-module-month-2011-9> 2011 / 9 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2011/08 classarchive-module-month-title archive-module-month-2011-8> 2011 / 8 /a> /li> li classarchive-module-month> a hrefhttps://taro.hatenablog.jp/archive/2011/07 classarchive-module-month-title archive-module-month-2011-7> 2011 / 7 /a> /li> /ul> /li> /ul> /div>/div> /div>/aside> /div>/div> /div> /div> footer idfooter data-brandhatenablog> div idfooter-inner> address classfooter-address> a hrefhttps://taro.hatenablog.jp/> img srchttps://cdn.blog.st-hatena.com/images/admin/blog-icon-noimage.png width16 height16 alt算譜王におれはなる!!!!/> span classfooter-address-name>算譜王におれはなる!!!!/span> /a> /address> p classservices> Powered by a hrefhttps://hatena.blog/>Hatena Blog/a> | a hrefhttps://blog.hatena.ne.jp/-/abuse_report?target_urlhttps%3A%2F%2Ftaro.hatenablog.jp%2F classreport-abuse-link test-report-abuse-link target_blank>ブログを報告する/a> /p> /div>/footer> script async srchttps://s.hatena.ne.jp/js/widget/star.js>/script> script> if (typeof window.Hatena undefined) { window.Hatena {}; } if (!Hatena.hasOwnProperty(Star)) { Hatena.Star { VERSION: 2, }; } /script> div idfb-root>/div>script>(function(d, s, id) { var js, fjs d.getElementsByTagName(s)0; if (d.getElementById(id)) return; js d.createElement(s); js.id id; js.src //connect.facebook.net/ja_JP/sdk.js#xfbml1&appId719729204785177&versionv17.0; fjs.parentNode.insertBefore(js, fjs);}(document, script, facebook-jssdk));/script> div classquote-box> div classtooltip-quote tooltip-quote-stock> i classblogicon-quote title引用をストック>/i> /div> div classtooltip-quote tooltip-quote-tweet js-tooltip-quote-tweet> a classjs-tweet-quote target_blank data-track-namequote-tweet data-track-once> img srchttps://cdn.blog.st-hatena.com/images/admin/quote/quote-x-icon.svg?versionf9947fdf1627a1d1b3c8c87a6a5233 title引用して投稿する > /a> /div>/div>div classquote-stock-panel idquote-stock-message-box styleposition: absolute; z-index: 3000> div classmessage-box idquote-stock-succeeded-message styledisplay: none> p>引用をストックしました/p> button classbtn btn-primary idquote-stock-show-editor-button data-track-namecuration-quote-edit-button>ストック一覧を見る/button> button classbtn quote-stock-close-message-button>閉じる/button> /div> div classmessage-box idquote-login-required-message styledisplay: none> p>引用するにはまずログインしてください/p> button classbtn btn-primary idquote-login-button>ログイン/button> button classbtn quote-stock-close-message-button>閉じる/button> /div> div classerror-box idquote-stock-failed-message styledisplay: none> p>引用をストックできませんでした。再度お試しください/p> button classbtn quote-stock-close-message-button>閉じる/button> /div> div classerror-box idunstockable-quote-message-box styledisplay: none; position: absolute; z-index: 3000;> p>限定公開記事のため引用できません。/p> /div>/div>script typex-underscore-template idjs-requote-button-template> div classrequote-button js-requote-button> button classrequote-button-btn tipsy-top title引用する>i classblogicon-quote>/i>/button> /div>/script> div idhidden-subscribe-button styledisplay: none;> div classhatena-follow-button-box btn-subscribe js-hatena-follow-button-box > a href# classhatena-follow-button js-hatena-follow-button> span classsubscribing> span classforeground>読者です/span> span classbackground>読者をやめる/span> /span> span classunsubscribing data-track-nameprofile-widget-subscribe-button data-track-once> span classforeground>読者になる/span> span classbackground>読者になる/span> /span> /a> div classsubscription-count-box js-subscription-count-box> i>/i> u>/u> span classsubscription-count js-subscription-count> /span> /div>/div> /div> script async srchttps://platform.twitter.com/widgets.js charsetutf-8>/script>script srchttps://b.st-hatena.com/js/bookmark_button.js charsetutf-8 asyncasync>/script>script typetext/javascript srchttps://cdn.blog.st-hatena.com/js/external/jquery.min.js?v1.12.4&versionf9947fdf1627a1d1b3c8c87a6a5233>/script>script srchttps://cdn.blog.st-hatena.com/js/texts-ja.js?versionf9947fdf1627a1d1b3c8c87a6a5233>/script> script idvendors-js data-envproduction srchttps://cdn.blog.st-hatena.com/js/vendors.js?versionf9947fdf1627a1d1b3c8c87a6a5233 crossoriginanonymous>/script>script idhatenablog-js data-envproduction srchttps://cdn.blog.st-hatena.com/js/hatenablog.js?versionf9947fdf1627a1d1b3c8c87a6a5233 crossoriginanonymous data-page-idindex>/script> script>Hatena.Diary.GlobalHeader.init()/script> script idvalve-dmp data-serviceblog srchttps://cdn.pool.st-hatena.com/valve/dmp.js data-test-iddmpjs async>/script> /body>/html>
View on OTX
|
View on ThreatMiner
Please enable JavaScript to view the
comments powered by Disqus.
Data with thanks to
AlienVault OTX
,
VirusTotal
,
Malwr
and
others
. [
Sitemap
]