FauzanAriyatmoko commited on
Commit
327cd3e
·
1 Parent(s): 5060d16

feat: Migrate the default LLM from ChatGLM3 to Qwen2-0.5B-Instruct, updating model loading, generation logic, and documentation.

Browse files
Files changed (7) hide show
  1. .env.example +1 -1
  2. QUICKSTART.md +1 -1
  3. README.md +6 -6
  4. app.py +3 -3
  5. config/model_config.py +1 -1
  6. requirements.txt +1 -0
  7. utils/rag_pipeline.py +122 -22
.env.example CHANGED
@@ -1,5 +1,5 @@
1
  # Model Configuration
2
- MODEL_NAME=THUDM/chatglm3-6b
3
  EMBEDDING_MODEL=sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2
4
 
5
  # Device Configuration (auto/cuda/cpu)
 
1
  # Model Configuration
2
+ MODEL_NAME=Qwen/Qwen2-0.5B-Instruct
3
  EMBEDDING_MODEL=sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2
4
 
5
  # Device Configuration (auto/cuda/cpu)
QUICKSTART.md CHANGED
@@ -22,7 +22,7 @@ Aplikasi akan:
22
  2. Inisialisasi vector database
23
  3. Launch Gradio interface di `http://localhost:7860`
24
 
25
- **Catatan**: Model GLM akan di-download otomatis saat pertama kali digunakan (ukuran ~13GB untuk ChatGLM3-6B).
26
 
27
  ## 📚 Workflow Penggunaan
28
 
 
22
  2. Inisialisasi vector database
23
  3. Launch Gradio interface di `http://localhost:7860`
24
 
25
+ **Catatan**: Model Qwen2 akan di-download otomatis saat pertama kali digunakan (ukuran ~1GB, jauh lebih kecil dari model sebelumnya).
26
 
27
  ## 📚 Workflow Penggunaan
28
 
README.md CHANGED
@@ -32,7 +32,7 @@ short_description: Chat dengan dokumen PDF menggunakan RAG dan GLM Model
32
 
33
  RAG ChatBot adalah aplikasi AI yang memungkinkan Anda untuk mengupload dokumen PDF dan melakukan tanya jawab interaktif tentang isi dokumen tersebut. Sistem menggunakan:
34
 
35
- - **ChatGLM3-6B**: Model bahasa generatif untuk menghasilkan jawaban
36
  - **RAG (Retrieval-Augmented Generation)**: Teknik untuk mencari informasi relevan dari dokumen
37
  - **ChromaDB**: Vector database untuk penyimpanan dan pencarian semantic
38
  - **Gradio**: Interface web yang modern dan interaktif
@@ -145,7 +145,7 @@ Aplikasi akan berjalan di `http://localhost:7860`
145
  └────┬─────┘
146
 
147
  ┌────▼─────┐
148
- ChatGLM3 │ (Response Generation)
149
  └──────────┘
150
  ```
151
 
@@ -183,7 +183,7 @@ Edit file `.env` untuk mengatur konfigurasi:
183
 
184
  ```bash
185
  # Model
186
- MODEL_NAME=THUDM/chatglm3-6b
187
  EMBEDDING_MODEL=sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2
188
 
189
  # Device (auto/cuda/cpu)
@@ -227,8 +227,8 @@ Berikut dependencies utama yang digunakan:
227
 
228
  ### Model Loading Error
229
  ```bash
230
- # Jika model terlalu besar, gunakan quantized version
231
- MODEL_NAME=THUDM/chatglm3-6b-32k
232
  ```
233
 
234
  ### PDF Extraction Error
@@ -254,5 +254,5 @@ Untuk pertanyaan dan support, silakan buat issue di repository ini.
254
  ---
255
 
256
  <div align="center">
257
- Made with ❤️ using Gradio and ChatGLM
258
  </div>
 
32
 
33
  RAG ChatBot adalah aplikasi AI yang memungkinkan Anda untuk mengupload dokumen PDF dan melakukan tanya jawab interaktif tentang isi dokumen tersebut. Sistem menggunakan:
34
 
35
+ - **Qwen2-0.5B-Instruct**: Model bahasa generatif yang ringan untuk menghasilkan jawaban
36
  - **RAG (Retrieval-Augmented Generation)**: Teknik untuk mencari informasi relevan dari dokumen
