File size: 7,053 Bytes
f0fd450 d8554d9 f0fd450 d8554d9 f0fd450 d8554d9 f0fd450 d8554d9 f0fd450 d8554d9 f0fd450 d8554d9 f0fd450 d8554d9 f0fd450 d8554d9 f0fd450 d8554d9 f0fd450 d8554d9 f0fd450 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# app.py (日本語化・最終改善版)
import os
import json
import uuid
from PIL import Image
from dotenv import load_dotenv
from flask import Flask, request, jsonify, send_from_directory
from flask_cors import CORS
import google.generativeai as genai
# --- 1. 初期設定 ---
load_dotenv()
# 定数とフォルダ設定
PERSONALITY_FILE = "personality.json"
SESSIONS_FILE = "chat_sessions.json"
UPLOADS_FOLDER = "uploads" # 画像を保存するフォルダ
DEFAULT_PERSONALITY = """
あなたは消防署用のAI、グラフを上手くわかりやすい説明が得意です。以下の制約条件と入力文をもとに、適切な回答を出力してください。(AI CoT)
「ステップごとに考えてみましょう。」)\n「あなたの推論を詳しく説明してください。」\n「問題をステップごとに分解してください。」\n「計算を示してください。」\n「よく考えてから答えを出してください。」
"""
# uploadsフォルダが存在しない場合は作成
if not os.path.exists(UPLOADS_FOLDER):
os.makedirs(UPLOADS_FOLDER)
app = Flask(__name__, static_folder='static', static_url_path='')
CORS(app)
# --- 2. Google Gemini APIの設定 ---
try:
api_key = "AIzaSyA0IZW7yEAdZ20eJ5urvVxHYGotzl1qO5c"
if not api_key: raise ValueError("環境変数 'GEMINI_API_KEY' が設定されていません。")
genai.configure(api_key=api_key)
print("✅ Gemini APIの設定が完了しました。")
except Exception as e:
print(f"❌ Gemini APIの初期化に失敗: {e}")
# --- 3. データ永続化ヘルパー関数 ---
def load_data(filepath, default_data):
if not os.path.exists(filepath): return default_data
try:
with open(filepath, 'r', encoding='utf-8') as f: return json.load(f)
except (IOError, json.JSONDecodeError): return default_data
def save_data(filepath, data):
with open(filepath, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2)
# --- 4. グローバル変数の読み込み ---
system_instruction = load_data(PERSONALITY_FILE, {"personality": DEFAULT_PERSONALITY})["personality"]
chat_sessions_data = load_data(SESSIONS_FILE, {})
# =================================
# APIエンドポイント
# =================================
# --- 4.1. アップロードされたファイルを提供するエンドポイント ---
@app.route('/uploads/<path:filename>')
def uploaded_file(filename):
"""uploadsフォルダから画像ファイルを配信する"""
return send_from_directory(UPLOADS_FOLDER, filename)
# --- 4.2. 会話セッション管理API ---
@app.route('/api/sessions', methods=['GET'])
def get_sessions():
session_list = [{"id": session_id, **data} for session_id, data in chat_sessions_data.items()]
session_list.sort(key=lambda x: (x.get('pinned', False), x.get('id', '')), reverse=True)
return jsonify(session_list)
@app.route('/api/session/<session_id>', methods=['GET'])
def get_session_history(session_id): return jsonify(chat_sessions_data.get(session_id, {}))
@app.route('/api/session/<session_id>', methods=['DELETE'])
def delete_session(session_id):
if session_id in chat_sessions_data:
del chat_sessions_data[session_id]; save_data(SESSIONS_FILE, chat_sessions_data)
return jsonify({"status": "success"})
return jsonify({"error": "セッションが見つかりません。"}), 404
@app.route('/api/session/<session_id>/rename', methods=['POST'])
def rename_session(session_id):
if session_id in chat_sessions_data:
new_title = request.get_json().get('title', '').strip()
if new_title:
chat_sessions_data[session_id]['title'] = new_title; save_data(SESSIONS_FILE, chat_sessions_data)
return jsonify({"status": "success"})
return jsonify({"error": "タイトルが空です。"}), 400
return jsonify({"error": "セッションが見つかりません。"}), 404
@app.route('/api/session/<session_id>/pin', methods=['POST'])
def pin_session(session_id):
if session_id in chat_sessions_data:
is_pinned = chat_sessions_data[session_id].get('pinned', False)
chat_sessions_data[session_id]['pinned'] = not is_pinned; save_data(SESSIONS_FILE, chat_sessions_data)
return jsonify({"status": "success", "pinned": not is_pinned})
return jsonify({"error": "セッションが見つかりません。"}), 404
# --- 4.3. チャットと設定のAPI ---
@app.route('/api/set_personality', methods=['POST'])
def set_personality():
global system_instruction
system_instruction = request.get_json().get('personality', '').strip() or DEFAULT_PERSONALITY
save_data(PERSONALITY_FILE, {"personality": system_instruction})
return jsonify({"status": "success", "message": f"人格を設定しました。"})
@app.route('/api/chat', methods=['POST'])
def handle_chat():
session_id = request.form.get('session_id')
user_input = request.form.get('message', '').strip()
file = request.files.get('file')
if not session_id or (not user_input and not file): return jsonify({"error": "必須情報が不足しています。"}), 400
try:
model = genai.GenerativeModel(model_name="gemini-2.5-pro", system_instruction=system_instruction)
session_data = chat_sessions_data.get(session_id, {"title": "", "history": [], "pinned": False})
past_history = session_data.get("history", [])
user_parts_for_api = [part for part in ([user_input] if user_input else []) + ([Image.open(file.stream)] if file else [])]
response = model.generate_content(past_history + [{'role': 'user', 'parts': user_parts_for_api}])
user_parts_for_history = [user_input] if user_input else []
if file:
ext = os.path.splitext(file.filename)[1]
unique_filename = f"{uuid.uuid4()}{ext}"
filepath = os.path.join(UPLOADS_FOLDER, unique_filename)
file.seek(0)
file.save(filepath)
user_parts_for_history.append(f"/uploads/{unique_filename}")
new_history = past_history + [
{'role': 'user', 'parts': user_parts_for_history},
{'role': 'model', 'parts': [response.text]}
]
session_data["history"] = new_history
if not session_data.get("title"):
session_data["title"] = user_input[:40] or (file.filename if file else "新しいチャット")
chat_sessions_data[session_id] = session_data
save_data(SESSIONS_FILE, chat_sessions_data)
return jsonify({"reply": response.text, "title": session_data["title"]})
except Exception as e:
print(f"❌ APIエラー: {e}")
return jsonify({"error": "APIとの通信中、またはファイル処理中にエラーが発生しました。"}), 500
@app.route('/')
def serve_index(): return send_from_directory(app.static_folder, 'index.html')
if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True) |