File size: 5,313 Bytes
1155486
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import os
import numpy as np
import pandas as pd
from functools import wraps
from dotenv import load_dotenv # dotenvをインポート
from flask import Flask, render_template, request, session, redirect, url_for
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
import csv
from datetime import datetime
import pytz
load_dotenv() # .envファイルを読み込む

app = Flask(__name__)
# 環境変数からSECRET_KEYを読み込む
app.secret_key = os.environ.get('SECRET_KEY')

# --- 質問を保存するCSVファイル ---
LOG_FILE = 'logged_questions.csv'

# --- AIモデルとデータの読み込み(サーバー起動時に一度だけ実行)---
try:
    # モデルの読み込み
    # model = SentenceTransformer('stsb-xlm-r-multilingual')
    model = SentenceTransformer('pkshatech/GLuCoSE-base-ja')
    # ベクトルデータの読み込み
    question_vectors = np.load('question_vectors.npy')
    # Q&Aデータの読み込み
    qa_df = pd.read_csv('qa_data.csv')
    print("モデルとデータの読み込みに成功しました。")
except Exception as e:
    print(f"モデルまたはデータの読み込みに失敗しました: {e}")
    model = None

def login_required(f):
    @wraps(f)
    def decorated_view(*args, **kwargs):
        if 'logged_in' not in session:
            return redirect(url_for('login'))
        return f(*args, **kwargs)
    return decorated_view

@app.route('/login', methods=['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        # 環境変数からパスワードを読み込む
        if request.form['password'] == os.environ.get('SITE_PASSWORD'):
            session['logged_in'] = True
            return redirect(url_for('home'))
        else:
            error = 'パスワードが正しくありません'
    return render_template('login.html', error=error)

@app.route('/logout')
def logout():
    session.pop('logged_in', None)
    return redirect(url_for('login'))

@app.route('/')
@login_required
def home():
    phone_number = os.environ.get('PHONE_NUMBER')
    return render_template('index.html', phone_number=phone_number)

@app.route('/documents')
@login_required
def documents():
    uploads_dir = os.path.join(app.static_folder, 'uploads')
    files = []
    if os.path.exists(uploads_dir):
        supportted_extensions = {'.pdf', '.png'}
        files = [f for f in os.listdir(uploads_dir) if os.path.splitext(f)[1].lower() in supportted_extensions]
    return render_template('documents.html', files=files)

# 新しく追加するルート
@app.route('/backstand_entrance')
@login_required
def backstand_entrance():
    return render_template('backstand_entrance.html')

@app.route('/backstand_inside')
@login_required
def backstand_inside():
    return render_template('backstand_inside.html')

@app.route('/sofa-seat')
@login_required
def third_floor_seats():
    return render_template('sofa-seat.html')

@app.route('/faq')
@login_required
def faq():
    return render_template('faq.html')

@app.route('/ask', methods=['GET', 'POST'])
@login_required
def ask():
    answer = None
    question = ""
    error = None

    if model is None:
        error = "AIモデルの読み込みに失敗したため、現在この機能を使用できません。"
        return render_template('ask.html', error=error)
    
    if request.method == 'POST':
        question = request.form['question']
        if question:
            # --- ここから質問を保存する処理 ---
            try:
                # 日本時間を取得
                jst = pytz.timezone('Asia/Tokyo')
                timestamp = datetime.now(jst).strftime('%Y-%m-%d %H:%M:%S')
                
                # ファイルが空かどうかの確認
                file_exists = os.path.isfile(LOG_FILE) and os.path.getsize(LOG_FILE) > 0

                # ファイルに追記モードで書き込み
                with open(LOG_FILE, 'a', newline='', encoding='utf-8') as f:
                    writer = csv.writer(f)
                    # ファイルが空の場合、ヘッダーを書き込む
                    if not file_exists:
                        writer.writerow(['timestamp', 'question'])
                    writer.writerow([timestamp, question])
            except Exception as e:
                print(f"質問の保存中にエラーが発生しました: {e}")
            # --- ここまで ---

            # 1. ユーザーの質問をベクトル化
            user_vector = model.encode([question], convert_to_numpy=True)
            
            # 2. コサイン類似度を計算
            similarities = cosine_similarity(user_vector, question_vectors)
            
            # 3. 最も類似度が高い質問のインデックスを取得
            most_similar_index = np.argmax(similarities)
            
            # 4. 対応する答えを取得
            answer = qa_df.iloc[most_similar_index]['answer']

    return render_template('ask.html', question=question, answer=answer)

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')