indahPurnamaSarii commited on
Commit
2047172
·
1 Parent(s): f01f577

Final: Menggunakan model ringan dan database baru

Browse files
Files changed (3) hide show
  1. Dockerfile +3 -0
  2. app.py +67 -10
  3. vector_embeddings.py +79 -0
Dockerfile CHANGED
@@ -2,4 +2,7 @@ FROM python:3.9-slim
2
  WORKDIR /code
3
  COPY . .
4
  RUN pip install --no-cache-dir --upgrade -r requirements.txt
 
 
 
5
  CMD ["gunicorn", "--bind", "0.0.0.0:7860", "--workers", "1", "app:app"]
 
2
  WORKDIR /code
3
  COPY . .
4
  RUN pip install --no-cache-dir --upgrade -r requirements.txt
5
+ RUN python download_model.py
6
+ RUN mkdir -p /app/.cache
7
+ ENV SENTENCE_TRANSFORMERS_HOME=/app/.cache
8
  CMD ["gunicorn", "--bind", "0.0.0.0:7860", "--workers", "1", "app:app"]
app.py CHANGED
@@ -1,39 +1,96 @@
1
- from flask import Flask, render_template, request, jsonify
2
  from langchain_google_genai import ChatGoogleGenerativeAI
 
 
 
 
 
 
3
  from dotenv import load_dotenv
4
  import os
5
 
 
6
  load_dotenv()
7
 
8
  app = Flask(__name__, template_folder='templates')
 
 
 
 
9
  llm = None
 
 
10
 
