ミリオンアプリ
Webアプリを数十秒でAIが作ってくれます!
どんなアプリを作ってみますか?
音声を認識するように改善 花と実を順に読み上げるので認識する。 結果を見やすくする。 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>生育調査アプリ</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.22.20/babel.min.js"></script> <style> body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; margin: 0; padding: 0; background-color: #f9fafb; } .container { max-width: 500px; margin: 20px auto; padding: 20px; background-color: #f7f8fa; border-radius: 8px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); } h1 { font-size: 24px; text-align: center; margin-bottom: 20px; color: #333; } .status-bar { padding: 8px; margin-bottom: 16px; text-align: center; border-radius: 4px; color: white; font-weight: 500; } .status-active { background-color: #10b981; } .status-inactive { background-color: #6b7280; } .section { margin-bottom: 16px; } .section-title { font-size: 14px; font-weight: 500; margin-bottom: 8px; color: #4b5563; } .card { background-color: #ffffff; padding: 12px; border-radius: 4px; border: 1px solid #e5e7eb; } .command-list { font-size: 14px; color: #6b7280; margin-bottom: 8px; } .command-list ul { list-style-type: disc; margin-left: 20px; padding-left: 0; } .button-row { display: flex; gap: 8px; } .button { padding: 8px; border-radius: 4px; color: white; border: none; cursor: pointer; flex: 1; font-weight: 500; display: flex; align-items: center; justify-content: center; } .button-mic { background-color: #3b82f6; } .button-mic.active { background-color: #ef4444; } .button-undo { background-color: #f59e0b; } .button-save { background-color: #10b981; } .button-clear { background-color: #6b7280; } .message { margin-bottom: 16px; padding: 8px; background-color: #dbeafe; color: #1e40af; border-radius: 4px; text-align: center; } .form-row { display: flex; margin-bottom: 8px; } .form-group { display: flex; align-items: center; margin-right: 16px; } .form-group.grow { flex-grow: 1; } .form-label { margin-right: 8px; } .form-select, .form-input { border: 1px solid #d1d5db; border-radius: 4px; padding: 4px; } .form-input { width: 100%; } .submit-button { width: 100%; padding: 8px; background-color: #3b82f6; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: 500; } .table-container { background-color: #fff; border: 1px solid #e5e7eb; border-radius: 4px; max-height: 256px; overflow-y: auto; } table { width: 100%; border-collapse: collapse; } thead { background-color: #f3f4f6; position: sticky; top: 0; } th, td { padding: 8px; text-align: left; font-size: 14px; } th { color: #4b5563; } tr { border-top: 1px solid #e5e7eb; } tr:first-child { border-top: none; } .empty-row { text-align: center; color: #9ca3af; padding: 8px; } .info-section { margin-top: 16px; padding-top: 16px; border-top: 1px solid #e5e7eb; } .info-title { font-size: 18px; font-weight: 500; margin-bottom: 8px; } .info-text { font-size: 14px; color: #6b7280; margin-bottom: 8px; line-height: 1.5; } .warning { padding: 8px; background-color: #fef3c7; color: #92400e; border-radius: 4px; font-size: 14px; } </style> </head> <body> <div id="root"></div> <script type="text/babel"> const { useState, useEffect, useRef } = React; function PlantGrowthTracker() { const [records, setRecords] = useState([]); const [isListening, setIsListening] = useState(false); const [inputType, setInputType] = useState('花'); const [inputValue, setInputValue] = useState(''); const [message, setMessage] = useState(''); // 音声認識のためのref const recognitionRef = useRef(null); // コンポーネントマウント時に音声認識を初期化 useEffect(() => { // ブラウザの音声認識APIをチェック const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; if (SpeechRecognition) { const recognition = new SpeechRecognition(); recognition.lang = 'ja-JP'; // 日本語に設定 recognition.continuous = true; // 連続認識モード recognition.interimResults = false; // 最終結果のみ使用 // 音声認識結果のイベントハンドラ recognition.onresult = (event) => { const transcript = event.results[event.results.length - 1][0].transcript.trim(); processVoiceCommand(transcript); }; // エラーハンドラ recognition.onerror = (event) => { console.error('音声認識エラー:', event.error); setMessage(`音声認識エラー: ${event.error}`); setIsListening(false); }; // 音声認識終了時のハンドラ recognition.onend = () => { // 継続モードの場合は再開する(停止フラグがfalseの場合) if (isListening) { recognition.start(); } else { setMessage('音声認識停止'); } }; recognitionRef.current = recognition; } else { setMessage('お使いのブラウザは音声認識をサポートしていません'); } // クリーンアップ関数 return () => { if (recognitionRef.current) { recognitionRef.current.stop(); } }; }, []); // isListeningの変更を監視 useEffect(() => { if (isListening) { if (recognitionRef.current) { try { recognitionRef.current.start(); setMessage('音声認識中... 「花 5」「実 3」「停止」などと話してください'); } catch (error) { console.error('音声認識開始エラー:', error); setMessage('音声認識の開始に失敗しました'); setIsListening(false); } } } else { if (recognitionRef.current) { try { recognitionRef.current.stop(); } catch (error) { console.error('音声認識停止エラー:', error); } } } }, [isListening]); // 音声認識の開始/停止切り替え const toggleListening = () => { setIsListening(prevState => !prevState); }; // 音声コマンドの処理 const processVoiceCommand = (command) => { console.log('認識されたコマンド:', command); setMessage(`認識: ${command}`); // 花の数を記録するコマンド const flowerMatch = command.match(/花\s*(\d+)/); if (flowerMatch) { const value = flowerMatch[1]; addRecord('花', value); return; } // 実の数を記録するコマンド const fruitMatch = command.match(/実\s*(\d+)/); if (fruitMatch) { const value = fruitMatch[1]; addRecord('実', value); return; } // 停止コマンド if (command.includes('停止')) { setIsListening(false); return; } // 取り消しコマンド if (command.includes('取り消し')) { undoLastRecord(); return; } // コマンドが認識できなかった場合 setMessage(`認識されましたが、コマンドとして処理できませんでした: ${command}`); }; // 記録追加関数 const addRecord = (type, value) => { if (!value || isNaN(value)) { setMessage('有効な数値を入力してください'); return; } const now = new Date(); const dateTimeStr = `${now.toLocaleDateString()} ${now.toLocaleTimeString()}`; setRecords(prevRecords => [ ...prevRecords, { date: dateTimeStr, type, value: parseInt(value, 10) } ]); setMessage(`${type} ${value}を記録しました`); setInputValue(''); }; // 手動追加 const handleManualAdd = () => { addRecord(inputType, inputValue); }; // 最後の記録を取り消し const undoLastRecord = () => { if (records.length > 0) { const newRecords = [...records]; newRecords.pop(); setRecords(newRecords); setMessage('最後の記録を取り消しました'); } else { setMessage('取り消す記録がありません'); } }; // CSVとしてダウンロード const downloadCSV = () => { if (records.length === 0) { setMessage('記録がありません'); return; } const header = '日付,時間,種類,数値\n'; const csvContent = records.map(record => { const [date, time] = record.date.split(' '); return `${date},${time},${record.type},${record.value}`; }).join('\n'); const blob = new Blob([header + csvContent], { type: 'text/csv' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `生育調査_${new Date().toISOString().split('T')[0]}.csv`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); setMessage('CSVファイルをダウンロードしました'); }; // 全記録クリア const clearAllRecords = () => { if (window.confirm('すべての記録を削除してもよろしいですか?')) { setRecords([]); setMessage('全記録をクリアしました'); } }; return ( <div className="container"> <h1>生育調査アプリ</h1> {/* 音声認識ステータス表示 */} <div className={`status-bar ${isListening ? 'status-active' : 'status-inactive'}`}> {isListening ? '音声認識中...' : '音声認識停止中'} </div> {/* 音声認識コントロール */} <div className="section"> <div className="section-title">音声認識</div> <div className="card"> <div className="command-list"> 音声コマンド一覧: <ul> <li>「花 [数値]」→ 花の数を記録</li> <li>「実 [数値]」→ 実の数を記録</li> <li>「停止」→ 音声認識を停止</li> <li>「取り消し」→ 最後の記録を取り消し</li> </ul> </div> <div className="button-row"> <button onClick={toggleListening} className={`button button-mic ${isListening ? 'active' : ''}`} > 🎤 {isListening ? '停止' : '開始'} </button> <button onClick={undoLastRecord} className="button button-undo" > 取り消し </button> <button onClick={downloadCSV} className="button button-save" > CSV保存 </button> <button onClick={clearAllRecords} className="button button-clear" > クリア </button> </div> </div> </div> {/* メッセージ表示 */} {message && ( <div className="message"> {message} </div> )} {/* 手動入力フォーム */} <div className="section"> <div className="section-title">手動入力</div> <div className="card"> <div className="form-row"> <div className="form-group"> <span className="form-label">種類:</span> <select value={inputType} onChange={(e) => setInputType(e.target.value)} className="form-select" > <option value="花">花</option> <option value="実">実</option> </select> </div> <div className="form-group grow"> <span className="form-label">数値:</span> <input type="number" value={inputValue} onChange={(e) => setInputValue(e.target.value)} className="form-input" min="0" /> </div> </div> <button onClick={handleManualAdd} className="submit-button" > 追加 </button> </div> </div> {/* 記録一覧 */} <div className="section"> <div className="section-title">記録一覧</div> <div className="table-container"> <table> <thead> <tr> <th>日付</th> <th>時間</th> <th>種類</th> <th>数値</th> </tr> </thead> <tbody> {records.length === 0 ? ( <tr> <td colSpan="4" className="empty-row"> 記録がありません </td> </tr> ) : ( records.map((record, index) => { const [date, time] = record.date.split(' '); return ( <tr key={index}> <td>{date}</td> <td>{time}</td> <td>{record.type}</td> <td>{record.value}</td> </tr> ); }) )} </tbody> </table> </div> </div> {/* 音声認識の使用説明 */} <div className="info-section"> <h3 className="info-title">音声認識の使い方</h3> <p className="info-text"> 1. 「🎤 開始」ボタンをクリックして音声認識を開始します。<br /> 2. マイクのアクセス許可を求められたら「許可」をクリックします。<br /> 3. 「花 5」のように話して記録を追加します。<br /> 4. 「停止」と言うか「🎤 停止」ボタンをクリックして音声認識を終了します。 </p> <div className="warning"> 注意: 音声認識はChrome、Edge、Safariなど一部のブラウザでのみ動作します。 また、インターネット接続が必要です。 </div> </div> </div> ); } ReactDOM.render(<PlantGrowthTracker />, document.getElementById('root')); </script> </body> </html> 記録が見えるようにする
作る
おすすめアプリ
九蓮宝燈があがれる麻雀ゲーム[gpt-3.5]
228 pv
音声を認識するように改善 花と実を順に読み上げるので認識する。 結果を見やすくする。 &a…[o1-mini]
26 pv
入力された文章に対して、「えー」、「まあ」、「あー」、「えーと」、「ええと」などのフィラーワー…[gpt-3.5]
287 pv
8つの数字(x1,x2,x3,x4,y1,y2,y3,y4)を入力する。そして、x1-x2、x…[gpt-3.5]
6 pv
くのいち「時雨」が、「彩眠香」を用いて雲雀城に潜む5人の忍者を全て眠らせるゲームを作って下さい…[gpt-3.5]
203 pv
🌞太陽の光が差し込む平和な朝。🏢オフィスビルの一室で、☕コーヒーを飲みながら📰新聞を読む👔スー…[gpt-4o]
263 pv
架空のZAKOS基地での哨戒任務ゲーム。 アプリの製作にあたり、evalは使用しないこと。画…[gpt-4o]
256 pv
競輪選手の選手登録番号を入力すると、選手名を教えてくれるアプリ[gpt-3.5]
1418 pv
グループ健康管理ツール[gpt-3.5]
1095 pv
タイトル「💩キャッチみーすけ!」 下記の「」内のゲームを作ってください。 「350x350の…[gpt-3.5]
43 pv
くのいち「時雨」が、敵の城「月影の城」に潜入するゲーム。 アプリの作成にあたっては、画像…[gpt-3.5]
273 pv
1から37の数字から7つの数字をランダムに抽選するアプリを作って下さい。 スタートとスト…[gpt-3.5]
260 pv
”自然数を入力するボックス” ”そのボックスに入力された数を連続して8回まで2倍にした数を縦…[gpt-3.5]
32 pv
IDとパスワードを入力する。パスワードの強度を5段階で評価してカラーバーで表示する。パスワード…[gpt-3.5]
1236 pv
犬が歩くアプリ[gpt-3.5]
210 pv
ボタンが押された時、100円ずつ溜まっていく[gpt-3.5]
247 pv
ブロック崩しを作ってください[gpt-3.5]
2037 pv
人狼ゲーム[gpt-3.5]
31 pv
ダイエットしてる人のトレーニングメニューを考えるアプリ。トレーニングの時間、強度を選択できる。…[gpt-3.5]
2034 pv
WordPress カウントダウンタイマーショートコード function[o1-mini]
34 pv
Create the calculator: UI layout: the calcu…[gpt-3.5]
566 pv
webサイトを上下自動スクロールする。倍速機能があり、1.0から3.0まで選択できる[gpt-3.5]
878 pv
じゃんけんアプリ。「グー✊」「チョキ✌️」「パー✋」を選択する。勝ったときだけ日本語でランダム…[gpt-3.5]
44 pv
旅行の候補を出してくれるアプリ[gpt-3.5]
20 pv
ランダムな状態で始まるライフゲームを表示するアプリ[gpt-3.5]
1549 pv
スマホをタップしている時間に応じてジャンプする高さが変わり、流れてくるゴミをよけながら人が進む…[gpt-3.5]
26825 pv
スロットゲーム。 「開始」ボタンを押すとランダムな絵文字を5つ表示する。 3つ揃うと「おめ…[gpt-3.5]
375 pv
好きな色を日本語で入力する。入力した色のカラーコードを16進数で表示する。すべての色のカラーコ…[gpt-3.5]
39 pv
熊本弁に変換するアプリ[gpt-3.5]
679 pv
インターネット未接続オフライン無しでスマホの撮った画像を送信するとアニメ調のイラストに変換して…[gpt-3.5]
882 pv