ビジネスアクセラレーション事業部の德永です!
前回の記事では雑なメモを投げるだけでGemini APIがタスクを自動で整理してくれるTodo管理アプリを作りました。作成までの工程など詳しくはこちらをご覧ください!
今回はそのアプリを実際に使ってみて気づいた課題を解決しながら機能を追加したのでそちらを紹介していきたいと思います。
目次
- 前回からの課題
- Streamlitとは — PythonだけでUIを作る
- 日付の正規化 — 「明日」を日付に変換する
- Slack通知機能 — 忘れない仕組みを作る
- 完了フラグ機能 — やった記録を残す
- タスク編集機能 — 後から変更できるように
- UI/UX改善で学んだこと — マイクロインタラクションとは?
- まとめと今後の展望
1. 前回からの課題
前回のアプリはメモを投げるとAIが自動で優先順位を判断してタスクを整理するという基本的な機能は動いていましたが、実際に使用してみると改善したい箇所がいくつか出てきました。
- フロント画面がシンプルすぎる
タスク追加はSwagger UIからしかできず、HTML画面との行き来が手間だった
- 「明日」「今日」などの日付が更新されない
Geminiが「明日」や「今日」という文字をそのまま返していたので、翌日にタスク一覧を見ても「明日」のままだった
- 通知機能がない
タスクの期限が来ても気づく仕組みがなかった
- 完了したタスクを管理できない
削除するしかなくやった記録を残せなかった
- 後からタスクを修正できない
一度登録した期限や優先度を変える手段がなかった
これらを今回の改善編では解決しました!
2. Streamlitとは — PythonだけでUIを作る
今回はフロント作成にあたりStreamlitというフレームワークを使いました。
※公式サイトより
Streamlitの特徴は以下の3つです。
- Pythonだけで完結できる
HTML/CSS/JavaScriptなどのフロントの知識が不要でPythonだけで書くことができます。
- 変更のリアルタイム反映
コードを書いてリロードボタンを押せば変更や修正した箇所がリアルタイムで画面に反映されます。試行錯誤しながら作るプロトタイプにすごく向いています。
- データ可視化が得意
メトリクスやテーブル、グラフなどデータの可視化に強いフレームワークなのでタスク件数を一目で把握できるUIを簡単に作成することができました。
こちらがStreamlit導入前のHTML版の画面です。

タスク追加はSwagger UIからしかできず、確認はこのHTML画面に戻るという行き来が発生していました。
また、コード量も50行以上ありました。
そしてこちらがStreamlit導入後です。

Streamlit版では、メモ追加・一覧・削除・Slack通知が全部1画面に収まり、コード量は約30行に削減できました。
実装ポイント
メモ入力欄とボタンはこれだけで作れます。
memo = st.text_area("メモを入力してください")
if st.button("ToDoを抽出"):
response = requests.post(
"http://localhost:8000/extract-todos",
json={"memo": memo}
)
期限別のメトリクス表示も数行で完成します。
col1, col2, col3, col4 = st.columns(4)
col1.metric("⚠️ 今日", f"{今日}件")
col2.metric("📅 明日", f"{明日}件")
st.columns()でレイアウトを分けて、st.metric()を呼ぶだけでカード状のUIができるのはStreamlitならではだと思います。
3. 日付の正規化 — 「明日」を日付に変換する
前回までの実装ではGemini APIが「明日」「今週末」などの文字列をそのままDBに保存していました。
例えば、4月1日に「明日レポート提出」と登録すると、DBにはそのまま「明日」という文字列で保存されます。翌日の4月2日にアプリを開いてもその「明日」の文字は変わらず日付としての計算ができていませんでした。
そこでプロンプトエンジニアリングで解決することができました。
プロンプトエンジニアリングとは、生成AIから、意図した通りの回答を得るために、AIへの指示文(プロンプト)を設計・最適化する手法のことです。
解決策として私が修正を加えたプロンプトは以下の3つです。
- 「期限は必ずYYYY-MM-DD形式で出力してください」という強い制約
- 「今日の日付は○○です」と具体的な日付を渡す
- 「明日→2026-02-27」のような例を示す
prompt = f"""以下のメモからToDoを抽出してください
【重要】期限は必ずYYYY-MM-DD形式で出力してください。
今日の日付は{today}です。
例: 「明日」→ {tomorrow}
"""
このようにすると「今日」「今週末」などの文字列が2026-04-02のような具体的な日付に変換され、自動で日付が変わるごとに更新してくれるようになりました。
AIへの指示は具体的・明確であるほど精度が上がると改めて実感した部分です。
表示の工夫
先ほど上記の設定で日付に変換されるように修正をしましたが、画面に表示する時には「今日」「明日」「○日後」のように出力したかったです。これを実現させるためにDBには具体的な日付(例: 2026-04-01)で保存して、画面に表示するときだけformat_deadline()という関数で「今日」「明日」「○日後」に変換しました。
日が変わると自動的に表示も更新されます。
DBの値は変わっていないのに、今日の日付との差分を毎回計算するので「明後日」を「明日」に変えることができました。それ以上の日にちは「○日後」という形で毎日自動更新される仕組みになります。