11
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash", temperature=0.2)
13
  print("Model AI (Gemini) berhasil diinisialisasi.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  except Exception as e:
15
- print(f"GALAT PENTING: Gagal menginisialisasi model Gemini: {e}")
 
 
16
 
17
  @app.route('/')
18
  def home():
 
19
  return render_template('index.html')
20
 
21
  @app.route('/get', methods=['GET'])
22
  def get_response():
23
- if not llm:
24
- return jsonify({"error": "Server belum siap. Model AI tidak terinisialisasi."}), 503
25
 
26
  user_message = request.args.get('msg')
27
  if not user_message:
28
  return jsonify({"error": "Pesan tidak boleh kosong."}), 400
29
-
 
 
 
30
  try:
31
- response = llm.invoke(user_message)
32
- answer = response.content
 
 
 
 
 
 
33
  return jsonify(answer)
 
34
  except Exception as e:
35
- print(f"GALAT saat memanggil LLM: {e}")
36
- return jsonify({"error": "Maaf, terjadi masalah saat memproses permintaan Anda."}), 500
37
 
38
  if __name__ == '__main__':
39
- app.run(debug=True, host='0.0.0.0', port=7860)
 
1
+ from flask import Flask, render_template, request, jsonify, session
2
  from langchain_google_genai import ChatGoogleGenerativeAI
3
+ from langchain_huggingface import HuggingFaceEmbeddings
4
+ from langchain_chroma import Chroma
5
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
6
+ from langchain.chains import create_history_aware_retriever, create_retrieval_chain
7
+ from langchain.chains.combine_documents import create_stuff_documents_chain
8
+ from langchain_core.messages import HumanMessage, AIMessage
9
  from dotenv import load_dotenv
10
  import os
11
 
12
+ # Memuat variabel lingkungan (untuk testing lokal dan kunci API di server)
13
  load_dotenv()
14
 
15
  app = Flask(__name__, template_folder='templates')
16
+ app.secret_key = os.urandom(24)
17
+
18
+ # --- Inisialisasi Komponen Utama ---
19
+ vectorstore = None
20
  llm = None
21
+ retriever = None
22
+ rag_chain = None
23
 
24
  try:
25
+ # 1. Menyiapkan Model Embedding yang Ringan
26
+ # Model ini akan mengambil data dari cache yang sudah di-download saat build
27
+ embedding_model = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
28
+
29
+ # 2. Memuat Vectorstore (Database Chroma)
30
+ vectorstore = Chroma(
31
+ persist_directory="data",
32
+ embedding_function=embedding_model
33
+ )
34
+ retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
35
+ print("Vectorstore berhasil dimuat dan retriever dibuat.")
36
+
37
+ # 3. Menyiapkan Model AI (LLM)
38
  llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash", temperature=0.2)
39
  print("Model AI (Gemini) berhasil diinisialisasi.")
40
+
41
+ # 4. Membuat RAG Chain (Logika Inti Aplikasi)
42
+ contextualize_q_prompt = ChatPromptTemplate.from_messages([
43
+ ("system", "Mengingat riwayat percakapan dan pertanyaan terbaru, formulasikan ulang pertanyaan menjadi pertanyaan yang berdiri sendiri."),
44
+ MessagesPlaceholder("chat_history"),
45
+ ("human", "{input}"),
46
+ ])
47
+ history_aware_retriever = create_history_aware_retriever(llm, retriever, contextualize_q_prompt)
48
+
49
+ qa_prompt = ChatPromptTemplate.from_messages([
50
+ ("system", "Anda adalah asisten AI untuk BPVP Kota Sorong. Gunakan potongan konteks berikut untuk menjawab pertanyaan. Jika tidak tahu jawabannya, katakan saja Anda tidak tahu. Jawab dalam bahasa Indonesia.\n\nKonteks:\n{context}"),
51
+ MessagesPlaceholder("chat_history"),
52
+ ("human", "{input}"),
53
+ ])
54
+ question_answer_chain = create_stuff_documents_chain(llm, qa_prompt)
55
+ rag_chain = create_retrieval_chain(history_aware_retriever, question_answer_chain)
56
+ print("RAG Chain berhasil dibuat.")
57
+
58
  except Exception as e:
59
+ print(f"GALAT PENTING SAAT INISIALISASI: {e}")
60
+
61
+ # --- Rute Aplikasi Flask ---
62
 
63
  @app.route('/')
64
  def home():
65
+ session.pop("chat_history", None)
66
  return render_template('index.html')
67
 
68
  @app.route('/get', methods=['GET'])
69
  def get_response():
70
+ if not rag_chain:
71
+ return jsonify({"error": "Server belum siap. Periksa log untuk galat inisialisasi."}), 503
72
 
73
  user_message = request.args.get('msg')
74
  if not user_message:
75
  return jsonify({"error": "Pesan tidak boleh kosong."}), 400
76
+
77
+ chat_history_from_session = session.get("chat_history", [])
78
+ chat_history = [HumanMessage(content=msg["message"]) if msg.get("sender") == "user" else AIMessage(content=msg["message"]) for msg in chat_history_from_session]
79
+
80
  try:
81
+ response = rag_chain.invoke({"input": user_message, "chat_history": chat_history})
82
+ answer = response.get("answer", "Maaf, saya tidak dapat menemukan jawaban untuk itu.")
83
+
84
+ new_history = session.get("chat_history", [])
85
+ new_history.append({"sender": "user", "message": user_message})
86
+ new_history.append({"sender": "ai", "message": answer})
87
+ session["chat_history"] = new_history
88
+
89
  return jsonify(answer)
90
+
91
  except Exception as e:
92
+ print(f"GALAT saat menjalankan RAG Chain: {e}")
93
+ return jsonify({"error": "Maaf, terjadi masalah internal saat memproses permintaan Anda."}), 500
94
 
95
  if __name__ == '__main__':
96
+ app.run(debug=True)
vector_embeddings.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from langchain_community.document_loaders import PyPDFLoader
3
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
4
+ from langchain_chroma import Chroma
5
+ from langchain_huggingface import HuggingFaceEmbeddings
6
+ from dotenv import load_dotenv
7
+
8
+ # Memuat variabel lingkungan dari file .env
9
+ load_dotenv()
10
+
11
+ # --- KONFIGURASI ---
12
+ SOURCE_DIRECTORY = "source_data"
13
+ PERSIST_DIRECTORY = "data"
14
+ # ✅ MODEL SUDAH DIGANTI KE VERSI YANG LEBIH RINGAN
15
+ EMBEDDING_MODEL = "all-MiniLM-L6-v2"
16
+ CHUNK_SIZE = 1000
17
+ CHUNK_OVERLAP = 100
18
+
19
+ def create_vector_store():
20
+ """
21
+ Fungsi untuk memuat PDF, membaginya menjadi potongan,
22
+ dan membuat database vektor Chroma yang persisten.
23
+ """
24
+ # 1. Memuat semua dokumen PDF dari direktori sumber
25
+ pdf_files = [f for f in os.listdir(SOURCE_DIRECTORY) if f.endswith('.pdf')]
26
+ if not pdf_files:
27
+ print(f"Tidak ada file PDF yang ditemukan di folder '{SOURCE_DIRECTORY}'.")
28
+ return
29
+
30
+ all_docs = []
31
+ print("Memulai proses memuat dokumen PDF...")
32
+ for pdf_file in pdf_files:
33
+ try:
34
+ file_path = os.path.join(SOURCE_DIRECTORY, pdf_file)
35
+ loader = PyPDFLoader(file_path)
36
+ data = loader.load()
37
+ all_docs.extend(data)
38
+ print(f"-> Berhasil memuat {len(data)} halaman dari '{pdf_file}'")
39
+ except Exception as e:
40
+ print(f"-> GAGAL memuat PDF '{pdf_file}': {e}")
41
+
42
+ if not all_docs:
43
+ print("Tidak ada data yang berhasil dimuat dari PDF. Proses dihentikan.")
44
+ return
45
+
46
+ # 2. Membagi dokumen menjadi potongan-potongan kecil (chunks)
47
+ print("\nMembagi dokumen menjadi potongan teks...")
48
+ text_splitter = RecursiveCharacterTextSplitter(
49
+ chunk_size=CHUNK_SIZE,
50
+ chunk_overlap=CHUNK_OVERLAP
51
+ )
52
+ docs_split = text_splitter.split_documents(all_docs)
53
+ print(f"Total potongan dokumen yang dibuat: {len(docs_split)}")
54
+
55
+ # 3. Menginisialisasi model embedding
56
+ print(f"\nMenginisialisasi model embedding: {EMBEDDING_MODEL}...")
57
+ try:
58
+ embeddings = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL)
59
+ except Exception as e:
60
+ print(f"GALAT: Gagal menginisialisasi model embedding: {e}")
61
+ print("Pastikan Anda memiliki koneksi internet dan library 'sentence-transformers' terinstal.")
62
+ return
63
+
64
+ # 4. Membuat dan menyimpan database vektor Chroma
65
+ print(f"\nMembuat dan menyimpan vector store di direktori '{PERSIST_DIRECTORY}'...")
66
+ try:
67
+ vectorstore = Chroma.from_documents(
68
+ documents=docs_split,
69
+ embedding=embeddings,
70
+ persist_directory=PERSIST_DIRECTORY
71
+ )
72
+ print("\n--- PROSES SELESAI ---")
73
+ print("Database vektor berhasil dibuat dan disimpan.")
74
+ print("Anda sekarang dapat menjalankan 'app.py' untuk memulai chatbot.")
75
+ except Exception as e:
76
+ print(f"GALAT: Gagal membuat vector store Chroma: {e}")
77
+
78
+ if __name__ == '__main__':
79
+ create_vector_store()