37
  - **ChromaDB**: Vector database untuk penyimpanan dan pencarian semantic
38
  - **Gradio**: Interface web yang modern dan interaktif
 
145
  └────┬─────┘
146
 
147
  ┌────▼─────┐
148
+ Qwen2 │ (Response Generation)
149
  └──────────┘
150
  ```
151
 
 
183
 
184
  ```bash
185
  # Model
186
+ MODEL_NAME=Qwen/Qwen2-0.5B-Instruct
187
  EMBEDDING_MODEL=sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2
188
 
189
  # Device (auto/cuda/cpu)
 
227
 
228
  ### Model Loading Error
229
  ```bash
230
+ # Model saat ini sudah sangat ringan (~1GB)
231
+ # Jika masih ada masalah, pastikan koneksi internet stabil untuk download
232
  ```
233
 
234
  ### PDF Extraction Error
 
254
  ---
255
 
256
  <div align="center">
257
+ Made with ❤️ using Gradio and Qwen2
258
  </div>
app.py CHANGED
@@ -375,7 +375,7 @@ with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Soft(), title="RAG ChatBot - GLM"
375
 
376
  **Tech Stack:**
377
  - Framework: Gradio
378
- - LLM: ChatGLM3 (Transformers)
379
  - Embeddings: Sentence Transformers
380
  - Vector DB: ChromaDB
381
  - PDF Processing: PyPDF2 + pdfplumber