4. Slack通知機能 — 忘れない仕組みを作る
Incoming Webhookとは?
Slack通知の実装にはIncoming Webhookを使って手動通知と自動通知の2種類を実装しました。Incoming Webhookとは、Slackが発行するメッセージ送信専用のURLのことです。
※公式サイトより
そのURLにHTTP POSTするだけで、指定したSlackチャンネルにメッセージが届きます。
手動通知にはStreamlitの画面にボタンを2つ配置しています。

「今日のタスクをSlackに送信」と「全タスク一覧を送信」です。ボタンを押すだけでその時点のタスク状況をSlackに送ることができました。こちらが実際に手動通知した時のSlack画面です。
コードはこれだけです。
webhook_url = os.getenv("SLACK_WEBHOOK_URL")
requests.post(webhook_url, json={"text": message})
認証も複雑な設定も不要で、シンプルに実装することができました。
ただしURLさえあれば誰でもメッセージを送れてしまうので、.envファイルで管理してコードに直書きしないようにしています。
自動通知はPythonのscheduleライブラリを使って毎日の決まった時間に自動で送る仕組みを作りました。
schedule.every().day.at("10:00").do(send_morning_notification)
while True:
schedule.run_pending()
time.sleep(60) # 1分ごとにチェック
1分ごとに時間をチェックして、10時になったら通知を送るという仕組みです。また、土日は通知不要なのでweekday()を使って平日のみ動作するようにもしました。
if datetime.now().weekday() >= 5: # 土=5、日=6
return # スキップ

たった3行のコード追加で自動通知を実現することができました!
5. 完了フラグ機能 — やった記録を残す
DBにカラムを追加する
次に、タスクを完了にしても削除せず、完了した記録として残す機能の追加についてです。以下の2つのカラムをDBに追加しました。
is_completed INTEGER DEFAULT 0 -- 0=未完了、1=完了 completed_at DATE -- 完了した日付
既存のDBに追加する場合はALTER TABLEを使います。ただしCREATE TABLE IF NOT EXISTSはすでにテーブルがあると実行されないので、カラムの存在チェックも入れています。
columns = [d[1] for d in cursor.execute("PRAGMA table_info(todos)").fetchall()]
if "is_completed" not in columns:
cursor.execute("ALTER TABLE todos ADD COLUMN is_completed INTEGER DEFAULT 0")
表示の工夫
DBには全データを保持したまま、表示上は7日以内の完了済みのみ表示しています。グラフは全期間のデータを使って推移を可視化できます。

また、Streamlitのst.data_editor()を使うと、テーブルにチェックボックスを追加して完了にできるUIが簡単に作れます。

完了タスクの推移グラフ
analyticsページ(別ページ)に完了タスクの推移グラフを作りました。Plotlyを使うことで日付単位のグラフを綺麗に表示できます。
マルチページ化はStreamlitのpages/フォルダにファイルを置くだけで実現できました。ファイル名がそのままサイドバーのページ名になります。

6. タスク編集機能 — 後から変更できるように
次にタスク編集機能についてです。元々タスク追加とタスク削除しか機能がありませんでしたが、登録後にタスク名/優先度/期限などを変更できる機能を追加しました。
@app.put("/todos/{todo_id}")
def update_todo(todo_id: int, update: TodoUpdate):
cursor.execute(
"UPDATE todos SET task=?, priority=?, deadline=? WHERE id=?",
(update.task, update.priority, update.deadline, todo_id)
)
Streamlit側では直接IDを入力するよりもタスク名でプルダウン選択できる方が使いやすいことに気づきました。
todo_options = {f"{todo['id']}: {todo['task']}": todo['id'] for todo in 未完了}
selected = st.selectbox("編集するタスクを選択", list(todo_options.keys()))
辞書内包表記でIDとタスク名のマッピングを作ることで、プルダウンで選んだらIDが取れる仕組みを作成しました!

