Spaces:
Runtime error
Runtime error
| from flask import Flask, request, jsonify, render_template, send_from_directory | |
| import base64 | |
| from pydub import AudioSegment # 変換用にpydubをインポート | |
| import os | |
| import shutil | |
| from process import AudioProcessor | |
| from transcription import TranscriptionMaker | |
| from analyze import TextAnalyzer | |
| import json | |
| process=AudioProcessor() | |
| transcripter = TranscriptionMaker() | |
| app = Flask(__name__) | |
| users = [] | |
| transcription_text="" | |
| harassment_keywords = [ | |
| "バカ", "馬鹿", "アホ", "死ね", "クソ", "うざい", | |
| "きもい", "キモい", "ブス", "デブ", "ハゲ", | |
| "セクハラ", "パワハラ", "モラハラ" | |
| ] | |
| total_audio = "" | |
| # トップページ(テンプレート: index.html) | |
| def index(): | |
| return render_template('index.html', users = users) | |
| # フィードバック画面(テンプレート: feedback.html) | |
| def feedback(): | |
| return render_template('feedback.html') | |
| # 会話詳細画面(テンプレート: talkDetail.html) | |
| def talk_detail(): | |
| return render_template('talkDetail.html') | |
| # 音声登録画面(テンプレート: userRegister.html) | |
| def userregister(): | |
| return render_template('userRegister.html') | |
| #人数確認 | |
| # 基本的にGETで取得する想定なので、GETのみに変更 | |
| def confirm(): | |
| return jsonify({'members': users}), 200 | |
| #リセット画面(テンプレート: reset.html) | |
| def reset_html(): | |
| return render_template('reset.html') | |
| #メンバー削除&累積音声削除 | |
| def reset_member(): | |
| global users | |
| global total_audio | |
| print(total_audio) | |
| process.delete_files_in_directory(total_audio) | |
| try: | |
| data = request.get_json() | |
| if not data or "names" not in data: | |
| return jsonify({"status": "error", "message": "Invalid request body"}), 400 # 400 Bad Request | |
| names = data.get("names", []) | |
| base_audio_dir = "/tmp/data/base_audio" | |
| for name in names: | |
| file_path = os.path.join(base_audio_dir, f"{name}.wav") | |
| if os.path.exists(file_path): | |
| try: | |
| os.remove(file_path) | |
| print(f"{file_path} を削除しました。") | |
| except Exception as e: | |
| print(f"削除中にエラーが発生しました: {e}") | |
| # ファイル削除に失敗した場合も、エラーを返す | |
| return jsonify({"status": "error", "message": f"Failed to delete {name}: {e}"}), 500 | |
| else: | |
| print(f"ファイルが存在しません: {file_path}") | |
| # usersリストを更新 | |
| users = [u for u in users if u not in names] | |
| # 成功した場合のレスポンス | |
| return jsonify({"status": "success", "message": "Members deleted successfully", "users": users}), 200 # 200 OK | |
| except Exception as e: | |
| print(f"An unexpected error occurred: {e}") | |
| return jsonify({"status": "error", "message": f"Internal server error: {e}"}), 500 # 500 Internal Server Error | |
| # 書き起こし作成エンドポイント | |
| def transcription(): | |
| global transcription_text | |
| global total_audio | |
| try: | |
| audio_directory = transcripter.merge_segments(total_audio) | |
| transcription_text = transcripter.create_transcription(audio_directory) | |
| with open(transcription_text,'r',encoding='utf-8') as file: | |
| file_content = file.read() | |
| print(file_content) | |
| return jsonify({'transcription': file_content}),200 | |
| except Exception as e: | |
| return jsonify({"error": str(e)}),500 | |
| # AI分析エンドポイント | |
| def analyze(): | |
| global transcription_text | |
| analyzer = TextAnalyzer(transcription_text, harassment_keywords) | |
| api_key = os.environ.get("DEEPSEEK") | |
| if api_key is None: | |
| raise ValueError("DEEPSEEK_API_KEY が設定されていません。") | |
| results = analyzer.analyze(api_key=api_key) | |
| print(json.dumps(results, ensure_ascii=False, indent=2)) | |
| if "deepseek_analysis" in results and results["deepseek_analysis"]: | |
| deepseek_data = results["deepseek_analysis"] | |
| conversation_level = deepseek_data.get("conversationLevel") | |
| harassment_present = deepseek_data.get("harassmentPresent") | |
| harassment_type = deepseek_data.get("harassmentType") | |
| repetition = deepseek_data.get("repetition") | |
| pleasantConversation = deepseek_data.get("pleasantConversation") | |
| blameOrHarassment = deepseek_data.get("blameOrHarassment") | |
| print("\n--- DeepSeek 分析結果 ---") | |
| print(f"会話レベル: {conversation_level}") | |
| print(f"ハラスメントの有無: {harassment_present}") | |
| print(f"ハラスメントの種類: {harassment_type}") | |
| print(f"繰り返しの程度: {repetition}") | |
| print(f"会話の心地よさ: {pleasantConversation}") | |
| print(f"非難またはハラスメントの程度: {blameOrHarassment}") | |
| return jsonify({"results": results}),200 | |
| # 音声アップロード&解析エンドポイント | |
| def upload_audio(): | |
| global total_audio | |
| try: | |
| data = request.get_json() | |
| # name か users のいずれかが必須。どちらも無い場合はエラー | |
| if not data or 'audio_data' not in data or ('name' not in data and 'users' not in data): | |
| return jsonify({"error": "音声データまたは名前がありません"}), 400 | |
| # Base64デコードして音声バイナリを取得 | |
| audio_binary = base64.b64decode(data['audio_data']) | |
| upload_name = 'tmp' | |
| audio_dir = "/tmp/data" | |
| os.makedirs(audio_dir, exist_ok=True) | |
| audio_path = os.path.join(audio_dir, f"{upload_name}.wav") | |
| with open(audio_path, 'wb') as f: | |
| f.write(audio_binary) | |
| print(users) | |
| # 各ユーザーの参照音声ファイルのパスをリストに格納 | |
| reference_paths = [] | |
| base_audio_dir = "/tmp/data/base_audio" | |
| for user in users: | |
| ref_path = os.path.abspath(os.path.join(base_audio_dir, f"{user}.wav")) | |
| if not os.path.exists(ref_path): | |
| return jsonify({"error": "参照音声ファイルが見つかりません", "details": ref_path}), 500 | |
| reference_paths.append(ref_path) | |
| # 複数人の場合は参照パスのリストを、1人の場合は単一のパスを渡す | |
| if len(users) > 1: | |
| print("複数人の場合の処理") | |
| matched_times, segments_dir = process.process_multi_audio(reference_paths, audio_path, threshold=0.05) | |
| total_audio = transcripter.merge_segments(segments_dir) | |
| # 各メンバーのrateを計算 | |
| total_time = sum(matched_times) | |
| rates = [(time / total_time) * 100 if total_time > 0 else 0 for time in matched_times] | |
| return jsonify({"rates": rates}), 200 | |
| else: | |
| matched_time, unmatched_time, segments_dir = process.process_audio(reference_paths[0], audio_path, threshold=0.05) | |
| total_audio = transcripter.merge_segments(segments_dir) | |
| total_time = matched_time + unmatched_time | |
| rate = (matched_time / total_time) * 100 if total_time > 0 else 0 | |
| return jsonify({"rate": rate}), 200 | |
| except Exception as e: | |
| print("Error in /upload_audio:", str(e)) | |
| return jsonify({"error": "サーバーエラー", "details": str(e)}), 500 | |
| def reset(): | |
| global users | |
| users=[] | |
| return 200 | |
| def upload_base_audio(): | |
| global users#グローバル変数を編集できるようにする | |
| try: | |
| data = request.get_json() | |
| if not data or 'audio_data' not in data or 'name' not in data: | |
| return jsonify({"error": "音声データまたは名前がありません"}), 400 | |
| name = data['name'] # 名前を取得 | |
| print(name) | |
| users.append(name) | |
| users=list(set(users))#重複排除 | |
| print(users) | |
| audio_path=process.save_audio_from_base64( | |
| base64_audio=data['audio_data'], # 音声データ | |
| output_dir= "/tmp/data/base_audio", #保存先 | |
| output_filename=f"{name}.wav" # 固定ファイル名(必要に応じて generate_filename() で一意のファイル名に変更可能) | |
| ) | |
| return jsonify({"state": "Registration Success!", "path": audio_path}), 200 | |
| except Exception as e: | |
| print("Error in /upload_base_audio:", str(e)) | |
| return jsonify({"error": "サーバーエラー", "details": str(e)}), 500 | |
| if __name__ == '__main__': | |
| port = int(os.environ.get("PORT", 7860)) | |
| app.run(debug=True, host="0.0.0.0", port=port) |