1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Copilotだけで0から動作確認まで Azure × OpenAI を用いたコールセンター音声分析デモの作成

1
Posted at

はじめに

本稿では、Copilot の支援のみを活用し、0 から動作確認可能なコールセンター音声分析デモアプリを作成した経験をシェアします。
Azure サービスと OpenAI を組み合わせ、実用性を意識した最小構成のデモを短期間で構築しました。
本取り組みを通じて特に重要だと感じたポイントは、以下の点です。

  • 要件定義の精密化(最重要)

🎯 アプリ概要

ニーズ

複数のコールセンター音声ファイル(WAV形式)から、以下を 自動抽出 したい:

  • 主要インテント(解約、料金照会、クレームなど)
  • 通話内容の要約
  • 顧客の質問と対応内容
  • オペレーターへのアドバイス

アプローチ

WAV ファイル
    ↓
Azure AI Speech(日本語文字起こし)
    ↓
Azure OpenAI(インテント抽出・分析)
    ↓
Streamlit(UI表示)

成果物

  • Streamlit アプリ ← 完全動作
  • 3つの結果ビュー ← UX設計済み
  • 18個のユニットテスト ← すべてグリーン
  • 詳細ドキュメント ← 実装ガイド付き

🏗️ 要件の精密化

AIとの対話プロセス

初期の要件指定は「曖昧さ」を含みがちです。実装前に 以下を明確化 しました:

❌ 曖昧な要件

「複数の音声ファイルを分析し、インテント抽出して結果を表示したい」

✅ 明確な要件に変換

ファイル入力:
  • WAV 形式のみ対応
  • 最大 200MB(1ファイル)
  • 複数選択可能
  • エラーハンドリング明記

処理パイプライン:
  • speech.py で Azure Speech を呼び出し(ja-JP)
  • llm.py で Azure OpenAI を呼び出し(GPT-4等)
  • parser.py で LLM 出力を構造化パース

結果表示:
  • セクション A: 各音声の要約(3カラム)
  • セクション B: インテント一覧表(DataFrame)
  • セクション C: 詳細分析(expander + 音声プレイヤー + 2カラム)

エラー処理:
  • ファイル不正 → st.warning() で表示
  • 音声認識失敗 → 「無音またはサポートされていない形式」
  • LLM API エラー → ユーザーフレンドリーなメッセージ

技術スタック選定

レイヤー 選択技術 理由
UI Streamlit 迅速なPrototyping、デプロイ容易
音声認識 Azure AI Speech 日本語精度、ストリーミング対応
LLM Azure OpenAI 長文出力対応、日本語性能
データ処理 Pandas テーブル表示が簡単
テスト pytest モック対応、CI/CD 統合

ディレクトリ構造の決定

call-analytics/
├── main.py              # Streamlit エントリ
├── models.py            # データクラス
├── services/            # ビジネスロジック
│   ├── speech.py
│   ├── llm.py
│   └── parser.py
├── tests/               # ユニットテスト
│   ├── test_parser.py
│   └── test_prompt.py
├── requirements.txt
├── .env.example
└── README.md

判断基準:

  • services/ で外部API呼び出しを集約 → テスト容易
  • models.py でデータモデルを統一 → 型安全性
  • tests/ でテストを分離 → 保守性

実装依頼

実行環境

Chat Editor > Agent > Claude Haiku 4.5

依頼内容(プロンプト)

あなたは熟練のフルスタックPythonエンジニアです。次の要件で、Streamlitベースのデモアプリを“新規リポジトリとして”実装してください。成果物は動作するコード一式、README、.env.example、単体テスト(pytest)を含みます。

# 1. ゴール(アプリの目的)
コールセンター音声(WAV)を複数まとめてアップロードし、各音声を
(1) Azure AI Speech で日本語文字起こし(ja-JP)
(2) Azure OpenAI で「主要インテント・要約・質問内容・回答内容・詳細・オペレーターへのアドバイス」を抽出
し、結果を一覧と詳細で表示する。

# 2. 技術スタック/制約
- 言語: Python
- UI: Streamlit
- 音声認識: Azure AI Speech SDK(azure-cognitiveservices-speech)
- LLM: Azure OpenAI(openai>=2.26.0 の AzureOpenAI クライアント)
- dotenvで環境変数を読み込む
- 1ファイルあたり最大200MB、拡張子.wavのみ、複数選択可
- ローカル起動: `streamlit run main.py` で http://localhost:8501 にアクセス(READMEにも明記)
- Secrets(API Key等)は絶対にコミットしない(.env / .env.example 運用)

