Spaces:
Sleeping
Sleeping
| # Impor library yang dibutuhkan | |
| from flask import Flask, render_template, request, jsonify, session | |
| from langchain_google_genai import ChatGoogleGenerativeAI | |
| from langchain_huggingface import HuggingFaceEmbeddings | |
| from langchain_chroma import Chroma | |
| from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder | |
| from langchain.memory import ConversationBufferMemory | |
| from langchain.chains import create_history_aware_retriever, create_retrieval_chain | |
| from langchain.chains.combine_documents import create_stuff_documents_chain | |
| from dotenv import load_dotenv | |
| import os | |
| # Memuat variabel lingkungan dari file .env | |
| load_dotenv() | |
| # Inisialisasi aplikasi Flask | |
| app = Flask(__name__) | |
| # Menetapkan secret key untuk keamanan sesi | |
| app.secret_key = os.urandom(24) | |
| # --- KONFIGURASI AWAL --- | |
| # Memuat vectorstore dari direktori "data" | |
| try: | |
| vectorstore = Chroma( | |
| persist_directory="data", | |
| embedding_function=HuggingFaceEmbeddings(model_name="firqaaa/indo-sentence-bert-large") | |
| ) | |
| print("Vectorstore berhasil dimuat.") | |
| except Exception as e: | |
| print(f"Kesalahan saat memuat vectorstore: {e}") | |
| # Menyiapkan retriever untuk mengambil dokumen dari vectorstore | |
| retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 20}) | |
| # Menyiapkan model bahasa (LLM) dari Google | |
| llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash", temperature=0) | |
| # --- MANAJEMEN MEMORI PERCAKAPAN --- | |
| # Variabel global untuk menyimpan objek memori di sisi server | |
| # Kunci: session_id, Nilai: objek ConversationBufferMemory | |
| session_memories = {} | |
| def get_session_memory(session_id: str) -> ConversationBufferMemory: | |
| """ | |
| Mengambil atau membuat objek memori untuk session_id tertentu. | |
| Objek memori disimpan di variabel global `session_memories`. | |
| """ | |
| if session_id not in session_memories: | |
| print(f"Membuat instance memori baru untuk sesi: {session_id}") | |
| session_memories[session_id] = ConversationBufferMemory( | |
| memory_key="chat_history", return_messages=True | |
| ) | |
| return session_memories[session_id] | |
| # --- PEMBUATAN RAG CHAIN (RANTAI RAG) --- | |
| # Prompt untuk memformulasikan ulang pertanyaan berdasarkan riwayat percakapan | |
| contextualize_q_system_prompt = ( | |
| "Berdasarkan riwayat percakapan dan pertanyaan terbaru dari pengguna, " | |
| "buatlah pertanyaan baru yang berdiri sendiri dan dapat dipahami tanpa melihat riwayat percakapan. " | |
| "JANGAN menjawab pertanyaan tersebut, cukup formulasikan ulang jika diperlukan, jika tidak, kembalikan pertanyaan asli." | |
| ) | |
| contextualize_q_prompt = ChatPromptTemplate.from_messages( | |
| [ | |
| ("system", contextualize_q_system_prompt), | |
| MessagesPlaceholder("chat_history"), | |
| ("human", "{input}"), | |
| ] | |
| ) | |
| # Rantai yang bertugas memformulasikan ulang pertanyaan | |
| history_aware_retriever = create_history_aware_retriever( | |
| llm, retriever, contextualize_q_prompt | |
| ) | |
| # Prompt utama untuk menjawab pertanyaan berdasarkan konteks yang diberikan retriever | |
| qa_system_prompt = ( | |
| "Anda adalah asisten AI yang teliti untuk BPVP Sorong. " | |
| "Gunakan HANYA informasi dari Konteks yang diberikan untuk menjawab pertanyaan. " | |
| "JANGAN gunakan pengetahuan eksternal. Jawaban Anda harus berdasarkan fakta dari konteks. " | |
| "Jika pertanyaan tidak bisa dijawab dari konteks, katakan: 'Maaf, saya tidak menemukan informasi tersebut dalam dokumen saya.'\n\n" | |
| "Konteks:\n{context}" | |
| ) | |
| qa_prompt = ChatPromptTemplate.from_messages( | |
| [ | |
| ("system", qa_system_prompt), | |
| MessagesPlaceholder("chat_history"), | |
| ("human", "{input}"), | |
| ] | |
| ) | |
| # Rantai yang menggabungkan dokumen-dokumen konteks menjadi satu string | |
| question_answer_chain = create_stuff_documents_chain(llm, qa_prompt) | |
| # Rantai RAG utama yang mengorkestrasi seluruh alur | |
| rag_chain = create_retrieval_chain(history_aware_retriever, question_answer_chain) | |
| # --- ROUTE (ENDPOINT) UNTUK APLIKASI WEB FLASK --- | |
| def home(): | |
| """Menampilkan halaman utama dan membuat session_id jika belum ada.""" | |
| if 'session_id' not in session: | |
| session['session_id'] = os.urandom(16).hex() | |
| return render_template('index.html') | |
| def get_response(): | |
| """Menerima pesan dari pengguna, memprosesnya dengan RAG chain, dan mengembalikan jawaban.""" | |
| user_message = request.args.get('msg') | |
| session_id = session.get('session_id') | |
| if not session_id: | |
| return jsonify({"error": "Sesi tidak ditemukan. Silakan muat ulang halaman."}), 400 | |
| # Mengambil memori yang sesuai untuk sesi ini | |
| memory = get_session_memory(session_id) | |
| chat_history = memory.load_memory_variables({})["chat_history"] | |
| # Menjalankan RAG chain dengan input yang diperlukan | |
| response = rag_chain.invoke({"input": user_message, "chat_history": chat_history}) | |
| # Menyimpan percakapan baru ke dalam memori | |
| memory.save_context({"input": user_message}, {"answer": response["answer"]}) | |
| # Mengembalikan hanya teks jawaban ke frontend | |
| return jsonify(response["answer"]) | |
| def load_history(): | |
| """Mengembalikan riwayat percakapan untuk sesi saat ini.""" | |
| session_id = session.get('session_id') | |
| if not session_id: | |
| return jsonify([]) | |
| memory = get_session_memory(session_id) | |
| history = memory.load_memory_variables({})["chat_history"] | |
| # Memformat riwayat agar mudah dibaca oleh frontend | |
| formatted_history = [] | |
| for i in range(0, len(history), 2): | |
| user_msg = history[i].content | |
| bot_msg = history[i+1].content if i+1 < len(history) else "" | |
| formatted_history.append({"sender": "user", "message": user_msg}) | |
| formatted_history.append({"sender": "bot", "message": bot_msg}) | |
| return jsonify(formatted_history) | |
| def clear_history(): | |
| """Menghapus riwayat percakapan untuk sesi saat ini dari memori server.""" | |
| session_id = session.get('session_id') | |
| if session_id and session_id in session_memories: | |
| del session_memories[session_id] | |
| print(f"Riwayat untuk sesi {session_id} telah dihapus dari memori server.") | |
| return jsonify({"status": "success", "message": "Riwayat percakapan telah dihapus"}) | |
| # Menjalankan aplikasi | |
| if __name__ == '__main__': | |
| app.run(debug=True) |