tosei0000 commited on
Commit
f0fd450
·
verified ·
1 Parent(s): 6c3e80c

Update app.py

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