Sukmadi commited on
Commit
dd77059
·
unverified ·
1 Parent(s): 45332bf

Cleanup (#5)

Browse files

* fix save to local

* remove prefix in utils

* update retrieval with faiss HNSW and better chunking

* save commit

* remove pdf plummer and minimalize requirements.txt

.gitignore CHANGED
@@ -1,5 +1,7 @@
1
  .vscode
2
  pdfs
 
 
3
 
4
  *.png
5
  *.jpg
 
1
  .vscode
2
  pdfs
3
+ app/__pycache__
4
+
5
 
6
  *.png
7
  *.jpg
README.md CHANGED
@@ -8,3 +8,8 @@ pinned: false
8
  ---
9
 
10
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
8
  ---
9
 
10
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
11
+
12
+ ---
13
+ TODO:
14
+ + Apply COhen's Kappa to measure rate of aggreement between human and AI.
15
+
app.py CHANGED
@@ -9,6 +9,7 @@ from pydantic import BaseModel
9
 
10
  # Import the user's RAGMCQ implementation
11
  from generator import RAGMCQ
 
12
 
13
  app = FastAPI(title="RAG MCQ Generator API")
14
 
@@ -36,10 +37,7 @@ def startup_event():
36
  global rag
37
 
38
  # instantiate the heavy object once
39
- rag = RAGMCQ(
40
- qdrant_url=os.environ['QDRANT_URL'],
41
- qdrant_api_key=os.environ['QDRANT_API_KEY']
42
- )
43
  print("RAGMCQ instance created on startup.")
44
 
45
  @app.get("/health")
@@ -105,8 +103,12 @@ async def generate_saved_endpoint(
105
  # don't fail the whole request for a validation error — return generator output and note the error
106
  validation_report = {"error": f"Validation failed: {e}"}
107
 
 
 
108
  return {"mcqs": mcqs, "validation": validation_report}
109
 
 
 
110
  @app.post("/generate", response_model=GenerateResponse)
111
  async def generate_endpoint(
112
  background_tasks: BackgroundTasks,
@@ -141,7 +143,7 @@ async def generate_endpoint(
141
 
142
  background_tasks.add_task(_cleanup, tmp_path)
143
 
144
- # save pdf
145
  try:
146
  rag.save_pdf_to_qdrant(tmp_path, filename=qdrant_filename, collection=collection_name, overwrite=True)
147
  except Exception as e:
@@ -171,6 +173,9 @@ async def generate_endpoint(
171
  # don't fail the whole request for a validation error — return generator output and note the error
172
  validation_report = {"error": f"Validation failed: {e}"}
173
 
 
 
 
174
  return {"mcqs": mcqs, "validation": validation_report}
175
 
176
 
 
9
 
10
  # Import the user's RAGMCQ implementation
11
  from generator import RAGMCQ
12
+ from utils import log_pipeline
13
 
14
  app = FastAPI(title="RAG MCQ Generator API")
15
 
 
37
  global rag
38
 
39
  # instantiate the heavy object once
40
+ rag = RAGMCQ()
 
 
 
41
  print("RAGMCQ instance created on startup.")
42
 
43
  @app.get("/health")
 
103
  # don't fail the whole request for a validation error — return generator output and note the error
104
  validation_report = {"error": f"Validation failed: {e}"}
105
 
106
+ log_pipeline('test/mcq_output.json', content={"mcqs": mcqs, "validation": validation_report})
107
+
108
  return {"mcqs": mcqs, "validation": validation_report}
109
 
110
+
111
+
112
  @app.post("/generate", response_model=GenerateResponse)
113
  async def generate_endpoint(
114
  background_tasks: BackgroundTasks,
 
143
 
144
  background_tasks.add_task(_cleanup, tmp_path)
145
 
146
+ # save pdf
147
  try:
148
  rag.save_pdf_to_qdrant(tmp_path, filename=qdrant_filename, collection=collection_name, overwrite=True)
149
  except Exception as e:
 
173
  # don't fail the whole request for a validation error — return generator output and note the error
174
  validation_report = {"error": f"Validation failed: {e}"}
175
 
176
+
177
+ log_pipeline('test/mcq_output.json', content={"mcqs": mcqs, "validation": validation_report})
178
+
179
  return {"mcqs": mcqs, "validation": validation_report}
180
 
181
 
app/app.py CHANGED
@@ -9,6 +9,7 @@ from pydantic import BaseModel
9
 
10
  # Import the user's RAGMCQ implementation
11
  from generator import RAGMCQ
 
12
 
13
  app = FastAPI(title="RAG MCQ Generator API")
14
 
@@ -102,6 +103,16 @@ async def generate_saved_endpoint(
102
  # don't fail the whole request for a validation error — return generator output and note the error
103
  validation_report = {"error": f"Validation failed: {e}"}
104
 
 
 
 
 
 
 
 
 
 
 
105
  return {"mcqs": mcqs, "validation": validation_report}
106
 
107
  @app.post("/generate", response_model=GenerateResponse)
@@ -168,6 +179,17 @@ async def generate_endpoint(
168
  # don't fail the whole request for a validation error — return generator output and note the error
169
  validation_report = {"error": f"Validation failed: {e}"}
170
 
 
 
 
 
 
 
 
 
 
 
 
171
  return {"mcqs": mcqs, "validation": validation_report}
172
 
173
 
 
9
 
10
  # Import the user's RAGMCQ implementation
11
  from generator import RAGMCQ
12
+ from utils import save_to_local, reset_token_count, get_token_count_record
13
 
14
  app = FastAPI(title="RAG MCQ Generator API")
15
 
 
103
  # don't fail the whole request for a validation error — return generator output and note the error
104
  validation_report = {"error": f"Validation failed: {e}"}
105
 
106
+ print("Save result to ../test/mcq_output.json")
107
+ save_to_local('../test/mcq_output.json', content={"mcqs": mcqs, "validation": validation_report})
108
+ token_record = get_token_count_record()
109
+
110
+ print("Token Record:")
111
+ for record, value in token_record.items():
112
+ print(f'{record}:{value}', '\n')
113
+
114
+ reset_token_count()
115
+
116
  return {"mcqs": mcqs, "validation": validation_report}
117
 
118
  @app.post("/generate", response_model=GenerateResponse)
 
179
  # don't fail the whole request for a validation error — return generator output and note the error
180
  validation_report = {"error": f"Validation failed: {e}"}
181
 
182
+ print("Save result to ../test/mcq_output.json")
183
+ save_to_local('../test/mcq_output.json', content={"mcqs": mcqs, "validation": validation_report})
184
+ token_record = get_token_count_record()
185
+
186
+ print("Token Record:")
187
+ for record, value in token_record.items():
188
+ print(f'{record}:{value}', '\n')
189
+
190
+ reset_token_count()
191
+ # save_logs(token_record)
192
+
193
  return {"mcqs": mcqs, "validation": validation_report}
194
 
195
 
app/generator.py CHANGED
@@ -1,11 +1,13 @@
1
  import re
2
  import random
 
3
  import numpy as np
4
- from typing import List, Tuple, Dict, Any, Optional
 
5
  from sentence_transformers import SentenceTransformer
6
  from uuid import uuid4
7
  import pymupdf4llm
8
- import pymupdf as fitz
9
 
10
  try:
11
  from qdrant_client import QdrantClient
@@ -28,19 +30,19 @@ try:
28
  except Exception:
29
  _HAS_FAISS = False
30
 
31
- from utils import generate_mcqs_from_text, _post_chat, _safe_extract_json
32
 
33
  class RAGMCQ:
34
  def __init__(
35
  self,
36
  embedder_model: str = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
37
- hf_model: str = "gpt-oss-120b",
38
- qdrant_url: str = None,
39
- qdrant_api_key: str = None,
40
  qdrant_prefer_grpc: bool = False,
41
  ):
42
  self.embedder = SentenceTransformer(embedder_model)
43
- self.hf_model = hf_model
44
  self.embeddings = None # np.array of shape (N, D)
45
  self.texts = [] # list of chunk texts
46
  self.metadata = [] # list of dicts (page, chunk_id, char_range)
@@ -51,37 +53,45 @@ class RAGMCQ:
51
  self.qdrant_url = qdrant_url
52
  self.qdrant_api_key = qdrant_api_key
53
  self.qdrant_prefer_grpc = qdrant_prefer_grpc
 
54
  if qdrant_url:
55
  self.connect_qdrant(qdrant_url, qdrant_api_key, qdrant_prefer_grpc)
56
 
57
  def extract_pages(
58
- self,
59
- pdf_path: str,
60
- *,
61
- pages: Optional[List[int]] = None,
62
- ignore_images: bool = False,
63
- dpi: int = 150
64
- ) -> List[str]:
65
- doc = fitz.open(pdf_path)
66
- try:
67
- # request page-wise output (page_chunks=True -> list[dict] per page)
68
- page_dicts = pymupdf4llm.to_markdown(
69
- doc,
70
- pages=pages,
71
- ignore_images=ignore_images,
72
- dpi=dpi,
73
- page_chunks=True,
74
- )
 
 
 
 
 
 
75
 
76
- # to_markdown(..., page_chunks=True) returns a list of dicts, each has key "text" (markdown)
77
- pages_md: List[str] = []
78
- for p in page_dicts:
79
- txt = p.get("text", "") or ""
80
- pages_md.append(txt.strip())
81
 
82
- return pages_md
83
- finally:
84
- doc.close()
 
 
 
85
 
86
  def chunk_text(self, text: str, max_chars: int = 1200) -> List[str]:
87
  text = text.strip()
@@ -89,7 +99,7 @@ class RAGMCQ:
89
  return []
90
  if len(text) <= max_chars:
91
  return [text]
92
-
93
  # split by sentence-like boundaries
94
  sentences = re.split(r'(?<=[\.\?\!])\s+', text)
95
  chunks = []
@@ -116,6 +126,7 @@ class RAGMCQ:
116
 
117
  def build_index_from_pdf(self, pdf_path: str, max_chars: int = 1200):
118
  pages = self.extract_pages(pdf_path)
 
119
  self.texts = []
120
  self.metadata = []
121
 
@@ -128,6 +139,8 @@ class RAGMCQ:
128
  if not self.texts:
129
  raise RuntimeError("No text extracted from PDF.")
130
 
 
 
131
  # compute embeddings
132
  emb = self.embedder.encode(self.texts, convert_to_numpy=True, show_progress_bar=True)
133
  self.embeddings = emb.astype("float32")
@@ -187,7 +200,7 @@ class RAGMCQ:
187
  # ask generator
188
  try:
189
  mcq_block = generate_mcqs_from_text(
190
- chunk_text, n=to_gen, model=self.hf_model, temperature=temperature
191
  )
192
  except Exception as e:
193
  # skip this chunk if generator fails
@@ -199,7 +212,7 @@ class RAGMCQ:
199
  output[str(qcount)] = mcq_block[item]
200
  if qcount >= n_questions:
201
  return output
202
-
203
  return output
204
 
205
  elif mode == "rag":
@@ -214,6 +227,10 @@ class RAGMCQ:
214
  # create a seed query: pick a random chunk, pick a sentence from it
215
  seed_idx = random.randrange(len(self.texts))
216
  chunk = self.texts[seed_idx]
 
 
 
 
217
  sents = re.split(r'(?<=[\.\?\!])\s+', chunk)
218
  seed_sent = random.choice([s for s in sents if len(s.strip()) > 20]) if sents else chunk[:200]
219
  query = f"Create questions about: {seed_sent}"
@@ -226,12 +243,16 @@ class RAGMCQ:
226
  context_parts.append(f"[page {md['page']}] {self.texts[ridx]}")
227
  context = "\n\n".join(context_parts)
228
 
 
 
 
229
  # call generator for 1 question (or small batch) with the retrieved context
230
  try:
231
  # request 1 question at a time to keep diversity
232
  mcq_block = generate_mcqs_from_text(
233
- context, n=1, model=self.hf_model, temperature=temperature
234
  )
 
235
  except Exception as e:
236
  print(f"Generator failed during RAG attempt {attempts}: {e}")
237
  continue
@@ -242,7 +263,7 @@ class RAGMCQ:
242
  output[str(qcount)] = mcq_block[item]
243
  if qcount >= n_questions:
244
  return output
245
-
246
  return output
247
  else:
248
  raise ValueError("mode must be 'per_page' or 'rag'.")
@@ -281,7 +302,7 @@ class RAGMCQ:
281
  system = {
282
  "role": "system",
283
  "content": (
284
- "Bạn là một trợ lý đánh giá tính thực chứng của câu hỏi trắc nghiệm dựa trên đoạn văn được cung cấp. "
285
  "Hãy trả lời DUY NHẤT bằng JSON hợp lệ (không có văn bản khác) theo schema:\n\n"
286
  "{\n"
287
  ' "supported": true/false, # câu trả lời đúng có được nội dung chứng thực không\n'
@@ -303,7 +324,7 @@ class RAGMCQ:
303
  )
304
  }
305
 
306
- raw = _post_chat([system, user], model=self.hf_model, temperature=model_verification_temperature)
307
 
308
  # parse JSON object in response
309
  try:
@@ -397,6 +418,7 @@ class RAGMCQ:
397
 
398
  # extract pages and chunks (re-using your existing helpers)
399
  pages = self.extract_pages(pdf_path)
 
400
  all_chunks = []
401
  all_meta = []
402
  for p_idx, page_text in enumerate(pages, start=1):
@@ -406,7 +428,7 @@ class RAGMCQ:
406
  all_meta.append({"page": p_idx, "chunk_id": cid, "length": len(ch)})
407
 
408
  if not all_chunks:
409
- raise RuntimeError("No text extracted from PDF.")
410
 
411
  # ensure collection exists
412
  self._ensure_collection(collection)
@@ -640,7 +662,7 @@ class RAGMCQ:
640
  continue
641
  to_gen = questions_per_chunk
642
  try:
643
- mcq_block = generate_mcqs_from_text(txt, n=to_gen, model=self.hf_model, temperature=temperature)
644
  except Exception as e:
645
  print(f"Generator failed on chunk (index {i}): {e}")
646
  continue
@@ -680,7 +702,7 @@ class RAGMCQ:
680
  context = "\n\n".join(context_parts)
681
 
682
  try:
683
- mcq_block = generate_mcqs_from_text(context, n=1, model=self.hf_model, temperature=temperature)
684
  except Exception as e:
685
  print(f"Generator failed during RAG attempt {attempts}: {e}")
686
  continue
 
1
  import re
2
  import random
3
+ import fitz
4
  import numpy as np
5
+ import os
6
+ from typing import List, Optional, Tuple, Dict, Any
7
  from sentence_transformers import SentenceTransformer
8
  from uuid import uuid4
9
  import pymupdf4llm
10
+ from utils import save_to_local
11
 
12
  try:
13
  from qdrant_client import QdrantClient
 
30
  except Exception:
31
  _HAS_FAISS = False
32
 
33
+ from utils import generate_mcqs_from_text, _post_chat, _safe_extract_json, save_to_local
34
 
35
  class RAGMCQ:
36
  def __init__(
37
  self,
38
  embedder_model: str = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
39
+ generation_model: str = "gpt-oss-120b",
40
+ qdrant_url: str = os.environ.get('QDRANT_URL') or "",
41
+ qdrant_api_key: str = os.environ.get('QDRANT_API_KEY') or "",
42
  qdrant_prefer_grpc: bool = False,
43
  ):
44
  self.embedder = SentenceTransformer(embedder_model)
45
+ self.generation_model = generation_model
46
  self.embeddings = None # np.array of shape (N, D)
47
  self.texts = [] # list of chunk texts
48
  self.metadata = [] # list of dicts (page, chunk_id, char_range)
 
53
  self.qdrant_url = qdrant_url
54
  self.qdrant_api_key = qdrant_api_key
55
  self.qdrant_prefer_grpc = qdrant_prefer_grpc
56
+
57
  if qdrant_url:
58
  self.connect_qdrant(qdrant_url, qdrant_api_key, qdrant_prefer_grpc)
59
 
60
  def extract_pages(
61
+ self,
62
+ pdf_path: str,
63
+ *,
64
+ pages: Optional[List[int]] = None,
65
+ ignore_images: bool = False,
66
+ dpi: int = 150
67
+ ) -> List[str]:
68
+ doc = fitz.open(pdf_path)
69
+ try:
70
+ # request page-wise output (page_chunks=True -> list[dict] per page)
71
+ page_dicts = pymupdf4llm.to_markdown(
72
+ doc,
73
+ pages=pages,
74
+ ignore_images=ignore_images,
75
+ dpi=dpi,
76
+ page_chunks=True,
77
+ )
78
+
79
+ # to_markdown(..., page_chunks=True) returns a list of dicts, each has key "text" (markdown)
80
+ pages_md: List[str] = []
81
+ for p in page_dicts:
82
+ txt = p.get("text", "") or ""
83
+ pages_md.append(txt.strip())
84
 
85
+ return pages_md
86
+ finally:
87
+ doc.close()
 
 
88
 
89
+ # pages = []
90
+ # with pdfplumber.open(pdf_path) as pdf:
91
+ # for p in pdf.pages:
92
+ # txt = p.extract_text() or ""
93
+ # pages.append(txt.strip())
94
+ # return pages
95
 
96
  def chunk_text(self, text: str, max_chars: int = 1200) -> List[str]:
97
  text = text.strip()
 
99
  return []
100
  if len(text) <= max_chars:
101
  return [text]
102
+
103
  # split by sentence-like boundaries
104
  sentences = re.split(r'(?<=[\.\?\!])\s+', text)
105
  chunks = []
 
126
 
127
  def build_index_from_pdf(self, pdf_path: str, max_chars: int = 1200):
128
  pages = self.extract_pages(pdf_path)
129
+
130
  self.texts = []
131
  self.metadata = []
132
 
 
139
  if not self.texts:
140
  raise RuntimeError("No text extracted from PDF.")
141
 
142
+ save_to_local('../test/text_chunks.md', file_content=self.texts)
143
+
144
  # compute embeddings
145
  emb = self.embedder.encode(self.texts, convert_to_numpy=True, show_progress_bar=True)
146
  self.embeddings = emb.astype("float32")
 
200
  # ask generator
201
  try:
202
  mcq_block = generate_mcqs_from_text(
203
+ chunk_text, n=to_gen, model=self.generation_model, temperature=temperature
204
  )
205
  except Exception as e:
206
  # skip this chunk if generator fails
 
212
  output[str(qcount)] = mcq_block[item]
213
  if qcount >= n_questions:
214
  return output
215
+
216
  return output
217
 
218
  elif mode == "rag":
 
227
  # create a seed query: pick a random chunk, pick a sentence from it
228
  seed_idx = random.randrange(len(self.texts))
229
  chunk = self.texts[seed_idx]
230
+
231
+ #? Investigate Chunking Strategy
232
+ with open("chunks.txt", "a", encoding="utf-8") as f: f.write(chunk + "\n")
233
+
234
  sents = re.split(r'(?<=[\.\?\!])\s+', chunk)
235
  seed_sent = random.choice([s for s in sents if len(s.strip()) > 20]) if sents else chunk[:200]
236
  query = f"Create questions about: {seed_sent}"
 
243
  context_parts.append(f"[page {md['page']}] {self.texts[ridx]}")
244
  context = "\n\n".join(context_parts)
245
 
246
+ save_to_local('../test/context.md', context)
247
+
248
+
249
  # call generator for 1 question (or small batch) with the retrieved context
250
  try:
251
  # request 1 question at a time to keep diversity
252
  mcq_block = generate_mcqs_from_text(
253
+ context, n=1, model=self.generation_model, temperature=temperature
254
  )
255
+
256
  except Exception as e:
257
  print(f"Generator failed during RAG attempt {attempts}: {e}")
258
  continue
 
263
  output[str(qcount)] = mcq_block[item]
264
  if qcount >= n_questions:
265
  return output
266
+
267
  return output
268
  else:
269
  raise ValueError("mode must be 'per_page' or 'rag'.")
 
302
  system = {
303
  "role": "system",
304
  "content": (
305
+ "Bạn là một trợ lý đánh giá tính thực chứng của câu hỏi trắc nghiệm dựa trên đoạn văn được cung cấp. Luôn trả lời bằng Tiếng Việt"
306
  "Hãy trả lời DUY NHẤT bằng JSON hợp lệ (không có văn bản khác) theo schema:\n\n"
307
  "{\n"
308
  ' "supported": true/false, # câu trả lời đúng có được nội dung chứng thực không\n'
 
324
  )
325
  }
326
 
327
+ raw = _post_chat([system, user], model=self.generation_model, temperature=model_verification_temperature)
328
 
329
  # parse JSON object in response
330
  try:
 
418
 
419
  # extract pages and chunks (re-using your existing helpers)
420
  pages = self.extract_pages(pdf_path)
421
+
422
  all_chunks = []
423
  all_meta = []
424
  for p_idx, page_text in enumerate(pages, start=1):
 
428
  all_meta.append({"page": p_idx, "chunk_id": cid, "length": len(ch)})
429
 
430
  if not all_chunks:
431
+ raise RuntimeError("No tSext extracted from PDF.")
432
 
433
  # ensure collection exists
434
  self._ensure_collection(collection)
 
662
  continue
663
  to_gen = questions_per_chunk
664
  try:
665
+ mcq_block = generate_mcqs_from_text(txt, n=to_gen, model=self.generation_model, temperature=temperature)
666
  except Exception as e:
667
  print(f"Generator failed on chunk (index {i}): {e}")
668
  continue
 
702
  context = "\n\n".join(context_parts)
703
 
704
  try:
705
+ mcq_block = generate_mcqs_from_text(context, n=1, model=self.generation_model, temperature=temperature)
706
  except Exception as e:
707
  print(f"Generator failed during RAG attempt {attempts}: {e}")
708
  continue
app/utils.py DELETED
@@ -1,88 +0,0 @@
1
- import re
2
- import json
3
- from typing import Dict, Any
4
- import requests
5
- import os
6
-
7
- #TODO: allow to choose different provider later + dynamic routing when token expired
8
- API_URL = "https://api.cerebras.ai/v1/chat/completions"
9
- CEREBRAS_API_KEY = os.environ['CEREBRAS_API_KEY']
10
-
11
- HEADERS = {"Authorization": f"Bearer {CEREBRAS_API_KEY}"}
12
- JSON_OBJ_RE = re.compile(r"(\{[\s\S]*\})", re.MULTILINE)
13
-
14
- def _post_chat(messages: list, model: str, temperature: float = 0.2, timeout: int = 60) -> str:
15
- payload = {"model": model, "messages": messages, "temperature": temperature}
16
- resp = requests.post(API_URL, headers=HEADERS, json=payload, timeout=timeout)
17
- resp.raise_for_status()
18
- data = resp.json()
19
-
20
- # handle various shapes
21
- if "choices" in data and len(data["choices"]) > 0:
22
- # prefer message.content
23
- ch = data["choices"][0]
24
-
25
- if isinstance(ch, dict) and "message" in ch and "content" in ch["message"]:
26
- return ch["message"]["content"]
27
-
28
- if "text" in ch:
29
- return ch["text"]
30
-
31
- # final fallback
32
- raise RuntimeError("Unexpected HF response shape: " + json.dumps(data)[:200])
33
-
34
- def _safe_extract_json(text: str) -> dict:
35
- # remove triple backticks
36
- text = re.sub(r"```(?:json)?\n?", "", text)
37
- m = JSON_OBJ_RE.search(text)
38
-
39
- if not m:
40
- raise ValueError("No JSON object found in model output.")
41
- js = m.group(1)
42
-
43
- # try load, fix trailing commas
44
- try:
45
- return json.loads(js)
46
- except json.JSONDecodeError:
47
- fixed = re.sub(r",\s*([}\]])", r"\1", js)
48
- return json.loads(fixed)
49
-
50
- def generate_mcqs_from_text(
51
- source_text: str,
52
- n: int = 3,
53
- model: str = "gpt-oss-120b",
54
- temperature: float = 0.2,
55
- ) -> Dict[str, Any]:
56
- system_message = {
57
- "role": "system",
58
- "content": (
59
- "Bạn là một trợ lý hữu ích chuyên tạo câu hỏi trắc nghiệm. "
60
- "Chỉ TRẢ VỀ duy nhất một đối tượng JSON theo đúng schema sau và không có bất kỳ văn bản nào khác:\n\n"
61
- "{\n"
62
- ' "1": { "câu hỏi": "...", "lựa chọn": {"a":"...","b":"...","c":"...","d":"..."}, "đáp án":"..."},\n'
63
- ' "2": { ... }\n'
64
- "}\n\n"
65
- "Lưu ý:\n"
66
- f"- Tạo đúng {n} mục, đánh YOUR_API_KEYsố từ 1 tới {n}.\n"
67
- "- Khóa 'lựa chọn' phải có các phím a, b, c, d.\n"
68
- "- 'đáp án' phải là toàn văn đáp án đúng (không phải ký tự chữ cái), và giá trị này phải khớp chính xác với một trong các giá trị trong 'lựa chọn'.\n"
69
- "- Không kèm giải thích hay trường thêm.\n"
70
- "- Các phương án sai (distractors) phải hợp lý và không lặp lại."
71
- )
72
- }
73
- user_message = {
74
- "role": "user",
75
- "content": (
76
- f"Hãy tạo {n} câu hỏi trắc nghiệm từ nội dung dưới đây. Dùng nội dung này làm nguồn duy nhất để trả lời."
77
- "Nếu nội dung quá ít để tạo câu hỏi chính xác, hãy tạo các phương án hợp lý nhưng có thể biện minh được.\n\n"
78
- f"Nội dung:\n\n{source_text}"
79
- )
80
- }
81
-
82
- raw = _post_chat([system_message, user_message], model=model, temperature=temperature)
83
- parsed = _safe_extract_json(raw)
84
-
85
- # validate structure and length
86
- if not isinstance(parsed, dict) or len(parsed) != n:
87
- raise ValueError(f"Generator returned invalid structure. Raw:\n{raw}")
88
- return parsed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
chunks.txt ADDED
@@ -0,0 +1,596 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ _MỤC LỤC_ _3_
2
+
3
+
4
+ 2.3 Các công thức tính tích phân mặt loại II . . . . . . . . . . . . . . . . . 153
5
+
6
+ 2.4 Công thức Ostrogradsky . . . . . . . . . . . . . . . . . . . . . . . . . . 157
7
+
8
+ 2.5 Công thức Stokes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
9
+
10
+ 2.6 Công thức liên hệgiữa tích phân mặt loại I và loại II . . . . . . . . . 161
11
+ **Chương 6 . Lý thuyết trường. . . . . . . . . . . . . . . . . . . . . . . . . 165**
12
+
13
+
14
+ 1 Trường vô hướng . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
15
+
16
+ 1.1 Định nghĩa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
17
+
18
+ 1.2 Đạo hàm theo hướng . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
19
+
20
+ 1.3 Gradient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
21
+
22
+ 1.4 Bài tập . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
23
+
24
+ 2 Trường véctơ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
25
+
26
+ 2.1 Định nghĩa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
27
+ 2.2 Thông lượng, dive, trường ống . . . . . . . . . . . . . . . . . . . . . . . 169
28
+
29
+ 2.3 Hoàn lưu, véctơ xoáy . . . . . . . . . . . . . . .
30
+ **Phương trình tiếp diện của mặt cong cho bởi phương trình tham số**
31
+
32
+
33
+ Bài toán: Tìm mặt phẳng tiếp diện của mặt cong S cho bởi phương trình tham số
34
+
35
+
36
+ r ( u, v ) = x ( u, v ) . [⃗] i + y ( t ) . [⃗] j + z ( t ) . [⃗] k
37
+
38
+
39
+ tại điểm P 0 ứng với u = u 0, v = v 0 . 16
40
+
41
+
42
+
43
+
44
+
45
+
46
+
47
+
48
+
49
+
50
+
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+ x = a sin [2] t
60
+ y = b sin t cos t tại điểm ứng với t = _[π]_ 4 [,] [ (] [a][,][ b][,][ c] [ >] [ 0] [)] [.]
61
+ z = c cos [2] t
62
+
63
+
64
+
65
+ x = [e] [t] [ sin][ t]
66
+ ~~√~~ 2
67
+
68
+ y = 1
69
+ z = [e] [t] [ cos][ t]
70
+ ~~√~~ 2
71
+
72
+
73
+
74
+ tại điểm ứng với t = 0. [a]
75
+
76
+ 2 = [y] [−] 2 [b]
77
+ a 0
78
+
79
+
80
+
81
+ 2
82
+
83
+ − c
84
+
85
+
86
+
87
+ _Lời giải_ . a. **–** Phương trình tiếp tuyến: ( d ) : [x] [−] 2 [a]
88
+
89
+
90
+
91
+ 0 2 = [z] − [−] c 2 [c]
92
+
93
+
94
+
95
+ **–** Phương trình pháp diện: ( P ) : a �x − 2 [a]
96
+
97
+
98
+
99
+
100
+ [c] = 0. 2 �
101
+
102
+
103
+
104
+
105
+ [a] − c z − [c]
106
+
107
+ 2 � � 2
108
+
109
+
110
+
111
+ x = [y] [−] [1]
112
+
113
+ 2 0
114
+ 2
115
+
116
+
117
+
118
+ 2
119
+ 2
120
+ ~~√~~ 2
121
+
122
+
123
+
124
+ 2 . 2
125
+
126
+
127
+
128
+ b. **–** Phương trình tiếp tuyến: ( d ) : ~~√~~ x
129
+
130
+
131
+
132
+
133
+
134
+ [−] [1] = [z] [−] 2
135
+
136
+ 0 ~~√~~ 2
137
+
138
+
139
+
140
+ **–** Phương trình pháp diện: ( P ) : √
141
+
142
+
143
+
144
+ 2 √
145
+ z −
146
+ 2 2
147
+
148
+
149
+
150
+
151
+ 2 √
152
+ 2 [x] [ +] 2
153
+
154
+
155
+
156
+ 2
157
+ = 0. 2
158
+
159
+
160
+
161
+
162
+ **Bài tập 1.6.** Viết phương trình pháp tuyến và tiếp diện của mặt cong:
163
+
164
+
165
+ a) x [2] − 4y [2] + 2z [2] = 6 tại điểm ( 2, 2, 3 ) . b) z = 2x [2] + 4y [2] tại điểm ( 2, 1, 12 ) . c) z = ln ( 2x + y ) tại điểm (− 1, 3, 0 )
166
+
167
+
168
+ 20
169
+ Ta có
170
+ N ⃗ ( t ) = _[γ]_ [′] [(] [t] [)]
171
+
172
+ | _γ_ ( t )|
173
+
174
+
175
+ nên
176
+ N [′] ( t ) =
177
+
178
+ #### 2.4 Mặt cong trong không gian R [3]
179
+
180
+
181
+ Tương tựnhư cách chúng ta biểu diễn đường cong trong không gian bởi một hàm véc tơ
182
+ một tham số r ( t ) = x ( t ) . [⃗] i + y ( t ) . [⃗] j + z ( t ) . [⃗] k, mỗi mặt cong trong không gian được biểu diễn
183
+ tham sốdưới dạng
184
+ r ( u, v ) = x ( u, v ) . [⃗] i + y ( t ) . [⃗] j + z ( t ) . [⃗] k,
185
+
186
+
187
+ tức là một hàm véc tơ phụthuộc vào hai tham số u, v. 15
188
+ . . 23
189
+
190
+ 1.1 Định nghĩa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
191
+
192
+ 1.2 Tính tích phân kép trong hệtoạđộDescartes . . . . . . . . . . . . . . 28
193
+ 1.3 Phép đổi biến sốtrong tích phân kép . . . . . . . . . . . . . . . . . . . 39
194
+
195
+ 1.4 Bài tập ôn tập . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
196
+
197
+ 2 Tích phân bội ba . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
198
+ 2.1 Định nghĩa và tính chất . . . . . . . . . . . . . . . . . . . . . . . . . . 54
199
+
200
+ 2.2 Tính tích phân bội ba trong hệtoạđộDescartes . . . . . . . . . . . . 54
201
+ 2.3 Đổi biến sốtrong tích phân bội ba . . . . . . . . . . . . . . . . . . . . . 58
202
+
203
+ 2.4 Bài tập ôn tập . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
204
+
205
+ 3 Các ứng dụng của tích phân bội . . . . . . . . . . . . . . . . . . . . . . . . . . 76
206
+ 3.1 Tính diện tích hình phẳng . . . . . . . . . . . . . . . . . . . . . . . . . 76
207
+ 3.2 Tính thểtích vật thể . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
208
+
209
+ 3.3 Tính diện tích mặt cong . . . . . . . . . . . . . . . . . . . . . . . . . . 89
210
+
211
+
212
+ 1
213
+ **AI VIETNAM** **aivietnam.edu.vn**
214
+
215
+
216
+ Cảhai biến age ởlần in đầu tiên đều là biến cục bộvì Python sẽưu tiên tìm biến cục bộtrước,
217
+ ởđây là đối số2 truyền vào age. Vì ta không định nghĩa self.age, nên khi gọi, Python sẽtìm đến
218
+ thứtựtiếp theo là biến Class. Chính vì vậy, ta sẽin ra được kết quảage = 1
219
+
220
+
221
+ **1.1.2** **Biến toàn cục (Global)**
222
+
223
+
224
+ Biến toàn cục được khai báo bên ngoài hàm hoặc class, sửdụng được trên toàn chương trình
225
+ nhưng nên hạn chếđểtránh gây khó kiểm soát. **Không khuyến khích:**
226
+
227
+
228
+ 1 `counter = 0` `# Global variable`
229
+
230
+
231
+ 2
232
+
233
+
234
+ 3 `class MyClass:`
235
+
236
+ 4 `def increment(self):`
237
+
238
+
239
+ 5 `global counter`
240
+
241
+
242
+ 6 `counter += 1`
243
+
244
+
245
+ **Khuyến khích:**
246
+
247
+
248
+ 1 `class MyClass:`
249
+
250
+
251
+ 2 `counter = 0` `# Class attribute`
252
+
253
+
254
+ 3
255
+
256
+
257
+ 4 `def increment(self):`
258
+
259
+
260
+ 5 `MyClass.counter += 1`
261
+
262
+ ### **2 Động lực cho sựra đời của OOP**
263
+
264
+
265
+ Trong thực tế, chúng ta luôn tìm cách mô hình hóa các thực thểthực tếthành các đối tượng số
266
+ hóa. Từnhu cầu quản lý và tổchức các thực thểnày, lập trình hướng đối tượng ra đời đểđơn
267
+ giản hóa và tối ưu hóa việc xây dựng phần mềm. Hãy tưởng tượng một thếgiới mạng xã hội, nơi mỗi người dùng chính là một đối tượng (object). Những thông tin như ngày sinh, giới tính, sốđiện thoại...
268
+ ập
269
+ được. - **Biến** **`private`** là thông tin tuyệt mật – chỉlớp khai báo nó mới có quyền truy cập. Lớp
270
+ con không thể“đọc nhật ký” hay can thiệp trực tiếp vào những gì cha mẹkhông cho phép. - **Biến** **`protected`** thì đặc biệt hơn – đây là những “di sản” được truyền lại, chỉdành cho
271
+ các lớp con và không ai khác ngoài hệthống kếthừa được phép sửdụng. Sựphân cấp này giúp bảo vệdữliệu và giữcho hệthống kếthừa hoạt động có tổchức. 7
272
+ **AI VIETNAM** **aivietnam.edu.vn**
273
+
274
+
275
+ Cảhai biến age ởlần in đầu tiên đều là biến cục bộvì Python sẽưu tiên tìm biến cục bộtrước,
276
+ ởđây là đối số2 truyền vào age. Vì ta không định nghĩa self.age, nên khi gọi, Python sẽtìm đến
277
+ thứtựtiếp theo là biến Class. Chính vì vậy, ta sẽin ra được kết quảage = 1
278
+
279
+
280
+ **1.1.2** **Biến toàn cục (Global)**
281
+
282
+
283
+ Biến toàn cục được khai báo bên ngoài hàm hoặc class, sửdụng được trên toàn chương trình
284
+ nhưng nên hạn chếđểtránh gây khó kiểm soát. **Không khuyến khích:**
285
+
286
+
287
+ 1 `counter = 0` `# Global variable`
288
+
289
+
290
+ 2
291
+
292
+
293
+ 3 `class MyClass:`
294
+
295
+ 4 `def increment(self):`
296
+
297
+
298
+ 5 `global counter`
299
+
300
+
301
+ 6 `counter += 1`
302
+
303
+
304
+ **Khuyến khích:**
305
+
306
+
307
+ 1 `class MyClass:`
308
+
309
+
310
+ 2 `counter = 0` `# Class attribute`
311
+
312
+
313
+ 3
314
+
315
+
316
+ 4 `def increment(self):`
317
+
318
+
319
+ 5 `MyClass.counter += 1`
320
+
321
+ ### **2 Động lực cho sựra đời của OOP**
322
+
323
+
324
+ Trong thực tế, chúng ta luôn tìm cách mô hình hóa các thực thểthực tếthành các đối tượng số
325
+ hóa. Từnhu cầu quản lý và tổchức các thực thểnày, lập trình hướng đối tượng ra đời đểđơn
326
+ giản hóa và tối ưu hóa việc xây dựng phần mềm. Hãy tưởng tượng một thếgiới mạng xã hội, nơi mỗi người dùng chính là một đối tượng (object). Những thông tin như ngày sinh, giới tính, sốđiện thoại...
327
+ es a function →Output: Hi Alice`
328
+
329
+
330
+ 2. **Stateful function** : Hàm có thểghi nhớtrạng thái bên trong. 1 `class Counter:`
331
+
332
+
333
+ 2 `def __init__(self):`
334
+
335
+
336
+ 3 `self.count = 0`
337
+
338
+
339
+ 4
340
+
341
+
342
+ 5 `def __call__(self):`
343
+
344
+
345
+ 6 `self.count += 1`
346
+
347
+
348
+ 7 `return self.count`
349
+
350
+
351
+ 8
352
+
353
+
354
+ 9 `counter = Counter()`
355
+
356
+
357
+ 10
358
+
359
+
360
+ 11 `print(counter())` `# 1`
361
+
362
+ 12 `print(counter())` `# 2`
363
+
364
+ 13 `print(counter())` `# 3`
365
+
366
+
367
+ Mỗi lần gọi `counter()` đều ghi nhớtrạng thái trước đó và cộng dồn lên, không giống như
368
+ các phương thức thông thường vốn không lưu trạng thái giữa các lần gọi. 3. **Decorator hoặc Callback handler** : (nâng cao cần tìm hiểu thêm). ## **Phần II: Các tính chất cơ bản trong Object-** **Oriented Programming**
369
+
370
+ ### **5** **Delegation (Ủy quyền)**
371
+
372
+
373
+ Delegation (ủy quyền) trong lập trình hướng đối tượng là một kỹthuật trong đó một đối tượng
374
+ ủy thác trách nhiệm thực hiện một hành vi cụthểcho một đối tượng khác. Thay vì kếthừa trực
375
+
376
+
377
+ 5
378
+ **AI VIETNAM** **aivietnam.edu.vn**
379
+
380
+
381
+ Trong Python, `__call__` là một **phương thức đặc biệt** (giống như `__init__`, `__str__`, v.v.)
382
+ được sửdụng khi một đối tượng cần hành xửgiống như một hàm. Nếu một lớp định nghĩa
383
+ `__call__`, thì các _instance_ của lớp đó có thểđược gọi như một hàm thực sự. Phương thức `__call__()` thường được dùng trong ba tình huống phổbiến:
384
+
385
+
386
+ 1. **Function factory** : Tạo ra các đối tượng có thểxửlý logic như một hàm. 1 `class SayHi:`
387
+
388
+ 2 `def __init__(self, name):`
389
+
390
+
391
+ 3 `self.name = name`
392
+
393
+
394
+ 4
395
+
396
+
397
+ 5 `def hello(self):`
398
+
399
+ 6 `print(f'Hello {self.name}')`
400
+
401
+
402
+ 7
403
+
404
+
405
+ 8 `def __call__(self, prefix):`
406
+
407
+ 9 `print(f'{prefix} {self.name}')`
408
+
409
+
410
+ 10
411
+
412
+
413
+ 11 `obj = SayHi("Alice")`
414
+
415
+ 12 `obj.hello()`
416
+
417
+ 13 `obj("Hi")` `# __call__ make it becomes a function →Output: Hi Alice`
418
+
419
+
420
+ 2. **Stateful function** : Hàm có thểghi nhớtrạng thái bên trong.
421
+ ### **4.4** **Các lỗhổng được khai thác**
422
+
423
+ #### **4.4.1 Command injection trong tính năng chuẩn đoán** **ping**
424
+
425
+ Lỗhổng này có mã CVE là **CVE-2024-51186** [13]. Đây là lỗhổng trong
426
+ dịch vụ **ncc2** của thiết bịnày. Trong dịch vụ **ncc2** này, có một endpoint xử
427
+ lý CGI request là **ping.ccp** . Endpoint này cho phép chuẩn đoán các thiết
428
+ bịqua mạng bằng cách "ping"các thiết bịđó. Dưới đây là ảnh giao diện cho
429
+ phép người dùng tương tác với tính năng này.
430
+
431
+
432
+ 18
433
+ w.theguardian.com/technology/2017/feb/28/cloudpets-data-breach-leaks-details-of-500000-children-and-adults/)
434
+ [cloudpets-data-breach-leaks-details-of-500000-children-and-adults/.](https://www.theguardian.com/technology/2017/feb/28/cloudpets-data-breach-leaks-details-of-500000-children-and-adults/)
435
+
436
+
437
+ 33
438
+ # **Chương 2** **Các mối đe dọa vềbảo mật** **trong IoT**
439
+
440
+ Hệsinh thái IoT đã tạo ra một môi trường đe dọa đa tầng. Các mối đe dọa
441
+ vềmặt bảo mật trong IoT có thểđược được phân loại theo các tầng khác
442
+ nhau trong kiến trúc IoT, đồng thời các phương thức khai thác có thểcó các
443
+ hậu quảkhác nhau.
444
+
445
+ ### **2.1** **Mối đe dọa tầng cảm biến**
446
+
447
+ #### **2.1.1 Khai thác thiết bịvật lý**
448
+
449
+
450
+ Nhiều nhà sản xuất thiết bịIoT thường đểlộchân UART/JTAG hoặc bật
451
+ chếđộconsole gỡlỗi ngay trên thiết bịthương mại. Khi có quyền truy cập vật
452
+ lý, kẻtấn công có thểtrích xuất dữliệu từbộnhớflash, trích xuất firmware,
453
+ chiếm quyền shell root hoặc thậm chí cài đặt firmware có chứa mã độc. [3]
454
+
455
+ #### **2.1.2 Tấn công side-channel**
456
+
457
+
458
+ Bằng cách theo dõi mức tiêu thụđiện năng hay bức xạđiện từcủa thiết bị
459
+ khi thực hiện các phép toán mã hóa và giải mã, người tấn công có thểchiết
460
+ xuất khóa bí mật dùng đểmã hóa/giải mã hoặc trộm cắp dữliệu nhạy cảm
461
+ bên trong. [4]
462
+
463
+ #### **2.1.3 Chỉnh sửa firmware**
464
+
465
+
466
+ Một người tấn công có thểlợi dụng việc thiếu cơ chếxác thực chặt chẽtrong
467
+ quá trình cập nhật firmware qua OTA (Over-The-Air). Họcó thểkhiến thiết
468
+
469
+
470
+ 6
471
+ w.theguardian.com/technology/2017/feb/28/cloudpets-data-breach-leaks-details-of-500000-children-and-adults/)
472
+ [cloudpets-data-breach-leaks-details-of-500000-children-and-adults/.](https://www.theguardian.com/technology/2017/feb/28/cloudpets-data-breach-leaks-details-of-500000-children-and-adults/)
473
+
474
+
475
+ 33
476
+ ### **4.4** **Các lỗhổng được khai thác**
477
+
478
+ #### **4.4.1 Command injection trong tính năng chuẩn đoán** **ping**
479
+
480
+ Lỗhổng này có mã CVE là **CVE-2024-51186** [13]. Đây là lỗhổng trong
481
+ dịch vụ **ncc2** của thiết bịnày. Trong dịch vụ **ncc2** này, có một endpoint xử
482
+ lý CGI request là **ping.ccp** . Endpoint này cho phép chuẩn đoán các thiết
483
+ bịqua mạng bằng cách "ping"các thiết bịđó. Dưới đây là ảnh giao diện cho
484
+ phép người dùng tương tác với tính năng này.
485
+
486
+
487
+ 18
488
+ ### **Ví dụ với đống lớn nhất (max-heap)**
489
+
490
+ Sau buildHeap() Sau deleteMax() đầu tiên
491
+ ### **Ví dụ về sắp xếp trộn (merge sort)**
492
+
493
+ 1 24 26 15 13 2 27 38
494
+
495
+
496
+ 1 24 26 15 13 2 27 38
497
+
498
+
499
+ 1 24 26 15 13 2 27 38
500
+
501
+
502
+ 1 24 26 15 13 2 27 38
503
+
504
+
505
+ 1 24 15 26 2 13 27 38
506
+
507
+
508
+ 1 15 24 26 2 13 27 38
509
+
510
+
511
+ 1 2 13 15 24 26 27 38
512
+ ## **Các thuật toán sắp xếp - phần 2**
513
+
514
+
515
+ Sắp xếp vun đống (heap sort)
516
+
517
+ Sắp xếp trộn (merge sort)
518
+
519
+ Sắp xếp nhanh (quick sort)
520
+ ## **Ví dụ về trộn (merge)**
521
+
522
+ 1 15 24 26 2 13 27 38
523
+
524
+ |1|15|24|26|
525
+ |---|---|---|---|
526
+ |||||
527
+
528
+
529
+ |2|13|27|38|
530
+ |---|---|---|---|
531
+ |||||
532
+
533
+
534
+
535
+ 1 15 24 26 2 13 27 38 1
536
+
537
+ |1|15|24|26|
538
+ |---|---|---|---|
539
+ |||||
540
+
541
+
542
+ |2|13|27|38|
543
+ |---|---|---|---|
544
+ |||||
545
+
546
+
547
+ |1|Col2|Col3|Col4|Col5|Col6|Col7|Col8|
548
+ |---|---|---|---|---|---|---|---|
549
+ |||||||||
550
+
551
+
552
+
553
+ 1 15 24 26 2 13 27 38 1 2
554
+
555
+ |1|15|24|26|
556
+ |---|---|---|---|
557
+ |||||
558
+
559
+
560
+ |2|13|27|38|
561
+ |---|---|---|---|
562
+ |||||
563
+
564
+
565
+ |1|2|Col3|Col4|Col5|Col6|Col7|Col8|
566
+ |---|---|---|---|---|---|---|---|
567
+ |||||||||
568
+
569
+
570
+
571
+ 1 15 24 26 2 13 27 38 1 2 13
572
+
573
+
574
+
575
+ |1|15|24|26|
576
+ |---|---|---|---|
577
+ |||||
578
+
579
+ Có N bước
580
+
581
+
582
+ |2|13|27|38|
583
+ |---|---|---|---|
584
+ |||||
585
+
586
+
587
+ |1|2|13|Col4|Col5|Col6|Col7|Col8|
588
+ |---|---|---|---|---|---|---|---|
589
+ |||||||||
590
+
591
+ Mỗi bước có thể có một phép so sánh và có một phần tử được
592
+
593
+ chèn vào mảng thứ ba  mỗi bước mất thời gian hằng
594
+
595
+  Tổng thời gian là O(N)
596
+ #### **Cài đặt sắp xếp trộn**
generator.py CHANGED
@@ -1,11 +1,12 @@
1
  import re
2
  import random
 
3
  import numpy as np
4
- from typing import List, Tuple, Dict, Any, Optional
 
5
  from sentence_transformers import SentenceTransformer
6
  from uuid import uuid4
7
  import pymupdf4llm
8
- import pymupdf as fitz
9
 
10
  try:
11
  from qdrant_client import QdrantClient
@@ -28,19 +29,19 @@ try:
28
  except Exception:
29
  _HAS_FAISS = False
30
 
31
- from utils import generate_mcqs_from_text, _post_chat, _safe_extract_json
32
 
33
  class RAGMCQ:
34
  def __init__(
35
  self,
36
  embedder_model: str = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
37
- hf_model: str = "gpt-oss-120b",
38
- qdrant_url: str = None,
39
- qdrant_api_key: str = None,
40
  qdrant_prefer_grpc: bool = False,
41
  ):
42
  self.embedder = SentenceTransformer(embedder_model)
43
- self.hf_model = hf_model
44
  self.embeddings = None # np.array of shape (N, D)
45
  self.texts = [] # list of chunk texts
46
  self.metadata = [] # list of dicts (page, chunk_id, char_range)
@@ -51,56 +52,61 @@ class RAGMCQ:
51
  self.qdrant_url = qdrant_url
52
  self.qdrant_api_key = qdrant_api_key
53
  self.qdrant_prefer_grpc = qdrant_prefer_grpc
 
54
  if qdrant_url:
55
  self.connect_qdrant(qdrant_url, qdrant_api_key, qdrant_prefer_grpc)
56
 
57
  def extract_pages(
58
- self,
59
- pdf_path: str,
60
- *,
61
- pages: Optional[List[int]] = None,
62
- ignore_images: bool = False,
63
- dpi: int = 150
64
- ) -> List[str]:
65
- doc = fitz.open(pdf_path)
66
- try:
67
- # request page-wise output (page_chunks=True -> list[dict] per page)
68
- page_dicts = pymupdf4llm.to_markdown(
69
- doc,
70
- pages=pages,
71
- ignore_images=ignore_images,
72
- dpi=dpi,
73
- page_chunks=True,
74
- )
75
 
76
- # to_markdown(..., page_chunks=True) returns a list of dicts, each has key "text" (markdown)
77
- pages_md: List[str] = []
78
- for p in page_dicts:
79
- txt = p.get("text", "") or ""
80
- pages_md.append(txt.strip())
81
 
82
- return pages_md
83
- finally:
84
- doc.close()
85
 
86
  def chunk_text(self, text: str, max_chars: int = 1200, overlap: int = 100) -> List[str]:
87
  text = text.strip()
88
  if not text:
89
  return []
 
90
  if len(text) <= max_chars:
91
  return [text]
92
-
93
  # split by sentence-like boundaries
94
  sentences = re.split(r'(?<=[\.\?\!])\s+', text)
95
  chunks = []
96
  cur = ""
 
97
  for s in sentences:
98
  if len(cur) + len(s) + 1 <= max_chars:
99
  cur += (" " if cur else "") + s
100
  else:
101
  if cur:
102
  chunks.append(cur)
 
103
  cur = (cur[-overlap:] + " " + s) if overlap > 0 else s
 
104
  if cur:
105
  chunks.append(cur)
106
 
@@ -112,10 +118,12 @@ class RAGMCQ:
112
  else:
113
  for i in range(0, len(c), max_chars):
114
  final.append(c[i:i+max_chars])
 
115
  return final
116
 
117
  def build_index_from_pdf(self, pdf_path: str, max_chars: int = 1200):
118
  pages = self.extract_pages(pdf_path)
 
119
  self.texts = []
120
  self.metadata = []
121
 
@@ -128,6 +136,8 @@ class RAGMCQ:
128
  if not self.texts:
129
  raise RuntimeError("No text extracted from PDF.")
130
 
 
 
131
  # compute embeddings
132
  emb = self.embedder.encode(self.texts, convert_to_numpy=True, show_progress_bar=True)
133
  self.embeddings = emb.astype("float32")
@@ -188,7 +198,7 @@ class RAGMCQ:
188
  # ask generator
189
  try:
190
  mcq_block = generate_mcqs_from_text(
191
- chunk_text, n=to_gen, model=self.hf_model, temperature=temperature
192
  )
193
  except Exception as e:
194
  # skip this chunk if generator fails
@@ -200,7 +210,7 @@ class RAGMCQ:
200
  output[str(qcount)] = mcq_block[item]
201
  if qcount >= n_questions:
202
  return output
203
-
204
  return output
205
 
206
  elif mode == "rag":
@@ -215,13 +225,12 @@ class RAGMCQ:
215
  # create a seed query: pick a random chunk, pick a sentence from it
216
  seed_idx = random.randrange(len(self.texts))
217
  chunk = self.texts[seed_idx]
 
 
 
 
218
  sents = re.split(r'(?<=[\.\?\!])\s+', chunk)
219
- candidate = [s for s in sents if len(s.strip()) > 20]
220
- if candidate:
221
- seed_sent = random.choice(candidate)
222
- else:
223
- stripped = chunk.strip()
224
- seed_sent = (stripped[:200] if stripped else "[no text available]")
225
  query = f"Create questions about: {seed_sent}"
226
 
227
  # retrieve top_k chunks
@@ -232,12 +241,15 @@ class RAGMCQ:
232
  context_parts.append(f"[page {md['page']}] {self.texts[ridx]}")
233
  context = "\n\n".join(context_parts)
234
 
 
 
235
  # call generator for 1 question (or small batch) with the retrieved context
236
  try:
237
  # request 1 question at a time to keep diversity
238
  mcq_block = generate_mcqs_from_text(
239
- context, n=1, model=self.hf_model, temperature=temperature
240
  )
 
241
  except Exception as e:
242
  print(f"Generator failed during RAG attempt {attempts}: {e}")
243
  continue
@@ -248,7 +260,7 @@ class RAGMCQ:
248
  output[str(qcount)] = mcq_block[item]
249
  if qcount >= n_questions:
250
  return output
251
-
252
  return output
253
  else:
254
  raise ValueError("mode must be 'per_page' or 'rag'.")
@@ -287,7 +299,7 @@ class RAGMCQ:
287
  system = {
288
  "role": "system",
289
  "content": (
290
- "Bạn là một trợ lý đánh giá tính thực chứng của câu hỏi trắc nghiệm dựa trên đoạn văn được cung cấp. "
291
  "Hãy trả lời DUY NHẤT bằng JSON hợp lệ (không có văn bản khác) theo schema:\n\n"
292
  "{\n"
293
  ' "supported": true/false, # câu trả lời đúng có được nội dung chứng thực không\n'
@@ -309,7 +321,7 @@ class RAGMCQ:
309
  )
310
  }
311
 
312
- raw = _post_chat([system, user], model=self.hf_model, temperature=model_verification_temperature)
313
 
314
  # parse JSON object in response
315
  try:
@@ -403,6 +415,7 @@ class RAGMCQ:
403
 
404
  # extract pages and chunks (re-using your existing helpers)
405
  pages = self.extract_pages(pdf_path)
 
406
  all_chunks = []
407
  all_meta = []
408
  for p_idx, page_text in enumerate(pages, start=1):
@@ -412,7 +425,7 @@ class RAGMCQ:
412
  all_meta.append({"page": p_idx, "chunk_id": cid, "length": len(ch)})
413
 
414
  if not all_chunks:
415
- raise RuntimeError("No text extracted from PDF.")
416
 
417
  # ensure collection exists
418
  self._ensure_collection(collection)
@@ -646,7 +659,7 @@ class RAGMCQ:
646
  continue
647
  to_gen = questions_per_chunk
648
  try:
649
- mcq_block = generate_mcqs_from_text(txt, n=to_gen, model=self.hf_model, temperature=temperature)
650
  except Exception as e:
651
  print(f"Generator failed on chunk (index {i}): {e}")
652
  continue
@@ -662,19 +675,19 @@ class RAGMCQ:
662
  max_attempts = n_questions * 4
663
  while qcount < n_questions and attempts < max_attempts:
664
  attempts += 1
665
- # sample a seed sentence from a random chunk of this file
666
- seed_idx = random.randrange(len(texts))
667
- chunk = texts[seed_idx]
668
  sents = re.split(r'(?<=[\.\?\!])\s+', chunk)
669
- seed_sent = None
670
- for s in sents:
671
- if len(s.strip()) > 20:
672
- seed_sent = s
673
- break
674
- if not seed_sent:
675
- seed_sent = chunk[:200]
676
  query = f"Create questions about: {seed_sent}"
677
 
 
678
  # retrieve top_k chunks from the same file (restricted by filename filter)
679
  retrieved = self._retrieve_qdrant(query=query, collection=collection, filename=filename, top_k=top_k)
680
  context_parts = []
@@ -686,7 +699,7 @@ class RAGMCQ:
686
  context = "\n\n".join(context_parts)
687
 
688
  try:
689
- mcq_block = generate_mcqs_from_text(context, n=1, model=self.hf_model, temperature=temperature)
690
  except Exception as e:
691
  print(f"Generator failed during RAG attempt {attempts}: {e}")
692
  continue
 
1
  import re
2
  import random
3
+ import fitz
4
  import numpy as np
5
+ import os
6
+ from typing import List, Optional, Tuple, Dict, Any
7
  from sentence_transformers import SentenceTransformer
8
  from uuid import uuid4
9
  import pymupdf4llm
 
10
 
11
  try:
12
  from qdrant_client import QdrantClient
 
29
  except Exception:
30
  _HAS_FAISS = False
31
 
32
+ from utils import generate_mcqs_from_text, _post_chat, _safe_extract_json, save_to_local
33
 
34
  class RAGMCQ:
35
  def __init__(
36
  self,
37
  embedder_model: str = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
38
+ generation_model: str = "gpt-oss-120b",
39
+ qdrant_url: str = os.environ.get('QDRANT_URL') or "",
40
+ qdrant_api_key: str = os.environ.get('QDRANT_API_KEY') or "",
41
  qdrant_prefer_grpc: bool = False,
42
  ):
43
  self.embedder = SentenceTransformer(embedder_model)
44
+ self.generation_model = generation_model
45
  self.embeddings = None # np.array of shape (N, D)
46
  self.texts = [] # list of chunk texts
47
  self.metadata = [] # list of dicts (page, chunk_id, char_range)
 
52
  self.qdrant_url = qdrant_url
53
  self.qdrant_api_key = qdrant_api_key
54
  self.qdrant_prefer_grpc = qdrant_prefer_grpc
55
+
56
  if qdrant_url:
57
  self.connect_qdrant(qdrant_url, qdrant_api_key, qdrant_prefer_grpc)
58
 
59
  def extract_pages(
60
+ self,
61
+ pdf_path: str,
62
+ *,
63
+ pages: Optional[List[int]] = None,
64
+ ignore_images: bool = False,
65
+ dpi: int = 150
66
+ ) -> List[str]:
67
+ doc = fitz.open(pdf_path)
68
+ try:
69
+ # request page-wise output (page_chunks=True -> list[dict] per page)
70
+ page_dicts = pymupdf4llm.to_markdown(
71
+ doc,
72
+ pages=pages,
73
+ ignore_images=ignore_images,
74
+ dpi=dpi,
75
+ page_chunks=True,
76
+ )
77
 
78
+ # to_markdown(..., page_chunks=True) returns a list of dicts, each has key "text" (markdown)
79
+ pages_md: List[str] = []
80
+ for p in page_dicts:
81
+ txt = p.get("text", "") or ""
82
+ pages_md.append(txt.strip())
83
 
84
+ return pages_md
85
+ finally:
86
+ doc.close()
87
 
88
  def chunk_text(self, text: str, max_chars: int = 1200, overlap: int = 100) -> List[str]:
89
  text = text.strip()
90
  if not text:
91
  return []
92
+
93
  if len(text) <= max_chars:
94
  return [text]
95
+
96
  # split by sentence-like boundaries
97
  sentences = re.split(r'(?<=[\.\?\!])\s+', text)
98
  chunks = []
99
  cur = ""
100
+
101
  for s in sentences:
102
  if len(cur) + len(s) + 1 <= max_chars:
103
  cur += (" " if cur else "") + s
104
  else:
105
  if cur:
106
  chunks.append(cur)
107
+
108
  cur = (cur[-overlap:] + " " + s) if overlap > 0 else s
109
+
110
  if cur:
111
  chunks.append(cur)
112
 
 
118
  else:
119
  for i in range(0, len(c), max_chars):
120
  final.append(c[i:i+max_chars])
121
+
122
  return final
123
 
124
  def build_index_from_pdf(self, pdf_path: str, max_chars: int = 1200):
125
  pages = self.extract_pages(pdf_path)
126
+
127
  self.texts = []
128
  self.metadata = []
129
 
 
136
  if not self.texts:
137
  raise RuntimeError("No text extracted from PDF.")
138
 
139
+ save_to_local('test/text_chunks.md', content=self.texts)
140
+
141
  # compute embeddings
142
  emb = self.embedder.encode(self.texts, convert_to_numpy=True, show_progress_bar=True)
143
  self.embeddings = emb.astype("float32")
 
198
  # ask generator
199
  try:
200
  mcq_block = generate_mcqs_from_text(
201
+ chunk_text, n=to_gen, model=self.generation_model, temperature=temperature
202
  )
203
  except Exception as e:
204
  # skip this chunk if generator fails
 
210
  output[str(qcount)] = mcq_block[item]
211
  if qcount >= n_questions:
212
  return output
213
+
214
  return output
215
 
216
  elif mode == "rag":
 
225
  # create a seed query: pick a random chunk, pick a sentence from it
226
  seed_idx = random.randrange(len(self.texts))
227
  chunk = self.texts[seed_idx]
228
+
229
+ #? Investigate Chunking Strategy
230
+ with open("chunks.txt", "a", encoding="utf-8") as f: f.write(chunk + "\n")
231
+
232
  sents = re.split(r'(?<=[\.\?\!])\s+', chunk)
233
+ seed_sent = random.choice([s for s in sents if len(s.strip()) > 20]) if sents else chunk[:200]
 
 
 
 
 
234
  query = f"Create questions about: {seed_sent}"
235
 
236
  # retrieve top_k chunks
 
241
  context_parts.append(f"[page {md['page']}] {self.texts[ridx]}")
242
  context = "\n\n".join(context_parts)
243
 
244
+ save_to_local('test/context.md', content=context)
245
+
246
  # call generator for 1 question (or small batch) with the retrieved context
247
  try:
248
  # request 1 question at a time to keep diversity
249
  mcq_block = generate_mcqs_from_text(
250
+ context, n=1, model=self.generation_model, temperature=temperature
251
  )
252
+
253
  except Exception as e:
254
  print(f"Generator failed during RAG attempt {attempts}: {e}")
255
  continue
 
260
  output[str(qcount)] = mcq_block[item]
261
  if qcount >= n_questions:
262
  return output
263
+
264
  return output
265
  else:
266
  raise ValueError("mode must be 'per_page' or 'rag'.")
 
299
  system = {
300
  "role": "system",
301
  "content": (
302
+ "Bạn là một trợ lý đánh giá tính thực chứng của câu hỏi trắc nghiệm dựa trên đoạn văn được cung cấp. Luôn trả lời bằng Tiếng Việt"
303
  "Hãy trả lời DUY NHẤT bằng JSON hợp lệ (không có văn bản khác) theo schema:\n\n"
304
  "{\n"
305
  ' "supported": true/false, # câu trả lời đúng có được nội dung chứng thực không\n'
 
321
  )
322
  }
323
 
324
+ raw = _post_chat([system, user], model=self.generation_model, temperature=model_verification_temperature)
325
 
326
  # parse JSON object in response
327
  try:
 
415
 
416
  # extract pages and chunks (re-using your existing helpers)
417
  pages = self.extract_pages(pdf_path)
418
+
419
  all_chunks = []
420
  all_meta = []
421
  for p_idx, page_text in enumerate(pages, start=1):
 
425
  all_meta.append({"page": p_idx, "chunk_id": cid, "length": len(ch)})
426
 
427
  if not all_chunks:
428
+ raise RuntimeError("No tSext extracted from PDF.")
429
 
430
  # ensure collection exists
431
  self._ensure_collection(collection)
 
659
  continue
660
  to_gen = questions_per_chunk
661
  try:
662
+ mcq_block = generate_mcqs_from_text(txt, n=to_gen, model=self.generation_model, temperature=temperature)
663
  except Exception as e:
664
  print(f"Generator failed on chunk (index {i}): {e}")
665
  continue
 
675
  max_attempts = n_questions * 4
676
  while qcount < n_questions and attempts < max_attempts:
677
  attempts += 1
678
+ # create a seed query: pick a random chunk, pick a sentence from it
679
+ seed_idx = random.randrange(len(self.texts))
680
+ chunk = self.texts[seed_idx]
681
  sents = re.split(r'(?<=[\.\?\!])\s+', chunk)
682
+ candidate = [s for s in sents if len(s.strip()) > 20]
683
+ if candidate:
684
+ seed_sent = random.choice(candidate)
685
+ else:
686
+ stripped = chunk.strip()
687
+ seed_sent = (stripped[:200] if stripped else "[no text available]")
 
688
  query = f"Create questions about: {seed_sent}"
689
 
690
+
691
  # retrieve top_k chunks from the same file (restricted by filename filter)
692
  retrieved = self._retrieve_qdrant(query=query, collection=collection, filename=filename, top_k=top_k)
693
  context_parts = []
 
699
  context = "\n\n".join(context_parts)
700
 
701
  try:
702
+ mcq_block = generate_mcqs_from_text(context, n=1, model=self.generation_model, temperature=temperature)
703
  except Exception as e:
704
  print(f"Generator failed during RAG attempt {attempts}: {e}")
705
  continue
requirements.txt CHANGED
@@ -1,8 +1,8 @@
1
  boto3
2
- pdfplumber
3
  faiss-cpu
4
  sentence-transformers
5
  fastapi[standard]
6
  uvicorn[standard]
7
  qdrant-client
8
  pymupdf4llm
 
 
1
  boto3
 
2
  faiss-cpu
3
  sentence-transformers
4
  fastapi[standard]
5
  uvicorn[standard]
6
  qdrant-client
7
  pymupdf4llm
8
+ uuid
test/DeepLearning_mcq_output.json ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "mcqs": {
3
+ "1": {
4
+ "câu hỏi": "Theo nội dung trên, điểm khác biệt chính của kiến trúc Transformer so với các mô hình trước đó là gì?",
5
+ "lựa chọn": {
6
+ "a": "Sử dụng mạng hồi tiếp (recurrent) để mô hình hoá phụ thuộc dài hạn",
7
+ "b": "Dựa hoàn toàn vào cơ chế attention mà không có bất kỳ thành phần hồi tiếp nào",
8
+ "c": "Áp dụng các lớp convolution để tính toán các biểu diễn ẩn",
9
+ "d": "Chỉ sử dụng các lớp feed‑forward điểm‑điểm mà không có attention"
10
+ },
11
+ "đáp án": "Dựa hoàn toàn vào cơ chế attention mà không có bất kỳ thành phần hồi tiếp nào"
12
+ },
13
+ "2": {
14
+ "câu hỏi": "Trong quá trình huấn luyện các mô hình được mô tả, thuật toán tối ưu nào đã được sử dụng?",
15
+ "lựa chọn": {
16
+ "a": "Adam optimizer",
17
+ "b": "Stochastic Gradient Descent (SGD)",
18
+ "c": "RMSprop",
19
+ "d": "Adagrad"
20
+ },
21
+ "đáp án": "Adam optimizer"
22
+ },
23
+ "3": {
24
+ "câu hỏi": "Theo Bảng 3, mô hình Transformer cơ bản (base) đạt điểm BLEU bao nhiêu trên tập phát triển English‑to‑German (newstest2013)?",
25
+ "lựa chọn": {
26
+ "a": "25.8",
27
+ "b": "24.9",
28
+ "c": "26.4",
29
+ "d": "23.7"
30
+ },
31
+ "đáp án": "25.8"
32
+ },
33
+ "4": {
34
+ "câu hỏi": "Theo mô tả trong tài liệu, số bước warmup (warmup steps) được sử dụng trong quá trình huấn luyện là bao nhiêu?",
35
+ "lựa chọn": {
36
+ "a": "2000",
37
+ "b": "4000",
38
+ "c": "8000",
39
+ "d": "10000"
40
+ },
41
+ "đáp án": "4000"
42
+ },
43
+ "5": {
44
+ "câu hỏi": "Theo nội dung, mô hình Transformer (big) đạt được điểm BLEU bao nhiêu trên nhiệm vụ dịch tiếng Anh‑tiếng Đức WMT 2014?",
45
+ "lựa chọn": {
46
+ "a": "28.4",
47
+ "b": "30.0",
48
+ "c": "26.5",
49
+ "d": "27.0"
50
+ },
51
+ "đáp án": "28.4"
52
+ }
53
+ },
54
+ "validation": {
55
+ "1": {
56
+ "supported_by_embeddings": true,
57
+ "max_similarity": 0.7559994459152222,
58
+ "evidence": [
59
+ {
60
+ "idx": 9,
61
+ "page": 2,
62
+ "score": 0.7559994459152222,
63
+ "text": "To the best of our knowledge, however, the Transformer is the first transduction model relying\nentirely on self-attention to compute representations of its input and output without using sequencealigned RNNs or convolution. In the following sections, we will describe the Transformer, motivate\nself-attention and discuss its advantages over models such as [17, 18] and [9]. **3** **Model Architecture**\n\n\nMost competitive neural sequence transduction models have an encoder-decoder structure [ 5, 2, 35 ]. Here, the encoder maps an input sequence of symbol representations ( _x_ 1 _, ..., x_ _n_ ) to a sequence\nof continuous representations **z** = ( _z_ 1 _, ..., z_ _n_ ) . Given **z**, the decoder then generates an output\nsequence ( _y_ 1 _, ..., y_ _m_ ) of symbols one element at a time. At each step the model is auto-regressive\n\n[10], consuming the previously generated symbols as additional input when generating the next. 2"
64
+ },
65
+ {
66
+ "idx": 5,
67
+ "page": 3,
68
+ "score": 0.6882933974266052,
69
+ "text": "Figure 1: The Transformer - model architecture.\n\n\nThe Transformer follows this overall architecture using stacked self-attention and point-wise, fully\nconnected layers for both the encoder and decoder, shown in the left and right halves of Figure 1,\nrespectively.\n\n\n**3.1** **Encoder and Decoder Stacks**\n\nthe two sub-layers, followed by layer normalization [ 1 ]. That is, the output of each sub-layer is\nLayerNorm( _x_ + Sublayer( _x_ )), where Sublayer( _x_ ) is the function implemented by the sub-layer\nitself. To facilitate these residual connections, all sub-layers in the model, as well as the embedding\nlayers, produce outputs of dimension _d_ model = 512.\n\nmasking, combined with fact that the output embeddings are offset by one position, ensures that the\npredictions for position _i_ can depend only on the known outputs at positions less than _i_ .\n\n\n**3.2** **Attention**\n\n\n3"
70
+ },
71
+ {
72
+ "idx": 11,
73
+ "page": 10,
74
+ "score": 0.6689025163650513,
75
+ "text": "We\nplan to extend the Transformer to problems involving input and output modalities other than text and\nto investigate local, restricted attention mechanisms to efficiently handle large inputs and outputs\nsuch as images, audio and video. Making generation less sequential is another research goals of ours. The code we used to train and evaluate our models is available at `[https://github.com/](https://github.com/tensorflow/tensor2tensor)`\n`[tensorflow/tensor2tensor](https://github.com/tensorflow/tensor2tensor)` . **Acknowledgements** We are grateful to Nal Kalchbrenner and Stephan Gouws for their fruitful\ncomments, corrections and inspiration. **References**\n\n\n[1] Jimmy Lei Ba, Jamie Ryan Kiros, and Geoffrey E Hinton. Layer normalization. _arXiv preprint_\n_[arXiv:1607.06450](http://arxiv.org/abs/1607.06450)_, 2016. [2] Dzmitry Bahdanau, Kyunghyun Cho, and Yoshua Bengio. Neural machine translation by jointly\nlearning to align and translate. _CoRR_, abs/1409.0473, 2014. [3] Denny Britz, A..."
76
+ }
77
+ ],
78
+ "model_verdict": {
79
+ "supported": true,
80
+ "confidence": 0.99,
81
+ "evidence": "the Transformer is the first transduction model relying entirely on self-attention ... without using sequence‑aligned RNNs or convolution.",
82
+ "reason": "Context explicitly states Transformer relies fully on attention and has no recurrent components."
83
+ }
84
+ },
85
+ "2": {
86
+ "supported_by_embeddings": true,
87
+ "max_similarity": 0.6170728206634521,
88
+ "evidence": [
89
+ {
90
+ "idx": 33,
91
+ "page": 10,
92
+ "score": 0.6170728206634521,
93
+ "text": "Our results in Table 4 show that despite the lack of task-specific tuning our model performs surprisingly well, yielding better results than all previously reported models with the exception of the\nRecurrent Neural Network Grammar [8]. In contrast to RNN sequence-to-sequence models [ 37 ], the Transformer outperforms the BerkeleyParser [29] even when training only on the WSJ training set of 40K sentences. **7** **Conclusion**\n\n\nIn this work, we presented the Transformer, the first sequence transduction model based entirely on\nattention, replacing the recurrent layers most commonly used in encoder-decoder architectures with\nmulti-headed self-attention. For translation tasks, the Transformer can be trained significantly faster than architectures based\non recurrent or convolutional layers. On both WMT 2014 English-to-German and WMT 2014\nEnglish-to-French translation tasks, we achieve a new state of the art. In the former task our best\nmodel outperforms even all previously reported ensembl..."
94
+ },
95
+ {
96
+ "idx": 3,
97
+ "page": 9,
98
+ "score": 0.5712530016899109,
99
+ "text": "This task presents specific challenges: the output is subject to strong structural\nconstraints and is significantly longer than the input. Furthermore, RNN sequence-to-sequence\nmodels have not been able to attain state-of-the-art results in small-data regimes [37]. We trained a 4-layer transformer with _d_ _model_ = 1024 on the Wall Street Journal (WSJ) portion of the\nPenn Treebank [ 25 ], about 40K training sentences. We also trained it in a semi-supervised setting,\nusing the larger high-confidence and BerkleyParser corpora from with approximately 17M sentences\n\n[ 37 ]. We used a vocabulary of 16K tokens for the WSJ only setting and a vocabulary of 32K tokens\nfor the semi-supervised setting. We performed only a small number of experiments to select the dropout, both attention and residual\n(section 5.4), learning rates and beam size on the Section 22 development set, all other parameters\nremained unchanged from the English-to-German base translation model. During inference, we\n\n\n9"
100
+ },
101
+ {
102
+ "idx": 10,
103
+ "page": 8,
104
+ "score": 0.5459271669387817,
105
+ "text": "**Label Smoothing** During training, we employed label smoothing of value _ϵ_ _ls_ = 0 _._ 1 [ 36 ]. This\nhurts perplexity, as the model learns to be more unsure, but improves accuracy and BLEU score. **6** **Results**\n\n\n**6.1** **Machine Translation**\n\n\nOn the WMT 2014 English-to-German translation task, the big transformer model (Transformer (big)\nin Table 2) outperforms the best previously reported models (including ensembles) by more than 2 _._ 0\nBLEU, establishing a new state-of-the-art BLEU score of 28 _._ 4 . The configuration of this model is\nlisted in the bottom line of Table 3. Training took 3 _._ 5 days on 8 P100 GPUs. Even our base model\nsurpasses all previously published models and ensembles, at a fraction of the training cost of any of\nthe competitive models. On the WMT 2014 English-to-French translation task, our big model achieves a BLEU score of 41 _._ 0,\noutperforming all of the previously published single models, at less than 1 _/_ 4 the training cost of the\nprevious..."
106
+ }
107
+ ],
108
+ "model_verdict": {
109
+ "supported": false,
110
+ "confidence": 0.99,
111
+ "evidence": "",
112
+ "reason": "Trong đoạn văn cung cấp không có thông tin nào đề cập đến thuật toán tối ưu được sử dụng, vì vậy không thể chứng thực đáp án 'Adam optimizer'."
113
+ }
114
+ },
115
+ "3": {
116
+ "supported_by_embeddings": true,
117
+ "max_similarity": 0.7403339743614197,
118
+ "evidence": [
119
+ {
120
+ "idx": 24,
121
+ "page": 8,
122
+ "score": 0.7403339743614197,
123
+ "text": "Table 2: The Transformer achieves better BLEU scores than previous state-of-the-art models on the\nEnglish-to-German and English-to-French newstest2014 tests at a fraction of the training cost. BLEU Training Cost (FLOPs)\nModel\n\nEN-DE EN-FR EN-DE EN-FR\nByteNet [18] 23.75\nDeep-Att + PosUnk [39] 39.2 1 _._ 0 _·_ 10 [20]\n\nGNMT + RL [38] 24.6 39.92 2 _._ 3 _·_ 10 [19] 1 _._ 4 _·_ 10 [20]\n\nConvS2S [9] 25.16 40.46 9 _._ 6 _·_ 10 [18] 1 _._ 5 _·_ 10 [20]\n\nMoE [32] 26.03 40.56 2 _._ 0 _·_ 10 [19] 1 _._ 2 _·_ 10 [20]\n\nDeep-Att + PosUnk Ensemble [39] 40.4 8 _._ 0 _·_ 10 [20]\n\nGNMT + RL Ensemble [38] 26.30 41.16 1 _._ 8 _·_ 10 [20] 1 _._ 1 _·_ 10 [21]\n\nConvS2S Ensemble [9] 26.36 **41.29** 7 _._ 7 _·_ 10 [19] 1 _._ 2 _·_ 10 [21]\n\nTransformer (base model) 27.3 38.1 **3** _**.**_ **3** _**·**_ **10** **[18]**\n\nTransformer (big) **28.4** **41.8** 2 _._ 3 _·_ 10 [19]\n\n\n**Residual Dropout** We apply dropout [ 33 ] to the output of each sub-layer, before it is added to the\nsub-layer input and normalized. ..."
124
+ },
125
+ {
126
+ "idx": 1,
127
+ "page": 9,
128
+ "score": 0.6753625273704529,
129
+ "text": "Table 3: Variations on the Transformer architecture. Unlisted values are identical to those of the base\nmodel. All metrics are on the English-to-German translation development set, newstest2013. Listed\nperplexities are per-wordpiece, according to our byte-pair encoding, and should not be compared to\nper-word perplexities. |Col1|train<br>N d d h d d P ϵ<br>model ff k v drop ls steps|PPL BLEU params<br>(dev) (dev) ×106|\n|---|---|---|\n|base|6<br>512<br>2048<br>8<br>64<br>64<br>0.1<br>0.1<br>100K|4.92<br>25.8<br>65|\n|(A)|1<br>512<br>512<br>4<br>128<br>128<br>16<br>32<br>32<br>32<br>16<br>16|5.29<br>24.9<br>5.00<br>25.5<br>4.91<br>25.8<br>5.01<br>25.4|\n|(B)|16<br>32|5.16<br>25.1<br>58<br>5.01<br>25.4<br>60|\n|(C)|2<br>4<br>8<br>256<br>32<br>32<br>1024<br>128<br>128<br>1024<br>4096|6.11<br>23.7<br>36<br>5.19<br>25.3<br>50<br>4.88<br>25.5<br>80<br>5.75<br>24.5<br>28<br>4.66<br>26.0<br>168<br>5.12<br>25.4<br>53<br>4.75<br>26.2<br>90|\n|(D)|0.0<br>0.2<br>0.0<br>0.2|5.77<br>24.6<br>4.95<br>25.5<br..."
130
+ },
131
+ {
132
+ "idx": 9,
133
+ "page": 2,
134
+ "score": 0.5718259811401367,
135
+ "text": "To the best of our knowledge, however, the Transformer is the first transduction model relying\nentirely on self-attention to compute representations of its input and output without using sequencealigned RNNs or convolution. In the following sections, we will describe the Transformer, motivate\nself-attention and discuss its advantages over models such as [17, 18] and [9]. **3** **Model Architecture**\n\n\nMost competitive neural sequence transduction models have an encoder-decoder structure [ 5, 2, 35 ]. Here, the encoder maps an input sequence of symbol representations ( _x_ 1 _, ..., x_ _n_ ) to a sequence\nof continuous representations **z** = ( _z_ 1 _, ..., z_ _n_ ) . Given **z**, the decoder then generates an output\nsequence ( _y_ 1 _, ..., y_ _m_ ) of symbols one element at a time. At each step the model is auto-regressive\n\n[10], consuming the previously generated symbols as additional input when generating the next. 2"
136
+ }
137
+ ],
138
+ "model_verdict": {
139
+ "supported": true,
140
+ "confidence": 0.99,
141
+ "evidence": "base|6 512 2048 8 64 64 0.1 0.1 100K|4.92 25.8 65",
142
+ "reason": "Bảng 3 liệt kê mô hình Transformer (base) với BLEU = 25.8 trên tập phát triển newstest2013, khớp với đáp án."
143
+ }
144
+ },
145
+ "4": {
146
+ "supported_by_embeddings": true,
147
+ "max_similarity": 0.6373076438903809,
148
+ "evidence": [
149
+ {
150
+ "idx": 36,
151
+ "page": 7,
152
+ "score": 0.6373076438903809,
153
+ "text": "Each training\nbatch contained a set of sentence pairs containing approximately 25000 source tokens and 25000\ntarget tokens. **5.2** **Hardware and Schedule**\n\n\nWe trained our models on one machine with 8 NVIDIA P100 GPUs. For our base models using\nthe hyperparameters described throughout the paper, each training step took about 0.4 seconds. We\ntrained the base models for a total of 100,000 steps or 12 hours. For our big models,(described on the\nbottom line of table 3), step time was 1.0 seconds. The big models were trained for 300,000 steps\n(3.5 days). **5.3** **Optimizer**\n\n\nWe used the Adam optimizer [ 20 ] with _β_ 1 = 0 _._ 9, _β_ 2 = 0 _._ 98 and _ϵ_ = 10 _[−]_ [9] . We varied the learning\nrate over the course of training, according to the formula:\n\n\n_lrate_ = _d_ _[−]_ model [0] _[.]_ [5] _[·]_ [ min(] _[step]_ [_] _[num]_ _[−]_ [0] _[.]_ [5] _[, step]_ [_] _[num][ ·][ warmup]_ [_] _[steps]_ _[−]_ [1] _[.]_ [5] [)] (3)\n\n\nThis corresponds to increasing the learning rate linearly f..."
154
+ }
155
+ ],
156
+ "model_verdict": {
157
+ "supported": true,
158
+ "confidence": 0.99,
159
+ "evidence": "We used _warmup_ _ _steps_ = 4000.",
160
+ "reason": "Context explicitly states that warmup steps were set to 4000, matching the answer."
161
+ }
162
+ },
163
+ "5": {
164
+ "supported_by_embeddings": true,
165
+ "max_similarity": 0.7000005841255188,
166
+ "evidence": [
167
+ {
168
+ "idx": 24,
169
+ "page": 8,
170
+ "score": 0.7000005841255188,
171
+ "text": "Table 2: The Transformer achieves better BLEU scores than previous state-of-the-art models on the\nEnglish-to-German and English-to-French newstest2014 tests at a fraction of the training cost. BLEU Training Cost (FLOPs)\nModel\n\nEN-DE EN-FR EN-DE EN-FR\nByteNet [18] 23.75\nDeep-Att + PosUnk [39] 39.2 1 _._ 0 _·_ 10 [20]\n\nGNMT + RL [38] 24.6 39.92 2 _._ 3 _·_ 10 [19] 1 _._ 4 _·_ 10 [20]\n\nConvS2S [9] 25.16 40.46 9 _._ 6 _·_ 10 [18] 1 _._ 5 _·_ 10 [20]\n\nMoE [32] 26.03 40.56 2 _._ 0 _·_ 10 [19] 1 _._ 2 _·_ 10 [20]\n\nDeep-Att + PosUnk Ensemble [39] 40.4 8 _._ 0 _·_ 10 [20]\n\nGNMT + RL Ensemble [38] 26.30 41.16 1 _._ 8 _·_ 10 [20] 1 _._ 1 _·_ 10 [21]\n\nConvS2S Ensemble [9] 26.36 **41.29** 7 _._ 7 _·_ 10 [19] 1 _._ 2 _·_ 10 [21]\n\nTransformer (base model) 27.3 38.1 **3** _**.**_ **3** _**·**_ **10** **[18]**\n\nTransformer (big) **28.4** **41.8** 2 _._ 3 _·_ 10 [19]\n\n\n**Residual Dropout** We apply dropout [ 33 ] to the output of each sub-layer, before it is added to the\nsub-layer input and normalized. ..."
172
+ },
173
+ {
174
+ "idx": 1,
175
+ "page": 9,
176
+ "score": 0.5974264144897461,
177
+ "text": "Table 3: Variations on the Transformer architecture. Unlisted values are identical to those of the base\nmodel. All metrics are on the English-to-German translation development set, newstest2013. Listed\nperplexities are per-wordpiece, according to our byte-pair encoding, and should not be compared to\nper-word perplexities. |Col1|train<br>N d d h d d P ϵ<br>model ff k v drop ls steps|PPL BLEU params<br>(dev) (dev) ×106|\n|---|---|---|\n|base|6<br>512<br>2048<br>8<br>64<br>64<br>0.1<br>0.1<br>100K|4.92<br>25.8<br>65|\n|(A)|1<br>512<br>512<br>4<br>128<br>128<br>16<br>32<br>32<br>32<br>16<br>16|5.29<br>24.9<br>5.00<br>25.5<br>4.91<br>25.8<br>5.01<br>25.4|\n|(B)|16<br>32|5.16<br>25.1<br>58<br>5.01<br>25.4<br>60|\n|(C)|2<br>4<br>8<br>256<br>32<br>32<br>1024<br>128<br>128<br>1024<br>4096|6.11<br>23.7<br>36<br>5.19<br>25.3<br>50<br>4.88<br>25.5<br>80<br>5.75<br>24.5<br>28<br>4.66<br>26.0<br>168<br>5.12<br>25.4<br>53<br>4.75<br>26.2<br>90|\n|(D)|0.0<br>0.2<br>0.0<br>0.2|5.77<br>24.6<br>4.95<br>25.5<br..."
178
+ },
179
+ {
180
+ "idx": 32,
181
+ "page": 1,
182
+ "score": 0.5703283548355103,
183
+ "text": "Experiments on two machine translation tasks show these models to\nbe superior in quality while being more parallelizable and requiring significantly\nless time to train. Our model achieves 28.4 BLEU on the WMT 2014 Englishto-German translation task, improving over the existing best results, including\nensembles, by over 2 BLEU. On the WMT 2014 English-to-French translation task,\nour model establishes a new single-model state-of-the-art BLEU score of 41.8 after\ntraining for 3.5 days on eight GPUs, a small fraction of the training costs of the\nbest models from the literature. We show that the Transformer generalizes well to\nother tasks by applying it successfully to English constituency parsing both with\nlarge and limited training data. _∗_ Equal contribution. Listing order is random. Jakob proposed replacing RNNs with self-attention and started\nthe effort to evaluate this idea. Ashish, with Illia, designed and implemented the first Transformer models and\nhas been crucially involved in eve..."
184
+ }
185
+ ],
186
+ "model_verdict": {
187
+ "supported": true,
188
+ "confidence": 0.99,
189
+ "evidence": "Transformer (big) **28.4** ...; Our model achieves 28.4 BLEU on the WMT 2014 English-to-German translation task",
190
+ "reason": "Context explicitly states that the Transformer (big) model achieved a BLEU score of 28.4 on the English‑German WMT 2014 task."
191
+ }
192
+ }
193
+ }
194
+ }
test/ML_mcq_output.json ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "mcqs": {
3
+ "1": {
4
+ "câu hỏi": "Trong thuật toán K-Means, centroid của một cụm được định nghĩa như thế nào?",
5
+ "lựa chọn": {
6
+ "a": "Là điểm dữ liệu ngẫu nhiên được chọn làm trung tâm ban đầu của cụm.",
7
+ "b": "Là trung tâm hình học (geometric center) của tất cả các điểm trong cụm, tính bằng trung bình cộng các điểm thuộc cụm.",
8
+ "c": "Là điểm dữ liệu có khoảng cách lớn nhất tới các điểm còn lại trong cùng cụm.",
9
+ "d": "Là vị trí trung bình của các centroid của các cụm khác."
10
+ },
11
+ "đáp án": "Là trung tâm hình học (geometric center) của tất cả các điểm trong cụm, tính bằng trung bình cộng các điểm thuộc cụm."
12
+ },
13
+ "2": {
14
+ "câu hỏi": "Trong đoạn triển khai lớp KMeans bằng NumPy, câu lệnh nào sau đây khởi tạo các centroid một cách ngẫu nhiên?",
15
+ "lựa chọn": {
16
+ "a": "self.centroids = X[np.random.choice(X.shape[0], self.k, replace=False)]",
17
+ "b": "self.centroids = np.random.rand(self.k, X.shape[1])",
18
+ "c": "self.centroids = X[:self.k]",
19
+ "d": "self.centroids = np.zeros((self.k, X.shape[1]))"
20
+ },
21
+ "đáp án": "self.centroids = X[np.random.choice(X.shape[0], self.k, replace=False)]"
22
+ },
23
+ "3": {
24
+ "câu hỏi": "Trong mục \"Các thuộc tính của thuật toán K-means Clustering\" của tài liệu, đâu là mục không được liệt kê là một thuộc tính của thuật toán K-means?",
25
+ "lựa chọn": {
26
+ "a": "Thuộc tính thứ nhất của thuật toán K-means",
27
+ "b": "Thuộc tính thứ hai của thuật toán K-means",
28
+ "c": "Tại sao chúng ta cần phân cụm?",
29
+ "d": "Ứng dụng của phân cụm trong thực tế"
30
+ },
31
+ "đáp án": "Ứng dụng của phân cụm trong thực tế"
32
+ },
33
+ "4": {
34
+ "câu hỏi": "Trong thuật toán K-Means, bước nào được mô tả là “Mỗi điểm dữ liệu x_i được gán nhãn cụm l_i bằng cách chọn centroid gần nhất”?",
35
+ "lựa chọn": {
36
+ "a": "Bước khởi tạo (Initialization Step)",
37
+ "b": "Bước gán nhãn (Assignment Step)",
38
+ "c": "Bước cập nhật centroid (Update Step)",
39
+ "d": "Bước kiểm tra hội tụ (Convergence Check Step)"
40
+ },
41
+ "đáp án": "Bước gán nhãn (Assignment Step)"
42
+ },
43
+ "5": {
44
+ "câu hỏi": "Trong đoạn mã triển khai K-Means++, phương thức nào được sử dụng để khởi tạo centroids?",
45
+ "lựa chọn": {
46
+ "a": "kmeans_text.fit",
47
+ "b": "kmeans_plus_plus_init",
48
+ "c": "np.linalg.norm",
49
+ "d": "np.array"
50
+ },
51
+ "đáp án": "kmeans_plus_plus_init"
52
+ }
53
+ },
54
+ "validation": {
55
+ "1": {
56
+ "supported_by_embeddings": true,
57
+ "max_similarity": 0.6017358303070068,
58
+ "evidence": [
59
+ {
60
+ "idx": 18,
61
+ "page": 9,
62
+ "score": 0.6017358303070068,
63
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\nvà nợcao, trong khi cụm xanh có thu nhập cao nhưng nợthấp. Rõ ràng cụm phân chia trong trường\nhợp II hợp lý hơn. Như vậy, các điểm dữliệu từcác cụm khác nhau nên khác biệt nhiều nhất có thểđểtạo thành các\ncụm có ý nghĩa hơn. Thuật toán K-means dùng phương pháp lặp đểtìm phân cụm tối ưu bằng cách\ngiảm thiểu tổng bình phương khoảng cách giữa các điểm và centroid của cụm. **5.3** **Tại sao chúng ta cần phân cụm?**\n\n\nChúng ta đã hiểu phân cụm là gì và các thuộc tính khác nhau của cụm. Vậy tại sao phải dùng phân\ncụm? Phần tiếp theo sẽgiải đáp thắc mắc này và giới thiệu một sốứng dụng thực tế. **6** **Ứng dụng của phân cụm trong thực tế**\n\n\nPhân cụm được sửdụng rộng rãi trong nhiều lĩnh vực, từngân hàng, hệthống đềxuất, đến phân cụm\nvăn bản và phân đoạn ảnh. - **Phân đoạn khách hàng:** Đây là ứng dụng phổbiến nhất của phân cụm, không chỉtrong ngân\nhàng mà còn trong viễn thông, thương mại điện tử, thểthao, quảng cáo, bán hàng,... - **Phân cụm văn bản:** N..."
64
+ },
65
+ {
66
+ "idx": 29,
67
+ "page": 5,
68
+ "score": 0.5860570669174194,
69
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n**4** **Thuật toán K-Means**\n\n\nThuật toán K-Means hoạt động như sau:\n\n\n1. **Đầu vào:** Tập dữliệu _X_ = _{x_ 1 _, x_ 2 _, . . ., x_ _n_ _}_ và sốlượng cụm _k_ .\n\n\n2. **Đầu ra:** Tập các centroid _{c_ 1 _, c_ 2 _, . . ., c_ _k_ _}_ và nhãn cụm tương ứng cho mỗi điểm dữliệu _{l_ 1 _, l_ 2 _, . . ., l_ _n_ _}_ .\n\n\n3. **Khởi tạo:** Chọn ng��u nhiên _k_ centroid ban đầu.\n\n\nHình 1: Chọn k centroid ban đầu\n\n\n4. **Khởi tạo biến** `converged` bằng `false` đểkiểm soát vòng lặp.\n\n\n5. **Lặp cho đến khi hội tụhoặc đạt sốlần lặp tối đa:**\n\n\n - **Bước gán nhãn (Assignment Step):** Mỗi điểm dữliệu _x_ _i_ được gán nhãn cụm _l_ _i_ bằng\ncách chọn centroid gần nhất:\n_l_ _i_ = arg min _∥x_ _i_ _−_ _c_ _j_ _∥_ [2]\n_j_\n\n\nHình 2: Bước gán nhãn\n\n\n4"
70
+ },
71
+ {
72
+ "idx": 3,
73
+ "page": 18,
74
+ "score": 0.5734704732894897,
75
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n**4** **Bước 4: Triển khai thuật toán K-Means chính**\n\n\nTiếp theo, chúng ta sẽđịnh nghĩa một sốđiều kiện đểtriển khai thuật toán K-Means Clustering."
76
+ }
77
+ ],
78
+ "model_verdict": {
79
+ "supported": false,
80
+ "confidence": 0.9,
81
+ "evidence": "",
82
+ "reason": "Trong ngữ cảnh không có câu nào mô tả centroid là trung tâm hình học hay tính bằng trung bình cộng các điểm; chỉ đề cập tới việc giảm thiểu khoảng cách và khởi tạo centroid ngẫu nhiên."
83
+ }
84
+ },
85
+ "2": {
86
+ "supported_by_embeddings": true,
87
+ "max_similarity": 0.5771877765655518,
88
+ "evidence": [
89
+ {
90
+ "idx": 15,
91
+ "page": 17,
92
+ "score": 0.5771877765655518,
93
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n12 `plt.ylabel(’Loan` `Amount (Thousands) ’)`\n\n13 `plt.show ()`\n\n\nListing 3: Chọn biến và trực quan hóa dữliệu\n\n\n**3** **Bước 3: Chọn sốcụm và khởi tạo centroids**\n\n\nBước 1 và 2 của K-Means là vềviệc chọn sốlượng cụm (k) và chọn các centroids ngẫu nhiên cho mỗi\ncụm. Chúng ta sẽchọn 3 cụm và sau đó chọn các quan sát ngẫu nhiên từdữliệu làm centroids:\n\n\n1 `# Step 1 and 2 - Choose the number of clusters (k) and` `randomly` `select` `centroids` `for`\n\n```\n each cluster\n\n```\n\n2\n\n\n3 `# number of clusters`\n\n\n4 `K = 3`\n\n\n5\n\n\n6 `# Randomly` `select` `observations as centroids`\n\n7 `Centroids = X.sample(n=K)`\n\n8 `plt.scatter(X[\" ApplicantIncome \"], X[\" LoanAmount \"], c=’black ’)`\n\n9 `plt.scatter(Centroids [\" ApplicantIncome \"], Centroids [\" LoanAmount \"], c=’red ’)`\n\n10 `plt.xlabel(’Annual Income ’)`\n\n11 `plt.ylabel(’Loan` `Amount (Thousands) ’)`\n\n\nListing 4: Chọn sốcụm và khởi tạo centroids\n\n\nỞđây, các chấm đỏđại diện cho 3 centroids của mỗi cụm. Lưu ý rằ..."
94
+ },
95
+ {
96
+ "idx": 20,
97
+ "page": 18,
98
+ "score": 0.5511029958724976,
99
+ "text": "Hãy\n\nxem mã trước:\n\n\n1 `# Step 3 - Assign all points to the` `nearest` `cluster` `centroid`\n\n2 `# Step 4 - Recalculate` `the` `centroids of the newly` `formed` `clusters`\n\n3 `# Step 5 - Repeat` `steps 3 and 4`\n\n\n4\n\n\n5 `diff = 1`\n\n\n6 `j = 0`\n\n\n7\n\n\n8 `while` `diff != 0:`\n\n\n9 `XD = X.copy ()`\n\n\n10 `i = 1`\n\n\n11 `for index1, row_c in Centroids.iterrows ():`\n\n\n12 `ED = []`\n\n\n13 `for index2, row_d in XD.iterrows ():`\n\n14 `d1 = (row_c [\" ApplicantIncome \"] - row_d [\" ApplicantIncome \"]) **2`\n\n15 `d2 = (row_c [\" LoanAmount \"] - row_d [\" LoanAmount \"]) **2`\n\n16 `d = np.sqrt(d1 + d2)`\n\n17 `ED.append(d)`\n\n18 `X[i] = ED`\n\n\n19 `i += 1`\n\n\n20\n\n\n21 `C = []`\n\n\n22 `for index, row in X.iterrows ():`\n\n23 `min_dist = row [1]`\n\n\n24 `pos = 1`\n\n25 `for i in range(K):`\n\n26 `if row[i + 1] < min_dist:`\n\n\n27 `min_dist = row[i + 1]`\n\n\n28 `pos = i + 1`\n\n29 `C.append(pos)`\n\n30 `X[\" Cluster \"] = C`\n\n31 `Centroids_new = X.groupby ([\" Cluster \"]).mean ()[[\" LoanAmount\", \" ApplicantIncome \"]]`\n\n\n32\n\n\n33 `if j == 0:`\n\n\n34..."
100
+ },
101
+ {
102
+ "idx": 30,
103
+ "page": 15,
104
+ "score": 0.550550639629364,
105
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n21 `return np.array(centroids)`\n\n\n22\n\n\n23 `# Using K-Means ++`\n\n24 `class` `KMeansPlusPlus(KMeans):`\n\n\n25 `def fit(self, X):`\n\n\n26 `# Use K-Means ++ initialization`\n\n\n27 `self.centroids = kmeans_plus_plus_init (X, self.k)`\n\n\n28\n\n\n29 `# Continue as in regular K-Means`\n\n30 `for i in range` `(self.max_iters):`\n\n31 `distances = np.linalg.norm(X[:, np.newaxis, :] - self.centroids, axis =2)`\n\n32 `labels = np.argmin(distances, axis =1)`\n\n\n33\n\n\n34 `new_centroids = np.array ([X[labels == j]. mean(axis =0) for j in range` `(self.`\n```\n k)])\n\n```\n\n35\n\n\n36 `if np.` `all` `(np.` `abs` `(self.centroids - new_centroids ) < 1e-4):`\n\n\n37 `break`\n\n\n38\n\n\n39 `self.centroids = new_centroids`\n\n\n40\n\n\n41 `return` `labels`\n\n\n14"
106
+ }
107
+ ],
108
+ "model_verdict": {
109
+ "supported": false,
110
+ "confidence": 0.9,
111
+ "evidence": "",
112
+ "reason": "Trong ngữ cảnh chỉ đề cập đến việc chọn centroids ngẫu nhiên bằng X.sample(n=K) hoặc các phương pháp khác, không có câu lệnh self.centroids = X[np.random.choice(...)] được nêu."
113
+ }
114
+ },
115
+ "3": {
116
+ "supported_by_embeddings": true,
117
+ "max_similarity": 0.7246736288070679,
118
+ "evidence": [
119
+ {
120
+ "idx": 3,
121
+ "page": 18,
122
+ "score": 0.7246736288070679,
123
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n**4** **Bước 4: Triển khai thuật toán K-Means chính**\n\n\nTiếp theo, chúng ta sẽđịnh nghĩa một sốđiều kiện đểtriển khai thuật toán K-Means Clustering."
124
+ },
125
+ {
126
+ "idx": 13,
127
+ "page": 4,
128
+ "score": 0.7182997465133667,
129
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\nBài toán trên là ví dụđiển hình cho việc ứng dụng kỹthuật _clustering_ trong khai phá dữliệu, đặc\nbiệt là thuật toán **K-means clustering**, một trong những phương pháp phân nhóm phổbiến và đơn\ngiản nhất hiện nay. ## **2. Lý thuyết K-Means**\n\n\n**1** **Định nghĩa và Khái niệm cơ bản**\n\n\nK-Means là thuật toán học không giám sát (unsupervised learning) thuộc nhóm phân cụm (clustering),\nnhằm chia tập dữliệu gồm _n_ điểm dữliệu _{x_ 1 _, x_ 2 _, . . ., x_ _n_ _}_ với _x_ _i_ _∈_ R _[d]_ thành _k_ cụm _{C_ 1 _, C_ 2 _, . . ., C_ _k_ _}_\nsao cho:\n\n\n - **Cohesion (Tính gắn kết)** : Các điểm trong cùng một cụm có độtương tựcao nhất có thể\n\n\n - **Separation (Tính phân tách)** : Các điểm thuộc cụm khác nhau có độtương tựthấp nhất có\nthể\n\n\n - **Completeness (Tính đầy đủ)** : Mọi điểm dữliệu đều được gán vào đúng một cụm\n\n\n**2** **Khái niệm Centroid và Cluster**\n\n\n**Centroid** _µ_ _i_ của cụm _C_ _i_ là trung tâm hình học (geometric center) của tất cảcác điể..."
130
+ },
131
+ {
132
+ "idx": 0,
133
+ "page": 3,
134
+ "score": 0.6935104727745056,
135
+ "text": "Đây chính là lúc các thuật toán học máy không giám sát (unsupervised learning) như **K-means**\n**clustering** trởnên rất hữu ích. Thuật toán này cho phép tựđộng phân nhóm dữliệu dựa trên sựtương\nđồng giữa các điểm dữliệu mà không cần thông tin nhãn từtrước. Nhờvậy, K-means giúp phát hiện\ncấu trúc tiềm ẩn trong dữliệu và hỗtrợcác bước phân tích tiếp theo. **2** **Vấn đềcốt lõi**\n\n\nĐểminh họa cho bài toán phân nhóm không giám sát, hãy xem xét một ví dụđơn giản với dữliệu về\ntuổi và chi tiêu hàng tháng của 9 khách hàng như sau:\n\n|Index|Tuổi|Chi tiêu (USD)|\n|---|---|---|\n|1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9|18<br>20<br>22<br>30<br>34<br>40<br>60<br>66<br>70|80<br>90<br>85<br>50<br>64<br>60<br>30<br>40<br>25|\n\n\n\nBảng 1: Dữliệu mẫu vềkhách hàng\n\n\nMục tiêu của bài toán là phân chia tựđộng 9 khách hàng này thành 3 nhóm khác nhau, ví dụnhư\nnhóm _Trẻ_, _Trung niên_ và _Cao tuổi_, dựa trên đặc điểm tuổi tác và chi tiêu, mà không cần biết trước\nnhóm nhãn phân loại. Việc này sẽgiúp doanh nghi..."
136
+ }
137
+ ],
138
+ "model_verdict": {
139
+ "supported": false,
140
+ "confidence": 0.9,
141
+ "evidence": "Context does not contain a list of attributes of K-means nor mention 'Ứng dụng của phân cụm trong thực tế' as an attribute.",
142
+ "reason": "Không có bằng chứng trong nội dung cung cấp rằng mục này được liệt kê hoặc không được liệt kê; do đó không thể khẳng định đáp án được chứng thực."
143
+ }
144
+ },
145
+ "4": {
146
+ "supported_by_embeddings": true,
147
+ "max_similarity": 0.6494988203048706,
148
+ "evidence": [
149
+ {
150
+ "idx": 0,
151
+ "page": 3,
152
+ "score": 0.6494988203048706,
153
+ "text": "Đây chính là lúc các thuật toán học máy không giám sát (unsupervised learning) như **K-means**\n**clustering** trởnên rất hữu ích. Thuật toán này cho phép tựđộng phân nhóm dữliệu dựa trên sựtương\nđồng giữa các điểm dữliệu mà không cần thông tin nhãn từtrước. Nhờvậy, K-means giúp phát hiện\ncấu trúc tiềm ẩn trong dữliệu và hỗtrợcác bước phân tích tiếp theo. **2** **Vấn đềcốt lõi**\n\n\nĐểminh họa cho bài toán phân nhóm không giám sát, hãy xem xét một ví dụđơn giản với dữliệu về\ntuổi và chi tiêu hàng tháng của 9 khách hàng như sau:\n\n|Index|Tuổi|Chi tiêu (USD)|\n|---|---|---|\n|1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9|18<br>20<br>22<br>30<br>34<br>40<br>60<br>66<br>70|80<br>90<br>85<br>50<br>64<br>60<br>30<br>40<br>25|\n\n\n\nBảng 1: Dữliệu mẫu vềkhách hàng\n\n\nMục tiêu của bài toán là phân chia tựđộng 9 khách hàng này thành 3 nhóm khác nhau, ví dụnhư\nnhóm _Trẻ_, _Trung niên_ và _Cao tuổi_, dựa trên đặc điểm tuổi tác và chi tiêu, mà không cần biết trước\nnhóm nhãn phân loại. Việc này sẽgiúp doanh nghi..."
154
+ },
155
+ {
156
+ "idx": 3,
157
+ "page": 18,
158
+ "score": 0.6462726593017578,
159
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n**4** **Bước 4: Triển khai thuật toán K-Means chính**\n\n\nTiếp theo, chúng ta sẽđịnh nghĩa một sốđiều kiện đểtriển khai thuật toán K-Means Clustering."
160
+ },
161
+ {
162
+ "idx": 18,
163
+ "page": 9,
164
+ "score": 0.6377543210983276,
165
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\nvà nợcao, trong khi cụm xanh có thu nhập cao nhưng nợthấp. Rõ ràng cụm phân chia trong trường\nhợp II hợp lý hơn. Như vậy, các điểm dữliệu từcác cụm khác nhau nên khác biệt nhiều nhất có thểđểtạo thành các\ncụm có ý nghĩa hơn. Thuật toán K-means dùng phương pháp lặp đểtìm phân cụm tối ưu bằng cách\ngiảm thiểu tổng bình phương khoảng cách giữa các điểm và centroid của cụm. **5.3** **Tại sao chúng ta cần phân cụm?**\n\n\nChúng ta đã hiểu phân cụm là gì và các thuộc tính khác nhau của cụm. Vậy tại sao phải dùng phân\ncụm? Phần tiếp theo sẽgiải đáp thắc mắc này và giới thiệu một sốứng dụng thực tế. **6** **Ứng dụng của phân cụm trong thực tế**\n\n\nPhân cụm được sửdụng rộng rãi trong nhiều lĩnh vực, từngân hàng, hệthống đềxuất, đến phân cụm\nvăn bản và phân đoạn ảnh. - **Phân đoạn khách hàng:** Đây là ứng dụng phổbiến nhất của phân cụm, không chỉtrong ngân\nhàng mà còn trong viễn thông, thương mại điện tử, thểthao, quảng cáo, bán hàng,... - **Phân cụm văn bản:** N..."
166
+ }
167
+ ],
168
+ "model_verdict": {
169
+ "supported": false,
170
+ "confidence": 0.9,
171
+ "evidence": "",
172
+ "reason": "Trong ngữ cảnh cung cấp không có đoạn nào mô tả bước gán nhãn như “Mỗi điểm dữ liệu x_i được gán nhãn cụm l_i bằng cách chọn centroid gần nhất”, vì vậy không có bằng chứng hỗ trợ đáp án."
173
+ }
174
+ },
175
+ "5": {
176
+ "supported_by_embeddings": true,
177
+ "max_similarity": 0.590252161026001,
178
+ "evidence": [
179
+ {
180
+ "idx": 30,
181
+ "page": 15,
182
+ "score": 0.590252161026001,
183
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n21 `return np.array(centroids)`\n\n\n22\n\n\n23 `# Using K-Means ++`\n\n24 `class` `KMeansPlusPlus(KMeans):`\n\n\n25 `def fit(self, X):`\n\n\n26 `# Use K-Means ++ initialization`\n\n\n27 `self.centroids = kmeans_plus_plus_init (X, self.k)`\n\n\n28\n\n\n29 `# Continue as in regular K-Means`\n\n30 `for i in range` `(self.max_iters):`\n\n31 `distances = np.linalg.norm(X[:, np.newaxis, :] - self.centroids, axis =2)`\n\n32 `labels = np.argmin(distances, axis =1)`\n\n\n33\n\n\n34 `new_centroids = np.array ([X[labels == j]. mean(axis =0) for j in range` `(self.`\n```\n k)])\n\n```\n\n35\n\n\n36 `if np.` `all` `(np.` `abs` `(self.centroids - new_centroids ) < 1e-4):`\n\n\n37 `break`\n\n\n38\n\n\n39 `self.centroids = new_centroids`\n\n\n40\n\n\n41 `return` `labels`\n\n\n14"
184
+ },
185
+ {
186
+ "idx": 29,
187
+ "page": 5,
188
+ "score": 0.5836479663848877,
189
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n**4** **Thuật toán K-Means**\n\n\nThuật toán K-Means hoạt động như sau:\n\n\n1. **Đầu vào:** Tập dữliệu _X_ = _{x_ 1 _, x_ 2 _, . . ., x_ _n_ _}_ và sốlượng cụm _k_ .\n\n\n2. **Đầu ra:** Tập các centroid _{c_ 1 _, c_ 2 _, . . ., c_ _k_ _}_ và nhãn cụm tương ứng cho mỗi điểm dữliệu _{l_ 1 _, l_ 2 _, . . ., l_ _n_ _}_ .\n\n\n3. **Khởi tạo:** Chọn ngẫu nhiên _k_ centroid ban đầu.\n\n\nHình 1: Chọn k centroid ban đầu\n\n\n4. **Khởi tạo biến** `converged` bằng `false` đểkiểm soát vòng lặp.\n\n\n5. **Lặp cho đến khi hội tụhoặc đạt sốlần lặp tối đa:**\n\n\n - **Bước gán nhãn (Assignment Step):** Mỗi điểm dữliệu _x_ _i_ được gán nhãn cụm _l_ _i_ bằng\ncách chọn centroid gần nhất:\n_l_ _i_ = arg min _∥x_ _i_ _−_ _c_ _j_ _∥_ [2]\n_j_\n\n\nHình 2: Bước gán nhãn\n\n\n4"
190
+ },
191
+ {
192
+ "idx": 32,
193
+ "page": 2,
194
+ "score": 0.5471374988555908,
195
+ "text": ". . . . . . . . . . . . . . . . . . . . . 13\n\n2 K-Means++ Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13\n\n\n**1** **Phần II: Triển khai Thuật toán K-Means từđầu trong Python** **15**\n1 Bước 1: Import các thư viện cần thiết . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15\n2 B��ớc 2: Đọc và khám phá dữliệu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15\n3 Bước 3: Chọn sốcụm và khởi tạo centroids . . . . . . . . . . . . . . . . . . . . . . . . . 16\n4 Bước 4: Triển khai thuật toán K-Means chính . . . . . . . . . . . . . . . . . . . . . . . . 17\n5 Bước 5: Trực quan hóa kết quả . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17\n\n\n1"
196
+ }
197
+ ],
198
+ "model_verdict": {
199
+ "supported": true,
200
+ "confidence": 1.0,
201
+ "evidence": "self.centroids = kmeans_plus_plus_init (X, self.k)",
202
+ "reason": "Đoạn mã cho thấy centroids được khởi tạo bằng hàm kmeans_plus_plus_init"
203
+ }
204
+ }
205
+ }
206
+ }
test/calculus_mcq_output.json ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "mcqs": {
3
+ "1": {
4
+ "câu hỏi": "Theo nội dung, khi D là miền hình chữ nhật a ≤ x ≤ b, c ≤ y ≤ d, biểu thức nào sau đây đúng cho tích phân kép \\(\\iint_D f(x,y)\\,dxdy\\)?",
5
+ "lựa chọn": {
6
+ "a": "∫_a^b ∫_c^d f(x,y) dy dx",
7
+ "b": "∫_c^d ∫_a^b f(x,y) dx dy",
8
+ "c": "∫_a^b ∫_c^d f(x,y) dy dx = ∫_c^d ∫_a^b f(x,y) dx dy",
9
+ "d": "Không có biểu thức nào đúng"
10
+ },
11
+ "đáp án": "∫_a^b ∫_c^d f(x,y) dy dx = ∫_c^d ∫_a^b f(x,y) dx dy"
12
+ },
13
+ "2": {
14
+ "câu hỏi": "Theo Định nghĩa 1.3, một mặt phẳng có phương trình ax + by + cz + d = 0 có thể được biểu diễn tham số như thế nào?",
15
+ "lựa chọn": {
16
+ "a": "x = u, y = v, z = -(d + a u + b v)/c",
17
+ "b": "x = u, y = v, z = d + a u + b v",
18
+ "c": "x = u, y = v, z = (d - a u - b v)/c",
19
+ "d": "x = u, y = v, z = (a u + b v - d)/c"
20
+ },
21
+ "đáp án": "x = u, y = v, z = -(d + a u + b v)/c"
22
+ },
23
+ "3": {
24
+ "câu hỏi": "Phương trình tiếp tuyến (tangent plane) của mặt cong x² − 4y² + 2z² = 6 tại điểm (2, 2, 3) là:",
25
+ "lựa chọn": {
26
+ "a": "x − 4y + 3z = 3",
27
+ "b": "x + 4y − 3z = 3",
28
+ "c": "2x − 8y + 6z = 6",
29
+ "d": "x − 4y + 3z = 0"
30
+ },
31
+ "đáp án": "x − 4y + 3z = 3"
32
+ },
33
+ "4": {
34
+ "câu hỏi": "Trong tiêu đề của bài giảng \"GIẢI TÍCH II\" tại Trường Đại học Bách Khoa Hà Nội, các phép tính nào được liệt kê là ứng dụng?",
35
+ "lựa chọn": {
36
+ "a": "Các ứng dụng của phép tính vi phân, tích phân bộ, tích phân phụ thuộc tham số, tích phân đường, tích phân mặt, lý thuyết",
37
+ "b": "Bài giảng về giải tích I",
38
+ "c": "Giảng viên TS. Bùi Xuân Diệu",
39
+ "d": "Ngày cập nhật 28 tháng 8 năm 2017"
40
+ },
41
+ "đáp án": "Các ứng dụng của phép tính vi phân, tích phân bộ, tích phân phụ thuộc tham số, tích phân đường, tích phân mặt, lý thuyết"
42
+ },
43
+ "5": {
44
+ "câu hỏi": "Khi chia miền R thành m × n hình chữ nhật con có độ dài bằng nhau, ký hiệu của một hình chữ nhật con R_{ij} được cho bởi:",
45
+ "lựa chọn": {
46
+ "a": "R_{ij} = [x_i, x_{i+1}] × [y_j, y_{j+1}]",
47
+ "b": "R_{ij} = [x_{i-1}, x_i] × [y_{j-1}, y_j]",
48
+ "c": "R_{ij} = [x_{i}, x_{i-1}] × [y_{j}, y_{j-1}]",
49
+ "d": "R_{ij} = [x_{i-1}, x_{i+1}] × [y_{j-1}, y_{j+1}]"
50
+ },
51
+ "đáp án": "R_{ij} = [x_{i-1}, x_i] × [y_{j-1}, y_j]"
52
+ }
53
+ },
54
+ "validation": {
55
+ "1": {
56
+ "supported_by_embeddings": true,
57
+ "max_similarity": 0.8958114981651306,
58
+ "evidence": [
59
+ {
60
+ "idx": 74,
61
+ "page": 30,
62
+ "score": 0.8958114981651306,
63
+ "text": "_28_ _Chương 2. Tích phân bội_\n\n\n**Chú ý 2.3.** Nếu tồn tại tích phân kép f ( x, y ) dxdy thì ta nói hàm số f ( x, y ) khảtích\n��\n\nD\n\ntrong miền D .\n\n\n**Tính chất cơ bản:**\n\n\n Tính chất tuyến tính:\n\n\n\n��\n\n\n\nf ( x, y ) dxdy +\n��\nD D\n\n\n\n\n[ f ( x, y ) + g ( x, y )] dxdy =\n��\nD D\n\n\n\ng ( x, y ) dxdy\n\nD\n\n\n\n��\n\n\n\nk f ( x, y ) dxdy = k\n��\nD D\n\n\n\nf ( x, y ) dxdy\n\nD\n\n\n\n\n- Tính chất cộng tính: Nếu D = D 1 ∪ D 2, ởđó D 1 và D 2 không \"chồng\" lên nhau (có thể\nngoại trừphần biên) thì\n\n\n\n��\n\n\n\nf ( x, y ) dxdy =\n��\nD D\n\n\n\nf ( x, y ) dxdy.\n\n\n\nD 1\n\n\n\nf ( x, y ) dxdy +\n��\n\nD 2\n\n\n\n\n\n\n\n\n\n\n#### **1.2 Tính tích phân kép trong hệtoạđộDescartes**\n\nĐểtính các tích phân hai lớp, ta cần phải đưa vềtính các tích phân lặp.\n\n\n1. Nếu D là miền hình chữnhật ( D ) : a ⩽ x ⩽ b, c ⩽ y ⩽ d thì ta có thểsửdụng một\ntrong hai tích phân lặp\n\n\n\nd\n\n\ndy\n\n�\n\n\nc\n\n\n\nd\n\n\nf ( x, y ) dx.\n\n�\n\n\nc\n\n\n\nd\n\n\nf ( x, y ) dy =\n\n�\n\n\nc\n\n\n28\n\n\n\nf ( x, y ) dxdy =\n\n��\n\nD\n\n\n\nb\n\n\ndx\n\n�\n\n\na"
64
+ },
65
+ {
66
+ "idx": 50,
67
+ "page": 30,
68
+ "score": 0.8958114981651306,
69
+ "text": "_28_ _Chương 2. Tích phân bội_\n\n\n**Chú ý 2.3.** Nếu tồn tại tích phân kép f ( x, y ) dxdy thì ta nói hàm số f ( x, y ) khảtích\n��\n\nD\n\ntrong miền D .\n\n\n**Tính chất cơ bản:**\n\n\n Tính chất tuyến tính:\n\n\n\n��\n\n\n\nf ( x, y ) dxdy +\n��\nD D\n\n\n\n\n[ f ( x, y ) + g ( x, y )] dxdy =\n��\nD D\n\n\n\ng ( x, y ) dxdy\n\nD\n\n\n\n��\n\n\n\nk f ( x, y ) dxdy = k\n��\nD D\n\n\n\nf ( x, y ) dxdy\n\nD\n\n\n\n\n- Tính chất cộng tính: Nếu D = D 1 ∪ D 2, ởđó D 1 và D 2 không \"chồng\" lên nhau (có thể\nngoại trừphần biên) thì\n\n\n\n��\n\n\n\nf ( x, y ) dxdy =\n��\nD D\n\n\n\nf ( x, y ) dxdy.\n\n\n\nD 1\n\n\n\nf ( x, y ) dxdy +\n��\n\nD 2\n\n\n\n\n\n\n\n\n\n\n#### **1.2 Tính tích phân kép trong hệtoạđộDescartes**\n\nĐểtính các tích phân hai lớp, ta cần phải đưa vềtính các tích phân lặp.\n\n\n1. Nếu D là miền hình chữnhật ( D ) : a ⩽ x ⩽ b, c ⩽ y ⩽ d thì ta có thểsửdụng một\ntrong hai tích phân lặp\n\n\n\nd\n\n\ndy\n\n�\n\n\nc\n\n\n\nd\n\n\nf ( x, y ) dx.\n\n�\n\n\nc\n\n\n\nd\n\n\nf ( x, y ) dy =\n\n�\n\n\nc\n\n\n28\n\n\n\nf ( x, y ) dxdy =\n\n��\n\nD\n\n\n\nb\n\n\ndx\n\n�\n\n\na"
70
+ },
71
+ {
72
+ "idx": 38,
73
+ "page": 30,
74
+ "score": 0.8958114981651306,
75
+ "text": "_28_ _Chương 2. Tích phân bội_\n\n\n**Chú ý 2.3.** Nếu tồn tại tích phân kép f ( x, y ) dxdy thì ta nói hàm số f ( x, y ) khảtích\n��\n\nD\n\ntrong miền D .\n\n\n**Tính chất cơ bản:**\n\n\n Tính chất tuyến tính:\n\n\n\n��\n\n\n\nf ( x, y ) dxdy +\n��\nD D\n\n\n\n\n[ f ( x, y ) + g ( x, y )] dxdy =\n��\nD D\n\n\n\ng ( x, y ) dxdy\n\nD\n\n\n\n��\n\n\n\nk f ( x, y ) dxdy = k\n��\nD D\n\n\n\nf ( x, y ) dxdy\n\nD\n\n\n\n\n- Tính chất cộng tính: Nếu D = D 1 ∪ D 2, ởđó D 1 và D 2 không \"chồng\" lên nhau (có thể\nngoại trừphần biên) thì\n\n\n\n��\n\n\n\nf ( x, y ) dxdy =\n��\nD D\n\n\n\nf ( x, y ) dxdy.\n\n\n\nD 1\n\n\n\nf ( x, y ) dxdy +\n��\n\nD 2\n\n\n\n\n\n\n\n\n\n\n#### **1.2 Tính tích phân kép trong hệtoạđộDescartes**\n\nĐểtính các tích phân hai lớp, ta cần phải đưa vềtính các tích phân lặp.\n\n\n1. Nếu D là miền hình chữnhật ( D ) : a ⩽ x ⩽ b, c ⩽ y ⩽ d thì ta có thểsửdụng một\ntrong hai tích phân lặp\n\n\n\nd\n\n\ndy\n\n�\n\n\nc\n\n\n\nd\n\n\nf ( x, y ) dx.\n\n�\n\n\nc\n\n\n\nd\n\n\nf ( x, y ) dy =\n\n�\n\n\nc\n\n\n28\n\n\n\nf ( x, y ) dxdy =\n\n��\n\nD\n\n\n\nb\n\n\ndx\n\n�\n\n\na"
76
+ }
77
+ ],
78
+ "model_verdict": {
79
+ "supported": true,
80
+ "confidence": 0.96,
81
+ "evidence": "Nếu D là miền hình chữ nhật ( D ) : a ≤ x ≤ b, c ≤ y ≤ d thì ta có thể sử dụng một trong hai tích phân lặp ... ∫_a^b ∫_c^d f(x,y) dy dx = ∫_c^d ∫_a^b f(x,y) dx dy",
82
+ "reason": "Đoạn văn nêu rõ rằng với miền hình chữ nhật, hai dạng tích phân lặp đều đúng và bằng nhau, nên đáp án c được chứng thực."
83
+ }
84
+ },
85
+ "2": {
86
+ "supported_by_embeddings": true,
87
+ "max_similarity": 0.7703134417533875,
88
+ "evidence": [
89
+ {
90
+ "idx": 46,
91
+ "page": 23,
92
+ "score": 0.7703134417533875,
93
+ "text": "Vậy:\n\n\n\n12 [−] [1] [=] [y] − [−] 4 [3]\n\n\n\n3\n\n\n\n**–** Phương trình tiếp tuyến ( d ) : [x] 12 [−] [1]\n\n\n\n− [−] 4 [=] [z] [−] 3 [4]\n\n\n\n**–** Phương trình pháp diện ( P ) : 12 ( x − 1 ) − 4 ( y − 3 ) + 3 ( z − 4 ) = 0\n\n\n\nb. Tương tự,\n\n\n\nn f = (− 8, 6, 12 )\n� n g = (− 4, 4, − 1 ) [,][ n] [ f] [ ∧] [n] [g] [ =][ −] [2] [ (] [27, 27, 4] [)] [ nên]\n\n\n\n\n[+] [2] [y] [−] [1]\n\n27 [=] 27\n\n\n\n4\n\n\n\n**–** Phương trình tiếp tuyến ( d ) : [x] 27 [+] [2]\n\n\n\n\n[−] [z] [−] [6]\n\n27 [=] 4\n\n\n\n**–** Phương trình pháp diện ( P ) : 27 ( x + 2 ) + 27 ( y − 1 ) + 4 ( z − 6 ) = 0\n\n\n21"
94
+ },
95
+ {
96
+ "idx": 31,
97
+ "page": 23,
98
+ "score": 0.7703134417533875,
99
+ "text": "Vậy:\n\n\n\n12 [−] [1] [=] [y] − [−] 4 [3]\n\n\n\n3\n\n\n\n**–** Phương trình tiếp tuyến ( d ) : [x] 12 [−] [1]\n\n\n\n− [−] 4 [=] [z] [−] 3 [4]\n\n\n\n**–** Phương trình pháp diện ( P ) : 12 ( x − 1 ) − 4 ( y − 3 ) + 3 ( z − 4 ) = 0\n\n\n\nb. Tương tự,\n\n\n\nn f = (− 8, 6, 12 )\n� n g = (− 4, 4, − 1 ) [,][ n] [ f] [ ∧] [n] [g] [ =][ −] [2] [ (] [27, 27, 4] [)] [ nên]\n\n\n\n\n[+] [2] [y] [−] [1]\n\n27 [=] 27\n\n\n\n4\n\n\n\n**–** Phương trình tiếp tuyến ( d ) : [x] 27 [+] [2]\n\n\n\n\n[−] [z] [−] [6]\n\n27 [=] 4\n\n\n\n**–** Phương trình pháp diện ( P ) : 27 ( x + 2 ) + 27 ( y − 1 ) + 4 ( z − 6 ) = 0\n\n\n21"
100
+ },
101
+ {
102
+ "idx": 23,
103
+ "page": 23,
104
+ "score": 0.7703134417533875,
105
+ "text": "Vậy:\n\n\n\n12 [−] [1] [=] [y] − [−] 4 [3]\n\n\n\n3\n\n\n\n**–** Phương trình tiếp tuyến ( d ) : [x] 12 [−] [1]\n\n\n\n− [−] 4 [=] [z] [−] 3 [4]\n\n\n\n**–** Phương trình pháp diện ( P ) : 12 ( x − 1 ) − 4 ( y − 3 ) + 3 ( z − 4 ) = 0\n\n\n\nb. Tương tự,\n\n\n\nn f = (− 8, 6, 12 )\n� n g = (− 4, 4, − 1 ) [,][ n] [ f] [ ∧] [n] [g] [ =][ −] [2] [ (] [27, 27, 4] [)] [ nên]\n\n\n\n\n[+] [2] [y] [−] [1]\n\n27 [=] 27\n\n\n\n4\n\n\n\n**–** Phương trình tiếp tuyến ( d ) : [x] 27 [+] [2]\n\n\n\n\n[−] [z] [−] [6]\n\n27 [=] 4\n\n\n\n**–** Phương trình pháp diện ( P ) : 27 ( x + 2 ) + 27 ( y − 1 ) + 4 ( z − 6 ) = 0\n\n\n21"
106
+ }
107
+ ],
108
+ "model_verdict": {
109
+ "supported": false,
110
+ "confidence": 0.9,
111
+ "evidence": "",
112
+ "reason": "Context does not contain any statement about the parametric form of the plane ax + by + cz + d = 0, so the answer is not supported by the given text."
113
+ }
114
+ },
115
+ "3": {
116
+ "supported_by_embeddings": true,
117
+ "max_similarity": 0.7455167770385742,
118
+ "evidence": [
119
+ {
120
+ "idx": 160,
121
+ "page": 12,
122
+ "score": 0.7455167770385742,
123
+ "text": "_10_ _Chương 1. Các ứng dụng của phép tính vi phân trong hình học_\n\n\n3. Nếu họđường cong đã cho có điểm kì dịthì hệphương trình (1.2) bao gồm hình bao\n( E ) và quỹtích các điểm kì dịthuộc họcác đường cong đã cho. **Bài tập 1.1.** Viết phương trình tiếp tuyến và pháp tuyến với đường cong:\n\n\na) y = x [3] + 2x [2] − 4x − 3 tại (− 2, 5 ) . Phương trình pháp tuyến x = − 2\n\n\n\n_Lời giải_ . \n\n\n\n\nPhương trình tiếp tuyến y = 5\n\nPhương trình pháp tuyến x =\n\n\n\n\n\nb) y = e [1] [−] [x] [2] tại giao điểm của đường cong với đường thằng y = 1 . Phương trình pháp tuyến x + 2y − 1 = 0\n\n\n\n_Lời giải_ . **–** Tại M 1 (− 1, 1 ),\n\n\n\n\n\n\n\n\nPhương trình tiếp tuyến 2x − y + 3 = 0\n\nPhương trình pháp tuyến x + 2y − 1 =\n\n\n\nPhương trình pháp tuyến x − 2y + 1 = 0\n\n\n\n**–** Tại M 2 (− 1, 1 ),\n\n\n\n\n\n\n\n\nPhương trình tiếp tuyến 2x + y − 3 = 0\n\nPhương trình pháp tuyến x − 2y + 1 =\n\n\n\nc. x = [1] [+] [t]\n\nt [3]\n3\n\n� y = 2t [3]\n\n\n\nt [3]\n3\ny = 2t [3] [+] 2 [1]\n\n\n\ntại A ( 2, 2 ) . [1]\n\n2t\n\n\n\n_Lời giải_ . **–** Phương t..."
124
+ },
125
+ {
126
+ "idx": 108,
127
+ "page": 12,
128
+ "score": 0.7455167770385742,
129
+ "text": "_10_ _Chương 1. Các ứng dụng của phép tính vi phân trong hình học_\n\n\n3. Nếu họđường cong đã cho có điểm kì dịthì hệphương trình (1.2) bao gồm hình bao\n( E ) và quỹtích các điểm kì dịthuộc họcác đường cong đã cho. **Bài tập 1.1.** Viết phương trình tiếp tuyến và pháp tuyến với đường cong:\n\n\na) y = x [3] + 2x [2] − 4x − 3 tại (− 2, 5 ) . Phương trình pháp tuyến x = − 2\n\n\n\n_Lời giải_ . \n\n\n\n\nPhương trình tiếp tuyến y = 5\n\nPhương trình pháp tuyến x =\n\n\n\n\n\nb) y = e [1] [−] [x] [2] tại giao điểm của đường cong với đường thằng y = 1 . Phương trình pháp tuyến x + 2y − 1 = 0\n\n\n\n_Lời giải_ . **–** Tại M 1 (− 1, 1 ),\n\n\n\n\n\n\n\n\nPhương trình tiếp tuyến 2x − y + 3 = 0\n\nPhương trình pháp tuyến x + 2y − 1 =\n\n\n\nPhương trình pháp tuyến x − 2y + 1 = 0\n\n\n\n**–** Tại M 2 (− 1, 1 ),\n\n\n\n\n\n\n\n\nPhương trình tiếp tuyến 2x + y − 3 = 0\n\nPhương trình pháp tuyến x − 2y + 1 =\n\n\n\nc. x = [1] [+] [t]\n\nt [3]\n3\n\n� y = 2t [3]\n\n\n\nt [3]\n3\ny = 2t [3] [+] 2 [1]\n\n\n\ntại A ( 2, 2 ) . [1]\n\n2t\n\n\n\n_Lời giải_ . **–** Phương t..."
130
+ },
131
+ {
132
+ "idx": 106,
133
+ "page": 12,
134
+ "score": 0.7455167770385742,
135
+ "text": "_10_ _Chương 1. Các ứng dụng của phép tính vi phân trong hình học_\n\n\n3. Nếu họđường cong đã cho có điểm kì dịthì hệphương trình (1.2) bao gồm hình bao\n( E ) và quỹtích các điểm kì dịthuộc họcác đường cong đã cho. **Bài tập 1.1.** Viết phương trình tiếp tuyến và pháp tuyến với đường cong:\n\n\na) y = x [3] + 2x [2] − 4x − 3 tại (− 2, 5 ) . Phương trình pháp tuyến x = − 2\n\n\n\n_Lời giải_ . \n\n\n\n\nPhương trình tiếp tuyến y = 5\n\nPhương trình pháp tuyến x =\n\n\n\n\n\nb) y = e [1] [−] [x] [2] tại giao điểm của đường cong với đường thằng y = 1 . Phương trình pháp tuyến x + 2y − 1 = 0\n\n\n\n_Lời giải_ . **–** Tại M 1 (− 1, 1 ),\n\n\n\n\n\n\n\n\nPhương trình tiếp tuyến 2x − y + 3 = 0\n\nPhương trình pháp tuyến x + 2y − 1 =\n\n\n\nPhương trình pháp tuyến x − 2y + 1 = 0\n\n\n\n**–** Tại M 2 (− 1, 1 ),\n\n\n\n\n\n\n\n\nPhương trình tiếp tuyến 2x + y − 3 = 0\n\nPhương trình pháp tuyến x − 2y + 1 =\n\n\n\nc. x = [1] [+] [t]\n\nt [3]\n3\n\n� y = 2t [3]\n\n\n\nt [3]\n3\ny = 2t [3] [+] 2 [1]\n\n\n\ntại A ( 2, 2 ) . [1]\n\n2t\n\n\n\n_Lời giải_ . **–** Phương t..."
136
+ }
137
+ ],
138
+ "model_verdict": {
139
+ "supported": false,
140
+ "confidence": 0.9,
141
+ "evidence": "",
142
+ "reason": "Trong nội dung cung cấp không có bất kỳ đề cập nào đến mặt cong x² − 4y² + 2z² = 6, điểm (2, 2, 3) hay phương trình tiếp tuyến của nó, vì vậy không thể chứng thực đáp án được."
143
+ }
144
+ },
145
+ "4": {
146
+ "supported_by_embeddings": true,
147
+ "max_similarity": 0.552233099937439,
148
+ "evidence": [
149
+ {
150
+ "idx": 160,
151
+ "page": 12,
152
+ "score": 0.552233099937439,
153
+ "text": "_10_ _Chương 1. Các ứng dụng của phép tính vi phân trong hình học_\n\n\n3. Nếu họđường cong đã cho có điểm kì dịthì hệphương trình (1.2) bao gồm hình bao\n( E ) và quỹtích các điểm kì dịthuộc họcác đường cong đã cho. **Bài tập 1.1.** Viết phương trình tiếp tuyến và pháp tuyến với đường cong:\n\n\na) y = x [3] + 2x [2] − 4x − 3 tại (− 2, 5 ) . Phương trình pháp tuyến x = − 2\n\n\n\n_Lời giải_ . \n\n\n\n\nPhương trình tiếp tuyến y = 5\n\nPhương trình pháp tuyến x =\n\n\n\n\n\nb) y = e [1] [−] [x] [2] tại giao điểm của đường cong với đường thằng y = 1 . Phương trình pháp tuyến x + 2y − 1 = 0\n\n\n\n_Lời giải_ . **–** Tại M 1 (− 1, 1 ),\n\n\n\n\n\n\n\n\nPhương trình tiếp tuyến 2x − y + 3 = 0\n\nPhương trình pháp tuyến x + 2y − 1 =\n\n\n\nPhương trình pháp tuyến x − 2y + 1 = 0\n\n\n\n**–** Tại M 2 (− 1, 1 ),\n\n\n\n\n\n\n\n\nPhương trình tiếp tuyến 2x + y − 3 = 0\n\nPhương trình pháp tuyến x − 2y + 1 =\n\n\n\nc. x = [1] [+] [t]\n\nt [3]\n3\n\n� y = 2t [3]\n\n\n\nt [3]\n3\ny = 2t [3] [+] 2 [1]\n\n\n\ntại A ( 2, 2 ) . [1]\n\n2t\n\n\n\n_Lời giải_ . **–** Phương t..."
154
+ },
155
+ {
156
+ "idx": 108,
157
+ "page": 12,
158
+ "score": 0.552233099937439,
159
+ "text": "_10_ _Chương 1. Các ứng dụng của phép tính vi phân trong hình học_\n\n\n3. Nếu họđường cong đã cho có điểm kì dịthì hệphương trình (1.2) bao gồm hình bao\n( E ) và quỹtích các điểm kì dịthuộc họcác đường cong đã cho. **Bài tập 1.1.** Viết phương trình tiếp tuyến và pháp tuyến với đường cong:\n\n\na) y = x [3] + 2x [2] − 4x − 3 tại (− 2, 5 ) . Phương trình pháp tuyến x = − 2\n\n\n\n_Lời giải_ . \n\n\n\n\nPhương trình tiếp tuyến y = 5\n\nPhương trình pháp tuyến x =\n\n\n\n\n\nb) y = e [1] [−] [x] [2] tại giao điểm của đường cong với đường thằng y = 1 . Phương trình pháp tuyến x + 2y − 1 = 0\n\n\n\n_Lời giải_ . **–** Tại M 1 (− 1, 1 ),\n\n\n\n\n\n\n\n\nPhương trình tiếp tuyến 2x − y + 3 = 0\n\nPhương trình pháp tuyến x + 2y − 1 =\n\n\n\nPhương trình pháp tuyến x − 2y + 1 = 0\n\n\n\n**–** Tại M 2 (− 1, 1 ),\n\n\n\n\n\n\n\n\nPhương trình tiếp tuyến 2x + y − 3 = 0\n\nPhương trình pháp tuyến x − 2y + 1 =\n\n\n\nc. x = [1] [+] [t]\n\nt [3]\n3\n\n� y = 2t [3]\n\n\n\nt [3]\n3\ny = 2t [3] [+] 2 [1]\n\n\n\ntại A ( 2, 2 ) . [1]\n\n2t\n\n\n\n_Lời giải_ . **–** Phương t..."
160
+ },
161
+ {
162
+ "idx": 106,
163
+ "page": 12,
164
+ "score": 0.552233099937439,
165
+ "text": "_10_ _Chương 1. Các ứng dụng của phép tính vi phân trong hình học_\n\n\n3. Nếu họđường cong đã cho có điểm kì dịthì hệphương trình (1.2) bao gồm hình bao\n( E ) và quỹtích các điểm kì dịthuộc họcác đường cong đã cho. **Bài tập 1.1.** Viết phương trình tiếp tuyến và pháp tuyến với đường cong:\n\n\na) y = x [3] + 2x [2] − 4x − 3 tại (− 2, 5 ) . Phương trình pháp tuyến x = − 2\n\n\n\n_Lời giải_ . \n\n\n\n\nPhương trình tiếp tuyến y = 5\n\nPhương trình pháp tuyến x =\n\n\n\n\n\nb) y = e [1] [−] [x] [2] tại giao điểm của đường cong với đường thằng y = 1 . Phương trình pháp tuyến x + 2y − 1 = 0\n\n\n\n_Lời giải_ . **–** Tại M 1 (− 1, 1 ),\n\n\n\n\n\n\n\n\nPhương trình tiếp tuyến 2x − y + 3 = 0\n\nPhương trình pháp tuyến x + 2y − 1 =\n\n\n\nPhương trình pháp tuyến x − 2y + 1 = 0\n\n\n\n**–** Tại M 2 (− 1, 1 ),\n\n\n\n\n\n\n\n\nPhương trình tiếp tuyến 2x + y − 3 = 0\n\nPhương trình pháp tuyến x − 2y + 1 =\n\n\n\nc. x = [1] [+] [t]\n\nt [3]\n3\n\n� y = 2t [3]\n\n\n\nt [3]\n3\ny = 2t [3] [+] 2 [1]\n\n\n\ntại A ( 2, 2 ) . [1]\n\n2t\n\n\n\n_Lời giải_ . **–** Phương t..."
166
+ }
167
+ ],
168
+ "model_verdict": {
169
+ "supported": false,
170
+ "confidence": 0.9,
171
+ "evidence": "Ngữ cảnh không chứa tiêu đề 'GIẢI TÍCH II' hay danh sách các phép tính được liệt kê là ứng dụng.",
172
+ "reason": "Không có bằng chứng trong nội dung cung cấp để xác nhận đáp án."
173
+ }
174
+ },
175
+ "5": {
176
+ "supported_by_embeddings": true,
177
+ "max_similarity": 0.789191484451294,
178
+ "evidence": [
179
+ {
180
+ "idx": 156,
181
+ "page": 26,
182
+ "score": 0.789191484451294,
183
+ "text": "Như vậy ta đã chia miền][ R][ thành][ m] [ ×] [ n][ hình chữ]\n\n\n\ncon với độdài bằng nhau và bằng [d] [−] n [c] [. Như vậy ta đã chia miền][ R][ thành][ m] [ ×] [ n][ hình chữ]\n\nnhật con\nR ij = [ x i − 1, x i ] × [ y j − 1, y j ]\n\n\n\n24"
184
+ },
185
+ {
186
+ "idx": 79,
187
+ "page": 26,
188
+ "score": 0.789191484451294,
189
+ "text": "Như vậy ta đã chia miền][ R][ thành][ m] [ ×] [ n][ hình chữ]\n\n\n\ncon với độdài bằng nhau và bằng [d] [−] n [c] [. Như vậy ta đã chia miền][ R][ thành][ m] [ ×] [ n][ hình chữ]\n\nnhật con\nR ij = [ x i − 1, x i ] × [ y j − 1, y j ]\n\n\n\n24"
190
+ },
191
+ {
192
+ "idx": 13,
193
+ "page": 26,
194
+ "score": 0.789191484451294,
195
+ "text": "Như vậy ta đã chia miền][ R][ thành][ m] [ ×] [ n][ hình chữ]\n\n\n\ncon với độdài bằng nhau và bằng [d] [−] n [c] [. Như vậy ta đã chia miền][ R][ thành][ m] [ ×] [ n][ hình chữ]\n\nnhật con\nR ij = [ x i − 1, x i ] × [ y j − 1, y j ]\n\n\n\n24"
196
+ }
197
+ ],
198
+ "model_verdict": {
199
+ "supported": true,
200
+ "confidence": 0.99,
201
+ "evidence": "R ij = [ x i − 1, x i ] × [ y j − 1, y j ]",
202
+ "reason": "Context explicitly gives the definition matching the answer"
203
+ }
204
+ }
205
+ }
206
+ }
test/cerebras-api.py CHANGED
@@ -1,6 +1,5 @@
1
  # import os
2
  # from cerebras.cloud.sdk import Cerebras
3
- import tiktoken
4
 
5
  # client = Cerebras(
6
  # # This is the default and can be omitted
@@ -20,29 +19,14 @@ import tiktoken
20
  # temperature=1,
21
  # top_p=1
22
  # )
23
- import numpy as np
24
 
25
- INPUT_TOKEN_COUNT = np.array([], dtype=int)
26
- OUTPUT_TOKEN_COUNT = np.array([], dtype=int)
27
 
28
- # for chunk in stream:
29
- # print(chunk.choices[0].delta.content or "", end="")
30
- with open('../test/mcq_output.json', 'r', encoding='utf-8') as f:
31
- text = f.read()
32
 
33
- def count_tokens(text: str, model_name='gpt-oss-120b', encoding_name='cl100k_base') -> int:
34
- """Look up model encoding; fallback to encoding_name if model not known."""
35
- try:
36
- # encoding_for_model can raise if model is unknown to tiktoken
37
- enc = tiktoken.encoding_for_model(model_name)
38
- except Exception:
39
- enc = None
40
-
41
- if enc is None:
42
- enc = tiktoken.get_encoding(encoding_name)
43
-
44
- return len(enc.encode(text))
45
-
46
- c = count_tokens(text)
47
- INPUT_TOKEN_COUNT = np.append(INPUT_TOKEN_COUNT, c)
48
- print(INPUT_TOKEN_COUNT)
 
1
  # import os
2
  # from cerebras.cloud.sdk import Cerebras
 
3
 
4
  # client = Cerebras(
5
  # # This is the default and can be omitted
 
19
  # temperature=1,
20
  # top_p=1
21
  # )
 
22
 
23
+ my_dict = {'apple': 1, 'banana': 2, 'cherry': 3}
 
24
 
25
+ # Enumerate through both keys and values
26
+ for index, (key, value) in enumerate(my_dict.items()):
27
+ print(f"Index: {index}, Key: {key}, Value: {value}")
 
28
 
29
+ # Enumerate only through keys (less common with dictionaries)
30
+ print("\nEnumerate through keys only:")
31
+ for index, key in enumerate(my_dict): # By default, iterating a dict iterates its keys
32
+ print(f"Index: {index}, Key: {key}")
 
 
 
 
 
 
 
 
 
 
 
 
test/context.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [page 9] #### **Cài đặt sắp xếp trộn**
2
+
3
+ [page 5] #### **Cài đặt sắp xếp vun đống**
4
+
5
+ [page 2] ## **Các thuật toán sắp xếp - phần 2**
6
+
7
+
8
+ Sắp xếp vun đống (heap sort)
9
+
10
+ Sắp xếp trộn (merge sort)
11
+
12
+ Sắp xếp nhanh (quick sort)
test/general_mcq_output.json ADDED
@@ -0,0 +1,664 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "mcqs": {
3
+ "1": {
4
+ "câu hỏi": "Theo chứng minh tính chất 2 (Bịchặn) dựa trên bất đẳng thức Cauchy‑Schwarz, khi nào giá trị K cos(x_j , q) bằng -1?",
5
+ "lựa chọn": {
6
+ "a": "K cos(x_j , q) = -1 nếu x_j và q vuông góc",
7
+ "b": "K cos(x_j , q) = -1 nếu x_j và q cùng hướng",
8
+ "c": "K cos(x_j , q) = -1 nếu x_j và q ngược hướng: x_j = c·q với c < 0",
9
+ "d": "K cos(x_j , q) = -1 nếu x_j = 0 hoặc q = 0"
10
+ },
11
+ "đáp án": "K cos(x_j , q) = -1 nếu x_j và q ngược hướng: x_j = c·q với c < 0"
12
+ },
13
+ "2": {
14
+ "câu hỏi": "Các bước chính trong quy trình xử lý của BERT cho bài toán phân loại tin nhắn spam/ham bao gồm những gì?",
15
+ "lựa chọn": {
16
+ "a": "Mã hóa đầu vào, Tạo embedding từ [MASK] và Đánh giá độ chính xác",
17
+ "b": "Mã hóa đầu vào, Xử lý qua Transformer encoder và Phân loại",
18
+ "c": "Tiền xử lý dữ liệu, Huấn luyện mô hình CNN và Dự đoán nhãn",
19
+ "d": "Phân tách token, Áp dụng TF-IDF và Sử dụng Naive Bayes"
20
+ },
21
+ "đáp án": "Mã hóa đầu vào, Xử lý qua Transformer encoder và Phân loại"
22
+ },
23
+ "3": {
24
+ "câu hỏi": "Trong hệ thống phân loại spam, loại spam nào được mô tả là nguy hiểm nhất, nhằm lừa đảo người dùng cung cấp thông tin cá nhân?",
25
+ "lựa chọn": {
26
+ "a": "Spam khác (Miscellaneous Spam)",
27
+ "b": "Spam hệ thống/lừa đảo (Phishing/System Spam)",
28
+ "c": "Spam quảng cáo",
29
+ "d": "Spam tinh vi (Sophisticated Spam)"
30
+ },
31
+ "đáp án": "Spam hệ thống/lừa đảo (Phishing/System Spam)"
32
+ },
33
+ "4": {
34
+ "câu hỏi": "Trong quy trình phân loại spam/ham được mô tả, vector nào được đưa vào lớp tuyến tính để dự đoán nhãn?",
35
+ "lựa chọn": {
36
+ "a": "Các embedding của từng token trong câu",
37
+ "b": "[CLS] vector",
38
+ "c": "Các trọng số attention",
39
+ "d": "Đầu ra của mạng FFN"
40
+ },
41
+ "đáp án": "[CLS] vector"
42
+ },
43
+ "5": {
44
+ "câu hỏi": "Theo nội dung đã cho, yếu tố nào sau đây được nêu là nhược điểm khi sử dụng mô hình học sâu để tăng cường dataset?",
45
+ "lựa chọn": {
46
+ "a": "Yêu cầu tài nguyên tính toán lớn, thời gian và chi phí cao",
47
+ "b": "Có khả năng hiểu được sự khác biệt tinh tế giữa các cách diễn đạt",
48
+ "c": "Tạo ra các mẫu mới để mở rộng dữ liệu",
49
+ "d": "Kết hợp BERT embeddings với nối từ khóa trong phương pháp bán giám sát"
50
+ },
51
+ "đáp án": "Yêu cầu tài nguyên tính toán lớn, thời gian và chi phí cao"
52
+ },
53
+ "6": {
54
+ "câu hỏi": "Theo nội dung, nhược điểm nào của mô hình được nêu ra?",
55
+ "lựa chọn": {
56
+ "a": "Đòi hỏi tài nguyên tính toán lớn",
57
+ "b": "Tăng cường dữ liệu",
58
+ "c": "Phương pháp semi-supervised",
59
+ "d": "Cải thiện hiệu suất ở k=5"
60
+ },
61
+ "đáp án": "Đòi hỏi tài nguyên tính toán lớn"
62
+ },
63
+ "7": {
64
+ "câu hỏi": "Trong hệ thống phân loại tin nhắn, tham số α có vai trò gì?",
65
+ "lựa chọn": {
66
+ "a": "Điều chỉnh mức độ ưu tiên của điểm saliency so với độ tương đồng tổng thể của tin nhắn.",
67
+ "b": "Xác định ngưỡng cho điểm bỏ phiếu.",
68
+ "c": "Chỉ định loại spam cụ thể.",
69
+ "d": "Đánh giá độ chính xác của mô hình."
70
+ },
71
+ "đáp án": "Điều chỉnh mức độ ưu tiên của điểm saliency so với độ tương đồng tổng thể của tin nhắn."
72
+ },
73
+ "8": {
74
+ "câu hỏi": "Trong hệ thống phân loại spam sử dụng FAISS, chỉ số nào được mô tả là sử dụng phép nhân vô hướng (Inner Product) để cho kết quả tương đương với độ tương đồng cosine?",
75
+ "lựa chọn": {
76
+ "a": "IndexFlatIP",
77
+ "b": "IndexIVFFlat",
78
+ "c": "IndexHNSW",
79
+ "d": "IndexPQ"
80
+ },
81
+ "đáp án": "IndexFlatIP"
82
+ },
83
+ "9": {
84
+ "câu hỏi": "Trong các loại spam được mô tả, loại nào được mô tả là nguy hiểm nhất, nhằm lừa đảo người dùng cung cấp thông tin cá nhân như mật khẩu, mã OTP hoặc thông tin thẻ tín dụng?",
85
+ "lựa chọn": {
86
+ "a": "Spam quảng cáo (Promotional Spam)",
87
+ "b": "Spam hệ thống/lừa đảo (Phishing/System Spam)",
88
+ "c": "Spam khác (Miscellaneous Spam)",
89
+ "d": "Spam không xác định"
90
+ },
91
+ "đáp án": "Spam hệ thống/lừa đảo (Phishing/System Spam)"
92
+ },
93
+ "10": {
94
+ "câu hỏi": "Phương pháp semi-supervised sub-category của spam được mô tả trong nội dung sử dụng kỹ thuật nào để tạo biểu diễn văn bản?",
95
+ "lựa chọn": {
96
+ "a": "Word2Vec",
97
+ "b": "BERT embeddings",
98
+ "c": "TF‑IDF",
99
+ "d": "LSTM"
100
+ },
101
+ "đáp án": "BERT embeddings"
102
+ },
103
+ "11": {
104
+ "câu hỏi": "Theo công thức kết hợp lồi được nêu trong nội dung, trọng số được tính như thế nào khi sử dụng tham số α?",
105
+ "lựa chọn": {
106
+ "a": "(1-α) × w_similarity + α × w_saliency",
107
+ "b": "(1-α) × w_similarity×ICF + α × w_saliency",
108
+ "c": "w_similarity×ICF + w_saliency",
109
+ "d": "α × w_similarity×ICF + (1-α) × w_saliency"
110
+ },
111
+ "đáp án": "(1-α) × w_similarity×ICF + α × w_saliency"
112
+ },
113
+ "12": {
114
+ "câu hỏi": "Theo bảng so sánh, độ chính xác của mô hình cải tiến với k = 1 tăng bao nhiêu phần trăm so với mô hình gốc?",
115
+ "lựa chọn": {
116
+ "a": "4.72%",
117
+ "b": "0.77%",
118
+ "c": "92%",
119
+ "d": "86.96%"
120
+ },
121
+ "đáp án": "4.72%"
122
+ },
123
+ "13": {
124
+ "câu hỏi": "Trong công thức trọng số mới đề xuất cho quá trình voting của KNN, yếu tố nào biểu thị tầm quan trọng tinh tế của từng thực thể?",
125
+ "lựa chọn": {
126
+ "a": "similarity( x_j , q )",
127
+ "b": "ICF( y( x_j ) )",
128
+ "c": "saliency( x_j , q )",
129
+ "d": "α (tham số cân bằng)"
130
+ },
131
+ "đáp án": "saliency( x_j , q )"
132
+ },
133
+ "14": {
134
+ "câu hỏi": "Trong kiến trúc BERT-base, mỗi lớp encoder có bao nhiêu head trong Multi-Head Self-Attention?",
135
+ "lựa chọn": {
136
+ "a": "8 head",
137
+ "b": "12 head",
138
+ "c": "16 head",
139
+ "d": "24 head"
140
+ },
141
+ "đáp án": "12 head"
142
+ },
143
+ "15": {
144
+ "câu hỏi": "Theo nội dung, BERT được huấn luyện trước bằng hai nhiệm vụ nào?",
145
+ "lựa chọn": {
146
+ "a": "Masked Language Modeling và Next Sentence Prediction",
147
+ "b": "Sentiment Analysis và Text Summarization",
148
+ "c": "Machine Translation và Question Answering",
149
+ "d": "Named Entity Recognition và Part-of-Speech Tagging"
150
+ },
151
+ "đáp án": "Masked Language Modeling và Next Sentence Prediction"
152
+ },
153
+ "16": {
154
+ "câu hỏi": "Theo bảng tổng hợp, câu nào thuộc nhóm \"lottery_phrases\"?",
155
+ "lựa chọn": {
156
+ "a": "“Flash sale ends tonight – 30% of all items!”",
157
+ "b": "“You’ve been selected for a loyalty reward.”",
158
+ "c": "“Unusual login detected. Was this you?”",
159
+ "d": "“Act now to secure your spot in the seminar.”"
160
+ },
161
+ "đáp án": "“You’ve been selected for a loyalty reward.”"
162
+ },
163
+ "17": {
164
+ "câu hỏi": "Theo nội dung, một nhược điểm của phương pháp dựa trên từ khóa trong việc phát hiện spam là gì?",
165
+ "lựa chọn": {
166
+ "a": "Có thể xử lý linh hoạt các biến thể từ và lỗi chính tả.",
167
+ "b": "Thiếu linh hoạt, không thể xử lý các biến thể từ và lỗi chính tả.",
168
+ "c": "Hiểu ngữ cảnh, phân biệt đúng từ 'free' trong các câu khác nhau.",
169
+ "d": "Sử dụng embedding ngữ cảnh sâu như BERT để nắm bắt ý nghĩa."
170
+ },
171
+ "đáp án": "Thiếu linh hoạt, không thể xử lý các biến thể từ và lỗi chính tả."
172
+ },
173
+ "18": {
174
+ "câu hỏi": "Theo nội dung trên, một nhược điểm chính của các mô hình ngôn ngữ lớn là gì?",
175
+ "lựa chọn": {
176
+ "a": "Yêu cầu tài nguyên tính toán lớn, bao gồm thời gian và chi phí huấn luyện và fine‑tuning.",
177
+ "b": "Có khả năng giải thích quyết định dự đoán một cách rõ ràng và trực quan.",
178
+ "c": "Có thể học được ranh giới phân biệt tốt hơn khi tăng cường dữ liệu.",
179
+ "d": "Cho phép phân loại nhanh chóng với độ chính xác cao ở k = 1."
180
+ },
181
+ "đáp án": "Yêu cầu tài nguyên tính toán lớn, bao gồm thời gian và chi phí huấn luyện và fine‑tuning."
182
+ },
183
+ "19": {
184
+ "câu hỏi": "Trong phương pháp Weighted KNN được mô tả, yếu tố nào được sử dụng làm trọng số để ưu tiên các láng giềng gần hơn?",
185
+ "lựa chọn": {
186
+ "a": "Độ lệch chuẩn",
187
+ "b": "Điểm tương đồng (similarity score)",
188
+ "c": "Khoảng cách Euclid",
189
+ "d": "Số lượng láng giềng"
190
+ },
191
+ "đáp án": "Điểm tương đồng (similarity score)"
192
+ },
193
+ "20": {
194
+ "câu hỏi": "Trong phương pháp kết hợp điểm ngữ nghĩa BERT và điểm từ khóa để đưa ra quyết định cuối cùng, trọng số được gán cho mỗi loại điểm là bao nhiêu?",
195
+ "lựa chọn": {
196
+ "a": "0.5 BERT và 0.5 từ khóa",
197
+ "b": "0.7 BERT và 0.3 từ khóa",
198
+ "c": "0.6 BERT và 0.4 từ khóa",
199
+ "d": "0.8 BERT và 0.2 từ khóa"
200
+ },
201
+ "đáp án": "0.7 BERT và 0.3 từ khóa"
202
+ }
203
+ },
204
+ "validation": {
205
+ "1": {
206
+ "supported_by_embeddings": true,
207
+ "max_similarity": 0.9192600250244141,
208
+ "evidence": [
209
+ {
210
+ "idx": 41,
211
+ "page": 19,
212
+ "score": 0.7189286947250366,
213
+ "text": "Đối với điểm truy vấn _q_, KNN truyền thống tính toán:\n\n\nˆ\n_y_ = arg max _c_ _i_ _∈C_ _[|{][x]_ _[j]_ _[ ∈N]_ _[K]_ [(] _[q]_ [) :] _[ y]_ [(] _[x]_ _[j]_ [) =] _[ c]_ _[i]_ _[}|]_ (1)\n\n\n**Phân tích Bias:**\nXác suất đểmột K-neighborhood ngẫu nhiên chứa _k_ thực thểtừlớp _c_ _i_ tuân theo phân phối siêu hình\nhọc:\n\n\n19"
214
+ },
215
+ {
216
+ "idx": 8,
217
+ "page": 23,
218
+ "score": 0.7741187810897827,
219
+ "text": "**Chứng minh tính chất 2 (Bịchặn):**\nTheo bất đẳng thức Cauchy-Schwarz:\n\n\n_|x_ _j_ _· q| ≤∥x_ _j_ _∥× ∥q∥_ (29)\n\n\nChia cảhai vếcho _∥x_ _j_ _∥× ∥q∥_ (giảsử _x_ _j_ _, q ̸_ = 0):\n\n\n\n_x_ _j_ _·_ _q_\n���� _∥x_ _j_ _∥× ∥q∥_\n\n\n\n_≤_ 1 (30)\n����\n\n\n\nĐiều này có nghĩa là:\n\n\nDấu bằng xảy ra khi:\n\n\n\n_−_ 1 _≤_ _K_ cos ( _x_ _j_ _, q_ ) _≤_ 1 (31)\n\n\n\n\n - _K_ cos ( _x_ _j_ _, q_ ) = 1 nếu _x_ _j_ và _q_ cùng hướng: _x_ _j_ = _c · q_ với _c >_ 0\n\n\n - _K_ cos ( _x_ _j_ _, q_ ) = _−_ 1 nếu _x_ _j_ và _q_ ngược hướng: _x_ _j_ = _c · q_ với _c <_ 0\n\n\n - _K_ cos ( _x_ _j_ _, q_ ) = 0 nếu _x_ _j_ và _q_ vuông góc: _x_ _j_ _⊥_ _q_\n\n\n**Chứng minh tính chất 3 (Chuẩn hóa - Không đổi với độlớn vector):**\nXét hai vector _x_ _[′]_ _j_ [=] _[ λx]_ _[j]_ [ và] _[ q]_ _[′]_ [ =] _[ µq]_ [ với] _[ λ, µ >]_ [ 0][:]\n\n\n23"
220
+ },
221
+ {
222
+ "idx": 56,
223
+ "page": 24,
224
+ "score": 0.9192600250244141,
225
+ "text": "**6.4.3** **Trọng sốNội dung dựa trên Saliency**\n\n\n**Định nghĩa 3** (Gradient-based Saliency) **.** _Thành phần saliency nắm bắt_ _**tầm quan trọng cụthể**_\n_**theo đầu vào**_ _dựa trên mô hình explainable AI:_\n\n\n_saliency_ ( _x_ _j_ _, q_ ) = _∥∇_ _x_ _j_ _L_ ( _f_ ( _x_ _j_ ) _,_ ˆ _y_ ) _∥_ 2 (38)\n\n\n**6.4.4** **Kết hợp Lồi và Tham sốCân bằng** _α_\n\n\n**Định lý 6.1** (Tính chất Convex Combination) **.** _Tham số_ _α tạo ra_ _**kết hợp lồi**_ _của hai lược đồtrọng_\n_số:_\n\n_weight_ = (1 _−_ _α_ ) _× w_ _similarity×ICF_ + _α × w_ _saliency_ (39)\n\n_Với α ∈_ [0 _,_ 1] _, kết quảnằm trong convex hull của hai thành phần._\n\n\n**6.5** **Phân tích Lý thuyết: Tại sao Công thức này Hợp lý**\n\n\n**6.5.1** **Phân tích Hiệu chỉnh Bias**\n\n\n**Định lý 6.2** (Bias Correction) **.** _Đối với majority voting truyền thống, ảnh hưởng kỳvọng của lớp c_ _i_ _là:_\n\nE[ _Influence_ _traditional_ ( _c_ _i_ )] = _K × P_ ( _c_ _i_ ) = _K ×_ _N_ _[n]_ _[i]_ (40)\n\n\n_Với phương pháp trọng sốcủa chúng ta:_\n\n\nE[ _Influence..."
226
+ }
227
+ ],
228
+ "model_verdict": null
229
+ },
230
+ "2": {
231
+ "supported_by_embeddings": true,
232
+ "max_similarity": 0.7949658036231995,
233
+ "evidence": [
234
+ {
235
+ "idx": 21,
236
+ "page": 15,
237
+ "score": 0.5949141979217529,
238
+ "text": "Trong bài toán spam/ham, BERT được tinh\nchỉnh đểtối ưu hóa dựđoán nhãn và tập trung vào các từkhóa quan trọng như “miễn phí” hoặc “quà\ntặng” trong tin nhắn spam. **Ứng dụng** : Trong phân loại tin nhắn spam/ham, BERT chuyển tin nhắn thành vector số, hiểu ngữ\ncảnh sâu sắc (ví dụ: nhận diện ”miễn phí” trong ngữcảnh quảng cáo), và dựđoán nhãn (spam hoặc\nham). **Ưu điểm** :\n\n\n - Hiểu ngữcảnh hai chiều, vượt trội so với các phương pháp truyền thống như TF-IDF. - Sửdụng vector [CLS] đểtổng hợp thông tin toàn câu, phù hợp cho phân loại. **5.3** **Kiến trúc BERT**\n\n\nQuy trình xửlý của BERT bao gồm ba giai đoạn chính:\n\n\n1. **Mã hóa đầu vào** : Chuyển tin nhắn thành token, embedding, và attention mask. 2. **Xửlý qua Transformer encoder** : Tạo biểu diễn ngữcảnh cho từng token, đặc biệt là vector\n\n[CLS]. 3. **Phân loại** : Sửdụng vector [CLS] đểdựđoán nhãn spam/ham. Phần này trình bày chi tiết từng thành phần của kiến trúc BERT và cách chúng hỗtrợbài toán phân\nloại tin nhắn spam/ham. **5.3.1** *..."
239
+ },
240
+ {
241
+ "idx": 52,
242
+ "page": 11,
243
+ "score": 0.7382397651672363,
244
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n - 2039 mẫu _hard spam_ : được tạo ra đểtăng sốlượng và độphức tạp của các tin nhắn spam, giúp\nmô hình nhận diện tốt hơn các biến thểcủa spam. - 815 mẫu _hard ham_ : là những tin nhắn hợp lệnhưng có chứa từkhóa gần giống spam, buộc mô\nhình phải học cách phân biệt tinh vi hơn giữa hai lớp. - 1053 mẫu được sinh ra bằng kỹthuật _synonym replacement_ (thay thếtừđồng nghĩa), giúp tăng\nsựđa dạng vềmặt ngôn ngữcho cảhai lớp. Kết quảlà một dataset dùng đểphân loại có kích thước 9479 mẫu gồm 6556 mẫu Ham, 2923 mẫu Spam\ncó phân phối cân bằng hơn, tạo nền tảng vững chắc cho việc huấn luyện mô hình phân loại hiệu quả. **Phương pháp**\n\n\nĐểđạt được mục tiêu trên, nhóm mình đã thiết kếmột hệthống data augmentation chuyên biệt, kết\nhợp giữa kỹthuật sinh dữliệu bằng mô hình ngôn ngữlớn (LLM), thay thếtừđồng nghĩa, và khung\nsinh câu theo kịch bản có kiểm soát. Hệthống gồm ba giai đoạn chính:\n\n\n1."
245
+ },
246
+ {
247
+ "idx": 64,
248
+ "page": 27,
249
+ "score": 0.7949658036231995,
250
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n## **7 Semi-supervised đểphân loại sub-category của spam**\n\n\n**7.1** **Vấn đề”Spam” không chỉlà ”Spam”**\n\n\nKhi đối mặt với vấn đềspam, việc phân loại nhịphân (binary classification) thành hai loại ”spam” và\n”không spam” (ham) là chưa đủđểxây dựng một hệthống phòng chống hiệu quả. Bản chất của tin\nnhắn spam đã thay đổi và trởnên đa dạng hơn rất nhiều. Việc coi tất cảcác tin nhắn spam như nhau sẽ\nbỏqua những sắc thái quan trọng, dẫn đến việc chúng ta không thểđưa ra các biện pháp xửlý phù hợp. Khi phân tích sâu hơn, chúng ta thấy rằng spam có thểđược chia thành nhiều **thểloại con (sub-**\n**category) khác nhau**, mỗi loại có mục tiêu và phương thức hoạt động riêng biệt:\n\n\n **Spam quảng cáo** (Promotional Spam): Nhằm mục đích tiếp thịsản phẩm, dịch vụ, các chương\ntrình khuyến mãi, giảm giá, hoặc các thông báo trúng thưởng. Đặc điểm của loại này là thường\nchứa các từkhóa liên quan đến mua sắm, giá cả, ưu đãi..."
251
+ }
252
+ ],
253
+ "model_verdict": null
254
+ },
255
+ "3": {
256
+ "supported_by_embeddings": true,
257
+ "max_similarity": 0.5782788991928101,
258
+ "evidence": [
259
+ {
260
+ "idx": 52,
261
+ "page": 11,
262
+ "score": 0.5782788991928101,
263
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n - 2039 mẫu _hard spam_ : được tạo ra đểtăng sốlượng và độphức tạp của các tin nhắn spam, giúp\nmô hình nhận diện tốt hơn các biến thểcủa spam. - 815 mẫu _hard ham_ : là những tin nhắn hợp lệnhưng có chứa từkhóa gần giống spam, buộc mô\nhình phải học cách phân biệt tinh vi hơn giữa hai lớp. - 1053 mẫu được sinh ra bằng kỹthuật _synonym replacement_ (thay thếtừđồng nghĩa), giúp tăng\nsựđa dạng vềmặt ngôn ngữcho cảhai lớp. Kết quảlà một dataset dùng đểphân loại có kích thước 9479 mẫu gồm 6556 mẫu Ham, 2923 mẫu Spam\ncó phân phối cân bằng hơn, tạo nền tảng vững chắc cho việc huấn luyện mô hình phân loại hiệu quả. **Phương pháp**\n\n\nĐểđạt được mục tiêu trên, nhóm mình đã thiết kếmột hệthống data augmentation chuyên biệt, kết\nhợp giữa kỹthuật sinh dữliệu bằng mô hình ngôn ngữlớn (LLM), thay thếtừđồng nghĩa, và khung\nsinh câu theo kịch bản có kiểm soát. Hệthống gồm ba giai đoạn chính:\n\n\n1."
264
+ }
265
+ ],
266
+ "model_verdict": null
267
+ },
268
+ "4": {
269
+ "supported_by_embeddings": true,
270
+ "max_similarity": 0.7534276247024536,
271
+ "evidence": [
272
+ {
273
+ "idx": 21,
274
+ "page": 15,
275
+ "score": 0.7180466651916504,
276
+ "text": "Trong bài toán spam/ham, BERT được tinh\nchỉnh đểtối ưu hóa dựđoán nhãn và tập trung vào các từkhóa quan trọng như “miễn phí” hoặc “quà\ntặng” trong tin nhắn spam. **Ứng dụng** : Trong phân loại tin nhắn spam/ham, BERT chuyển tin nhắn thành vector số, hiểu ngữ\ncảnh sâu sắc (ví dụ: nhận diện ”miễn phí” trong ngữcảnh quảng cáo), và dựđoán nhãn (spam hoặc\nham). **Ưu điểm** :\n\n\n - Hiểu ngữcảnh hai chiều, vượt trội so với các phương pháp truyền thống như TF-IDF. - Sửdụng vector [CLS] đểtổng hợp thông tin toàn câu, phù hợp cho phân loại. **5.3** **Kiến trúc BERT**\n\n\nQuy trình xửlý của BERT bao gồm ba giai đoạn chính:\n\n\n1. **Mã hóa đầu vào** : Chuyển tin nhắn thành token, embedding, và attention mask. 2. **Xửlý qua Transformer encoder** : Tạo biểu diễn ngữcảnh cho từng token, đặc biệt là vector\n\n[CLS]. 3. **Phân loại** : Sửdụng vector [CLS] đểdựđoán nhãn spam/ham. Phần này trình bày chi tiết từng thành phần của kiến trúc BERT và cách chúng hỗtrợbài toán phân\nloại tin nhắn spam/ham. **5.3.1** *..."
277
+ },
278
+ {
279
+ "idx": 64,
280
+ "page": 27,
281
+ "score": 0.7191596031188965,
282
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n## **7 Semi-supervised đểphân loại sub-category của spam**\n\n\n**7.1** **Vấn đề”Spam” không chỉlà ”Spam”**\n\n\nKhi đối mặt với vấn đềspam, việc phân loại nhịphân (binary classification) thành hai loại ”spam” và\n”không spam” (ham) là chưa đủđểxây dựng một hệthống phòng chống hiệu quả. Bản chất của tin\nnhắn spam đã thay đổi và trởnên đa dạng hơn rất nhiều. Việc coi tất cảcác tin nhắn spam như nhau sẽ\nbỏqua những sắc thái quan trọng, dẫn đến việc chúng ta không thểđưa ra các biện pháp xửlý phù hợp. Khi phân tích sâu hơn, chúng ta thấy rằng spam có thểđược chia thành nhiều **thểloại con (sub-**\n**category) khác nhau**, mỗi loại có mục tiêu và phương thức hoạt động riêng biệt:\n\n\n **Spam quảng cáo** (Promotional Spam): Nhằm mục đích tiếp thịsản phẩm, dịch vụ, các chương\ntrình khuyến mãi, giảm giá, hoặc các thông báo trúng thưởng. Đặc điểm của loại này là thường\nchứa các từkhóa liên quan đến mua sắm, giá cả, ưu đãi..."
283
+ },
284
+ {
285
+ "idx": 1,
286
+ "page": 5,
287
+ "score": 0.7534276247024536,
288
+ "text": "Điều này đặc biệt quan trọng\ntrong các hệthống chống spam hiện đại, giúp người dùng hiểu rõ liệu một email nên bịxóa, xem qua\nhay báo cáo. Ngoài ra, nhóm còn hướng đến việc **mởrộng phân loại chi tiết trong nhóm spam**\n(quảng cáo, hệthống, lừa đảo, v.v...) nhằm tăng trải nghiệm và bảo mật cho người dùng. Hệthống phân loại tin nhắn spam/ham được thiết kếvới cơ chếđầu vào – đầu ra như sau:\n\n\n\n\n\n5"
289
+ }
290
+ ],
291
+ "model_verdict": null
292
+ },
293
+ "5": {
294
+ "supported_by_embeddings": true,
295
+ "max_similarity": 0.7267791032791138,
296
+ "evidence": [
297
+ {
298
+ "idx": 60,
299
+ "page": 10,
300
+ "score": 0.6037057638168335,
301
+ "text": "Đểgiải quyết vấn đềnày, dataset đã được tăng cường đáng kểbằng cách sửdụng một mô hình học sâu\nđểtạo ra các mẫu mới:\n\n\n10"
302
+ },
303
+ {
304
+ "idx": 3,
305
+ "page": 28,
306
+ "score": 0.7101945281028748,
307
+ "text": "**–**\nNhờđó, mô hình có thểhiểu được sựkhác biệt tinh tếgiữa các cách diễn đạt, xửlý được\ncác từđồng nghĩa và các biến thểngôn ngữ. **Nhược điểm:**\n\n\n**– Đòi hỏi tài nguyên tính toán lớn:** Việc huấn luyện và fine-tuning các mô hình này cần\nnhiều thời gian và chi phí. **– Phức tạp:** Việc fine-tuning cho từng tác vụcụthểcó thểphức tạp. Đặc biệt, nếu không có\nđủdữliệu đã được gán nhãn, hiệu quảcủa các mô hình này sẽbịhạn chế. **7.3** **Phương pháp Semi-supervised sub-category của spam**\n\n\nĐểtận dụng ưu điểm của 2 phương pháp phân loại sub-category phần trên. Chúng tôi đềxuất thực\nhiện một phương pháp semi-supervised bằng cách kết hợp bert embeđings với nối từkhóa. Phương pháp này được gọi là ”bán giám sát” vì nó sửdụng một lượng nhỏdữliệu có nhãn (reference_texts\nvà category_keywords) đểphân loại một lượng lớn dữliệu chưa có nhãn (spam_texts). Tiến trình thực hiện của phương pháp như sau:\n\n\n1. **Bước 1: BERT embeddings**\n\n\n **Tạo Embeddings của Văn bản Spam:** đểbiến mỗi tin nhắn spam ..."
308
+ },
309
+ {
310
+ "idx": 61,
311
+ "page": 26,
312
+ "score": 0.7267791032791138,
313
+ "text": "Những cải thiện này đến từcác yếu tốsau:\n\n\n **Tăng cường dữliệu:** sinh thêm mẫu khó và thay từđồng nghĩa giúp đa dạng hóa ngữcảnh và\nlàm mô hình học được ranh giới phân biệt tốt hơn. **Tập huấn luyện lớn hơn:** từdưới 1.000 mẫu lên hơn 9.000 mẫu giúp mô hình tổng quát hóa\ntốt hơn. **Tập trung vào mẫu khó:** ưu tiên những ví dụgần ranh giới giữa spam/ham nhằm tăng tính\nphân biệt cho mô hình. **Kết luận:** Mô hình mới không chỉđạt hiệu suất cao ở _k_ = 5 mà còn cải thiện đáng kểở _k_ = 1, rất hữu\ních cho các ứng dụng yêu cầu tốc độsuy luận nhanh mà vẫn đảm bảo độchính xác cao. 26"
314
+ }
315
+ ],
316
+ "model_verdict": null
317
+ },
318
+ "6": {
319
+ "supported_by_embeddings": true,
320
+ "max_similarity": 1.1316804885864258,
321
+ "evidence": [
322
+ {
323
+ "idx": 3,
324
+ "page": 28,
325
+ "score": 0.8143035769462585,
326
+ "text": "**–**\nNhờđó, mô hình có thểhiểu được sựkhác biệt tinh tếgiữa các cách diễn đạt, xửlý được\ncác từđồng nghĩa và các biến thểngôn ngữ. **Nhược điểm:**\n\n\n**– Đòi hỏi tài nguyên tính toán lớn:** Việc huấn luyện và fine-tuning các mô hình này cần\nnhiều thời gian và chi phí. **– Phức tạp:** Việc fine-tuning cho từng tác vụcụthểcó thểphức tạp. Đặc biệt, nếu không có\nđủdữliệu đã được gán nhãn, hiệu quảcủa các mô hình này sẽbịhạn chế. **7.3** **Phương pháp Semi-supervised sub-category của spam**\n\n\nĐểtận dụng ưu điểm của 2 phương pháp phân loại sub-category phần trên. Chúng tôi đềxuất thực\nhiện một phương pháp semi-supervised bằng cách kết hợp bert embeđings với nối từkhóa. Phương pháp này được gọi là ”bán giám sát” vì nó sửdụng một lượng nhỏdữliệu có nhãn (reference_texts\nvà category_keywords) đểphân loại một lượng lớn dữliệu chưa có nhãn (spam_texts). Tiến trình thực hiện của phương pháp như sau:\n\n\n1. **Bước 1: BERT embeddings**\n\n\n **Tạo Embeddings của Văn bản Spam:** đểbiến mỗi tin nhắn spam ..."
327
+ },
328
+ {
329
+ "idx": 61,
330
+ "page": 26,
331
+ "score": 0.9040168523788452,
332
+ "text": "Những cải thiện này đến từcác yếu tốsau:\n\n\n **Tăng cường dữliệu:** sinh thêm mẫu khó và thay từđồng nghĩa giúp đa dạng hóa ngữcảnh và\nlàm mô hình học được ranh giới phân biệt tốt hơn. **Tập huấn luyện lớn hơn:** từdưới 1.000 mẫu lên hơn 9.000 mẫu giúp mô hình tổng quát hóa\ntốt hơn. **Tập trung vào mẫu khó:** ưu tiên những ví dụgần ranh giới giữa spam/ham nhằm tăng tính\nphân biệt cho mô hình. **Kết luận:** Mô hình mới không chỉđạt hiệu suất cao ở _k_ = 5 mà còn cải thiện đáng kểở _k_ = 1, rất hữu\ních cho các ứng dụng yêu cầu tốc độsuy luận nhanh mà vẫn đảm bảo độchính xác cao. 26"
333
+ },
334
+ {
335
+ "idx": 60,
336
+ "page": 10,
337
+ "score": 1.1316804885864258,
338
+ "text": "Đểgiải quyết vấn đềnày, dataset đã được tăng cường đáng kểbằng cách sửdụng một mô hình học sâu\nđểtạo ra các mẫu mới:\n\n\n10"
339
+ }
340
+ ],
341
+ "model_verdict": null
342
+ },
343
+ "7": {
344
+ "supported_by_embeddings": true,
345
+ "max_similarity": 0.9357913732528687,
346
+ "evidence": [
347
+ {
348
+ "idx": 18,
349
+ "page": 7,
350
+ "score": 0.7424218058586121,
351
+ "text": "Tham số _α_ là tham sốđiều chỉnh, quyết định mức độưu tiên của điểm saliency so với độ\ntương đồng tổng thểcủa tin nhắn. - **Vote Scores:** Hệthống hiển thịđiểm sốbỏphiếu cho mỗi lớp ( _Ham_ và _Spam_ ). Dựđoán cuối\ncùng sẽlà lớp có điểm sốcao nhất. - **Spam Subcategory:** Nếu tin nhắn được phân loại là _SPAM_, hệthống tiếp tục phân tích đểxác\nđịnh tiểu mục spam cụthể(ví dụ: _spam_quangcao_, _spam_hethong_ ). **Cơ sởgiải thích (Top neighbors):** Hệthống liệt kê một sốhàng xóm gần nhất trong cơ sởdữ\nliệu vector. Mỗi neighbors bao gồm:\n\n\n**–** _Nhãn (Label):_ Nhãn của tin nhắn gốc ( _ham_ hoặc _spam_ ). **–**\n_Độtương đồng (Similarity):_ Giá trịthểhiện mức độtương đồng giữa tin nhắn đầu vào và\nhàng xóm. **–**\n_Nội dung (Message):_ Nội dung của tin nhắn hàng xóm. 7"
352
+ },
353
+ {
354
+ "idx": 11,
355
+ "page": 29,
356
+ "score": 0.909127414226532,
357
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n **Tính Độtương đồng Ngữnghĩa:** Đối với mỗi tin nhắn spam, thuật toán tính toán độ\ntương đồng cosine giữa embedding của tin nhắn đó và embedding của từng điểm neo tham\nchiếu. Kết quảlà một điểm số( _bert_scores_ ) cho thấy mức độliên quan vềmặt ngữnghĩa\ncủa tin nhắn với từng tiểu thểloại. 2. **Bước 2: Keyword matching**\n\n\n **Định nghĩa Từkhóa:** tạo một danh sách từkhóa chi tiết cho từng thểloại con. - **Tính Điểm Từkhóa:** Với mỗi tin nhắn, đoạn mã s���đếm sốlượng từkhóa trong danh sách\nxuất hiện. Điểm sốnày được chuẩn hóa.( _keyword_scores_ ) đểso sánh công bằng giữa các thể\nloại con có sốlượng từkhóa khác nhau. 3. **Bước 3: combine và ra quyết định** Đây là bước then chốt của phương pháp lai này. **Kết hợp có trọng số:** Mô hình kết hợp hai điểm sốtrên bằng cách sửdụng trọng số. Với\nđiểm ngữnghĩa của BERT chiếm 70% và điểm từkhóa chiếm 30% (0 _._ 7 _×_ bert_scores +0 _._ 3 _×_\nkeyword_scores). Sựkết hợp này tận dụng khảnăng hiểu ngữnghĩa sâu củ..."
358
+ },
359
+ {
360
+ "idx": 68,
361
+ "page": 13,
362
+ "score": 0.9357913732528687,
363
+ "text": "Trong trường hợp này, phép nhân vô hướng (Inner Product) mà\nIndexFlatIP sửdụng sẽcho kết quảtương đương với độtương đồng cosine. Độtương đồng cosine\nlà thước đo tiêu chuẩn đểđánh giá sựtương đồng ngữnghĩa trong các bài toán NLP. Do đó,\nIndexFlatIP là lựa chọn hoàn hảo đểtruy vấn các tin nhắn có ý nghĩa tương tự, tạo ra một hệ\nthống tìm kiếm ngữnghĩa hiệu quảvà chính xác. ## **4 Explainable AI: Masking-based saliency heat map**\n\n\nNhận thấy rằng toàn bộhệthống phân loại sửdụng mô hình embedding E5 kết hợp với cơ sởdữliệu\nFAISS đểtruy vấn và tìm kiếm `k` tin nhắn gần nhất là một mô hình dạng “hộp đen” (black-box), nên\nnhóm đặt mục tiêu tăng tính giải thích của mô hình bằng cách chỉra cụthểnhững token nào trong\ncâu đầu vào thực sựảnh hưởng đến embedding câu, từđó dẫn đến quyết định phân loại. Ý tưởng cụ\nthểlà trực quan hóa mức độđóng góp của từng token bằng bản đồnhiệt (heatmap) — token nào càng\nđóng góp nhiều thì sẽđược tô màu đậm hơn. Do nhóm tập trung chủyếu vào việc phân loại và giải t..."
364
+ }
365
+ ],
366
+ "model_verdict": null
367
+ },
368
+ "8": {
369
+ "supported_by_embeddings": true,
370
+ "max_similarity": 0.610893189907074,
371
+ "evidence": [
372
+ {
373
+ "idx": 1,
374
+ "page": 5,
375
+ "score": 0.5394615530967712,
376
+ "text": "Điều này đặc biệt quan trọng\ntrong các hệthống chống spam hiện đại, giúp người dùng hiểu rõ liệu một email nên bịxóa, xem qua\nhay báo cáo. Ngoài ra, nhóm còn hướng đến việc **mởrộng phân loại chi tiết trong nhóm spam**\n(quảng cáo, hệthống, lừa đảo, v.v...) nhằm tăng trải nghiệm và bảo mật cho người dùng. Hệthống phân loại tin nhắn spam/ham được thiết kếvới cơ chếđầu vào – đầu ra như sau:\n\n\n\n\n\n5"
377
+ },
378
+ {
379
+ "idx": 64,
380
+ "page": 27,
381
+ "score": 0.5891628265380859,
382
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n## **7 Semi-supervised đểphân loại sub-category của spam**\n\n\n**7.1** **Vấn đề”Spam” không chỉlà ”Spam”**\n\n\nKhi đối mặt với vấn đềspam, việc phân loại nhịphân (binary classification) thành hai loại ”spam” và\n”không spam” (ham) là chưa đủđểxây dựng một hệthống phòng chống hiệu quả. Bản chất của tin\nnhắn spam đã thay đổi và trởnên đa dạng hơn rất nhiều. Việc coi tất cảcác tin nhắn spam như nhau sẽ\nbỏqua những sắc thái quan trọng, dẫn đến việc chúng ta không thểđưa ra các biện pháp xửlý phù hợp. Khi phân tích sâu hơn, chúng ta thấy rằng spam có thểđược chia thành nhiều **thểloại con (sub-**\n**category) khác nhau**, mỗi loại có mục tiêu và phương thức hoạt động riêng biệt:\n\n\n **Spam quảng cáo** (Promotional Spam): Nhằm mục đích tiếp thịsản phẩm, dịch vụ, các chương\ntrình khuyến mãi, giảm giá, hoặc các thông báo trúng thưởng. Đặc điểm của loại này là thường\nchứa các từkhóa liên quan đến mua sắm, giá cả, ưu đãi..."
383
+ },
384
+ {
385
+ "idx": 52,
386
+ "page": 11,
387
+ "score": 0.610893189907074,
388
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n - 2039 mẫu _hard spam_ : được tạo ra đểtăng sốlượng và độphức tạp của các tin nhắn spam, giúp\nmô hình nhận diện tốt hơn các biến thểcủa spam. - 815 mẫu _hard ham_ : là những tin nhắn hợp lệnhưng có chứa từkhóa gần giống spam, buộc mô\nhình phải học cách phân biệt tinh vi hơn giữa hai lớp. - 1053 mẫu được sinh ra bằng kỹthuật _synonym replacement_ (thay thếtừđồng nghĩa), giúp tăng\nsựđa dạng vềmặt ngôn ngữcho cảhai lớp. Kết quảlà một dataset dùng đểphân loại có kích thước 9479 mẫu gồm 6556 mẫu Ham, 2923 mẫu Spam\ncó phân phối cân bằng hơn, tạo nền tảng vững chắc cho việc huấn luyện mô hình phân loại hiệu quả. **Phương pháp**\n\n\nĐểđạt được mục tiêu trên, nhóm mình đã thiết kếmột hệthống data augmentation chuyên biệt, kết\nhợp giữa kỹthuật sinh dữliệu bằng mô hình ngôn ngữlớn (LLM), thay thếtừđồng nghĩa, và khung\nsinh câu theo kịch bản có kiểm soát. Hệthống gồm ba giai đoạn chính:\n\n\n1."
389
+ }
390
+ ],
391
+ "model_verdict": null
392
+ },
393
+ "9": {
394
+ "supported_by_embeddings": true,
395
+ "max_similarity": 0.5543808341026306,
396
+ "evidence": [
397
+ {
398
+ "idx": 39,
399
+ "page": 4,
400
+ "score": 0.5543808341026306,
401
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n\n\n\n**Các lĩnh vực dễbịnhầm lẫn giữa spam và ham**\n\n\nTrong những năm gần đây, sựphát triển của công nghệemail marketing và các hình thức lừa đảo trực\ntuyến đã dẫn đến sựgia tăng mạnh mẽcủa các loại **spam tinh vi** – những tin nhắn rác được _thiết kế_\n_cẩn thận đểvượt qua các bộlọc tựđộng_ . Chúng thường sửdụng ngôn ngữlịch sự, cú pháp tựnhiên như\nemail thật, thậm chí mô phỏng cách viết của email công việc hoặc cá nhân. Cùng lúc đó, cũng tồn tại nhiều email hợp lệ( **ham** ) có chứa các từkhóa như _“transfer”_, _“discount”_,\n_“verify”_ vốn thường xuất hiện trong spam, khiến hệthống nhầm lẫn. Những trường hợp như vậy được\ngọi là **hard ham** – tức là các email hợp pháp nhưng có đặc điểm giống với spam. Vì vậy, các mô hình học máy nếu chỉdựa vào keyword hoặc kỹthuật phân loại đơn giản như TF-IDF,\nNaive Bayes,... sẽkhó đạt hiệu quảcao. Thay vào đó, mô hình cần có khảnăng **hiểu sâu ngữnghĩa**,\nkết hợp thông tin ngữcảnh, cú pháp, và thậm chí cảlịch sửng..."
402
+ }
403
+ ],
404
+ "model_verdict": null
405
+ },
406
+ "10": {
407
+ "supported_by_embeddings": true,
408
+ "max_similarity": 0.5062772035598755,
409
+ "evidence": [
410
+ {
411
+ "idx": 64,
412
+ "page": 27,
413
+ "score": 0.5062772035598755,
414
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n## **7 Semi-supervised đểphân loại sub-category của spam**\n\n\n**7.1** **Vấn đề”Spam” không chỉlà ”Spam”**\n\n\nKhi đối mặt với vấn đềspam, việc phân loại nhịphân (binary classification) thành hai loại ”spam” và\n”không spam” (ham) là chưa đủđểxây dựng một hệthống phòng chống hiệu quả. Bản chất của tin\nnhắn spam đã thay đổi và trởnên đa dạng hơn rất nhiều. Việc coi tất cảcác tin nhắn spam như nhau sẽ\nbỏqua những sắc thái quan trọng, dẫn đến việc chúng ta không thểđưa ra các biện pháp xửlý phù hợp. Khi phân tích sâu hơn, chúng ta thấy rằng spam có thểđược chia thành nhiều **thểloại con (sub-**\n**category) khác nhau**, mỗi loại có mục tiêu và phương thức hoạt động riêng biệt:\n\n\n **Spam quảng cáo** (Promotional Spam): Nhằm mục đích tiếp thịsản phẩm, dịch vụ, các chương\ntrình khuyến mãi, giảm giá, hoặc các thông báo trúng thưởng. Đặc điểm của loại này là thường\nchứa các từkhóa liên quan đến mua sắm, giá cả, ưu đãi..."
415
+ }
416
+ ],
417
+ "model_verdict": null
418
+ },
419
+ "11": {
420
+ "supported_by_embeddings": true,
421
+ "max_similarity": 0.7763429880142212,
422
+ "evidence": [
423
+ {
424
+ "idx": 14,
425
+ "page": 20,
426
+ "score": 0.7428227663040161,
427
+ "text": "**6.1** **Khung Phân loại Trọng sốĐềxuất**\n\n\nVì vậy nhóm đã nghiên cứu và đềxuất áp dụng công thức trọng sốmới trong quá trình voting của KNN\nbằng kết hợp hai yếu tốtương đồng (similarity) và tầm quan trọng tinh tếcủa từng thực thể(saliency). **6.2** **Công thức Cốt lõi**\n\n\nweight( _x_ _j_ _,_ _q_ ) = (1 _−_ _α_ ) _×_ similarity( _x_ _j_ _,_ _q_ ) _×_ ICF( _y_ ( _x_ _j_ )) + _α ×_ saliency( _x_ _j_ _,_ _q_ ) (5)\n\n\nTrong đó:\n\n\n_x_ _j_ _·_ _q_\nsimilarity( _x_ _j_ _, q_ ) = cos( _x_ _j_ _, q_ ) = (6)\n_∥x_ _j_ _∥× ∥q∥_\n\n\n\n_N_\nICF( _c_ _i_ ) =\n_M × n_ _i_\n\n\n\n(7)\n\n\n\nsaliency( _x_ _j_ _, q_ ) = _∥∇_ _x_ _j_ _L_ ( _f_ ( _x_ _j_ ) _,_ ˆ _y_ ) _∥_ 2 (8)\n\n_α ∈_ [0 _,_ 1] (tham sốcân bằng) (9)\n\n\n**6.3** **Quyết định Phân loại Cuối cùng**\n\n\n\nˆ\n_y_ = arg max\n_c_ _i_ _∈C_\n\n\n\n�\n\n_x_ _j_ _∈N_ _K_ ( _q_ )\n_y_ ( _x_ _j_ )= _c_ _i_\n\n\n20\n\n\n\nweight( _x_ _j_ _, q_ ) (10)"
428
+ },
429
+ {
430
+ "idx": 56,
431
+ "page": 24,
432
+ "score": 0.7464016675949097,
433
+ "text": "**6.4.3** **Trọng sốNội dung dựa trên Saliency**\n\n\n**Định nghĩa 3** (Gradient-based Saliency) **.** _Thành phần saliency nắm bắt_ _**tầm quan trọng cụthể**_\n_**theo đầu vào**_ _dựa trên mô hình explainable AI:_\n\n\n_saliency_ ( _x_ _j_ _, q_ ) = _∥∇_ _x_ _j_ _L_ ( _f_ ( _x_ _j_ ) _,_ ˆ _y_ ) _∥_ 2 (38)\n\n\n**6.4.4** **Kết hợp Lồi và Tham sốCân bằng** _α_\n\n\n**Định lý 6.1** (Tính chất Convex Combination) **.** _Tham số_ _α tạo ra_ _**kết hợp lồi**_ _của hai lược đồtrọng_\n_số:_\n\n_weight_ = (1 _−_ _α_ ) _× w_ _similarity×ICF_ + _α × w_ _saliency_ (39)\n\n_Với α ∈_ [0 _,_ 1] _, kết quảnằm trong convex hull của hai thành phần._\n\n\n**6.5** **Phân tích Lý thuyết: Tại sao Công thức này Hợp lý**\n\n\n**6.5.1** **Phân tích Hiệu chỉnh Bias**\n\n\n**Định lý 6.2** (Bias Correction) **.** _Đối với majority voting truyền thống, ảnh hưởng kỳvọng của lớp c_ _i_ _là:_\n\nE[ _Influence_ _traditional_ ( _c_ _i_ )] = _K × P_ ( _c_ _i_ ) = _K ×_ _N_ _[n]_ _[i]_ (40)\n\n\n_Với phương pháp trọng sốcủa chúng ta:_\n\n\nE[ _Influence..."
434
+ },
435
+ {
436
+ "idx": 48,
437
+ "page": 24,
438
+ "score": 0.7763429880142212,
439
+ "text": "]_ (43)\n\n_M_ _[×]_ [ E][[] _[similarity][ ×][ saliency]_ []]\n\n\n24"
440
+ }
441
+ ],
442
+ "model_verdict": null
443
+ },
444
+ "12": {
445
+ "supported_by_embeddings": true,
446
+ "max_similarity": 0.8878604173660278,
447
+ "evidence": [
448
+ {
449
+ "idx": 47,
450
+ "page": 26,
451
+ "score": 0.7113279104232788,
452
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n## **Đánh giá và So sánh Mô hình**\n\n\n**Kết quảmô hình gốc (do TA cung cấp)**\n\n\nChúng tôi tiến hành đánh giá mô hình phân loại KNN ban đầu trên tập kiểm tra gồm 884 mẫu, với các\ngiá trị _k_ khác nhau. Kết quảđộchính xác như sau:\n\n|Giá trị k|Độ chính xác|Số mẫu lỗi|\n|---|---|---|\n|1<br>3<br>5|82.24%<br>88.91%<br>92.87%|157/884<br>98/884<br>63/884|\n\n\n\nBảng 3: Hiệu suất mô hình gốc trên tập kiểm tra\n\n\n**Kết quảmô hình cải tiến (do nhóm phát triển)**\n\n\nVới mô hình cải tiến, chúng tôi đã huấn luyện trên một tập dữliệu lớn hơn rất nhiều (9.400 mẫu), được\ntăng cường từtập dữliệu GDrive gốc thông qua kỹthuật tạo mẫu khó và thay thếtừđồng nghĩa. Kết\nquảđạt được như sau:\n\n|Giá trị k|Độ chính xác|\n|---|---|\n|1<br>3<br>5|86.96%<br>89.68%<br>92.20%|\n\n\n\nBảng 4: Hiệu suất mô hình cải tiến trên tập dữliệu mởrộng\n\n\n**Phân tích kết quả**\n\n\nMô hình cải tiến cho thấy sựvượt trội rõ rệt ởmọi mức _k_ :\n\n\n - Với _k_ = 1: tăng từ **82.24%** lên **86.96%** ( **+4.72%** ). - ..."
453
+ },
454
+ {
455
+ "idx": 9,
456
+ "page": 1,
457
+ "score": 0.8842895030975342,
458
+ "text": "25\n\n6.5.4 Phân tích Consistency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25\n6.6 Kết luận . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25\n\n\n1"
459
+ },
460
+ {
461
+ "idx": 14,
462
+ "page": 20,
463
+ "score": 0.8878604173660278,
464
+ "text": "**6.1** **Khung Phân loại Trọng sốĐềxuất**\n\n\nVì vậy nhóm đã nghiên cứu và đềxuất áp dụng công thức trọng sốmới trong quá trình voting của KNN\nbằng kết hợp hai yếu tốtương đồng (similarity) và tầm quan trọng tinh tếcủa từng thực thể(saliency). **6.2** **Công thức Cốt lõi**\n\n\nweight( _x_ _j_ _,_ _q_ ) = (1 _−_ _α_ ) _×_ similarity( _x_ _j_ _,_ _q_ ) _×_ ICF( _y_ ( _x_ _j_ )) + _α ×_ saliency( _x_ _j_ _,_ _q_ ) (5)\n\n\nTrong đó:\n\n\n_x_ _j_ _·_ _q_\nsimilarity( _x_ _j_ _, q_ ) = cos( _x_ _j_ _, q_ ) = (6)\n_∥x_ _j_ _∥× ∥q∥_\n\n\n\n_N_\nICF( _c_ _i_ ) =\n_M × n_ _i_\n\n\n\n(7)\n\n\n\nsaliency( _x_ _j_ _, q_ ) = _∥∇_ _x_ _j_ _L_ ( _f_ ( _x_ _j_ ) _,_ ˆ _y_ ) _∥_ 2 (8)\n\n_α ∈_ [0 _,_ 1] (tham sốcân bằng) (9)\n\n\n**6.3** **Quyết định Phân loại Cuối cùng**\n\n\n\nˆ\n_y_ = arg max\n_c_ _i_ _∈C_\n\n\n\n�\n\n_x_ _j_ _∈N_ _K_ ( _q_ )\n_y_ ( _x_ _j_ )= _c_ _i_\n\n\n20\n\n\n\nweight( _x_ _j_ _, q_ ) (10)"
465
+ }
466
+ ],
467
+ "model_verdict": null
468
+ },
469
+ "13": {
470
+ "supported_by_embeddings": true,
471
+ "max_similarity": 0.8059824109077454,
472
+ "evidence": [
473
+ {
474
+ "idx": 14,
475
+ "page": 20,
476
+ "score": 0.5798600316047668,
477
+ "text": "**6.1** **Khung Phân loại Trọng sốĐềxuất**\n\n\nVì vậy nhóm đã nghiên cứu và đềxuất áp dụng công thức trọng sốmới trong quá trình voting của KNN\nbằng kết hợp hai yếu tốtương đồng (similarity) và tầm quan trọng tinh tếcủa từng thực thể(saliency). **6.2** **Công thức Cốt lõi**\n\n\nweight( _x_ _j_ _,_ _q_ ) = (1 _−_ _α_ ) _×_ similarity( _x_ _j_ _,_ _q_ ) _×_ ICF( _y_ ( _x_ _j_ )) + _α ×_ saliency( _x_ _j_ _,_ _q_ ) (5)\n\n\nTrong đó:\n\n\n_x_ _j_ _·_ _q_\nsimilarity( _x_ _j_ _, q_ ) = cos( _x_ _j_ _, q_ ) = (6)\n_∥x_ _j_ _∥× ∥q∥_\n\n\n\n_N_\nICF( _c_ _i_ ) =\n_M × n_ _i_\n\n\n\n(7)\n\n\n\nsaliency( _x_ _j_ _, q_ ) = _∥∇_ _x_ _j_ _L_ ( _f_ ( _x_ _j_ ) _,_ ˆ _y_ ) _∥_ 2 (8)\n\n_α ∈_ [0 _,_ 1] (tham sốcân bằng) (9)\n\n\n**6.3** **Quyết định Phân loại Cuối cùng**\n\n\n\nˆ\n_y_ = arg max\n_c_ _i_ _∈C_\n\n\n\n�\n\n_x_ _j_ _∈N_ _K_ ( _q_ )\n_y_ ( _x_ _j_ )= _c_ _i_\n\n\n20\n\n\n\nweight( _x_ _j_ _, q_ ) (10)"
478
+ },
479
+ {
480
+ "idx": 18,
481
+ "page": 7,
482
+ "score": 0.7496178150177002,
483
+ "text": "Tham số _α_ là tham sốđiều chỉnh, quyết định mức độưu tiên của điểm saliency so với độ\ntương đồng tổng thểcủa tin nhắn. - **Vote Scores:** Hệthống hiển thịđiểm sốbỏphiếu cho mỗi lớp ( _Ham_ và _Spam_ ). Dựđoán cuối\ncùng sẽlà lớp có điểm sốcao nhất. - **Spam Subcategory:** Nếu tin nhắn được phân loại là _SPAM_, hệthống tiếp tục phân tích đểxác\nđịnh tiểu mục spam cụthể(ví dụ: _spam_quangcao_, _spam_hethong_ ). **Cơ sởgiải thích (Top neighbors):** Hệthống liệt kê một sốhàng xóm gần nhất trong cơ sởdữ\nliệu vector. Mỗi neighbors bao gồm:\n\n\n**–** _Nhãn (Label):_ Nhãn của tin nhắn gốc ( _ham_ hoặc _spam_ ). **–**\n_Độtương đồng (Similarity):_ Giá trịthểhiện mức độtương đồng giữa tin nhắn đầu vào và\nhàng xóm. **–**\n_Nội dung (Message):_ Nội dung của tin nhắn hàng xóm. 7"
484
+ },
485
+ {
486
+ "idx": 33,
487
+ "page": 6,
488
+ "score": 0.8059824109077454,
489
+ "text": "**Similarity Search (KNN-Classifier):**\n\n\n **Vấn đềtồn đọng:** Phương pháp bỏphiếu đa số( _majority vote_ ) đơn giản trong KNN bỏqua\nmức độquan trọng của từng hàng xóm, nên các điểm ”xa” nhưng đông vẫn có thểáp đảo những\nđiểm ”gần” và ảnh hưởng sai lệch đến kết quảphân loại. **Giải pháp:** Khi có một tin nhắn mới, hệthống tìm kiếm những tin nhắn tương tựnhất. Quyết\nđịnh phân loại được đưa ra bằng Weighted KNN, sửdụng độtương đồng ( _similarity score_ ) làm\ntrọng sốđểưu tiên các hàng xóm gần hơn. 6"
490
+ }
491
+ ],
492
+ "model_verdict": null
493
+ },
494
+ "14": {
495
+ "supported_by_embeddings": true,
496
+ "max_similarity": 1.1322075128555298,
497
+ "evidence": [
498
+ {
499
+ "idx": 53,
500
+ "page": 17,
501
+ "score": 0.6295226812362671,
502
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n**Cấu trúc** BERT-base có **12 lớp encoder**, mỗi lớp bao gồm:\n\n\n1. **Multi-Head Self-Attention** : Cho phép mỗi token “chú ý” đến các token khác trong chuỗi để\ncập nhật vector của nó. Công thức:\n\n\n\n_QK_ _T_\nAttention( _Q, K, V_ ) = softmax\n� ~~_√_~~ _d_ _k_\n\n\n\n_V_\n�\n\n\n\n\n - _Q_, _K_, _V_ : Ma trận query, key, value, được tạo từma trận embedding qua các trọng số _W_ _Q_,\n_W_ _K_, _W_ _V_ . - _d_ _k_ : Kích thước mỗi head (768 / 12 = 64). - Mỗi lớp có **12 head**, mỗi head xửlý một góc nhìn khác của ngữcảnh. Ví dụ: Trong “Nhận ngay quà tặng miễn phí!”, token “miễn” chú ý mạnh đến “quà” và “tặng”,\ntạo ngữcảnh quảng cáo. Attention Mask đảm bảo không chú ý đến [PAD]. Kết quả: Ma trận 16\n_×_ 768, với mỗi token được cập nhật dựa trên ngữcảnh. 2. **Residual Connection và Layer Normalization** : Cộng đầu vào và đầu ra của attention:\n\n\n_x_ + Attention( _x_ )\n\n\nSau đó chuẩn hóa:\nLayerNorm( _x_ + Attention( _x_ ))\n\n\n3. **Feed-Forward Neural Network (FFN)** : ..."
503
+ },
504
+ {
505
+ "idx": 50,
506
+ "page": 7,
507
+ "score": 1.0809839963912964,
508
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n**Explainable AI (XAI) và Classifier:**\n\n\n **Vấn đềtồn đọng:** Mô hình hoạt động như một ”hộp đen”, khó giải thích lý do đưa ra dựđoán. Khảnăng giải thích thường bịtách rời khỏi quá trình phân loại chính. **Giải pháp:** Tích hợp khảnăng giải thích vào lõi của bộphân loại. **–**\n_Masking-based Saliency:_ Phương pháp này xác định các từkhóa quan trọng nhất trong tin\nnhắn. Nói trực quan thì từnào quan trọng trong quyết định spam hơn sẽđược tô đậm hơn. **–**\n_Phân loại có tích hợp Saliency:_ Bộphân loại sửdụng một tham số‘alpha‘ đểđiều chỉnh mức\nđộảnh hưởng của điểm nổi bật (saliency score) vào công thức phân loại cuối cùng, giúp kết\nquảchính xác hơn và có thểgiải thích được. **Đầu ra cuối cùng:** Đầu ra cho mỗi câu gồm thông tin dựđoán và chỉsốgiải thích cho dựđoán đó,\ngiúp người dùng hiểu rõ quyết định của mô hình. Cấu trúc đầu ra bao gồm:\n\n\n - **Lớp dựđoán:** Tin nhắn được gán nhãn dựđoán cuối cùng ( _SPAM_ hoặc _HAM_ ) dựa trên kết quả\nphân loại. *..."
509
+ },
510
+ {
511
+ "idx": 54,
512
+ "page": 22,
513
+ "score": 1.1322075128555298,
514
+ "text": "Lấy ví dụđơn giản, giảsửchúng ta có một mã là một chuỗi nhịphân độdài 5, chẳng hạn như “ `10001` ”. Khi đó, lượng tin của mã này sẽlà 5 bit. Hình 3: Minh họa mối quan hệgiữa nội dung thông tin và tần suất lớp\n\n\nTừlý thuyết thông tin, nội dung thông tin của lớp _c_ _i_ là:\n\n\n\n_n_ _i_\n_I_ ( _c_ _i_ ) = _−_ log 2 ( _P_ ( _c_ _i_ )) = _−_ log 2\n� _N_\n\n\n\n(20)\n�\n\n\n\nICF của chúng ta tỷlệthuận với 2 _[I]_ [(] _[c]_ _[i]_ [)/][ log] [2] [(] _[N]_ [/] _[M]_ [)], có nghĩa là **các lớp hiếm hơn mang nhiều thông**\n**tin hơn** và nên nhận được trọng sốtỷlệcao hơn. **6.4.2** **Trọng sốKhoảng cách dựa trên Similarity**\n\n\n**Định nghĩa 2** (Cosine Similarity Kernel) **.** _Thành phần similarity đảm bảo rằng_ _**láng giềng gần hơn**_\n_**có ảnh hưởng mạnh hơn**_ _:_\n\n\n_x_ _j_ _·_ _q_\n_K_ cos ( _x_ _j_ _, q_ ) = cos( _x_ _j_ _, q_ ) = (21)\n_∥x_ _j_ _∥× ∥q∥_\n\n\n**Mệnh đề2** (Tính chất Kernel) **.** _K_ cos _là một Mercer kernel hợp lệthỏa mãn dựa trên nghiên cứu Ghojogh,_\n_B., Ghodsi, A., Karray, F., & Crowl..."
515
+ }
516
+ ],
517
+ "model_verdict": null
518
+ },
519
+ "15": {
520
+ "supported_by_embeddings": true,
521
+ "max_similarity": 0.9300246834754944,
522
+ "evidence": [
523
+ {
524
+ "idx": 3,
525
+ "page": 28,
526
+ "score": 0.746843695640564,
527
+ "text": "**–**\nNhờđó, mô hình có thểhiểu được sựkhác biệt tinh tếgiữa các cách diễn đạt, xửlý được\ncác từđồng nghĩa và các biến thểngôn ngữ. **Nhược điểm:**\n\n\n**– Đòi hỏi tài nguyên tính toán lớn:** Việc huấn luyện và fine-tuning các mô hình này cần\nnhiều thời gian và chi phí. **– Phức tạp:** Việc fine-tuning cho từng tác vụcụthểcó thểphức tạp. Đặc biệt, nếu không có\nđủdữliệu đã được gán nhãn, hiệu quảcủa các mô hình này sẽbịhạn chế. **7.3** **Phương pháp Semi-supervised sub-category của spam**\n\n\nĐểtận dụng ưu điểm của 2 phương pháp phân loại sub-category phần trên. Chúng tôi đềxuất thực\nhiện một phương pháp semi-supervised bằng cách kết hợp bert embeđings với nối từkhóa. Phương pháp này được gọi là ”bán giám sát” vì nó sửdụng một lượng nhỏdữliệu có nhãn (reference_texts\nvà category_keywords) đểphân loại một lượng lớn dữliệu chưa có nhãn (spam_texts). Tiến trình thực hiện của phương pháp như sau:\n\n\n1. **Bước 1: BERT embeddings**\n\n\n **Tạo Embeddings của Văn bản Spam:** đểbiến mỗi tin nhắn spam ..."
528
+ },
529
+ {
530
+ "idx": 2,
531
+ "page": 15,
532
+ "score": 0.8782092928886414,
533
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\nmua, thanh toán,.... **Bi-directional (hai chiều):** Ngữnghĩa của một từkhông chỉđược biểu diễn bởi những từliền trước\nmà còn được giải thích bởi toàn bộcác từxung quanh. Luồng giải thích tuân theo đồng thời từtrái\nqua phải và từphải qua trái cùng một lúc. Đại diện cho các phép biểu diễn từnày là những mô hình\nsửdụng kỹthuật transformer ví dụnhư BERT. **5.2** **BERT là gì?**\n\n\nBERT (Bidirectional Encoder Representations from Transformers) là một mô hình học sâu tiên tiến do\nGoogle phát triển, nổi bật với khảnăng hiểu ngữcảnh ngôn ngữtựnhiên theo hai chiều. Trong bài toán\nphân loại tin nhắn spam/ham, BERT chuyển đổi tin nhắn thành biểu diễn số, nắm bắt ngữcảnh sâu sắc,\nvà dựđoán nhãn (spam hoặc ham) với độchính xác cao. Kiến trúc BERT-base gồm **12 lớp encoder**\n**Transformer**, mỗi lớp có **768 chiều ẩn** (hidden size) và **12 head attention**, với tổng cộng khoảng\n**110 triệu tham số** . Mô hình được huấn luyện trước trên dữliệu lớn (Wikipedia, Bo..."
534
+ },
535
+ {
536
+ "idx": 16,
537
+ "page": 13,
538
+ "score": 0.9300246834754944,
539
+ "text": "Nếu có thêm thời gian, nhóm sẽmởrộng phương pháp này đểgiải thích cho cảcác câu được\nphân loại là ham, tuy nhiên cách làm sẽhoàn toàn tương tự. **Ý tưởng thuật toán:** Đầu tiên, ta tính `spam_scores` ban đầu — là tổng điểm tương đồng giữa\nembedding của câu đầu vào với các láng giềng có nhãn “spam” trong tập huấn luyện. Sau đó, ta đo\nmức độgiảm điểm `spam_scores` khi lần lượt che từng token, theo các bước sau:\n\n\n13"
540
+ }
541
+ ],
542
+ "model_verdict": null
543
+ },
544
+ "16": {
545
+ "supported_by_embeddings": true,
546
+ "max_similarity": 1.2162450551986694,
547
+ "evidence": [
548
+ {
549
+ "idx": 46,
550
+ "page": 11,
551
+ "score": 0.9961504340171814,
552
+ "text": "**Xây dựng tập cụm ngữnghĩa theo chủđề** : Các nhóm cụm từđược phân loại theo 7 chủđề\ndễgây nhầm lẫn giữa spam và ham, bao gồm:\n\n\n - `financial_phrases` (liên quan đến giao dịch, tiền bạc)\n\n\n - `promotion_phrases` (quảng cáo, ưu đãi)\n\n - `lottery_phrases` (trúng thưởng, phần thưởng)\n\n\n - `scam_alert_phrases` (cảnh báo giảmạo)\n\n\n - `call_to_action_phrases` (dẫn dụngười dùng hành động)\n\n\n - `social_engineering_phrases` (lừa đảo cảm xúc)\n\n - `obfuscated_phrases` (che giấu, tránh bộlọc spam)\n\n\n2. **Sinh dữliệu bằng kịch bản và LLM** :\n\n\n - Với mỗi nhóm cụm từ, nhóm thiết kếmột tập các kịch bản “base” như: _“Hey, did you hear_\n_about...”_, _“Bro, you should check this out”_ ... - Các cụm spam hoặc ham tương ứng được **chèn vào base**, tạo ra các mẫu dữliệu mới, theo\ncấu trúc _“base + insert”_ hoặc _“insert + base”_ . - Ngoài ra, nhóm chúng mình sửdụng LLM (như GPT hoặc Mixtral) đểsinh các câu mới theo\ntemplate kịch bản thực tế, nhằm tái hiện các loại spam ngụy trang phổbiến."
553
+ },
554
+ {
555
+ "idx": 66,
556
+ "page": 3,
557
+ "score": 1.1186320781707764,
558
+ "text": "**Email Spam là gì?**\n\n\n\n\n\n**Ví dụ(Spam Email):**\n\n\n _“Win a brand new iPhone today! Just click this link to claim!”_\n\n\n _“You’ve been selected for a $1000 Walmart gift card!”_\n\n\n _“Invest in crypto now and double your money overnight!”_\n\n\n**Email Ham là gì?**\n\n\n\n\n\n**Ví dụ(Ham Email):**\n\n\n _“Hi John, just a reminder that your doctor’s appointment is at 3PM today.”_\n\n\n _“Your monthly salary has been transferred to your account.”_\n\n\n _“Please review the attached report before the meeting tomorrow.”_\n\n\n3"
559
+ },
560
+ {
561
+ "idx": 26,
562
+ "page": 14,
563
+ "score": 1.2162450551986694,
564
+ "text": "Các kết quảbiểu diễn từđã\ncó bối cảnh nhưng chỉđược giải thích bởi một chiều từtrái qua phải hoặc từphải qua trái. VD:\n\n\n**Câu C:** Hôm nay tôi mang 200 tỷ[gửi] ởngân hàng. **Câu D:** Hôm nay tôi mang 200 tỷ[gửi] …. Như vậy véc tơ biểu diễn của từ **gửi** được xác định thông qua các từliền trước với nó. Nếu chỉdựa vào\ncác từliền trước Hôm nay tôi mang 200 tỷthì ta có thểnghĩ từphù hợp ởvịtrí hiện tại là cho vay,\n\n\n14"
565
+ }
566
+ ],
567
+ "model_verdict": null
568
+ },
569
+ "17": {
570
+ "supported_by_embeddings": true,
571
+ "max_similarity": 0.6036962270736694,
572
+ "evidence": [
573
+ {
574
+ "idx": 21,
575
+ "page": 15,
576
+ "score": 0.5917988419532776,
577
+ "text": "Trong bài toán spam/ham, BERT được tinh\nchỉnh đểtối ưu hóa dựđoán nhãn và tập trung vào các từkhóa quan trọng như “miễn phí” hoặc “quà\ntặng” trong tin nhắn spam. **Ứng dụng** : Trong phân loại tin nhắn spam/ham, BERT chuyển tin nhắn thành vector số, hiểu ngữ\ncảnh sâu sắc (ví dụ: nhận diện ”miễn phí” trong ngữcảnh quảng cáo), và dựđoán nhãn (spam hoặc\nham). **Ưu điểm** :\n\n\n - Hiểu ngữcảnh hai chiều, vượt trội so với các phương pháp truyền thống như TF-IDF. - Sửdụng vector [CLS] đểtổng hợp thông tin toàn câu, phù hợp cho phân loại. **5.3** **Kiến trúc BERT**\n\n\nQuy trình xửlý của BERT bao gồm ba giai đoạn chính:\n\n\n1. **Mã hóa đầu vào** : Chuyển tin nhắn thành token, embedding, và attention mask. 2. **Xửlý qua Transformer encoder** : Tạo biểu diễn ngữcảnh cho từng token, đặc biệt là vector\n\n[CLS]. 3. **Phân loại** : Sửdụng vector [CLS] đểdựđoán nhãn spam/ham. Phần này trình bày chi tiết từng thành phần của kiến trúc BERT và cách chúng hỗtrợbài toán phân\nloại tin nhắn spam/ham. **5.3.1** *..."
578
+ },
579
+ {
580
+ "idx": 1,
581
+ "page": 5,
582
+ "score": 0.6036962270736694,
583
+ "text": "Điều này đặc biệt quan trọng\ntrong các hệthống chống spam hiện đại, giúp người dùng hiểu rõ liệu một email nên bịxóa, xem qua\nhay báo cáo. Ngoài ra, nhóm còn hướng đến việc **mởrộng phân loại chi tiết trong nhóm spam**\n(quảng cáo, hệthống, lừa đảo, v.v...) nhằm tăng trải nghiệm và bảo mật cho người dùng. Hệthống phân loại tin nhắn spam/ham được thiết kếvới cơ chếđầu vào – đầu ra như sau:\n\n\n\n\n\n5"
584
+ }
585
+ ],
586
+ "model_verdict": null
587
+ },
588
+ "18": {
589
+ "supported_by_embeddings": true,
590
+ "max_similarity": 0.974981427192688,
591
+ "evidence": [
592
+ {
593
+ "idx": 3,
594
+ "page": 28,
595
+ "score": 0.5795202255249023,
596
+ "text": "**–**\nNhờđó, mô hình có thểhiểu được sựkhác biệt tinh tếgiữa các cách diễn đạt, xửlý được\ncác từđồng nghĩa và các biến thểngôn ngữ. **Nhược điểm:**\n\n\n**– Đòi hỏi tài nguyên tính toán lớn:** Việc huấn luyện và fine-tuning các mô hình này cần\nnhiều thời gian và chi phí. **– Phức tạp:** Việc fine-tuning cho từng tác vụcụthểcó thểphức tạp. Đặc biệt, nếu không có\nđủdữliệu đã được gán nhãn, hiệu quảcủa các mô hình này sẽbịhạn chế. **7.3** **Phương pháp Semi-supervised sub-category của spam**\n\n\nĐểtận dụng ưu điểm của 2 phương pháp phân loại sub-category phần trên. Chúng tôi đềxuất thực\nhiện một phương pháp semi-supervised bằng cách kết hợp bert embeđings với nối từkhóa. Phương pháp này được gọi là ”bán giám sát” vì nó sửdụng một lượng nhỏdữliệu có nhãn (reference_texts\nvà category_keywords) đểphân loại một lượng lớn dữliệu chưa có nhãn (spam_texts). Tiến trình thực hiện của phương pháp như sau:\n\n\n1. **Bước 1: BERT embeddings**\n\n\n **Tạo Embeddings của Văn bản Spam:** đểbiến mỗi tin nhắn spam ..."
597
+ },
598
+ {
599
+ "idx": 61,
600
+ "page": 26,
601
+ "score": 0.8431670665740967,
602
+ "text": "Những cải thiện này đến từcác yếu tốsau:\n\n\n **Tăng cường dữliệu:** sinh thêm mẫu khó và thay từđồng nghĩa giúp đa dạng hóa ngữcảnh và\nlàm mô hình học được ranh giới phân biệt tốt hơn. **Tập huấn luyện lớn hơn:** từdưới 1.000 mẫu lên hơn 9.000 mẫu giúp mô hình tổng quát hóa\ntốt hơn. **Tập trung vào mẫu khó:** ưu tiên những ví dụgần ranh giới giữa spam/ham nhằm tăng tính\nphân biệt cho mô hình. **Kết luận:** Mô hình mới không chỉđạt hiệu suất cao ở _k_ = 5 mà còn cải thiện đáng kểở _k_ = 1, rất hữu\ních cho các ứng dụng yêu cầu tốc độsuy luận nhanh mà vẫn đảm bảo độchính xác cao. 26"
603
+ },
604
+ {
605
+ "idx": 13,
606
+ "page": 14,
607
+ "score": 0.974981427192688,
608
+ "text": "Hiệu quảbiểu thịnội dung và truyền đạt ý nghĩa sẽlớn hơn so với từng từđứng độc lập. Ngữcảnh trong câu có một sựảnh hưởng rất lớn trong việc giải thích ý nghĩa của từ. Hiểu được vai\ntrò mấu chốt đó, các thuật toán NLP SOTA đều cốgắng đưa ngữcảnh vào mô hình nhằm tạo ra sự\nđột phá, giúp mô hình học được thông tin chính xác hơn. Phân cấp mức độphát triển của các phương pháp embedding từtrong NLP có thểbao gồm các nhóm:\n\n\n**Non-context (không bối cảnh):** Là các thuật toán không tồn tại bối cảnh trong biểu diễn từ. Đó là\ncác thuật toán NLP đời đầu như ‘ word2vec, GLoVe, fasttext‘. Chúng ta chỉcó duy nhất một biểu diễn\nvéc tơ cho mỗi một từmà không thay đổi theo bối cảnh. VD:\n\n\n**Câu A:** Cánh [đồng] này sắp được thu hoạch. **Câu B:** Tôi [đồng] ý với ý kiến của anh! Thì từ **đồng** sẽmang 2 ý nghĩa khác nhau nên phải có hai biểu diễn từriêng biệt. Các thuật toán\nnon-context không đáp ứng được sựđa dạng vềngữnghĩa của từtrong NLP. **Uni-directional (một chiều):** Là các thuật toán đã bắt đ..."
609
+ }
610
+ ],
611
+ "model_verdict": null
612
+ },
613
+ "19": {
614
+ "supported_by_embeddings": true,
615
+ "max_similarity": 0.7636357545852661,
616
+ "evidence": [
617
+ {
618
+ "idx": 14,
619
+ "page": 20,
620
+ "score": 0.6900026798248291,
621
+ "text": "**6.1** **Khung Phân loại Trọng sốĐềxuất**\n\n\nVì vậy nhóm đã nghiên cứu và đềxuất áp dụng công thức trọng sốmới trong quá trình voting của KNN\nbằng kết hợp hai yếu tốtương đồng (similarity) và t���m quan trọng tinh tếcủa từng thực thể(saliency). **6.2** **Công thức Cốt lõi**\n\n\nweight( _x_ _j_ _,_ _q_ ) = (1 _−_ _α_ ) _×_ similarity( _x_ _j_ _,_ _q_ ) _×_ ICF( _y_ ( _x_ _j_ )) + _α ×_ saliency( _x_ _j_ _,_ _q_ ) (5)\n\n\nTrong đó:\n\n\n_x_ _j_ _·_ _q_\nsimilarity( _x_ _j_ _, q_ ) = cos( _x_ _j_ _, q_ ) = (6)\n_∥x_ _j_ _∥× ∥q∥_\n\n\n\n_N_\nICF( _c_ _i_ ) =\n_M × n_ _i_\n\n\n\n(7)\n\n\n\nsaliency( _x_ _j_ _, q_ ) = _∥∇_ _x_ _j_ _L_ ( _f_ ( _x_ _j_ ) _,_ ˆ _y_ ) _∥_ 2 (8)\n\n_α ∈_ [0 _,_ 1] (tham sốcân bằng) (9)\n\n\n**6.3** **Quyết định Phân loại Cuối cùng**\n\n\n\nˆ\n_y_ = arg max\n_c_ _i_ _∈C_\n\n\n\n�\n\n_x_ _j_ _∈N_ _K_ ( _q_ )\n_y_ ( _x_ _j_ )= _c_ _i_\n\n\n20\n\n\n\nweight( _x_ _j_ _, q_ ) (10)"
622
+ },
623
+ {
624
+ "idx": 0,
625
+ "page": 19,
626
+ "score": 0.7097625732421875,
627
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n## **6 KNN with Weight Voting**\n\n\n**1.6.1 Vấn đềMất cân bằng Lớp trong K-Nearest Neighbors**\n\n\nPhân phối lớp mất cân bằng đại diện cho cảthách thức lý thuyết và thực tiễn trong phân loại KNearest Neighbors, được tài liệu hóa rộng rãi trong văn hệmáy học (A survey on imbalanced learning:\nlatest research, applications and future directions: https://link.springer.com/article/10.1007/s10462024-10759-6). Vấn đềnày trởnên đặc biệt nghiêm trọng trong các lĩnh vực có phân phối lớp bịlệch tự\nnhiên, chẳng hạn như phát hiện gian lận (giao dịch gian lận _∼_ 0 _._ 1%), sàng lọc y tế(tỷlệmắc bệnh\n_∼_ 1 _−_ 5%), và lọc thư rác (tỷlệspam _∼_ 10 _−_ 40%). Vấn đềcơ bản xuất phát từviệc KNN dựa vào **majority voting**, hệthống ưu tiên lớp chiếm ưu thế\nbất kểmức độliên quan ngữnghĩa của từng láng giềng. Hình 2: Enter Caption\n\n\n**1.7.1 Hạn chếcủa Majority Voting trong Môi trường Mất cân bằng**\n\n\n**1.7.1.1 Phân tích Toán học vềBias của Majority Voting**\n\n\nGọi _C_ = _{c_ ..."
628
+ },
629
+ {
630
+ "idx": 33,
631
+ "page": 6,
632
+ "score": 0.7636357545852661,
633
+ "text": "**Similarity Search (KNN-Classifier):**\n\n\n **Vấn đềtồn đọng:** Phương pháp bỏphiếu đa số( _majority vote_ ) đơn giản trong KNN bỏqua\nmức độquan trọng của từng hàng xóm, nên các điểm ”xa” nhưng đông vẫn có thểáp đảo những\nđiểm ”gần” và ảnh hưởng sai lệch đến kết quảphân loại. **Giải pháp:** Khi có một tin nhắn mới, hệthống tìm kiếm những tin nhắn tương tựnhất. Quyết\nđịnh phân loại được đưa ra bằng Weighted KNN, sửdụng độtương đồng ( _similarity score_ ) làm\ntrọng sốđểưu tiên các hàng xóm gần hơn. 6"
634
+ }
635
+ ],
636
+ "model_verdict": null
637
+ },
638
+ "20": {
639
+ "supported_by_embeddings": true,
640
+ "max_similarity": 1.0194404125213623,
641
+ "evidence": [
642
+ {
643
+ "idx": 41,
644
+ "page": 19,
645
+ "score": 0.8875085115432739,
646
+ "text": "Đối với điểm truy vấn _q_, KNN truyền thống tính toán:\n\n\nˆ\n_y_ = arg max _c_ _i_ _∈C_ _[|{][x]_ _[j]_ _[ ∈N]_ _[K]_ [(] _[q]_ [) :] _[ y]_ [(] _[x]_ _[j]_ [) =] _[ c]_ _[i]_ _[}|]_ (1)\n\n\n**Phân tích Bias:**\nXác suất đểmột K-neighborhood ngẫu nhiên chứa _k_ thực thểtừlớp _c_ _i_ tuân theo phân phối siêu hình\nhọc:\n\n\n19"
647
+ },
648
+ {
649
+ "idx": 28,
650
+ "page": 16,
651
+ "score": 1.0129456520080566,
652
+ "text": "**Position Embedding** : Biểu diễn vịtrí của token (0, 1, 2, ...) đểgiữthông tin thứtự(Trong\nBERT, Position Embedding không sửdụng hàm sin/cosin như Transformer gốc, mà là các\nvector học được (learned embeddings)). **Segment Embedding** : Phân biệt các câu (thường là 0 cho một tin nhắn). Ví dụ: Token “miễn” ởvịtrí 5:\n\n\n - Token Embedding: `[0.2, 0.1, ..., 0.3]` (768 chiều). - Position Embedding: `[0.01, -0.02, ..., 0.1]` (vịtrí 5). - Segment Embedding: `[0, 0, ..., 0]` (một câu). - Tổng embedding: `[0.21, 0.08, ..., 0.4]` (768 chiều). Kết quả: Ma trận embedding **16** _×_ **768** (16 token _×_ 768 chiều). 4. **Attention Mask** : Vector nhịphân chỉđịnh token nào được xửlý (1 cho token thực, 0 cho [PAD]). Ví dụ: `[1, 1, 1, 1, 1, 1, 1, 1, 1, 0, ..., 0]` (9 token thực, 7 [PAD]). **Liên hệvới spam/ham** Mã hóa đầu vào đảm bảo tin nhắn như “Nhận ngay quà tặng miễn phí!”\nđược chuyển thành ma trận số, với token [CLS] đóng vai trò tổng hợp ngữcảnh (như đặc trưng quảng\ncáo của “miễn phí”) đểhỗ..."
653
+ },
654
+ {
655
+ "idx": 18,
656
+ "page": 7,
657
+ "score": 1.0194404125213623,
658
+ "text": "Tham số _α_ là tham sốđiều chỉnh, quyết định mức độưu tiên của điểm saliency so với độ\ntương đồng tổng thểcủa tin nhắn. - **Vote Scores:** Hệthống hiển thịđiểm sốbỏphiếu cho mỗi lớp ( _Ham_ và _Spam_ ). Dựđoán cuối\ncùng sẽlà lớp có điểm sốcao nhất. - **Spam Subcategory:** Nếu tin nhắn được phân loại là _SPAM_, hệthống tiếp tục phân tích đểxác\nđịnh tiểu mục spam cụthể(ví dụ: _spam_quangcao_, _spam_hethong_ ). **Cơ sởgiải thích (Top neighbors):** Hệthống liệt kê một sốhàng xóm gần nhất trong cơ sởdữ\nliệu vector. Mỗi neighbors bao gồm:\n\n\n**–** _Nhãn (Label):_ Nhãn của tin nhắn gốc ( _ham_ hoặc _spam_ ). **–**\n_Độtương đồng (Similarity):_ Giá trịthểhiện mức độtương đồng giữa tin nhắn đầu vào và\nhàng xóm. **–**\n_Nội dung (Message):_ Nội dung của tin nhắn hàng xóm. 7"
659
+ }
660
+ ],
661
+ "model_verdict": null
662
+ }
663
+ }
664
+ }
test/mcq_output.json CHANGED
@@ -1,162 +1,199 @@
1
  {
2
  "mcqs": {
3
  "1": {
4
- "câu hỏi": "Trong lớp Str_OutputParser, biểu thức chính quy nào được sử dụng để trích xuất câu trả lời từ chuỗi phản hồi?",
5
  "lựa chọn": {
6
- "a": "r\"Answer:\\s*(.*)\"",
7
- "b": "r\"Respuesta:\\s*(.*)\"",
8
- "c": "r\"Answer :\\s*(.*)\"",
9
- "d": "r\"Result:\\s*(.*)\""
10
  },
11
- "đáp án": "r\"Answer :\\s*(.*)\""
12
  },
13
  "2": {
14
- "câu hỏi": "Trong dự án RAG, file nào được dùng để khai báo các hàm load file PDF?",
15
  "lựa chọn": {
16
- "a": "src/rag/main.py",
17
- "b": "src/rag/file_loader.py",
18
- "c": "src/rag/offline_rag.py",
19
- "d": "src/rag/utils.py"
20
  },
21
- "đáp án": "src/rag/file_loader.py"
22
  },
23
  "3": {
24
- "câu hỏi": "Trong file src/rag/vectorstore.py, lớp nào được đặt làm giá trị mặc định cho vector database?",
25
  "lựa chọn": {
26
- "a": "FAISS",
27
- "b": "Chroma",
28
- "c": "Pinecone",
29
- "d": "Milvus"
30
  },
31
- "đáp án": "Chroma"
32
  },
33
  "4": {
34
- "câu hỏi": "Trong đoạn mã được trích dẫn, tham số nào được sử dụng cho kiểu lượng tử (quantization type) trong cấu hình BitsAndBytesConfig?",
35
  "lựa chọn": {
36
- "a": "nf4",
37
- "b": "int8",
38
- "c": "fp16",
39
- "d": "int4"
40
  },
41
- "đáp án": "nf4"
42
  },
43
  "5": {
44
- "câu hỏi": "Theo tả trong nội dung, bước nào liên quan đến việc tạo sở dữ liệu vector bằng mô hình embedding?",
45
  "lựa chọn": {
46
- "a": "Tách danh sách các bài báo khoa học thành các văn bản nhỏ.",
47
- "b": "Xây dựng một sở dữ liệu vector từ các văn bản nhỏ bằng hình embedding.",
48
- "c": "Truy vấn các mẫu văn bản liên quan đến câu hỏi đầu vào để làm ngữ cảnh.",
49
- "d": "Đưa câu prompt (câu hỏingữ cảnh) vào hình để nhận câu trả lời."
50
  },
51
- "đáp án": "Xây dựng một sở dữ liệu vector từ các văn bản nhỏ bằng hình embedding."
52
  }
53
  },
54
  "validation": {
55
  "1": {
56
  "supported_by_embeddings": true,
57
- "max_similarity": 0.5152225494384766,
58
  "evidence": [
59
  {
60
- "idx": 26,
61
- "page": 15,
62
- "score": 0.5152225494384766,
63
- "text": "Ý nghĩa của phương thức `from_template()` trong class PromptTemplate là? ( _a_ ) Đểkhởi tạo prompt template từmột file. ( _b_ ) Đểkhởi tạo prompt template từmột string. ( _c_ ) Đểkhởi tạo prompt template từmột danh sách các tin nhắn. ( _d_ ) Đểkhởi tạo prompt template từmột prompt template sẵn. 15"
 
 
 
 
 
 
 
 
 
 
 
 
64
  }
65
  ],
66
  "model_verdict": {
67
- "supported": false,
68
- "confidence": 0.9,
69
- "evidence": "",
70
- "reason": "Context không chứa thông tin về lớp Str_OutputParser hay biểu thức chính quy được sử dụng, vì vậy không thể chứng thực đáp án được đưa ra."
71
  }
72
  },
73
  "2": {
74
  "supported_by_embeddings": true,
75
- "max_similarity": 0.694902777671814,
76
  "evidence": [
77
  {
78
- "idx": 4,
79
- "page": 4,
80
- "score": 0.694902777671814,
81
- "text": "**AI VIETNAM (AIO2024)** **aivietnam.edu.vn**\n\n\n_ **src/rag/:** Thư mục dùng đểlưu trữcác code liên quan đến xây dựng RAG, bao gồm:\n\n\n1. **src/rag/file_loader.py:** File code dùng đểkhai báo các hàm load file pdf (vì tài\nliệu của chúng ta thu thập thuộc file pdf). 2. **src/rag/main.py:** File code dùng đểkhai báo hàm khởi tạo chains. 3. **src/rag/offline_rag.py:** File code dùng đểkhai báo PromptTemplate. 4. **src/rag/utils.py:** File code dùng đểkhai báo hàm tách câu trảlời từmodel. 5. **src/rag/vectorstore.py:** File code dùng đểkhai báo hàm khởi tạo hệcơ sởdữliệu\n\nvector. _ **src/app.py:** File code dùng đểkhởi tạo API. _ **requirements.txt:** File code dùng đểkhai báo các thư viện cần thiết đểsửdụng source\ncode. ## II.2. Cập nhật file requirements.txt\n\n\nĐểbắt đầu, chúng ta sẽliệt kê các gói thư viện cần thiết đểchạy được chương trình này."
82
  },
83
  {
84
- "idx": 28,
85
- "page": 16,
86
- "score": 0.5763600468635559,
87
- "text": "document_loaders` `import` `PyPDFLoader`\n\n\n2\n\n\n3 `pdf_loader = PyPDFLoader(url, extract_images =` `True` `)`\n\n\n4\n\n\n5 `docs = pdf_loader.load ()`\n\n\nTham số `extract_images` tại dòng code 3 chức năng gì? ( _a_ ) Trảvềtất cảảnh từfile pdf. ( _b_ ) Bỏqua ảnh, chỉload text. ( _c_ ) Phân tích ảnh thành vector. ( _d_ ) Chuyển đổi ảnh trong file pdf thành text. 16"
88
  },
89
  {
90
- "idx": 16,
91
- "page": 9,
92
- "score": 0.5420067310333252,
93
- "text": "**AI VIETNAM (AIO2024)** **aivietnam.edu.vn**\n\n\n86 `return` `self.load(files, workers=workers)`\n\n## II.6. Cập nhật file src/rag/vectorstore.py\n\n\nTại file này, ta định nghĩa một class đểkhởi tạo hệcơ sởdữliệu vector. Trong project này, chúng\nta sẽsửdụng Chroma. Vềviệc tìm kiếm tài liệu tương đồng, ta sửdụng FAISS. Như vậy, nội\ndung của file như sau:\n\n\nHình 4: Minh họa việc sửdụng vector database Chroma đểtruy vấn các tài liệu có liên quan\n[làm context trong prompt. Ảnh: Link.](https://heidloff.net/article/retrieval-augmented-generation-chroma-langchain/)\n\n\n1 `from` `typing` `import` `Union`\n\n2 `from` `langchain_chroma` `import` `Chroma`\n\n3 `from` `langchain_community .vectorstores` `import` `FAISS`\n\n4 `from` `langchain_community .embeddings` `import` `HuggingFaceEmbeddings`\n\n\n5\n\n\n6 `class` `VectorDB:`\n\n\n7 `def` `__init__(self,`\n\n\n8 `documents = None,`\n\n9 `vector_db: Union[Chroma, FAISS] = Chroma,`\n\n10 `embedding = HuggingFaceEmbeddings (),`\n\n11 `) -> None` `:`\n\n\n12\n\n\n13 `self.vector_db ..."
94
  }
95
  ],
96
  "model_verdict": {
97
  "supported": true,
98
  "confidence": 0.99,
99
- "evidence": "src/rag/file_loader.py: File code dùng để khai báo các hàm load file pdf",
100
- "reason": "Context explicitly states that src/rag/file_loader.py declares functions for loading PDF files, matching the answer."
101
  }
102
  },
103
  "3": {
104
  "supported_by_embeddings": true,
105
- "max_similarity": 0.579485297203064,
106
  "evidence": [
107
  {
108
- "idx": 20,
109
- "page": 11,
110
- "score": 0.579485297203064,
111
- "text": "Cập nhật file src/rag/main.py\n\n\nTại file này, ta khởi tạo toàn bộcác instance của các class, các hàm ta đã khai báo trước đó\nvà kết nối chúng vào trong một hàm duy nhất gọi `build_rag_chain()` :\n\n\n1 `from` `pydantic` `import` `BaseModel, Field`\n\n\n2\n\n\n3 `from src.rag.file_loader` `import` `Loader`\n\n4 `from src.rag.vectorstore` `import` `VectorDB`\n\n5 `from src.rag.offline_rag` `import` `Offline_RAG`\n\n\n6\n\n\n7 `class` `InputQA(BaseModel):`\n\n8 `question: str = Field (..., title=` `\"Question to ask the model\"` `)`\n\n\n9\n\n\n10 `class` `OutputQA(BaseModel):`\n\n11 `answer: str = Field (..., title=` `\"Answer` `from the model\"` `)`\n\n\n12\n\n\n13 `def` `build_rag_chain (llm, data_dir, data_type):`\n\n14 `doc_loaded = Loader(file_type=data_type).load_dir(data_dir, workers=2)`\n\n15 `retriever = VectorDB(documents = doc_loaded).get_retriever ()`\n\n16 `rag_chain = Offline_RAG(llm).get_chain(retriever)`\n\n\n17\n\n\n18 `return` `rag_chain`\n\n\n11"
 
 
 
 
 
 
112
  },
113
  {
114
- "idx": 16,
115
- "page": 9,
116
- "score": 0.5778905749320984,
117
- "text": "**AI VIETNAM (AIO2024)** **aivietnam.edu.vn**\n\n\n86 `return` `self.load(files, workers=workers)`\n\n## II.6. Cập nhật file src/rag/vectorstore.py\n\n\nTại file này, ta định nghĩa một class đểkhởi tạo hệcơ sởdữliệu vector. Trong project này, chúng\nta sẽsửdụng Chroma. Vềviệc tìm kiếm tài liệu tương đồng, ta sửdụng FAISS. Như vậy, nội\ndung của file như sau:\n\n\nHình 4: Minh họa việc sửdụng vector database Chroma đểtruy vấn các tài liệu có liên quan\n[làm context trong prompt. Ảnh: Link.](https://heidloff.net/article/retrieval-augmented-generation-chroma-langchain/)\n\n\n1 `from` `typing` `import` `Union`\n\n2 `from` `langchain_chroma` `import` `Chroma`\n\n3 `from` `langchain_community .vectorstores` `import` `FAISS`\n\n4 `from` `langchain_community .embeddings` `import` `HuggingFaceEmbeddings`\n\n\n5\n\n\n6 `class` `VectorDB:`\n\n\n7 `def` `__init__(self,`\n\n\n8 `documents = None,`\n\n9 `vector_db: Union[Chroma, FAISS] = Chroma,`\n\n10 `embedding = HuggingFaceEmbeddings (),`\n\n11 `) -> None` `:`\n\n\n12\n\n\n13 `self.vector_db ..."
118
  }
119
  ],
120
  "model_verdict": {
121
  "supported": true,
122
- "confidence": 1.0,
123
- "evidence": "vector_db: Union[Chroma, FAISS] = Chroma",
124
- "reason": "Mặc định của tham số vector_db trong class VectorDB được đặt là Chroma"
125
  }
126
  },
127
  "4": {
128
- "supported_by_embeddings": false,
129
- "max_similarity": 0.43995893001556396,
130
- "evidence": [],
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  "model_verdict": {
132
- "supported": false,
133
- "confidence": 0.95,
134
- "evidence": "",
135
- "reason": "Trong nội dung Context không bất kỳ đoạn nào đề cập đến BitsAndBytesConfig hay tham số kiểu lượng tử, vì vậy không thể chứng thực đáp án nf4."
136
  }
137
  },
138
  "5": {
139
  "supported_by_embeddings": true,
140
- "max_similarity": 0.6268875598907471,
141
  "evidence": [
142
  {
143
- "idx": 1,
144
- "page": 2,
145
- "score": 0.6268875598907471,
146
- "text": "**AI VIETNAM (AIO2024)** **aivietnam.edu.vn**\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nHình 2: Tổng quan vềpipeline của project.\n\n\n**Theo đó:**\n\n\n1. Từdanh sách các bài báo khoa học, ta tách thành các văn bản nhỏ. Từđó, xây dựng một\nhệcơ sởdữliệu vector với một embedding model.\n\n\n2. Bên cạnh câu hỏi đầu vào (question), ta truy vấn các mẫu văn bản liên quan đến đến\ncâu hỏi, dùng làm ngữcảnh (context) trong câu prompt. Đây nguồn thông tin LLMs\ncó thểdựa vào đểtrảlời câu hỏi.\n\n\n3. Đưa câu prompt vào hình (question context) đểnhận câu trảlời từmô hình.\n\n\n2"
 
 
 
 
 
 
147
  },
148
  {
149
- "idx": 30,
150
- "page": 17,
151
- "score": 0.5708718299865723,
152
- "text": "split_documents (pdf_pages)`\n\n\n18\n\n\n19 _`# Embedding`_ _`model`_\n\n20 `embedding_model = HuggingFaceEmbeddings ()`\n\n\n21\n\n\n22 _`# vector`_ _`store`_\n\n\n23 `chroma_db = Chroma.from_documents(docs, embedding= embedding_model )`\n\n\nNhiệm vụcủa `embedding_model` gì? ( _a_ ) Dùng biến đổi chuỗi đầu vào thành các vector cho sởdữliệu vector. ( _b_ ) Dùng đểlập chỉmục cho sởdữliệu. ( _c_ ) Dùng đểtìm kiếm tài liệu. ( _d_ ) Dùng đểtính toán độtương đồng. 17"
153
  }
154
  ],
155
  "model_verdict": {
156
  "supported": true,
157
  "confidence": 0.99,
158
- "evidence": "1. Từ danh sách các bài báo khoa học, ta tách thành các văn bản nhỏ. Từ đó, xây dựng một hẹcơ sở dữ liệu vector với một embedding model.",
159
- "reason": "Context explicitly states that after splitting documents, a vector database is built using an embedding model, matching the chosen answer."
160
  }
161
  }
162
  }
 
1
  {
2
  "mcqs": {
3
  "1": {
4
+ "câu hỏi": "Trong bảng tổng hợp các nhóm nội dung dễ gây nhầm lẫn, nhóm nào liên quan đến giao dịch tiền bạc?",
5
  "lựa chọn": {
6
+ "a": "promotion_phrases",
7
+ "b": "financial_phrases",
8
+ "c": "lottery_phrases",
9
+ "d": "scam_alert_phrases"
10
  },
11
+ "đáp án": "financial_phrases"
12
  },
13
  "2": {
14
+ "câu hỏi": "Theo tả về kiến trúc BERT‑base trong nội dung, hình này bao nhiêu lớp encoder Transformer?",
15
  "lựa chọn": {
16
+ "a": "10",
17
+ "b": "12",
18
+ "c": "24",
19
+ "d": "48"
20
  },
21
+ "đáp án": "12"
22
  },
23
  "3": {
24
+ "câu hỏi": "Theo Định lý 6.1 (Tính chất Convex Combination), công thức tính trọng số kết hợp bằng tham số α là gì?",
25
  "lựa chọn": {
26
+ "a": "weight = (1 - α) × w_similarity × ICF + α × w_saliency",
27
+ "b": "weight = α × w_similarity × ICF + (1 - α) × w_saliency",
28
+ "c": "weight = w_similarity + w_saliency",
29
+ "d": "weight = α × (w_similarity + w_saliency)"
30
  },
31
+ "đáp án": "weight = (1 - α) × w_similarity × ICF + α × w_saliency"
32
  },
33
  "4": {
34
+ "câu hỏi": "Theo nội dung, một nhược điểm của phương pháp dựa trên từ khóa trong việc phát hiện spam là gì?",
35
  "lựa chọn": {
36
+ "a": "Có thể xử lý các biến thể và lỗi chính tả",
37
+ "b": "Thiếu linh hoạt khi từ khóa thay đổi",
38
+ "c": "Không hiểu ngữ cảnh của từ trong các câu",
39
+ "d": "Đòi hỏi tính toán phức tạp"
40
  },
41
+ "đáp án": "Không hiểu ngữ cảnh của từ trong các câu"
42
  },
43
  "5": {
44
+ "câu hỏi": "Theo đoạn văn, điều nào sau đây tả đúng về mô hình BERT?",
45
  "lựa chọn": {
46
+ "a": "BERT 12 lớp encoder, mỗi lớp kích thước ẩn 768 và 12 attention head.",
47
+ "b": "BERT chỉ được huấn luyện bằng nhiệm vụ Dự đoán câu tiếp theo (Next Sentence Prediction - NSP).",
48
+ "c": "BERT sử dụng kiến trúc một chiều, chỉ xử văn bản từ trái sang phải.",
49
+ "d": "BERT bao gồm 24 lớp encoder kích thước ẩn 1024."
50
  },
51
+ "đáp án": "BERT 12 lớp encoder, mỗi lớp kích thước ẩn 768 12 attention head."
52
  }
53
  },
54
  "validation": {
55
  "1": {
56
  "supported_by_embeddings": true,
57
+ "max_similarity": 1.0912104845046997,
58
  "evidence": [
59
  {
60
+ "idx": 27,
61
+ "page": 4,
62
+ "score": 0.7866219282150269,
63
+ "text": "Dưới đây bảng tổng hợp các nhóm nội dung dễgây nhầm lẫn – xuất hiện trong cảham và spam tinh\nvi, đòi hỏi mô hình phải rất tinh tếmới phân biệt được:\n\n\n\n|Nhóm nội dung|Ví dụ nội dung|Dễ nhầm với|\n|---|---|---|\n|`financial_phrases`|“Please<br>confrm<br>the<br>$200<br>transfer<br>from<br>your<br>account.”<br>“Your invoice for June is now available.”|Scam / Phishing|\n|`promotion_phrases`|“Flash sale ends tonight 30% of all items!”<br>“Exclusive discount for HUST students.”|Spam quảng cáo|\n|`lottery_phrases`|“You’ve been selected for a loyalty reward.”<br>“You may be eligible for a lucky draw.”|Spam quà tặng /<br>Random Reward|\n|`scam_alert_phrases`|“Unusual login detected. Was this you?”<br>“A payment attempt was blocked on your card.”|Cảnh báo giả/ Giả<br>danh ngân hàng|\n|`call_to_action_phrases`|“Act now to secure your spot in the seminar.”<br>“Verify your email to complete registration.”|Spam ép buộc /<br>Confrmation bait|\n\n\n4"
64
+ },
65
+ {
66
+ "idx": 46,
67
+ "page": 11,
68
+ "score": 0.7944862842559814,
69
+ "text": "**Xây dựng tập cụm ngữnghĩa theo chủđề** : Các nhóm cụm từđược phân loại theo 7 chủđề\ndễgây nhầm lẫn giữa spam và ham, bao gồm:\n\n\n - `financial_phrases` (liên quan đến giao dịch, tiền bạc)\n\n\n - `promotion_phrases` (quảng cáo, ưu đãi)\n\n - `lottery_phrases` (trúng thưởng, phần thưởng)\n\n\n - `scam_alert_phrases` (cảnh báo giảmạo)\n\n\n - `call_to_action_phrases` (dẫn dụngười dùng hành động)\n\n\n - `social_engineering_phrases` (lừa đảo cảm xúc)\n\n - `obfuscated_phrases` (che giấu, tránh bộlọc spam)\n\n\n2. **Sinh dữliệu bằng kịch bản và LLM** :\n\n\n - Với mỗi nhóm cụm từ, nhóm thiết kếmột tập các kịch bản “base” như: _“Hey, did you hear_\n_about...”_, _“Bro, you should check this out”_ ... - Các cụm spam hoặc ham tương ứng được **chèn vào base**, tạo ra các mẫu dữliệu mới, theo\ncấu trúc _“base + insert”_ hoặc _“insert + base”_ . - Ngoài ra, nhóm chúng mình sửdụng LLM (như GPT hoặc Mixtral) đểsinh các câu mới theo\ntemplate kịch bản thực tế, nhằm tái hiện các loại spam ngụy trang phổbiến."
70
+ },
71
+ {
72
+ "idx": 44,
73
+ "page": 12,
74
+ "score": 1.0912104845046997,
75
+ "text": "Tuy nhiên sau khi chèn cụm “$200 cashback”, nó trởthành\nmột tin nhắn spam ngụy trang. Những câu như vậy rất khó nhận diện nếu chỉhuấn luyện từtập dữ\nliệu spam kiểu cũ. **Tác dụng**\n\n\nViệc áp dụng data augmentation theo hướng có kiểm soát giúp:\n\n\n **Giảm hiện tượng bias** của mô hình khi gặp spam đời thực, vốn thường mang ngôn ngữtựnhiên\nvà ẩn dụhơn là spam thô sơ kiểu “FREE!!! Click now!!!”\n\n\n **Tăng độrobust** của hệthống khi xửlý các tin nhắn có bềngoài giống ham nhưng nội dung\ntiềm ẩn spam. 12"
76
  }
77
  ],
78
  "model_verdict": {
79
+ "supported": true,
80
+ "confidence": 0.99,
81
+ "evidence": "`financial_phrases` (liên quan đến giao dịch, tiền bạc)",
82
+ "reason": "Context explicitly states that the group 'financial_phrases' is related to transactions and money."
83
  }
84
  },
85
  "2": {
86
  "supported_by_embeddings": true,
87
+ "max_similarity": 1.0187240839004517,
88
  "evidence": [
89
  {
90
+ "idx": 30,
91
+ "page": 16,
92
+ "score": 0.6454246044158936,
93
+ "text": "**5.3.2** **Transformer Encoder**\n\n\n**Mục tiêu** Các lớp Transformer encoder xửlý ma trận embedding đểtạo biểu diễn ngữcảnh sâu sắc\ncho mỗi token, đặc biệt vector [CLS], giúp nắm bắt mối quan hệgiữa các từtrong tin nhắn. 16"
94
  },
95
  {
96
+ "idx": 53,
97
+ "page": 17,
98
+ "score": 0.9272838234901428,
99
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n**Cấu trúc** BERT-base có **12 lớp encoder**, mỗi lớp bao gồm:\n\n\n1. **Multi-Head Self-Attention** : Cho phép mỗi token “chú ý” đến các token khác trong chuỗi để\ncập nhật vector của nó. Công thức:\n\n\n\n_QK_ _T_\nAttention( _Q, K, V_ ) = softmax\n� ~~_√_~~ _d_ _k_\n\n\n\n_V_\n�\n\n\n\n\n - _Q_, _K_, _V_ : Ma trận query, key, value, được tạo từma trận embedding qua các trọng số _W_ _Q_,\n_W_ _K_, _W_ _V_ . - _d_ _k_ : Kích thước mỗi head (768 / 12 = 64). - Mỗi lớp có **12 head**, mỗi head xửlý một góc nhìn khác của ngữcảnh. dụ: Trong “Nhận ngay quà tặng miễn phí!”, token “miễn” chú ý mạnh đến “quà” và “tặng”,\ntạo ngữcảnh quảng cáo. Attention Mask đảm bảo không chú ý đến [PAD]. Kết quả: Ma trận 16\n_×_ 768, với mỗi token được cập nhật dựa trên ngữcảnh. 2. **Residual Connection và Layer Normalization** : Cộng đầu vào và đầu ra của attention:\n\n\n_x_ + Attention( _x_ )\n\n\nSau đó chuẩn hóa:\nLayerNorm( _x_ + Attention( _x_ ))\n\n\n3. **Feed-Forward Neural Network (FFN)** : ..."
100
  },
101
  {
102
+ "idx": 32,
103
+ "page": 28,
104
+ "score": 1.0187240839004517,
105
+ "text": "Các chuỗi này đóng vai trò ”điểm neo” ngữnghĩa cho mỗi loại. hình BERT\ncũng tạo ra một vector nhúng cho mỗi chuỗi này\n\n\n28"
106
  }
107
  ],
108
  "model_verdict": {
109
  "supported": true,
110
  "confidence": 0.99,
111
+ "evidence": "BERT-base **12 lớp encoder**",
112
+ "reason": "Context explicitly states BERT-base has 12 encoder layers, matching the answer."
113
  }
114
  },
115
  "3": {
116
  "supported_by_embeddings": true,
117
+ "max_similarity": 0.808438777923584,
118
  "evidence": [
119
  {
120
+ "idx": 14,
121
+ "page": 20,
122
+ "score": 0.7317581176757812,
123
+ "text": "**6.1** **Khung Phân loại Trọng sốĐềxuất**\n\n\nVì vậy nhóm đã nghiên cứu đềxuất áp dụng công thức trọng sốmới trong quá trình voting của KNN\nbằng kết hợp hai yếu tốtương đồng (similarity) tầm quan trọng tinh tếcủa từng thực thể(saliency). **6.2** **Công thức Cốt lõi**\n\n\nweight( _x_ _j_ _,_ _q_ ) = (1 _−_ _α_ ) _×_ similarity( _x_ _j_ _,_ _q_ ) _×_ ICF( _y_ ( _x_ _j_ )) + ×_ saliency( _x_ _j_ _,_ _q_ ) (5)\n\n\nTrong đó:\n\n\n_x_ _j_ _·_ _q_\nsimilarity( _x_ _j_ _, q_ ) = cos( _x_ _j_ _, q_ ) = (6)\n_∥x_ _j_ _∥× ∥q∥_\n\n\n\n_N_\nICF( _c_ _i_ ) =\n_M × n_ _i_\n\n\n\n(7)\n\n\n\nsaliency( _x_ _j_ _, q_ ) = _∥∇_ _x_ _j_ _L_ ( _f_ ( _x_ _j_ ) _,_ ˆ _y_ ) _∥_ 2 (8)\n\n_α ∈_ [0 _,_ 1] (tham sốcân bằng) (9)\n\n\n**6.3** **Quyết định Phân loại Cuối cùng**\n\n\n\nˆ\n_y_ = arg max\n_c_ _i_ _∈C_\n\n\n\n\n\n_x_ _j_ _∈N_ _K_ ( _q_ )\n_y_ ( _x_ _j_ )= _c_ _i_\n\n\n20\n\n\n\nweight( _x_ _j_ _, q_ ) (10)"
124
+ },
125
+ {
126
+ "idx": 56,
127
+ "page": 24,
128
+ "score": 0.765610933303833,
129
+ "text": "**6.4.3** **Trọng sốNội dung dựa trên Saliency**\n\n\n**Định nghĩa 3** (Gradient-based Saliency) **.** _Thành phần saliency nắm bắt_ _**tầm quan trọng cụthể**_\n_**theo đầu vào**_ _dựa trên mô hình explainable AI:_\n\n\n_saliency_ ( _x_ _j_ _, q_ ) = _∥∇_ _x_ _j_ _L_ ( _f_ ( _x_ _j_ ) _,_ ˆ _y_ ) _∥_ 2 (38)\n\n\n**6.4.4** **Kết hợp Lồi và Tham sốCân bằng** _α_\n\n\n**Định lý 6.1** (Tính chất Convex Combination) **.** _Tham số_ _α tạo ra_ _**kết hợp lồi**_ _của hai lược đồtrọng_\n_số:_\n\n_weight_ = (1 _−_ _α_ ) _× w_ _similarity×ICF_ + _α × w_ _saliency_ (39)\n\n_Với α ∈_ [0 _,_ 1] _, kết quảnằm trong convex hull của hai thành phần._\n\n\n**6.5** **Phân tích Lý thuyết: Tại sao Công thức này Hợp lý**\n\n\n**6.5.1** **Phân tích Hiệu chỉnh Bias**\n\n\n**Định lý 6.2** (Bias Correction) **.** _Đối với majority voting truyền thống, ảnh hưởng kỳvọng của lớp c_ _i_ _là:_\n\nE[ _Influence_ _traditional_ ( _c_ _i_ )] = _K × P_ ( _c_ _i_ ) = _K ×_ _N_ _[n]_ _[i]_ (40)\n\n\n_Với phương pháp trọng sốcủa chúng ta:_\n\n\nE[ _Influence..."
130
  },
131
  {
132
+ "idx": 41,
133
+ "page": 19,
134
+ "score": 0.808438777923584,
135
+ "text": "Đối với điểm truy vấn _q_, KNN truyền thống tính toán:\n\n\\n_y_ = arg max _c_ _i_ _∈C_ _[|{][x]_ _[j]_ _[ ∈N]_ _[K]_ [(] _[q]_ [) :] _[ y]_ [(] _[x]_ _[j]_ [) =] _[ c]_ _[i]_ _[}|]_ (1)\n\n\n**Phân tích Bias:**\nXác suất đểmột K-neighborhood ngẫu nhiên chứa _k_ thực thểtừlớp _c_ _i_ tuân theo phân phối siêu hình\nhọc:\n\n\n19"
136
  }
137
  ],
138
  "model_verdict": {
139
  "supported": true,
140
+ "confidence": 0.99,
141
+ "evidence": "weight = (1 - α) × w_similarity×ICF + α × w_saliency (39)",
142
+ "reason": "Công thức trong Định 6.1 khớp với đáp án đã cho"
143
  }
144
  },
145
  "4": {
146
+ "supported_by_embeddings": true,
147
+ "max_similarity": 0.5541524291038513,
148
+ "evidence": [
149
+ {
150
+ "idx": 21,
151
+ "page": 15,
152
+ "score": 0.5191619992256165,
153
+ "text": "Trong bài toán spam/ham, BERT được tinh\nchỉnh đểtối ưu hóa dựđoán nhãn và tập trung vào các từkhóa quan trọng như “miễn phí” hoặc “quà\ntặng” trong tin nhắn spam. **Ứng dụng** : Trong phân loại tin nhắn spam/ham, BERT chuyển tin nhắn thành vector số, hiểu ngữ\ncảnh sâu sắc (ví dụ: nhận diện ”miễn phí” trong ngữcảnh quảng cáo), và dựđoán nhãn (spam hoặc\nham). **Ưu điểm** :\n\n\n - Hiểu ngữcảnh hai chiều, vượt trội so với các phương pháp truyền thống như TF-IDF. - Sửdụng vector [CLS] đểtổng hợp thông tin toàn câu, phù hợp cho phân loại. **5.3** **Kiến trúc BERT**\n\n\nQuy trình xửlý của BERT bao gồm ba giai đoạn chính:\n\n\n1. **Mã hóa đầu vào** : Chuyển tin nhắn thành token, embedding, và attention mask. 2. **Xửlý qua Transformer encoder** : Tạo biểu diễn ngữcảnh cho từng token, đặc biệt là vector\n\n[CLS]. 3. **Phân loại** : Sửdụng vector [CLS] đểdựđoán nhãn spam/ham. Phần này trình bày chi tiết từng thành phần của kiến trúc BERT và cách chúng hỗtrợbài toán phân\nloại tin nhắn spam/ham. **5.3.1** *..."
154
+ },
155
+ {
156
+ "idx": 57,
157
+ "page": 10,
158
+ "score": 0.5541524291038513,
159
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n2. **Thiếu dữliệu vềspam tinh vi (Subtle or Obfuscated Spam)** :\n\n\n - Phần lớn mẫu spam trong tập train có dạng “truyền thống” — sửdụng từkhóa dễnhận\ndiện như _“FREE!!!”_, _“WIN now”_, _“Click here”_,... - Trong khi đó, spam thực tếngày nay ngày càng được thiết kếtinh vi hơn để **bắt chước văn**\n**phong tựnhiên của người thật**, ví dụ:\n\n\n_“Yo, this app gave me $200 cashback instantly, you should try =«”_\n\n\n - Do thiếu các ví dụkiểu này trong tập huấn luyện, mô hình không có cơ hội học được “ngữ\nnghĩa tiềm ẩn” của chúng, từđó dễbịđánh lừa. **2.2** **Giải pháp: Data Augmentation**\n\n\n**Mục tiêu**\n\n\nTăng độđa dạng của spam, đặc biệt là spam có dạng giống ham, nhằm:\n\n\n - Cân bằng dữliệu một cách hiệu quả\n\n\n - Tăng khảnăng mô hình phát hiện spam ngụy trang và những câu ham dễnhầm thành spam\n\n\n**Mô tảthay đổi của dataset trước và sau Augmentation**\n\n\nDataset gốc là _SMS Spam Collection Dataset_ từKaggle, có tổng cộng 5.572 tin nhắn, trong đó có 4.82..."
160
+ }
161
+ ],
162
  "model_verdict": {
163
+ "supported": true,
164
+ "confidence": 0.99,
165
+ "evidence": "Không hiểu ngữcảnh: Không thể phân biệt được ý nghĩa của một từ trong các ngữcảnh khác nhau.",
166
+ "reason": "Context explicitly lists 'Không hiểu ngữcảnh' as a disadvantage of keyword-based spam detection."
167
  }
168
  },
169
  "5": {
170
  "supported_by_embeddings": true,
171
+ "max_similarity": 1.0499497652053833,
172
  "evidence": [
173
  {
174
+ "idx": 53,
175
+ "page": 17,
176
+ "score": 0.7536194324493408,
177
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n**Cấu trúc** BERT-base có **12 lớp encoder**, mỗi lớp bao gồm:\n\n\n1. **Multi-Head Self-Attention** : Cho phép mỗi token “chú ý” đến các token khác trong chuỗi để\ncập nhật vector của nó. Công thức:\n\n\n\n_QK_ _T_\nAttention( _Q, K, V_ ) = softmax\n� ~~_√_~~ _d_ _k_\n\n\n\n_V_\n\n\n\n\n\n - _Q_, _K_, _V_ : Ma trận query, key, value, được tạo từma trận embedding qua các trọng số _W_ _Q_,\n_W_ _K_, _W_ _V_ . - _d_ _k_ : Kích thước mỗi head (768 / 12 = 64). - Mỗi lớp **12 head**, mỗi head xửlý một góc nhìn khác của ngữcảnh. dụ: Trong “Nhận ngay quà tặng miễn phí!”, token “miễn” chú ý mạnh đến “quà” “tặng”,\ntạo ngữcảnh quảng cáo. Attention Mask đảm bảo không chú ý đến [PAD]. Kết quả: Ma trận 16\n_×_ 768, với mỗi token được cập nhật dựa trên ngữcảnh. 2. **Residual Connection Layer Normalization** : Cộng đầu vào đầu ra của attention:\n\n\n_x_ + Attention( _x_ )\n\n\nSau đó chuẩn hóa:\nLayerNorm( _x_ + Attention( _x_ ))\n\n\n3. **Feed-Forward Neural Network (FFN)** : ..."
178
+ },
179
+ {
180
+ "idx": 50,
181
+ "page": 7,
182
+ "score": 1.0445164442062378,
183
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n**Explainable AI (XAI) và Classifier:**\n\n\n **Vấn đềtồn đọng:** Mô hình hoạt động như một ”hộp đen”, khó giải thích lý do đưa ra dựđoán. Khảnăng giải thích thường bịtách rời khỏi quá trình phân loại chính. **Giải pháp:** Tích hợp khảnăng giải thích vào lõi của bộphân loại. **–**\n_Masking-based Saliency:_ Phương pháp này xác định các từkhóa quan trọng nhất trong tin\nnhắn. Nói trực quan thì từnào quan trọng trong quyết định spam hơn sẽđược tô đậm hơn. **–**\n_Phân loại có tích hợp Saliency:_ Bộphân loại sửdụng một tham số‘alpha‘ đểđiều chỉnh mức\nđộảnh hưởng của điểm nổi bật (saliency score) vào công thức phân loại cuối cùng, giúp kết\nquảchính xác hơn và có thểgiải thích được. **Đầu ra cuối cùng:** Đầu ra cho mỗi câu gồm thông tin dựđoán và chỉsốgiải thích cho dựđoán đó,\ngiúp người dùng hiểu rõ quyết định của mô hình. Cấu trúc đầu ra bao gồm:\n\n\n - **Lớp dựđoán:** Tin nhắn được gán nhãn dựđoán cuối cùng ( _SPAM_ hoặc _HAM_ ) dựa trên kết quả\nphân loại. *..."
184
  },
185
  {
186
+ "idx": 42,
187
+ "page": 18,
188
+ "score": 1.0499497652053833,
189
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\n**Kết quả** Sau 12 lớp encoder, mỗi token có vector 768 chiều, chứa thông tin ngữcảnh sâu sắc. Vector\n\n[CLS] (hàng đầu tiên của ma trận đầu ra) tổng hợp ngữcảnh toàn tin nhắn, ví dụ: `[0.7, -0.1, ...,`\n`0.5]`, phản ánh đặc trưng spam như “miễn phí”, “quà”. **Liên hệvới spam/ham** Attention giúp BERT nhận diện mối quan hệgiữa các từ(như “miễn phí”\nvà “quà” gợi ý spam). FFN tinh chỉnh vector đểnhấn mạnh đặc trưng riêng của mỗi token, hỗtrợ\nvector [CLS] mang thông tin quảng cáo hoặc giao tiếp tựnhiên. **5.3.3** **Lớp Phân Loại**\n\n\n**Mục tiêu** Sửdụng vector [CLS] đểdựđoán nhãn spam (1) hoặc ham (0) cho tin nhắn. **Quy trình**\n\n\n1. **Lớp tuyến tính** : Vector [CLS] (768 chiều) được đưa qua lớp tuyến tính:\n\n\nlogits = _W_ cls _·_ vector [CLS] + _b_ cls\n\n\n - _W_ cls : Ma trận 768 _×_ 2 (2 nhãn: spam, ham). - _b_ cls : Bias 2 chiều. dụ: Vector [CLS] `[0.7, -0.1, ..., 0.5]` _→_ Logits `[2.8, -0.7]` . 2. **Softmax** : Chuyển logits thành xác suất:\n\n\nexp(..."
190
  }
191
  ],
192
  "model_verdict": {
193
  "supported": true,
194
  "confidence": 0.99,
195
+ "evidence": "BERT-base 12 lớp encoder ... Mỗi lớp 12 head ... mỗi token vector 768 chiều",
196
+ "reason": "Context xác nhận BERT-base 12 lớp encoder, hidden size 768 12 attention head, nên đáp án a được chứng thực."
197
  }
198
  }
199
  }
test/oop_mcq_output.json ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "mcqs": {
3
+ "1": {
4
+ "câu hỏi": "Trong ví dụ minh họa lớp Cat, khi gọi cat.describe(2), dòng lệnh `print(self.age)` sẽ in ra giá trị nào?",
5
+ "lựa chọn": {
6
+ "a": "2 (giá trị truyền vào hàm, là biến cục bộ)",
7
+ "b": "1 (giá trị của biến lớp)",
8
+ "c": "Lỗi vì self.age không được định nghĩa",
9
+ "d": "0 (giá trị mặc định của biến toàn cục)"
10
+ },
11
+ "đáp án": "1 (giá trị của biến lớp)"
12
+ },
13
+ "2": {
14
+ "câu hỏi": "Theo nội dung trên, biến nào được mô tả là “thông tin tuyệt mật – chỉ lớp khai báo nó mới có quyền truy cập”?",
15
+ "lựa chọn": {
16
+ "a": "private",
17
+ "b": "protected",
18
+ "c": "public",
19
+ "d": "static"
20
+ },
21
+ "đáp án": "private"
22
+ },
23
+ "3": {
24
+ "câu hỏi": "Biến cục bộ (local variable) trong lập trình hướng đối tượng có đặc điểm nào sau đây?",
25
+ "lựa chọn": {
26
+ "a": "Có thể truy cập ở bất kỳ đâu trong chương trình",
27
+ "b": "Chỉ tồn tại và có thể sử dụng trong một hàm hoặc phương thức cụ thể",
28
+ "c": "Là biến toàn cục được khai báo bên ngoài hàm",
29
+ "d": "Biến được tự động khởi tạo giá trị mặc định"
30
+ },
31
+ "đáp án": "Chỉ tồn tại và có thể sử dụng trong một hàm hoặc phương thức cụ thể"
32
+ },
33
+ "4": {
34
+ "câu hỏi": "Trong lập trình hướng đối tượng, thuộc tính (attributes) của một đối tượng là gì?",
35
+ "lựa chọn": {
36
+ "a": "Các hàm thực hiện hành động của đối tượng",
37
+ "b": "Các biến lưu trữ dữ liệu mô tả đối tượng",
38
+ "c": "Các lớp mà đối tượng kế thừa từ chúng",
39
+ "d": "Các phương thức tĩnh không phụ thuộc vào đối tượng"
40
+ },
41
+ "đáp án": "Các biến lưu trữ dữ liệu mô tả đối tượng"
42
+ },
43
+ "5": {
44
+ "câu hỏi": "Trong Python, phương thức đặc biệt nào cho phép một đối tượng được gọi như một hàm?",
45
+ "lựa chọn": {
46
+ "a": "__init__",
47
+ "b": "__str__",
48
+ "c": "__call__",
49
+ "d": "__len__"
50
+ },
51
+ "đáp án": "__call__"
52
+ }
53
+ },
54
+ "validation": {
55
+ "1": {
56
+ "supported_by_embeddings": true,
57
+ "max_similarity": 1.0644214153289795,
58
+ "evidence": [
59
+ {
60
+ "idx": 1,
61
+ "page": 1,
62
+ "score": 0.6182047724723816,
63
+ "text": "**Biến cục bộ(Local)**\n\n\nBiến cục bộchỉtồn tại và có thểsửdụng trong một hàm hoặc phương thức cụthể. **Quy tắc ưu tiên (Scope resolution):**\n\n\nLocal _>_ Instance _>_ Class _>_ Global (1)\n\n\n**Ví dụminh họa:**\n\n\n1 `class Cat():`\n\n\n2 `age = 1 #Class variabe`\n\n3 `def describe(self, age):`\n\n4 `print(age, age)` `# Ouput: 2,2 (both are local variables)`\n\n5 `print(self.age)` `# Output: 1 (class variable)`\n\n\n6\n\n\n7 `cat = Cat()`\n\n\n8 `cat.describe(2)`\n\n\n1"
64
+ },
65
+ {
66
+ "idx": 2,
67
+ "page": 2,
68
+ "score": 0.9349313378334045,
69
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\nCảhai biến age ởlần in đầu tiên đều là biến cục bộvì Python sẽưu tiên tìm biến cục bộtrước,\nởđây là đối số2 truyền vào age. Vì ta không định nghĩa self.age, nên khi gọi, Python sẽtìm đến\nthứtựtiếp theo là biến Class. Chính vì vậy, ta sẽin ra được kết quảage = 1\n\n\n**1.1.2** **Biến toàn cục (Global)**\n\n\nBiến toàn cục được khai báo bên ngoài hàm hoặc class, sửdụng được trên toàn chương trình\nnhưng nên hạn chếđểtránh gây khó kiểm soát. **Không khuyến khích:**\n\n\n1 `counter = 0` `# Global variable`\n\n\n2\n\n\n3 `class MyClass:`\n\n4 `def increment(self):`\n\n\n5 `global counter`\n\n\n6 `counter += 1`\n\n\n**Khuyến khích:**\n\n\n1 `class MyClass:`\n\n\n2 `counter = 0` `# Class attribute`\n\n\n3\n\n\n4 `def increment(self):`\n\n\n5 `MyClass.counter += 1`\n\n### **2 Động lực cho sựra đời của OOP**\n\n\nTrong thực tế, chúng ta luôn tìm cách mô hình hóa các thực thểthực tếthành các đối tượng số\nhóa. Từnhu cầu quản lý và tổchức các thực thểnày, lập trình hướng đối tượng ra đời đểđơn\ngiản hóa và ..."
70
+ },
71
+ {
72
+ "idx": 8,
73
+ "page": 5,
74
+ "score": 1.0644214153289795,
75
+ "text": "es a function →Output: Hi Alice`\n\n\n2. **Stateful function** : Hàm có thểghi nhớtrạng thái bên trong. 1 `class Counter:`\n\n\n2 `def __init__(self):`\n\n\n3 `self.count = 0`\n\n\n4\n\n\n5 `def __call__(self):`\n\n\n6 `self.count += 1`\n\n\n7 `return self.count`\n\n\n8\n\n\n9 `counter = Counter()`\n\n\n10\n\n\n11 `print(counter())` `# 1`\n\n12 `print(counter())` `# 2`\n\n13 `print(counter())` `# 3`\n\n\nMỗi lần gọi `counter()` đều ghi nhớtrạng thái trước đó và cộng dồn lên, không giống như\ncác phương thức thông thường vốn không lưu trạng thái giữa các lần gọi. 3. **Decorator hoặc Callback handler** : (nâng cao cần tìm hiểu thêm). ## **Phần II: Các tính chất cơ bản trong Object-** **Oriented Programming**\n\n### **5** **Delegation (Ủy quyền)**\n\n\nDelegation (ủy quyền) trong lập trình hướng đối tượng là một kỹthuật trong đó một đối tượng\nủy thác trách nhiệm thực hiện một hành vi cụthểcho một đối tượng khác. Thay vì kếthừa trực\n\n\n5"
76
+ }
77
+ ],
78
+ "model_verdict": {
79
+ "supported": true,
80
+ "confidence": 0.99,
81
+ "evidence": "print(self.age) # Output: 1 (class variable)",
82
+ "reason": "Context explicitly states that print(self.age) outputs 1, the class variable."
83
+ }
84
+ },
85
+ "2": {
86
+ "supported_by_embeddings": true,
87
+ "max_similarity": 1.3231226205825806,
88
+ "evidence": [
89
+ {
90
+ "idx": 15,
91
+ "page": 8,
92
+ "score": 1.0267785787582397,
93
+ "text": "p con của nó đều phải **bắt buộc** có phương thức tính diện\ntích. Nếu không, chương trình sẽbáo lỗi. ### **8 Encapsulation (Đóng gói)**\n\n\nTính đóng gói giúp thông tin nội bộcủa đối tượng và chỉcho phép truy cập qua phương thức\ncông khai (public methods). Điều này giúp bảo vệdữliệu và kiểm soát cách dữliệu bịthay đổi. **Ví dụminh họa:**\n\n\n1 `class BankAccount:`\n\n\n2 `def __init__(self, owner, balance):`\n\n\n3 `self.owner = owner`\n\n\n4 `self.__balance = balance` `# \"__\" indicates this is a private attribute`\n\n\n5\n\n\n6 `def deposit(self, amount):`\n\n\n7 `if amount > 0:`\n\n\n8 `self.__balance += amount`\n\n9 `print(f\"Deposited: {amount}\")`\n\n\n10 `else:`\n\n\n11 `print(\"Invalid deposit amount.\")`\n\n\n12\n\n\n13 `def withdraw(self, amount):`\n\n\n14 `if 0 < amount <= self.__balance:`\n\n\n15 `self.__balance -= amount`\n\n\n8"
94
+ },
95
+ {
96
+ "idx": 4,
97
+ "page": 3,
98
+ "score": 1.3231226205825806,
99
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\nTương tự:\nGiảsửbạn là một người quản lý thư viện. Trong đó, sách và người đọc chính là những đối tượng\n(objects), còn các quy trình như mượn sách, trảsách, đăng ký thẻđược xem là phương thức\n(methods) – tức là hành vi của các đối tượng. Đểcó thểquản lý hiệu quảtất cảcác đối tượng\nvà hành vi trong hệthống thư viện này, ta cần một cách tổchức logic và linh hoạt. Chính từ\nnhu cầu đó, lập trình hướng đối tượng (OOP) ra đời – như một phương pháp giúp mô hình hóa\nthếgiới thực thành các thành phần trong phần mềm một cách rõ ràng và dễmởrộng.\n\n### **3 Class và Object**\n\n#### **3.1 Class (Lớp)**\n\n\nClass như một bản vẽkỹthuật hoặc template, dùng đểđịnh nghĩa thuộc tính (attributes) và\nphương thức (methods) của các đối tượng.\n\n - **Attributes:** định nghĩa các thông tin, đặc điểm cũng như các thuộc tính của Object.\n\n\n - **Method** : định nghĩa các hành vi, phương thức cũng như các hành động thường có của\nObject\n\n\n3"
100
+ }
101
+ ],
102
+ "model_verdict": {
103
+ "supported": true,
104
+ "confidence": 0.99,
105
+ "evidence": "\"Biến `private` là thông tin tuyệt mật – chỉ lớp khai báo nó mới có quyền truy cập\"",
106
+ "reason": "Context explicitly mô tả biến private như vậy, nên đáp án private được chứng thực."
107
+ }
108
+ },
109
+ "3": {
110
+ "supported_by_embeddings": true,
111
+ "max_similarity": 1.127091884613037,
112
+ "evidence": [
113
+ {
114
+ "idx": 1,
115
+ "page": 1,
116
+ "score": 0.8878949880599976,
117
+ "text": "**Biến cục bộ(Local)**\n\n\nBiến cục bộchỉtồn tại và có thểsửdụng trong một hàm hoặc phương thức cụthể. **Quy tắc ưu tiên (Scope resolution):**\n\n\nLocal _>_ Instance _>_ Class _>_ Global (1)\n\n\n**Ví dụminh họa:**\n\n\n1 `class Cat():`\n\n\n2 `age = 1 #Class variabe`\n\n3 `def describe(self, age):`\n\n4 `print(age, age)` `# Ouput: 2,2 (both are local variables)`\n\n5 `print(self.age)` `# Output: 1 (class variable)`\n\n\n6\n\n\n7 `cat = Cat()`\n\n\n8 `cat.describe(2)`\n\n\n1"
118
+ },
119
+ {
120
+ "idx": 0,
121
+ "page": 1,
122
+ "score": 1.107263207435608,
123
+ "text": "# Tuần 3: Tổng hợp kiến thức buổi học số3 + 4\n\n#### Time-Series Team Ngày 21 tháng 6 năm 2025\n\n\n\n\n## **Phần I: Khái niệm cơ bản vềObject-Oriented** **Programming: Lập tr��nh hướng đối tượng**\n\n### **1** **Giới thiệu vềlập trình hướng đối tượng**\n\nLập trình hướng đối tượng (OOP) là một phương pháp lập trình phổbiến, lấy các đối tượng làm\ntrung tâm đểgiải quyết vấn đềthực tế. Đểhiểu rõ OOP, ta cần nắm các khái niệm cơ bản như\nphạm vi biến, trừu tượng hóa, lớp, đối tượng và các tính chất đặc trưng như kếthừa, đa hình,\nđóng gói và trừu tượng. #### **1.1** **Bước đầu cho OOP - Khái niệm biến local và global (biến cục bộ** **và biến toàn cục)**\n\n\nPhạm vi (scope) biến là yếu tốquan trọng trong lập trình, quyết định nơi một biến có thểtruy\ncập được. **1.1.1** **Biến cục bộ(Local)**\n\n\nBiến cục bộchỉtồn tại và có thểsửdụng trong một hàm hoặc phương thức cụthể."
124
+ },
125
+ {
126
+ "idx": 9,
127
+ "page": 6,
128
+ "score": 1.127091884613037,
129
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n\ntiếp hoặc xửlý toàn bộlogic nội bộ, đối tượng sẽgọi đến phương thức của một thành phần bên\ntrong đểthực hiện nhiệm vụ. Kỹthuật này giúp tách biệt trách nhiệm giữa các lớp, dễbảo trì\nvà mởrộng hệthống và tăng tính tái sửdụng của mã nguồn."
130
+ }
131
+ ],
132
+ "model_verdict": {
133
+ "supported": true,
134
+ "confidence": 0.99,
135
+ "evidence": "Biến cục bộ chỉ tồn tại và có thể sử dụng trong một hàm hoặc phương thức cụ thể.",
136
+ "reason": "Câu trả lời khớp với mô tả trong Context về đặc điểm của biến cục bộ."
137
+ }
138
+ },
139
+ "4": {
140
+ "supported_by_embeddings": true,
141
+ "max_similarity": 1.02956223487854,
142
+ "evidence": [
143
+ {
144
+ "idx": 5,
145
+ "page": 4,
146
+ "score": 0.7977743148803711,
147
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n#### **3.2** **Object (Đối tượng)**\n\n\nObject là một thực thểcụthểđược tạo ra từclass, chứa các giá trịthuộc tính cụthểvà khả\nnăng thực hiện các phương thức đã định nghĩa. ### **4 Cách tạo một Class**\n\n\nMột class diagram bao gồm: tên class, attributes, và methods. Sau khi khởi tạo, ta tạo ra một\nobject là instance của class vừa tạo. **Constructor (** **`__init__`** **):** được dùng đểtạo và gán giá trịban đầu cho các thuộc tính (attributes)\ncủa đối tượng.Nói một cách đơn giản, constructor giống như bản thiết kếban đầu giúp ta xác\nđịnh: ”Khi tạo ra một đối tượng mới, nó sẽcó những thông tin gì?”\n\n\n**Self keyword:** Là tham chiếu đến instance cụthểcủa class. **Ví dụ:**\n\n\n1 `class Rectangle:`\n\n2 `def __init__(self, width, height):`\n\n\n3 `self.width = width`\n\n\n4 `self.height = height`\n\n\n5\n\n\n6 `def area(self):`\n\n\n7 `return self.width * self.height`\n\n\n8\n\n\n9 `my_rec = Rectangle(4, 7)`\n\n10 `print(my_rec.area())` `# Output: 28`\n\n\nTa hình dung “self” là một vùn..."
148
+ },
149
+ {
150
+ "idx": 0,
151
+ "page": 1,
152
+ "score": 1.02956223487854,
153
+ "text": "# Tuần 3: Tổng hợp kiến thức buổi học số3 + 4\n\n#### Time-Series Team Ngày 21 tháng 6 năm 2025\n\n\n\n\n## **Phần I: Khái niệm cơ bản vềObject-Oriented** **Programming: Lập trình hướng đối tượng**\n\n### **1** **Giới thiệu vềlập trình hướng đối tượng**\n\nLập trình hướng đối tượng (OOP) là một phương pháp lập trình phổbiến, lấy các đối tượng làm\ntrung tâm đểgiải quyết vấn đềthực tế. Đểhiểu rõ OOP, ta cần nắm các khái niệm cơ bản như\nphạm vi biến, trừu tượng hóa, lớp, đối tượng và các tính chất đặc trưng như kếthừa, đa hình,\nđóng gói và trừu tượng. #### **1.1** **Bước đầu cho OOP - Khái niệm biến local và global (biến cục bộ** **và biến toàn cục)**\n\n\nPhạm vi (scope) biến là yếu tốquan trọng trong lập trình, quyết định nơi một biến có thểtruy\ncập được. **1.1.1** **Biến cục bộ(Local)**\n\n\nBiến cục bộchỉtồn tại và có thểsửdụng trong một hàm hoặc phương thức cụthể."
154
+ }
155
+ ],
156
+ "model_verdict": {
157
+ "supported": true,
158
+ "confidence": 0.98,
159
+ "evidence": "Những thông tin như ngày sinh, giới tính, sốđiện thoại... được xem là thuộc tính (attributes) của người dùng đó.",
160
+ "reason": "Context mô tả thuộc tính là các thông tin dữ liệu mô tả đối tượng, khớp với đáp án."
161
+ }
162
+ },
163
+ "5": {
164
+ "supported_by_embeddings": true,
165
+ "max_similarity": 1.0307352542877197,
166
+ "evidence": [
167
+ {
168
+ "idx": 5,
169
+ "page": 4,
170
+ "score": 0.9137221574783325,
171
+ "text": "**AI VIETNAM** **aivietnam.edu.vn**\n\n#### **3.2** **Object (Đối tượng)**\n\n\nObject là một thực thểcụthểđược tạo ra từclass, chứa các giá trịthuộc tính cụthểvà khả\nnăng thực hiện các phương thức đã định nghĩa. ### **4 Cách tạo một Class**\n\n\nMột class diagram bao gồm: tên class, attributes, và methods. Sau khi khởi tạo, ta tạo ra một\nobject là instance của class vừa tạo. **Constructor (** **`__init__`** **):** được dùng đểtạo và gán giá trịban đầu cho các thuộc tính (attributes)\ncủa đối tượng.Nói một cách đơn giản, constructor giống như bản thiết kếban đầu giúp ta xác\nđịnh: ”Khi tạo ra một đối tượng mới, nó sẽcó những thông tin gì?”\n\n\n**Self keyword:** Là tham chiếu đến instance cụthểcủa class. **Ví dụ:**\n\n\n1 `class Rectangle:`\n\n2 `def __init__(self, width, height):`\n\n\n3 `self.width = width`\n\n\n4 `self.height = height`\n\n\n5\n\n\n6 `def area(self):`\n\n\n7 `return self.width * self.height`\n\n\n8\n\n\n9 `my_rec = Rectangle(4, 7)`\n\n10 `print(my_rec.area())` `# Output: 28`\n\n\nTa hình dung “self” là một vùn..."
172
+ },
173
+ {
174
+ "idx": 3,
175
+ "page": 2,
176
+ "score": 1.0307352542877197,
177
+ "text": "gười dùng chính là một đối tượng (object). Những thông tin như ngày sinh, giới tính, sốđiện thoại... được xem là thuộc tính (attributes)\ncủa người dùng đó. Còn các hành vi như đăng bài, thích (like), chia sẻ(share), bình luận, kết\nbạn... chính là những phương thức (methods) – tức là hành động mà đối tượng đó có thểthực\nhiện. Đây chính là cách mà lập trình hướng đối tượng mô hình hóa và tổchức các thực thểtrong\nthếgiới số. 2"
178
+ }
179
+ ],
180
+ "model_verdict": {
181
+ "supported": true,
182
+ "confidence": 0.99,
183
+ "evidence": "Trong Python, `__call__` là một phương thức đặc biệt ... được sửdụng khi một đối tượng cần hành xử giống như một hàm. Nếu một lớp định nghĩa `__call__`, thì các instance của lớp đó có thể được gọi như một hàm thực sự.",
184
+ "reason": "Context explicitly states that __call__ is the special method allowing objects to be called like functions."
185
+ }
186
+ }
187
+ }
188
+ }
test/output.json DELETED
The diff for this file is too large to render. See raw diff
 
test/politic_mcq_output.json ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "mcqs": {
3
+ "1": {
4
+ "câu hỏi": "Theo nội dung, tính chất chính trị của tôn giáo chỉ xuất hiện khi nào?",
5
+ "lựa chọn": {
6
+ "a": "Khi xã hội không có giai cấp và không có xung đột lợi ích",
7
+ "b": "Khi xã hội đã phân chia giai cấp, có sự khác biệt, sự đối kháng về lợi ích",
8
+ "c": "Khi tôn giáo được nhà nước kiểm soát chặt chẽ",
9
+ "d": "Khi nền kinh tế phát triển mạnh và không có bất bình xã hội"
10
+ },
11
+ "đáp án": "Khi xã hội đã phân chia giai cấp, có sự khác biệt, sự đối kháng về lợi ích"
12
+ },
13
+ "2": {
14
+ "câu hỏi": "Theo nội dung, giai cấp công nhân hiện đại bao gồm những nhóm nào sau đây?",
15
+ "lựa chọn": {
16
+ "a": "Là sản phẩm và chủ thể của nền đại công nghiệp.",
17
+ "b": "Là nguồn nhân lực chủ yếu tham gia phát triển kinh tế thị trường định hướng XHCN.",
18
+ "c": "Bao gồm giai cấp nông dân và thợ thủ công.",
19
+ "d": "Được đại diện bởi Đảng Cộng sản."
20
+ },
21
+ "đáp án": "Bao gồm giai cấp nông dân và thợ thủ công."
22
+ },
23
+ "3": {
24
+ "câu hỏi": "Theo nội dung trên, yếu tố nào được nêu là một trong những điều kiện kinh tế để chủ nghĩa xã hội ra đời?",
25
+ "lựa chọn": {
26
+ "a": "Sự phát triển của công nghiệp cơ khí",
27
+ "b": "Sự giảm chênh lệch giàu nghèo",
28
+ "c": "Sự tồn tại của nền kinh tế kế hoạch",
29
+ "d": "Sự tăng trưởng của nông nghiệp truyền thống"
30
+ },
31
+ "đáp án": "Sự phát triển của công nghiệp cơ khí"
32
+ },
33
+ "4": {
34
+ "câu hỏi": "Theo nội dung trên, trong các đặc trưng bản chất của chủ nghĩa xã hội do Mác nêu, đặc điểm nào sau đây không được liệt kê?",
35
+ "lựa chọn": {
36
+ "a": "Có nền kinh tế phát triển cao",
37
+ "b": "Có nhà nước kiểu mới mang bản chất GCCN",
38
+ "c": "Có nền văn hóa phát triển cao",
39
+ "d": "Có hệ thống chính trị đa đảng"
40
+ },
41
+ "đáp án": "Có hệ thống chính trị đa đảng"
42
+ },
43
+ "5": {
44
+ "câu hỏi": "Theo quan điểm cơ bản của Marx‑Lenin, sứ mệnh lịch sử của Cách mạng xã hội chủ nghĩa (CNXH) là gì?",
45
+ "lựa chọn": {
46
+ "a": "Sự phát triển kinh tế nhanh chóng",
47
+ "b": "Sứ mệnh lịch sử là những nhiệm vụ quan trọng, thiêng liêng buộc phải thực hiện trong một điều kiện, hoàn cảnh lịch sử cụ thể nhất định",
48
+ "c": "Tăng cường quan hệ quốc tế",
49
+ "d": "Đảm bảo quyền lợi cá nhân"
50
+ },
51
+ "đáp án": "Sứ mệnh lịch sử là những nhiệm vụ quan trọng, thiêng liêng buộc phải thực hiện trong một điều kiện, hoàn cảnh lịch sử cụ thể nhất định"
52
+ }
53
+ },
54
+ "validation": {
55
+ "1": {
56
+ "supported_by_embeddings": true,
57
+ "max_similarity": 0.7614468336105347,
58
+ "evidence": [
59
+ {
60
+ "idx": 45,
61
+ "page": 23,
62
+ "score": 0.7614468336105347,
63
+ "text": "Nguồn gốc nhân thức\nNguồn gốc tâm lí\n\n##### **Tính chất của tôn giáo**\n\n\n Các điều kiện kinh tế-xã hội là cho các tôn giáo bịphân liệt, chia rẽ\n\n Các tôn giáo là nơi sinh hoạt văn hóa tinh thần của một cộng đồng\n\n TÍnh chất chính trịcủa tôn giáo chỉxuất hiện khi xã hội đã phân chia giai cấp,\ncó sựkhác biệt, sựđối kháng vềlợi ích. ##### **Nguyên tắc trong giải quyết vấn đềtôn giáo**\n\n\n Tôn trọng, đảm bảo quyền tựdo tín ngưỡng và không tín ngưỡng của nhân\n\ndân\n\n Khắc phục dần những ảnh hưởng tiêu cực của tôn giáo phải gắn liền với quá\ntrình cỉa tạo xã hội cũ, xây dựng xa hội mới."
64
+ },
65
+ {
66
+ "idx": 23,
67
+ "page": 23,
68
+ "score": 0.7602448463439941,
69
+ "text": "Phân biệt hai mặt chính trịvà tư tưởng, tín ngưỡng tôn giáo và lợi dụng tín\nngưỡng tôn giáo\n\n Quan điểm lịch sửcụthểtrong giải quyết vấn đềtín ngưỡng, tôn giáo\n\n##### **Tác động của tôn giáo**\n\n\n Khuyến khích đoàn kết, khoan dung giữa các tôn giáo, phát huy các giá trịtốt\nđẹp của tôn giáo\n\n Có vai trò xây dựng đối với xã hội và đóng góp những giá trịtốt đẹp\n\n Kênh quan trọng đểthúc đẩy mởrộng đối ngoại\n\n Phòng chống xung đột, kiến tạo hòa bình, quản trịxã hội\nTác hại tiêu cực của tôn giáo: phương hại đến chính sách tựdo tìn ngưỡng, nhân\nthức thái quá và sai lệch vềĐảng và nhà nước, thu tiền trái phép\n\n##### **Chính sách của Đảng và nhà nước**\n\n\n - Là nhu cầu tinh thần\n\n Tôn trọng quyền tựdo, tín ngưỡng, thực hiện chính sách đại đoàn kết là chính\nsách nhất quán, xuyên suốt của Đảng\n\n##### **Phương hướng hoạt động trong thời gian tới**\n\n\n Một, thực hiện hiệu quảchủtrương, chính sách đầu tư phát triển\n\n Nâng cao thống nhất quan điểm chỉđạo\n\n Tăng cường công tác kiểm tra\n\n Tiếp ..."
70
+ },
71
+ {
72
+ "idx": 30,
73
+ "page": 24,
74
+ "score": 0.6624355316162109,
75
+ "text": "Khi tôn giáo xây dựng thành công CNXH thì còn tôn giáo không? Vẫn có vấn đềkhông giái thích được\n\n Vẫn có người tin thì vẫn còn tồn tại\n\n Là một phần trong nhu cầu cơ bản thiết yếu của con người\n\n Điều kiện tồn tại của tôn giáo còn trên khách quan như cơ chếthịtrường\n(muốn xóa bỏtôn gióa phải xóa bỏdc…)\n\n##### **Sựkhác nhau tín ngưỡng và tôn giáo**\n\n\nTôn giáo phải có hệthống, cơ sởthờtự, tín đồ\nTôn giáo mới là sựpha trộn của ác tôn giáo truyền thống, khi có sựchuyển biến kt, xã\nhội có sựvận động của đời sống sẽxuất hiện nhiều tôn giáo. Hiện tượng chuyển đổi tôn giáo\n\n\n**Cô ôn tập**\nChủnghĩa dân tộc và chủnghĩa dân tộc cực đoan, chủnghĩa ly khai dân tộc\n\n Chủnghĩa dân tộc cực đoan và chủnghĩa ly khai dân tộc là trào lưu gây ra sự\nchia rẽvà kì thịdân tộc, khoét sâu và cốtình khơi dậy sựbất hòa, kịch động\nlòng thù hận giữa các dân tộc, thổi phồng sựtựcao tựđại vềdân tộc mình\n\n Hậu quảnghiêm trọng là xung đột, nội chiến thểhiện dưới nhiều hình thức\nchiến tranh lớn, vừa và nhỏ, chiến t..."
76
+ }
77
+ ],
78
+ "model_verdict": {
79
+ "supported": true,
80
+ "confidence": 0.99,
81
+ "evidence": "TÍnh chất chính trịcủa tôn giáo chỉ xuất hiện khi xã hội đã phân chia giai cấp, có sự khác biệt, sự đối kháng về lợi ích.",
82
+ "reason": "Câu trả lời trùng khớp với nội dung trong Context."
83
+ }
84
+ },
85
+ "2": {
86
+ "supported_by_embeddings": true,
87
+ "max_similarity": 0.7629456520080566,
88
+ "evidence": [
89
+ {
90
+ "idx": 34,
91
+ "page": 20,
92
+ "score": 0.7629456520080566,
93
+ "text": "Giai cấp thì có giai cấp công nhân và nông dân\nTầng lớp có tri thức, doanh nhân, thương,\nCơ cấu xã hội thời kì quá độ\n+Công nhân: vai trò nòng cốt trong liên minh, lực lượng đi đầu trong sựnghiệp\n\nCNH-HDH. +Nông dân: cơ sở, lực lương quan trọng phát triển kt-xã hội, giữvững ổn định chính\ntrị\n-Kinh tếcơ bản quy định nhất: xác định đúng cơ cấu\nQuan điểm nhất quán: phát triển nền kinh tếthành phần\n-Chính trị: giữvững lập trường chính trị- tư tưởng của giai cấp công nhân, vai trò\nlãnh đạo của Đảng cộng sản, xây dựng Đảng vững mạnh, xây dựng nhà nước pháp\nquyền vềXHCN của dân, do dân, vì dân\n-Văn hóa, xã hội: gắn tăng trưởng kinh tếvới phát triển văn hóa, phát triển, xây dựng\ncon người và thực hiện tiến bộ. Biến văn hóa trởthành tài sản của xã hội. Văn hóa, xã\nhội của liên minh giai cấp tầng lớp còn được thểhiện qua nâng cao chất lượng\nnguồn nhân lực, dân trí, xóa đói giảm nghèo, thực hiện an sinh xã hội\n\n\nPhương hướng tăng cường\n1. Đẩy mạnh quá trình CNH, HDH, giải quyết tốt mối quan hệgiữ..."
94
+ },
95
+ {
96
+ "idx": 1,
97
+ "page": 10,
98
+ "score": 0.5911743640899658,
99
+ "text": "##### **3.2. THỰC TRẠNG GCCN VIỆT NAM VÀ VẤN ĐỀĐẶT RA HIỆN NAY**\n\nNội dung SMLS hiện nay\nVỀNỘI DUNG KINH TẾ\n\n - Giai cấp công nhân là nguồn nhân lực chủyếu tham gia phát triển kinh tếthị\ntrường định hướng XHCN;\n\n - Lực lượng đi đầu trong sựnghiệp đẩy mạnh công nghiệp hóa, hiện đại hóa\n\nđất nước\n\n - Làm cho nước ta trởthành một nước công nghiệp theo hướng hiện đại, định\nhướng XHCN\nVỀNỘI DUNG CHÍNH TRỊ- XÃ HỘI\n\n - Giữvững và tăng cường sựlãnh đạo của Đảng,\n\n - Giữvững bản chất giai cấp công nhân của Đảng, giai cấp công nhân cùng với\nnhân dân lao động dưới sựlãnh đạo của Đảng cộng sản củng cốvà hoàn\nthiện hệthống chính trịXHCN\n\n - Xây dựng nhà nước của dân, do dân, vì dân, xây dựng nền dân chủXHCN, bảo\nvệchếđộxã hội chủnghĩa. VỀNỘI DUNG TƯ TƯỞNG – VĂN HÓA\n\n - Xây dựng và phát triển nền văn hóa Việt Nam tiên tiến, đậm đà bản sắc dân\ntộc, nội dung cốt lõi là xây dựng con người mới XHCN. - Bảo vệsựtrong sáng của chủnghĩa Mác – Lê nin và tư tưởng HồChí Minh,\nchống lại những quan điểm s..."
100
+ },
101
+ {
102
+ "idx": 22,
103
+ "page": 29,
104
+ "score": 0.5815836191177368,
105
+ "text": "Công nhân, nông dân, trí thức, thanh niên, doanh nhiên, phụnữ\n\n Phân tích dc vịtrí, vai trò từng giai cấp, tầng ớp\n\n Một câu tổng kết với từng vịtrí, vai trò, vì sao phải thực hiện liên minh các giai\ncấp\n\n\n5. **CHƯƠNG 6: VẤN ĐỀDÂN TỘC VÀ TÔN GIÁO**\n\n**TÔN GIÁO** : NẮM nguyên tắc giải quyết vấn đềTG trong thời kì quá độ, đặc điểm tôn\ngiáo ởVN, các chính sách của nhà nước và đảng vềtôn giáo\nLiên hệbản thân, ac nhận thức thếnào vềtôn giáo trong thời kì quá độxây dựng\n\nCNXH\n\n\nCHƯƠNG 7: GIA ĐINH\n\nNhững biến đổi của gia đình VN (3 biến đổi) - AC hãy nêu những biến đổi của gia\nđình VN trong thời kì quá độ, ac hãy nêu những phướng hướng, giái pháp đểxây\ndựng. Là sv, ac làm gì đểxây dựng\n\n\nDownloaded by Adoft Putin (dinhnhatthanh248@gmail.com)"
106
+ }
107
+ ],
108
+ "model_verdict": {
109
+ "supported": false,
110
+ "confidence": 0.96,
111
+ "evidence": "Giai cấp thì có giai cấp công nhân và nông dân",
112
+ "reason": "Ngữ cảnh chỉ liệt kê giai cấp công nhân và nông dân là hai giai cấp riêng biệt, không nói rằng giai cấp công nhân bao gồm nông dân và thợ thủ công"
113
+ }
114
+ },
115
+ "3": {
116
+ "supported_by_embeddings": true,
117
+ "max_similarity": 0.5998344421386719,
118
+ "evidence": [
119
+ {
120
+ "idx": 28,
121
+ "page": 2,
122
+ "score": 0.5998344421386719,
123
+ "text": "=> đây là những con đường không tưởng, muốn đạt được phải qua đấu tranh và cách mạng,\nkhông vạch ra đc giai cấp nào là giai cấp mang sứmệnh lịch sử. **3. Chủnghĩa xã hội khoa học:**\nCũng hướng đến những tựdo, bình đẳng, bác ái,... nhưng đã vạch ra được giai cấp\nmang sứmệnh lịch sửlà giai cấp công nhân\n**Nghĩa rộng: Là CN Mác- Lê nin luận giải từcác góc độTH, KTCT và chính trị- xã**\n**hội vềsựchuyển biến tất yếu của XH loài người từCNTB lên CNXH.**\n**Nghĩa hẹp: là một trong ba bộphận hợp thành của CN Mác- Lenin (triết học, kinh**\n**tếCT và chủnghĩa xã hội khoa học).**\n\n\n**4. Chủnghĩa xã hội lí luận**\nBao gồm chủnghĩa xã hội không tưởng và chủnghĩa xã hội khoa hoc. **5. Chủnghĩa xã hội hiện thực**\nVận dụng các chủnghĩa xã hội vào xây dựng thực tiễn (CMT10 Nga - 1917)\n\n\nDownloaded by Adoft Putin (dinhnhatthanh248@gmail.com)"
124
+ },
125
+ {
126
+ "idx": 5,
127
+ "page": 5,
128
+ "score": 0.5852417945861816,
129
+ "text": "Con đường, cách thức và phương thức đấu tranh nhằm giải phóng con người, giải\nphóng xã hội khỏi tư hữu, áp bức, bóc lột, xây dựng một xã hội mới tiến bộ, công\nbằng, bình đẳng\n**2. Là một chếđộxã hội hiện thức, một mô hinh, một kiểu tổchức xã hội theo**\n**những nguyên tắc của CNXH**\n\n\n**3. Là một phong trào thực tiễn**\n\n### **1.2 Những điều kiện ra đời của CNXH khoa học**\n\n\n1.2.1. Điều kiện khách quan\n1.2.2. Điều kiện chủquan (vai trò của Mac Angghen\n\n### **2.2 VI."
130
+ },
131
+ {
132
+ "idx": 31,
133
+ "page": 3,
134
+ "score": 0.576014518737793,
135
+ "text": "Chủnghĩa xã hội vs Xã hội chủnghĩa\nChủnghĩa xã hội là một danh từ\nXã hội chủnghĩa là một tính từ\n\n\nThếlực thù địch\n+ Phủnhận: 1886 -> Đổi mới\n+ Cho rằng kinh tếthịtrường định hướng xã hội chủnghĩa không có thực\n=> Có thành tựu hay không có thành tựu đều bịcông kích\n\n\n**Vì sao nói chủnghĩa Mác Lênin vừa thống nhất vừa độc lập với nhau?**\n➢ Thống nhất vì nó là những luận điểm khoa học,\n➢ là hệtư tưởng của giai cấp công nhân\n➢ Đều hướng đến những giá trịtựdo,... mà con người đang hướng đến\n\n\nTriết học Mác Lenin: nghiên cứu những quy luật chung nhất của tựnhiên, xã hội, tư\nduy của 5 HTKT-XH\nKT-CT học Mác Lenin: nghiên cứu quy luật kinh tếtrong quá trình SXVC của HTKT-XH\nTBCN và quá độlên CNXH\nChủnghĩa xã hội khoa học: nghiên cứu những quy luật chính trị- xã hội của HTKT\ncộng sản chủnghĩa\n\n### **1.1 Quan niệm vềchủnghĩa xã hội**\n\n\nCNTB →Ra đời vào thời kì chiếm hữu nô lệ: khi xã hội bắt đầu phân chia giai cấp\n(tầng lớp quý tộc, địa chủ,.."
136
+ }
137
+ ],
138
+ "model_verdict": {
139
+ "supported": false,
140
+ "confidence": 0.9,
141
+ "evidence": "Không có đề cập đến \"công nghiệp cơ khí\" trong nội dung cung cấp.",
142
+ "reason": "Context không chứa thông tin nào về sự phát triển của công nghiệp cơ khí là điều kiện kinh tế để chủ nghĩa xã hội ra đời."
143
+ }
144
+ },
145
+ "4": {
146
+ "supported_by_embeddings": true,
147
+ "max_similarity": 0.6957789659500122,
148
+ "evidence": [
149
+ {
150
+ "idx": 47,
151
+ "page": 18,
152
+ "score": 0.6957789659500122,
153
+ "text": "Phương diện tổchức và quản lí xã hội\n\n\nQuan điểm của Đảng cộng sản vềdân chủ(nền dân chủxã hội chủnghĩa)\n\n - QUyền lực thuộc vềnhân dân\n\n - Dân chủgắn liền với công bằng xã hội\n\n - Dân chủđi đôi với kỷluật, kỷcương\n\n - Dân chủtrên mọi lĩnh vực đời sống\n\n - Dân chủđược thểhiện bằng pháp luật\n\n\nNền dân chủchủnô và dân chủtư sản đều là quyền lực thuộc vềtay một giai cấp\nchứkhông phải tất cảcác giai cấp - không phải nền dân chủcho đa sốtrong xã hội\n(không có nền dân chủcho tất cảchỉcó cho đại đa số)\n\n\nĐặc điểm của nhà nước pháp quyền XHCN ởViệt Nam (6 nội dung phải nhớ)\n\n - Bản chất kinh tế\n\n - Bản chất chính trị\n\n - Bản chất xã hội - văn hóa\n\n\nPhải lí giải: vd nếu không có đảng thì có thểđảm bảo dân chủcho mọi tầng lớp\ntrong xã hội không\nQuan niệm chung vềnhà nước pháp quyền\n\n\nDownloaded by Adoft Putin (dinhnhatthanh248@gmail.com)"
154
+ },
155
+ {
156
+ "idx": 31,
157
+ "page": 3,
158
+ "score": 0.6646752953529358,
159
+ "text": "Chủnghĩa xã hội vs Xã hội chủnghĩa\nChủnghĩa xã hội là một danh từ\nXã hội chủnghĩa là một tính từ\n\n\nThếlực thù địch\n+ Phủnhận: 1886 -> Đổi mới\n+ Cho rằng kinh tếthịtrường định hướng xã hội chủnghĩa không có thực\n=> Có thành tựu hay không có thành tựu đều bịcông kích\n\n\n**Vì sao nói chủnghĩa Mác Lênin vừa thống nhất vừa độc lập với nhau?**\n➢ Thống nhất vì nó là những luận điểm khoa học,\n➢ là hệtư tưởng của giai cấp công nhân\n➢ Đều hướng đến những giá trịtựdo,... mà con người đang hướng đến\n\n\nTriết học Mác Lenin: nghiên cứu những quy luật chung nhất của tựnhiên, xã hội, tư\nduy của 5 HTKT-XH\nKT-CT học Mác Lenin: nghiên cứu quy luật kinh tếtrong quá trình SXVC của HTKT-XH\nTBCN và quá độlên CNXH\nChủnghĩa xã hội khoa học: nghiên cứu những quy luật chính trị- xã hội của HTKT\ncộng sản chủnghĩa\n\n### **1.1 Quan niệm vềchủnghĩa xã hội**\n\n\nCNTB →Ra đời vào thời kì chiếm hữu nô lệ: khi xã hội bắt đầu phân chia giai cấp\n(tầng lớp quý tộc, địa chủ,.."
160
+ },
161
+ {
162
+ "idx": 10,
163
+ "page": 13,
164
+ "score": 0.6248639822006226,
165
+ "text": "- Mâu thuẫn giữa LLSX và QHSX, mâu thuẫn tư sản và vô sản\n\n\nĐiều kiện chính trị\n\n\n - GCCN phát triển cảvềsốlượng và chất lượng\n\n\n - GCCN phải giác ngộcách mạng và tốchức ra chính Đảng của mình\n\n\n - GCCN phải kiên quyết giành chính quyền từtay GCTS khi có thời cơ cách\n\n\nmạng và muốn giành chính quyền phải thông qua cách mạng vô sản\n\n\n=> Áp lực của phong trào đấu tranh GCCN, áp lực từsựra đời icủa CNXH\n\n##### **1.3 Những đặc trưng bản chất của chủnghĩa xã hội theo quan điểm** **của Mác**\n\n\n1. Giai phóng GC, giải phóng DT, giải phóng XH, giải phóng con người (giải\nphóng toàn bộcác tầng lớp bịáp bức bóc lột khác)\n**2. Là chếđộdo NDLĐ làm chủ(mọi chính sách đều phục vụnhân dân)**\n3. Có nền KT phát triển cao\n4. Có nhà nước kiểu mới mang bản chất GCCN (chương 5)\n5. Có nền văn hóa phát triển cao\n6. Đẩm bảo bình đăng, đoàn kết giữa các dân tộc (VN là nc đa dân tộc, đa văn\nhóa nên xây dựng đn sẽkhó khăn hơn), quan hệhợp tác hữu nghị\n\n### **2."
166
+ }
167
+ ],
168
+ "model_verdict": {
169
+ "supported": true,
170
+ "confidence": 0.98,
171
+ "evidence": "1. Giai phóng GC... 2. Là chế độ... 3. Có nền KT phát triển cao 4. Có nhà nước kiểu mới mang bản chất GCCN 5. Có nền văn hóa phát triển cao 6. Đảm bảo bình đẳng, đoàn kết... (không có mục \"có hệ thống chính trị đa đảng\")",
172
+ "reason": "Trong danh sách 6 đặc trưng của chủ nghĩa xã hội theo Mác, không có mục nào đề cập đến hệ thống chính trị đa đảng, nên đáp án \"Có hệ thống chính trị đa đảng\" là đúng."
173
+ }
174
+ },
175
+ "5": {
176
+ "supported_by_embeddings": true,
177
+ "max_similarity": 0.5826756358146667,
178
+ "evidence": [
179
+ {
180
+ "idx": 3,
181
+ "page": 3,
182
+ "score": 0.5826756358146667,
183
+ "text": "nắm giữtài sản, nô lệlà công cụlao động)\nCNXH không tưởng (trước 1848, trước Mác- Ăngghen)\n**a) Tư tưởng xã hội chủnghĩa trước Mác**\n❖ Tư tưởng XHCN thời cổđại: Phương Đông (địa chủ- phong kiến), phương Tây\n(chủnô, tang lữ- nô lệ) => thểhiện bằng các cuộc đấu tranh của quần chúng\nnhân dân lao động đòi lại quyền dân chủtuy nhiên còn rời rạc (VD khởi nghĩa\nSpartacus). ❖ Tư tưởng XHCN thời trung đại: Phương Tây (đêm trường trung cổ, giáo hội có\nquyền lực hơn cảnhà nước). => thểhiện bằng những câu chuyện, văn thở\nphản ánh ước mơ về“thời đại hoàng kim”\n❖ Tư tưởng XHCN thời cận đại (đầu TK16 - đầu TK19): xuất hiện tầng lớp công\nnhân => tư tưởng CNXH bắt đầu được thành lập. Thểkỷ16 - Thomas More với\ntác phẩm Utopia) - thuật ngữ“Cừu ăn thịt người”. Grachus Babeuf - tuyên\nngôn của những người binh dân\n❖ Thếkỉ19: Tư tưởng XHCN thểhiện dạng học thuyết phê phán: 3 đại diện tiêu\nbiểu (Saint Simon, Charles Fourier, Robert Owen): bước sang giai đoạn mới\n\n\nDownloaded by Adoft Putin (dinhnhatthanh248@g..."
184
+ },
185
+ {
186
+ "idx": 40,
187
+ "page": 5,
188
+ "score": 0.5630186796188354,
189
+ "text": "Lenin bảo vệ, vận dụng và phát triển sáng tạo** **CNXHKH**\n\n\n2.2.2 Thời kì sau CM tháng 10 Nga:\nVềchính trị: vấn đềdân chủvà chuyên chính vô sản\nVềkinh tế: vận hành theo thịtrường, kinh tếNep\n\n##### **_Đối diện: Nhận diện cách mạng màu - Việt Nam có phải đối diện_** **_nguy cơ xảy ra cách mạng màu hay không?_**\n\n+ Biểu hiện của cách mạng màu: các cuộc lật độchếđộhiện tại bằng phương\nthức truyền bá, kích động, lôi kéo người dân tham gia vào các cuộc biểu tình\nkhiến cho các hoạt động xã hội bịngưng trệkhiến cho xung đột người dân và\nchính quyền ngày càng lớn\n+ Bắt nguồn từcáo buộc gian lận bầu cử, nạn tham nhũng, mâu thuẫn lợi ích,\nmâu thuẫn sắc tộc, khó khăn kinh tế… => bịkích động trởthành cách mạng\nhoa nhài, cách mạng hoa tulip,... + Hậu quả: đồng tiền mất giá, cuộc sống đình trệ, kinh tếrơi vào khủng hoảng\ntrầm trọng, đất nước trởthành vùng đệm quốc tế, người dân phải tịnạn, gặp\n\nkhó khăn\n\n+ VN có phải đối mặt với cách mạng màu không? Mục tiêu tấn công nhằm xóa\nbỏCNXH -> VN cũng nằm ..."
190
+ },
191
+ {
192
+ "idx": 28,
193
+ "page": 2,
194
+ "score": 0.5546197891235352,
195
+ "text": "=> đây là những con đường không tưởng, muốn đạt được phải qua đấu tranh và cách mạng,\nkhông vạch ra đc giai cấp nào là giai cấp mang sứmệnh lịch sử. **3. Chủnghĩa xã hội khoa học:**\nCũng hướng đến những tựdo, bình đẳng, bác ái,... nhưng đã vạch ra được giai cấp\nmang sứmệnh lịch sửlà giai cấp công nhân\n**Nghĩa rộng: Là CN Mác- Lê nin luận giải từcác góc độTH, KTCT và chính trị- xã**\n**hội vềsựchuyển biến tất yếu của XH loài người từCNTB lên CNXH.**\n**Nghĩa hẹp: là một trong ba bộphận hợp thành của CN Mác- Lenin (triết học, kinh**\n**tếCT và chủnghĩa xã hội khoa học).**\n\n\n**4. Chủnghĩa xã hội lí luận**\nBao gồm chủnghĩa xã hội không tưởng và chủnghĩa xã hội khoa hoc. **5. Chủnghĩa xã hội hiện thực**\nVận dụng các chủnghĩa xã hội vào xây dựng thực tiễn (CMT10 Nga - 1917)\n\n\nDownloaded by Adoft Putin (dinhnhatthanh248@gmail.com)"
196
+ }
197
+ ],
198
+ "model_verdict": {
199
+ "supported": false,
200
+ "confidence": 0.85,
201
+ "evidence": "Context chỉ đề cập đến giai cấp công nhân là giai cấp mang sứ mệnh lịch sử, nhưng không nêu rõ sứ mệnh lịch sử của Cách mạng xã hội chủ nghĩa là \"những nhiệm vụ quan trọng, thiêng liêng...\"",
202
+ "reason": "Không có bằng chứng trong nội dung cung cấp xác nhận định nghĩa cụ thể của sứ mệnh lịch sử như trong đáp án"
203
+ }
204
+ }
205
+ }
206
+ }
test/raw_resp.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "id": "chatcmpl-84e4f53d-9bca-4dd8-89d3-7a4a9b69b860",
3
+ "choices": [
4
+ {
5
+ "finish_reason": "stop",
6
+ "index": 0,
7
+ "message": {
8
+ "content": "{\n \"supported\": true,\n \"confidence\": 0.99,\n \"evidence\": \"BERT-base có 12 lớp encoder ... Mỗi lớp có 12 head ... mỗi token có vector 768 chiều\",\n \"reason\": \"Context xác nhận BERT-base có 12 lớp encoder, hidden size 768 và 12 attention head, nên đáp án a được chứng thực.\"\n}",
9
+ "reasoning": "We need to determine if the answer (option a) is supported by the context. The context includes: \"Cấu trúc BERT-base có 12 lớp encoder, mỗi lớp bao gồm: ... Mỗi lớp có 12 head, ... d_k: 768/12=64. ...\". Also earlier: \"BERT-base có 12 lớp encoder\". It mentions hidden size 768. So option a: \"BERT có 12 lớp encoder, mỗi lớp có kích thước ẩn là 768 và 12 attention head.\" This matches. So supported true. Provide confidence maybe 0.99. Evidence: \"BERT-base có 12 lớp encoder\" and \"Mỗi lớp có 12 head\" and hidden size 768 mentioned in description of token vector dimension. Provide short citation. Provide reason.",
10
+ "role": "assistant"
11
+ }
12
+ }
13
+ ],
14
+ "created": 1755749149,
15
+ "model": "gpt-oss-120b",
16
+ "system_fingerprint": "fp_e25f231b468af246abb0",
17
+ "object": "chat.completion",
18
+ "usage": {
19
+ "prompt_tokens": 1714,
20
+ "completion_tokens": 265,
21
+ "total_tokens": 1979,
22
+ "prompt_tokens_details": {
23
+ "cached_tokens": 0
24
+ }
25
+ },
26
+ "time_info": {
27
+ "queue_time": 0.000124009,
28
+ "prompt_time": 0.063482573,
29
+ "completion_time": 0.18115486,
30
+ "total_time": 0.2471165657043457,
31
+ "created": 1755749149
32
+ }
33
+ }
test/test-api-key.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from qdrant_client import QdrantClient
3
+
4
+ qdrant_client = QdrantClient(
5
+ url=os.environ.get('QDRANT_URL'),
6
+ api_key=os.environ.get('QDRANT_API_KEY'),
7
+ )
8
+ print(qdrant_client.get_collections())
9
+
10
+ # qdrant_client.recreate_collection(
11
+ # collection_name="programming",
12
+ # vectors_config={
13
+ # "my_vector_name": models.VectorParams(size=1536, distance=models.Distance.COSINE),
14
+ # },
15
+ # )
16
+ print()
17
+ print(os.environ.get('HF_API_KEY'))
18
+ print(os.environ.get('TOGETHER_API_KEY'))
19
+ print(os.environ.get('QDRANT_URL'))
20
+ print(os.environ.get('QDRANT_API_KEY'))
21
+ print(os.environ.get('CEREBRAS_API_KEY'))
22
+ # cerebras API: your_key
23
+
24
+
25
+ """
26
+ Debugging FastAPI:
27
+ uvicorn app.py:app --reload
28
+
29
+ MacOS:
30
+ export TOGETHER_API_KEY="YOUR_API_KEY"
31
+
32
+ Windows:
33
+ $env:CEREBRAS_API_KEY = "your_key"
34
+ $env:QDRANT_URL = "your_url"
35
+ $env:QDRANT_API_KEY = "your_key"
36
+ """
37
+
38
+
39
+ """Token Count Test
40
+ INPUT_token_count:10616
41
+ OUTPUT_token_count:4808
42
+ AVG_INPUT_token_count:1061.6
43
+ AVG_OUTPUT_token_count:480.8
44
+ TOTAL_TOKEN_COUNT:[1717 1743 1417 1419 1483 1630 1516 1619 1580 1300]
45
+ TOKEN_COUNT_PER_GENERATION - :[15424.]
46
+ AVG_TOKEN_COUNT_PER_GENERATION:[np.float64(15424.0), 1]
47
+
48
+ INPUT_token_count:10299.0
49
+ OUTPUT_token_count:5628.0
50
+ AVG_INPUT_token_count:1029.9
51
+ AVG_OUTPUT_token_count:562.8
52
+ TOTAL_TOKEN_COUNT:[1852. 1520. 1615. 1790. 1539. 1562. 1290. 1686. 1460. 1613.]
53
+ TOKEN_COUNT_PER_GENERATION - :[15424. 15927.]
54
+ AVG_TOKEN_COUNT_PER_GENERATION:[np.float64(15675.5), 2]
55
+
56
+ INPUT_token_count:9640.0
57
+ OUTPUT_token_count:5576.0
58
+ AVG_INPUT_token_count:964.0
59
+ AVG_OUTPUT_token_count:557.6
60
+ TOTAL_TOKEN_COUNT:[1252. 1835. 1490. 1537. 1394. 1620. 1670. 1707. 1458. 1253.]
61
+ TOKEN_COUNT_PER_GENERATION - :[15424. 15927. 15216.]
62
+ AVG_TOKEN_COUNT_PER_GENERATION:[np.float64(15522.333333333334), 3]
63
+
64
+ INPUT_token_count:9356.0
65
+ OUTPUT_token_count:5277.0
66
+ AVG_INPUT_token_count:935.6
67
+ AVG_OUTPUT_token_count:527.7
68
+ TOTAL_TOKEN_COUNT:[1368. 1295. 1849. 1523. 1468. 1473. 1486. 1426. 1595. 1150.]
69
+ TOKEN_COUNT_PER_GENERATION - :[15424. 15927. 15216. 14633.]
70
+ AVG_TOKEN_COUNT_PER_GENERATION:[np.float64(15300.0), 4]
71
+
72
+ INPUT_token_count:9828.0
73
+ OUTPUT_token_count:4758.0
74
+ AVG_INPUT_token_count:982.8
75
+ AVG_OUTPUT_token_count:475.8
76
+ TOTAL_TOKEN_COUNT:[1820. 1235. 1911. 1591. 1312. 1242. 1372. 1533. 1393. 1177.]
77
+ TOKEN_COUNT_PER_GENERATION - :[15424. 15927. 15216. 14633. 14586.]
78
+ AVG_TOKEN_COUNT_PER_GENERATION:[np.float64(15157.2), 5]
79
+ """
test/text_chunks.md ADDED
@@ -0,0 +1 @@
 
 
1
+ ['# **Các thuật toán sắp xếp (p2)** **(sorting algorithms)**\n\n**Nguyễn Mạnh Hiển**\nKhoa Công nghệ thông tin\n[hiennm@tlu.edu.vn](mailto:hiennm@wru.vn)', '## **Các thuật toán sắp xếp - phần 2**\n\n\nSắp xếp vun đống (heap sort)\n\nSắp xếp trộn (merge sort)\n\nSắp xếp nhanh (quick sort)', '## **Sắp xếp vun đống (heap sort)**\n\n\nĐống nhỏ nhất (min-heap)\n\n\n−\nXây dựng đống: O(N)\n\n−\nThực hiện N phép deleteMin để lấy ra phần tử nhỏ\n\nnhất: O(N log N)\n\n−\nĐộ phức tạp tổng thể: O(N log N)\n\n−\nYêu cầu thêm một mảng nữa để lưu trữ các kết quả\n\nĐống lớn nhất (max-heap):\n\n\n−\nLưu trữ các phần tử bị xóa ở cuối vector đống', '### **Ví dụ với đống lớn nhất (max-heap)**\n\nSau buildHeap() Sau deleteMax() đầu tiên', '#### **Cài đặt sắp xếp vun đống**', '## **Sắp xếp trộn (merge sort)**\n\n\nBan đầu có N phần tử chưa sắp xếp\n\nChia N phần tử thành hai nửa\n\nSắp xếp đệ quy mỗi nửa dùng mergeSort\n\n\n−\nTrường hợp cơ sở: N = 1 (không cần sắp xếp)\n\nTrộn (merge) hai nửa (đã được sắp xếp)', '## **Ví dụ về trộn (merge)**\n\n1 15 24 26 2 13 27 38\n\n|1|15|24|26|\n|---|---|---|---|\n|||||\n\n\n|2|13|27|38|\n|---|---|---|---|\n|||||\n\n\n\n1 15 24 26 2 13 27 38 1\n\n|1|15|24|26|\n|---|---|---|---|\n|||||\n\n\n|2|13|27|38|\n|---|---|---|---|\n|||||\n\n\n|1|Col2|Col3|Col4|Col5|Col6|Col7|Col8|\n|---|---|---|---|---|---|---|---|\n|||||||||\n\n\n\n1 15 24 26 2 13 27 38 1 2\n\n|1|15|24|26|\n|---|---|---|---|\n|||||\n\n\n|2|13|27|38|\n|---|---|---|---|\n|||||\n\n\n|1|2|Col3|Col4|Col5|Col6|Col7|Col8|\n|---|---|---|---|---|---|---|---|\n|||||||||\n\n\n\n1 15 24 26 2 13 27 38 1 2 13\n\n\n\n|1|15|24|26|\n|---|---|---|---|\n|||||\n\nCó N bước\n\n\n|2|13|27|38|\n|---|---|---|---|\n|||||\n\n\n|1|2|13|Col4|Col5|Col6|Col7|Col8|\n|---|---|---|---|---|---|---|---|\n|||||||||\n\nMỗi bước có thể có một phép so sánh và có một phần tử được\n\nchèn vào mảng thứ ba \uf0e0 mỗi bước mất thời gian hằng\n\n\uf0e0 Tổng thời gian là O(N)', '### **Ví dụ về sắp xếp trộn (merge sort)**\n\n1 24 26 15 13 2 27 38\n\n\n1 24 26 15 13 2 27 38\n\n\n1 24 26 15 13 2 27 38\n\n\n1 24 26 15 13 2 27 38\n\n\n1 24 15 26 2 13 27 38\n\n\n1 15 24 26 2 13 27 38\n\n\n1 2 13 15 24 26 27 38', '#### **Cài đặt sắp xếp trộn**']
utils.py CHANGED
@@ -3,19 +3,37 @@ import json
3
  from typing import Dict, Any
4
  import requests
5
  import os
 
 
 
 
6
 
 
7
  API_URL = "https://api.cerebras.ai/v1/chat/completions"
8
- # HF_KEY = os.environ['HF_API_KEY']
9
  CEREBRAS_API_KEY = os.environ['CEREBRAS_API_KEY']
 
10
  HEADERS = {"Authorization": f"Bearer {CEREBRAS_API_KEY}", "Content-Type": "application/json"}
11
  JSON_OBJ_RE = re.compile(r"(\{[\s\S]*\})", re.MULTILINE)
12
 
 
 
 
 
 
 
 
13
  def _post_chat(messages: list, model: str, temperature: float = 0.2, timeout: int = 60) -> str:
14
  payload = {"model": model, "messages": messages, "temperature": temperature}
15
  resp = requests.post(API_URL, headers=HEADERS, json=payload, timeout=timeout)
16
  resp.raise_for_status()
17
  data = resp.json()
18
 
 
 
 
 
 
 
19
  # handle various shapes
20
  if "choices" in data and len(data["choices"]) > 0:
21
  # prefer message.content
@@ -23,13 +41,15 @@ def _post_chat(messages: list, model: str, temperature: float = 0.2, timeout: in
23
 
24
  if isinstance(ch, dict) and "message" in ch and "content" in ch["message"]:
25
  return ch["message"]["content"]
26
-
27
  if "text" in ch:
28
  return ch["text"]
29
-
 
30
  # final fallback
31
  raise RuntimeError("Unexpected HF response shape: " + json.dumps(data)[:200])
32
 
 
33
  def _safe_extract_json(text: str) -> dict:
34
  # remove triple backticks
35
  text = re.sub(r"```(?:json)?\n?", "", text)
@@ -46,6 +66,7 @@ def _safe_extract_json(text: str) -> dict:
46
  fixed = re.sub(r",\s*([}\]])", r"\1", js)
47
  return json.loads(fixed)
48
 
 
49
  def generate_mcqs_from_text(
50
  source_text: str,
51
  n: int = 3,
@@ -85,3 +106,126 @@ def generate_mcqs_from_text(
85
  if not isinstance(parsed, dict) or len(parsed) != n:
86
  raise ValueError(f"Generator returned invalid structure. Raw:\n{raw}")
87
  return parsed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  from typing import Dict, Any
4
  import requests
5
  import os
6
+ import numpy as np
7
+ import uuid
8
+ import datetime
9
+ import pathlib
10
 
11
+ #TODO: allow to choose different provider later + dynamic routing when token expired
12
  API_URL = "https://api.cerebras.ai/v1/chat/completions"
 
13
  CEREBRAS_API_KEY = os.environ['CEREBRAS_API_KEY']
14
+
15
  HEADERS = {"Authorization": f"Bearer {CEREBRAS_API_KEY}", "Content-Type": "application/json"}
16
  JSON_OBJ_RE = re.compile(r"(\{[\s\S]*\})", re.MULTILINE)
17
 
18
+ INPUT_TOKEN_COUNT = np.array([], dtype=int)
19
+ OUTPUT_TOKEN_COUNT = np.array([], dtype=int)
20
+ TOTAL_TOKEN_COUNT = np.array([], dtype=int)
21
+ TOTAL_TOKEN_COUNT_EACH_GENERATION = np.array([])
22
+ TIME_INFOs = {}
23
+
24
+
25
  def _post_chat(messages: list, model: str, temperature: float = 0.2, timeout: int = 60) -> str:
26
  payload = {"model": model, "messages": messages, "temperature": temperature}
27
  resp = requests.post(API_URL, headers=HEADERS, json=payload, timeout=timeout)
28
  resp.raise_for_status()
29
  data = resp.json()
30
 
31
+ save_to_local('test/raw_resp.json', content=data)
32
+
33
+ #? Must update within _post_chat because it the original function for LLM generation
34
+ update_token_count(token_usage=data['usage']) # get data['usages']['prompt_tokens'] & data['usages']['completion_tokens']
35
+ update_time_info(time_info=data['time_info'])
36
+
37
  # handle various shapes
38
  if "choices" in data and len(data["choices"]) > 0:
39
  # prefer message.content
 
41
 
42
  if isinstance(ch, dict) and "message" in ch and "content" in ch["message"]:
43
  return ch["message"]["content"]
44
+
45
  if "text" in ch:
46
  return ch["text"]
47
+
48
+ print(f'Generation Time: {data["time_info"]}')
49
  # final fallback
50
  raise RuntimeError("Unexpected HF response shape: " + json.dumps(data)[:200])
51
 
52
+
53
  def _safe_extract_json(text: str) -> dict:
54
  # remove triple backticks
55
  text = re.sub(r"```(?:json)?\n?", "", text)
 
66
  fixed = re.sub(r",\s*([}\]])", r"\1", js)
67
  return json.loads(fixed)
68
 
69
+
70
  def generate_mcqs_from_text(
71
  source_text: str,
72
  n: int = 3,
 
106
  if not isinstance(parsed, dict) or len(parsed) != n:
107
  raise ValueError(f"Generator returned invalid structure. Raw:\n{raw}")
108
  return parsed
109
+
110
+
111
+ # helpers to read/reset token counts
112
+ def get_token_count_record():
113
+ global TOTAL_TOKEN_COUNT_EACH_GENERATION
114
+ TOTAL_TOKEN_COUNT_EACH_GENERATION = np.append(TOTAL_TOKEN_COUNT_EACH_GENERATION, np.sum(TOTAL_TOKEN_COUNT))
115
+
116
+ token_record = {
117
+ 'INPUT_token_count': np.sum(INPUT_TOKEN_COUNT),
118
+ 'OUTPUT_token_count': np.sum(OUTPUT_TOKEN_COUNT),
119
+ 'AVG_INPUT_token_count': np.average(INPUT_TOKEN_COUNT),
120
+ 'AVG_OUTPUT_token_count': np.average(OUTPUT_TOKEN_COUNT),
121
+ 'TOTAL_token_count': TOTAL_TOKEN_COUNT,
122
+ 'TOTAL_token_count_PER_GENERATION - ': TOTAL_TOKEN_COUNT_EACH_GENERATION,
123
+ 'AVG_TOTAL_token_count_PER_GENERATION': [np.average(TOTAL_TOKEN_COUNT_EACH_GENERATION), len(TOTAL_TOKEN_COUNT_EACH_GENERATION)],
124
+ }
125
+
126
+ return token_record
127
+
128
+
129
+ def reset_token_count(reset_all=None):
130
+ """Call in app.py. For Reset Token Count after 1 Generation Session"""
131
+ global INPUT_TOKEN_COUNT, OUTPUT_TOKEN_COUNT, TOTAL_TOKEN_COUNT, TOTAL_TOKEN_COUNT_EACH_GENERATION
132
+
133
+ INPUT_TOKEN_COUNT = np.array([])
134
+ OUTPUT_TOKEN_COUNT = np.array([])
135
+ TOTAL_TOKEN_COUNT = np.array([])
136
+
137
+ if reset_all:
138
+ TOTAL_TOKEN_COUNT_EACH_GENERATION = np.array([])
139
+
140
+
141
+ def update_token_count(token_usage):
142
+ """Update Token Count for each generation
143
+ "usage": {
144
+ "prompt_tokens": 1209,
145
+ "completion_tokens": 313,
146
+ "total_tokens": 1522,
147
+ "prompt_tokens_details": {
148
+ "cached_tokens": 0
149
+ }
150
+ """
151
+ global INPUT_TOKEN_COUNT, OUTPUT_TOKEN_COUNT, TOTAL_TOKEN_COUNT # get value from global
152
+ prompt_tokens = token_usage['prompt_tokens'] # INPUT token
153
+ completion_tokens = token_usage['completion_tokens'] # OUTPUT token
154
+ total_tokens = token_usage['total_tokens'] # TOTAL token
155
+
156
+ INPUT_TOKEN_COUNT = np.append(INPUT_TOKEN_COUNT, prompt_tokens)
157
+ OUTPUT_TOKEN_COUNT = np.append(OUTPUT_TOKEN_COUNT, completion_tokens)
158
+ TOTAL_TOKEN_COUNT = np.append(TOTAL_TOKEN_COUNT, total_tokens)
159
+
160
+ # print("Input Token Increase:", INPUT_TOKEN_COUNT)
161
+ # print("Output Token Increase:", OUTPUT_TOKEN_COUNT)
162
+
163
+
164
+ def save_logs(record: dict, log_path:str = "logs/generation_log.jsonl"):
165
+ """
166
+ Append log to log_path
167
+ record: dict with keys you want to store (e.g. filename, input/output token_count, collection, etc..)
168
+ """
169
+ # create file if not exist
170
+ p = pathlib.Path(log_path)
171
+ p.parent.mkdir(parents=True, exist_ok=True)
172
+
173
+ # add id/timestampt if missing
174
+ record.setdefault('id', str(uuid.uuid4()))
175
+ record.setdefault('timestamp_utc', datetime.datetime.now(datetime.timezone.utc).isoformat() + "Z") # get current time at timezone
176
+
177
+ # append as 1 json file for each generation
178
+ with open(p, "a", encoding='utf-8') as f:
179
+ f.write(json.dumps(record, ensure_ascii=False) + "\n")
180
+
181
+
182
+ def update_time_info(time_info):
183
+ """
184
+ "time_info": {
185
+ "queue_time": 0.000600429,
186
+ "prompt_time": 0.052739054,
187
+ "completion_time": 0.15692187,
188
+ "total_time": 0.2117476463317871,
189
+ "created": 1755599458
190
+ }
191
+ """
192
+ time_info['created'] = time_info
193
+ time_info['created'].pop('created')
194
+
195
+
196
+ def get_time_info():
197
+ global TIME_INFOs
198
+ return TIME_INFOs
199
+ # token_record = {
200
+ # 'completion_time': np.sum(INPUT_TOKEN_COUNT),
201
+ # 'total_time': np.sum(OUTPUT_TOKEN_COUNT),
202
+ # }
203
+
204
+ def log_pipeline(path, content):
205
+ print("Save result to test/mcq_output.json")
206
+ save_to_local(path=path, content=content)
207
+ token_record = get_token_count_record()
208
+
209
+ print("Token Record:")
210
+ for record, value in token_record.items():
211
+ print(f'{record}:{value}', '\n')
212
+
213
+ reset_token_count()
214
+
215
+ def save_to_local(path, content):
216
+ """
217
+ path = 'test/raw_data.json'
218
+ path = 'test/mcq_output.json'
219
+ path = 'test/extract_output.md'
220
+
221
+ """
222
+ p = pathlib.Path(path)
223
+ p.parent.mkdir(parents=True, exist_ok=True) # create folder if missing
224
+ p.touch(exist_ok=True) # create file if missing
225
+
226
+ if path.lower().endswith('.json'):
227
+ with open(path, 'w', encoding='utf-8') as f:
228
+ f.write(json.dumps(content, ensure_ascii=False, indent=2))
229
+ else:
230
+ with open(path, 'w', encoding='utf-8') as f:
231
+ f.write(f'{content}') # md, txt