7. UI/UX改善で学んだこと — マイクロインタラクションとは?
今回の開発で特に面白かったのがUI/UX改善の部分です。
初めに、UIとUXの違いについて簡単に整理します。
UIとは画面のデザインや見た目など「見える部分」、UXはその操作を通じた体験や感覚など「感じる部分」のことです。
Streamlitにはカードデザインやトースト通知、風船アニメーションなどユーザーに対して視覚的に分かりやすいフィードバックを返すことができます。
カードデザインはUIの改善、トーストや風船はUXの改善にあたります。
- 🎨 カードデザイン(UI改善)
一覧表示する際に優先度ごとに色分けされたカードで表示します。
- 🔔 トースト通知(UX改善)
「削除しました!」などのメッセージが画面右下に数秒だけ表示されて消える通知です。
- 🎈 風船アニメーション(UX改善)
編集完了時に画面いっぱいに風船が飛びます。
マイクロインタラクションとは?
マイクロインタラクションとは、ユーザーのちょっとしたアクションに対する細やかなフィードバックのことです。
例えばSNSでいいねボタンを押すとハートが弾けるアニメーションや、メール送信後に「送信しました!」とポップアップが出る、これらは全てマイクロインタラクションです。
デジタル上のやり取りでもユーザーと対話し物理的な手応えを与えるのが重要であるということを学びました。
自分のアプリで実装したこと
今回実装したUI/UX改善はこのマイクロインタラクションを取り入れた変更です。
| ユーザーのアクション | フィードバック | 効果 |
|---|---|---|
| 削除ボタンを押す | トースト通知「削除しました!」 | 操作が伝わった安心感 |
| 編集完了ボタンを押す | 風船🎈が画面を飛ぶ | 達成感・アプリへの愛着 |
| タスク一覧を見る | 優先度カラーのカード表示 | 瞬時に優先度を判断できる |
st.toast("削除しました!", icon="✅") # トースト通知
st.balloons() # 風船アニメーション

実装してみて感じたこと
今まで作ってきた画面は静的でボタンを押してもリアクションを実装していなかったので何かが起きた感覚が薄かったです。
しかし、トーストや風船などの視覚的に分かりやすい通知機能を入れたことでアプリがユーザーの入力に対して応えてくれる感覚に変わりました。
また、マイクロインタラクションを学ぶ中で目立ちすぎないことも重要であることがわかったので、風船アニメーションは編集完了のタイミングだけに絞りました。
毎回派手なリアクションがあっても疲れてしまうので使い分けが大事になりますね!
8. まとめと今後の展望
今回の改善を通じて学んだことを3つにまとめます。
DBの設計の重要性:
後からカラムを追加する場合はALTER TABLEで対応できますが、最初の設計段階から、後で機能を追加することも見据えた拡張性を意識することが大事だと実感しました。
UI/UXの工夫:
カードデザイン・トースト・風船など小さな工夫が使いやすさと開発モチベーションを大きく上げてくれました。機能の充実だけがアプリの質ではないことを学びました。
Streamlitのマルチページ:
pages/フォルダにファイルを置くだけでページ分割できます。よく使う機能と分析系を分けることで画面がスッキリして、それぞれの役割が明確になりました。
今後試したいこと
- タスクへのメモ機能 — タスクごとに作業ログを残せるようにしたい
※補足:例えば「エラー調査」というタスクに対して「このエラーはこう解決した」という証跡が残せると、個人の知識管理ツールとしても使えそうです。
- AI系機能の拡張 — 期限切れタスクの自動検出や優先度の自動提案
- 認証機能 — 複数ユーザーで使えるように
- フロントの継続改善 — 引き続きUI/UXの改善を行っていく
個人開発を通じて、機能を作るだけでなく使いやすさや体験の質にも目を向けるようになったのが今回の一番の収穫でした。
長くなりましたが最後までご覧いただきありがとうございました!