@@ -385,7 +385,7 @@ with gr.Blocks(css=CUSTOM_CSS, theme=gr.themes.Soft(), title="RAG ChatBot - GLM"
385
  gr.Markdown("""
386
  Untuk mengubah konfigurasi model, edit file `.env`:
387
  ```bash
388
- MODEL_NAME=THUDM/chatglm3-6b
389
  DEVICE=auto
390
  CHUNK_SIZE=500
391
  CHUNK_OVERLAP=50
@@ -401,7 +401,7 @@ if __name__ == "__main__":
401
  os.makedirs(config.VECTOR_DB_DIR, exist_ok=True)
402
 
403
  print("=" * 60)
404
- print("🚀 Launching RAG ChatBot dengan GLM")
405
  print("=" * 60)
406
  print(f"Model: {config.MODEL_NAME}")
407
  print(f"Device: {config.DEVICE}")
 
375
 
376
  **Tech Stack:**
377
  - Framework: Gradio
378
+ - LLM: Qwen2 (Transformers)
379
  - Embeddings: Sentence Transformers
380
  - Vector DB: ChromaDB
381
  - PDF Processing: PyPDF2 + pdfplumber
 
385
  gr.Markdown("""
386
  Untuk mengubah konfigurasi model, edit file `.env`:
387
  ```bash
388
+ MODEL_NAME=Qwen/Qwen2-0.5B-Instruct
389
  DEVICE=auto
390
  CHUNK_SIZE=500
391
  CHUNK_OVERLAP=50
 
401
  os.makedirs(config.VECTOR_DB_DIR, exist_ok=True)
402
 
403
  print("=" * 60)
404
+ print("🚀 Launching RAG ChatBot dengan Qwen2")
405
  print("=" * 60)
406
  print(f"Model: {config.MODEL_NAME}")
407
  print(f"Device: {config.DEVICE}")
config/model_config.py CHANGED
@@ -11,7 +11,7 @@ class Config:
11
  """Configuration class for RAG ChatBot"""
12
 
13
  # Model Settings
14
- MODEL_NAME = os.getenv("MODEL_NAME", "THUDM/chatglm3-6b")
15
  EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2")
16
 
17
  # Device Configuration
 
11
  """Configuration class for RAG ChatBot"""
12
 
13
  # Model Settings
14
+ MODEL_NAME = os.getenv("MODEL_NAME", "Qwen/Qwen2-0.5B-Instruct")
15
  EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2")
16
 
17
  # Device Configuration
requirements.txt CHANGED
@@ -11,6 +11,7 @@ langchain>=0.1.0
11
  langchain-community>=0.0.20
12
  langchain-text-splitters>=0.0.1
13
  sentencepiece
 
14
 
15
  # PDF Processing
16
  PyPDF2>=3.0.0
 
11
  langchain-community>=0.0.20
12
  langchain-text-splitters>=0.0.1
13
  sentencepiece
14
+ dontenv
15
 
16
  # PDF Processing
17
  PyPDF2>=3.0.0
utils/rag_pipeline.py CHANGED
@@ -3,7 +3,7 @@ RAG Pipeline for retrieving relevant context and generating responses
3
  """
4
  from typing import List, Dict, Optional
5
  import torch
6
- from transformers import AutoTokenizer, AutoModel
7
  from config.model_config import config
8
  from utils.vector_store import VectorStore
9
 
@@ -29,7 +29,7 @@ class RAGPipeline:
29
  return config.DEVICE
30
 
31
  def load_model(self):
32
- """Load GLM model and tokenizer"""
33
  if self.model is not None:
34
  print("Model already loaded")
35
  return
@@ -38,16 +38,23 @@ class RAGPipeline:
38
  print(f"Using device: {self.device}")
39
 
40
  try:
 
 
41
  self.tokenizer = AutoTokenizer.from_pretrained(
42
  config.MODEL_NAME,
43
  trust_remote_code=True
44
  )
45
 
46
- self.model = AutoModel.from_pretrained(
47
  config.MODEL_NAME,
48
  trust_remote_code=True,
49
- torch_dtype=torch.float16 if self.device == "cuda" else torch.float32
50
- ).to(self.device)
 
 
 
 
 
51
 
52
  # Set to evaluation mode
53
  self.model = self.model.eval()
@@ -113,7 +120,7 @@ class RAGPipeline:
113
 
114
  Args:
115
  query: User query
116
- history: Chat history (for ChatGLM format)
117
  use_rag: Whether to use RAG retrieval
118
  max_length: Maximum response length
119
  temperature: Sampling temperature
@@ -146,17 +153,58 @@ class RAGPipeline:
146
  else:
147
  prompt = query
148
 
149
- # Generate response using ChatGLM
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  try:
151
- response, history = self.model.chat(
152
- self.tokenizer,
153
- prompt,
154
- history=history or [],
155
- max_length=max_length,
156
- temperature=temperature,
157
- top_p=top_p
158
  )
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  return response, sources
161
 
162
  except Exception as e:
@@ -211,17 +259,69 @@ class RAGPipeline:
211
  else:
212
  prompt = query
213
 
214
- # Stream response using ChatGLM
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  try:
216
- for response, history in self.model.stream_chat(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  self.tokenizer,
218
- prompt,
219
- history=history or [],
220
- max_length=max_length,
 
 
 
 
 
 
221
  temperature=temperature,
222
- top_p=top_p
223
- ):
224
- yield response, sources
 
 
 
 
 
 
 
 
 
 
 
 
225
 
226
  except Exception as e:
227
  print(f"Error streaming response: {e}")
 
3
  """
4
  from typing import List, Dict, Optional
5
  import torch
6
+ from transformers import AutoTokenizer, AutoModelForCausalLM
7
  from config.model_config import config
8
  from utils.vector_store import VectorStore
9
 
 
29
  return config.DEVICE
30
 
31
  def load_model(self):
32
+ """Load Qwen2 model and tokenizer"""
33
  if self.model is not None:
34
  print("Model already loaded")
35
  return
 
38
  print(f"Using device: {self.device}")
39
 
40
  try:
41
+ from transformers import AutoModelForCausalLM
42
+
43
  self.tokenizer = AutoTokenizer.from_pretrained(
44
  config.MODEL_NAME,
45
  trust_remote_code=True
46
  )
47
 
48
+ self.model = AutoModelForCausalLM.from_pretrained(
49
  config.MODEL_NAME,
50
  trust_remote_code=True,
51
+ torch_dtype=torch.float16 if self.device == "cuda" else torch.float32,
52
+ device_map=self.device if self.device == "cuda" else None
53
+ )
54
+
55
+ # Move to device if CPU
56
+ if self.device == "cpu":
57
+ self.model = self.model.to(self.device)
58
 
59
  # Set to evaluation mode
60
  self.model = self.model.eval()
 
120
 
121
  Args:
122
  query: User query
123
+ history: Chat history (list of [user_msg, assistant_msg] pairs)
124
  use_rag: Whether to use RAG retrieval
125
  max_length: Maximum response length
126
  temperature: Sampling temperature
 
153
  else:
154
  prompt = query
155
 
156
+ # Build messages for Qwen2 chat format
157
+ messages = []
158
+
159
+ # Add system message
160
+ messages.append({
161
+ "role": "system",
162
+ "content": config.SYSTEM_PROMPT
163
+ })
164
+
165
+ # Add chat history
166
+ if history:
167
+ for user_msg, assistant_msg in history:
168
+ if user_msg:
169
+ messages.append({"role": "user", "content": user_msg})
170
+ if assistant_msg:
171
+ messages.append({"role": "assistant", "content": assistant_msg})
172
+
173
+ # Add current query
174
+ messages.append({"role": "user", "content": prompt})
175
+
176
+ # Generate response using Qwen2
177
  try:
178
+ # Apply chat template
179
+ text = self.tokenizer.apply_chat_template(
180
+ messages,
181
+ tokenize=False,
182
+ add_generation_prompt=True
 
 
183
  )
184
 
185
+ # Tokenize
186
+ model_inputs = self.tokenizer([text], return_tensors="pt").to(self.device)
187
+
188
+ # Generate
189
+ with torch.no_grad():
190
+ generated_ids = self.model.generate(
191
+ model_inputs.input_ids,
192
+ max_new_tokens=max_length,
193
+ temperature=temperature,
194
+ top_p=top_p,
195
+ do_sample=True,
196
+ pad_token_id=self.tokenizer.pad_token_id,
197
+ eos_token_id=self.tokenizer.eos_token_id
198
+ )
199
+
200
+ # Decode response
201
+ generated_ids = [
202
+ output_ids[len(input_ids):]
203
+ for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
204
+ ]
205
+
206
+ response = self.tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
207
+
208
  return response, sources
209
 
210
  except Exception as e:
 
259
  else:
260
  prompt = query
261
 
262
+ # Build messages for Qwen2 chat format
263
+ messages = []
264
+
265
+ # Add system message
266
+ messages.append({
267
+ "role": "system",
268
+ "content": config.SYSTEM_PROMPT
269
+ })
270
+
271
+ # Add chat history
272
+ if history:
273
+ for user_msg, assistant_msg in history:
274
+ if user_msg:
275
+ messages.append({"role": "user", "content": user_msg})
276
+ if assistant_msg:
277
+ messages.append({"role": "assistant", "content": assistant_msg})
278
+
279
+ # Add current query
280
+ messages.append({"role": "user", "content": prompt})
281
+
282
+ # Stream response using Qwen2
283
  try:
284
+ from transformers import TextIteratorStreamer
285
+ from threading import Thread
286
+
287
+ # Apply chat template
288
+ text = self.tokenizer.apply_chat_template(
289
+ messages,
290
+ tokenize=False,
291
+ add_generation_prompt=True
292
+ )
293
+
294
+ # Tokenize
295
+ model_inputs = self.tokenizer([text], return_tensors="pt").to(self.device)
296
+
297
+ # Setup streamer
298
+ streamer = TextIteratorStreamer(
299
  self.tokenizer,
300
+ skip_prompt=True,
301
+ skip_special_tokens=True
302
+ )
303
+
304
+ # Generation kwargs
305
+ generation_kwargs = dict(
306
+ model_inputs,
307
+ streamer=streamer,
308
+ max_new_tokens=max_length,
309
  temperature=temperature,
310
+ top_p=top_p,
311
+ do_sample=True,
312
+ pad_token_id=self.tokenizer.pad_token_id,
313
+ eos_token_id=self.tokenizer.eos_token_id
314
+ )
315
+
316
+ # Start generation in separate thread
317
+ thread = Thread(target=self.model.generate, kwargs=generation_kwargs)
318
+ thread.start()
319
+
320
+ # Stream output
321
+ full_response = ""
322
+ for new_text in streamer:
323
+ full_response += new_text
324
+ yield full_response, sources
325
 
326
  except Exception as e:
327
  print(f"Error streaming response: {e}")