環境変数名は以下を使用する(.env.exampleも同名で作る):
SPEECH_KEY
SPEECH_REGION
AZURE_OPENAI_ENDPOINT
AZURE_OPENAI_API_KEY
AZURE_OPENAI_DEPLOYMENT_NAME
AZURE_OPENAI_API_VERSION (省略時デフォルト: 2025-04-01-preview)

# 3. 画面要件(UI)
Streamlitで次の構成を実装する:

## 3.1 ヘッダー
- タイトル: 「📞 コールセンター音声 インテント抽出PoC」
- 説明文: 「複数のWAV形式の音声ファイルを一括でアップロードし、分析・比較できます。」

## 3.2 アップロード
- file_uploader:
  - ラベル: 「音声ファイル(.wav)をアップロードしてください(複数選択可)」
  - type=["wav"], accept_multiple_files=True
  - 200MB制限を超えるファイルがあればエラー表示して除外(もしくは処理停止)
- 選択された件数を info 表示(例: 「3件のファイルが選択されています。」)

## 3.3 一括解析ボタン
- primaryボタン: 「一括解析を実行する」
- 押下で処理開始し、進捗バーとステータステキストを表示:
  - 「処理中 (i/N): filename ...」
- 全完了時: 「すべてのファイルの解析が完了しました!」を success 表示

## 3.4 結果表示(3セクション)
A) 「📋 各音声の要約」
  - 各ファイルごとに
    - 要約
    - 質問内容
    - 回答内容
B) 「📊 インテント抽出結果一覧」
  - DataFrameで表表示(columns: ファイル名, 主要インテント, 分析結果)
  - hide_index=True, use_container_width=True
C) 「📄 各音声の詳細分析」
  - 各ファイルを expander で表示:
    - 見出し: 「📁 {ファイル名} (インテント: {主要インテント})」
    - st.audio で音声プレイヤー
    - 2カラム:
      - 左: 「📝 文字起こし結果」全文
      - 右: 「💡 分析結果」全文(LLMの生出力を表示)

# 4. 処理要件(パイプライン)
各アップロード音声に対し:

## 4.1 一時ファイル化
- tempfile.NamedTemporaryFile(delete=False, suffix=".wav") を使って保存
- 終了時に必ず削除(finallyでos.remove)

## 4.2 Azure AI Speechで文字起こし
- SpeechConfig(subscription=SPEECH_KEY, region=SPEECH_REGION)
- speech_recognition_language="ja-JP"
- SpeechRecognizer + start_continuous_recognition_async を使い、
  recognizedイベントでテキストをlistにappendし、session_stopped/canceledで終了
- 認識できない/無音等の場合は分かるメッセージ(例: 「音声が認識できませんでした。または無音でした。」)

## 4.3 Azure OpenAIで分析
- AzureOpenAI(azure_endpoint=AZURE_OPENAI_ENDPOINT.rstrip("/"), api_key=AZURE_OPENAI_API_KEY, api_version=AZURE_OPENAI_API_VERSION)
- chat.completions.create を使い model=AZURE_OPENAI_DEPLOYMENT_NAME
- system: 「あなたはコールセンターの優秀なアナリスト。客観的かつ簡潔に分析」
- user: 以下の出力フォーマットで必ず返すよう指示(日本語):

- インテント: [解約 / 料金照会 / クレーム / 使い方への質問 など]
- 要約: [通話全体の簡単な要約]
- 質問内容: [顧客の質問や要望]
- 回答内容: [オペレーターの対応・回答内容(オペレーターの発言がない場合は「なし」)]
- 詳細: [顧客が具体的に何を求めているか]
- オペレーターへのアドバイス: [対応時の心構えや提案内容]

- max_completion_tokens は十分大きく(例: 16384)
- 例外時は分かるエラーメッセージ(OpenAI APIエラーなど)を結果に反映

## 4.4 解析結果のパース
- LLMの出力テキストから以下を抽出する関数を作る:
  - main_intent
  - summary
  - question
  - answer
- 行頭の「- インテント:」「- 要約:」「- 質問内容:」「- 回答内容:」でパース
- 取れない場合はフォールバック("不明" 等)
- 「詳細」「オペレーターへのアドバイス」は“全文表示”で見られるので、最低限は表/要約表示に不要(ただし将来拡張しやすい構造に)

# 5. データ構造
analysis_results は list[dict] で保持し、最低限以下キーを持つ:
- ファイル名
- 主要インテント
- 要約
- 質問内容
- 回答内容
- 分析結果全文
- 文字起こし
- 音声データ(uploaded_fileのバイナリ/StreamlitのUploadedFile)

# 6. リポジトリ構成(提案: 1ファイルでもOKだが、テストしやすく分割推奨)
例:
call-analytics/
  main.py                 # Streamlitエントリ
  services/
    speech.py             # speech_to_text
    llm.py                # extract_intent, prompt生成
    parser.py             # parse_analysis_result
  models.py               # dataclass等(任意)
tests/
  test_parser.py
  test_prompt.py
requirements.txt or pyproject.toml(どちらでも可。READMEに手順を書く)

※依存関係は最低限:
azure-cognitiveservices-speech>=1.48.2
openai>=2.26.0
pandas>=2.3.3
python-dotenv>=1.2.2
streamlit>=1.55.0
pytest(テスト用)
pytest-mock(任意)

# 7. 単体テスト要件(pytest)
- parse_analysis_result が正しく値を抜けること
  - 正常ケース(全項目あり)
  - 一部欠落ケース("不明"にフォールバック)
- prompt生成が指定フォーマットを含むこと
- llm呼び出し/speech呼び出しは外部I/Oなので、モック前提のテストにする(実APIに接続しない)

# 8. README要件
README.md に以下を必ず含める:
- プロジェクト概要(何ができるか)
- 前提(WAV/200MB/ローカルURL)
- セットアップ手順
  - git clone
  - .env作成(.env.exampleからコピー)
  - pip install -r requirements.txt(またはuv/pip)
  - streamlit run main.py
- 使い方(アップロード→一括解析→3つの結果セクションの見方)
- 注意事項(個人情報が含まれうる、取り扱い注意)

# 9. 受け入れ基準(Acceptance Criteria)
- 複数wavをアップロードして一括解析できる
- 進捗が表示され、完了メッセージが出る
- 「各音声の要約」「一覧表」「詳細(音声プレイヤー+2カラム)」が表示される
- .env.example と README が揃っている
- pytest がローカルで実行できる(外部I/Oはモック)
- secretsがリポジトリに含まれない

上記を満たす形で、必要なファイルを全て生成し、コードを実装してください。

📊 成果物の全体像

ファイル一覧

callcenter-audio-intent-analyzer/
├── main.py                      # 495行 Streamlit UI
├── models.py                    # 45行 dataclass
├── services/
│   ├── speech.py               # 75行 Azure Speech
│   ├── llm.py                  # 70行 Azure OpenAI
│   └── parser.py               # 65行 パース処理
├── tests/
│   ├── test_parser.py          # 85行 7個テスト
│   └── test_prompt.py          # 140行 11個テスト
├── requirements.txt            # 7パッケージ
├── .env.example                # 環境変数テンプレ
├── README.md                   # セットアップガイド
├── ARCHITECTURE.md             # システム設計書
├── API_REFERENCE.md            # API 仕様書
└── IMPLEMENTATION_GUIDE.md     # 実装ガイド

コード行数: 約 950行(テスト含む)
ドキュメント: 1,500行以上

実現した機能

機能 実装状況
複数 WAV ファイル一括アップロード ✅ 完成
200MB ファイルサイズ制限 ✅ 完成
日本語文字起こし(Azure Speech) ✅ 完成
インテント抽出(Azure OpenAI) ✅ 完成
3セクション結果表示 ✅ 完成
エラーハンドリング ✅ 完成
ユニットテスト(18個) ✅ 完成
ドキュメント完備 ✅ 完成

💡 AI との協調が成功した理由

1. 要件の明確化

AI に「何をするのか」を正確に指示することが最重要。曖昧な要件は、曖昧なコードを産む。

(良い例)
- ファイル: .wav のみ、最大 200MB
- 処理: speech.py で ja-JP 文字起こし
- テスト: pytest で  18個のテストケース
- エラー: ユーザーフレンドリーなメッセージ

(悪い例)
- 「音声を分析するアプリを作ってほしい」

2. 段階的なアプローチ

一度にすべてを実装するのではなく、段階的に進めることで、修正が容易。

Phase 1: コアロジック(services/)
  ↓
Phase 2: UI(main.py)
  ↓
Phase 3: テスト(tests/)
  ↓
Phase 4: ドキュメント
  ↓
Phase 5: バグ修正

3. エラー駆動開発

エラーが出たら、そこから何かを学ぶ機会。AI に相談して、ドキュメントで学び、修正。

エラー出現
  ↓
原因究明(ドキュメント参照)
  ↓
AI による複数の修正案検討
  ↓
ベストプラクティスの選択と実装
  ↓
テストで検証

4. テスト駆動開発

テストを先に書くことで、実装の方向性が明確になり、バグが減った。

テスト設計(何をテストするか)
  ↓
実装(テストが成功するように)
  ↓
本番環境での検証
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?