Heng2004 commited on
Commit
bab6d73
·
verified ·
1 Parent(s): 9b1af99

Update data/manual_answers.py

Browse files
Files changed (1) hide show
  1. data/manual_answers.py +121 -30
data/manual_answers.py CHANGED
@@ -1,18 +1,20 @@
1
  # data/manual_answers.py – manual teacher answers
2
-
3
  import os
4
  import json
5
- from typing import Dict, List
6
 
7
  from .text_utils import normalize_question
8
 
9
  MANUAL_QA_PATH = "data/manual_qa.jsonl"
10
 
11
- # This dict will be used by the rest of the app
12
  MANUAL_ANSWERS: Dict[str, str] = {}
13
 
 
 
 
14
 
15
- # Fallback manual Q&A (in case file not found yet)
16
  _FALLBACK_MANUAL_QA: List[Dict[str, str]] = [
17
  {
18
  "q": "ປະຫວັດສາດມີຄວາມສໍາຄັນຈັ່ງໃດ໋?",
@@ -39,14 +41,37 @@ _FALLBACK_MANUAL_QA: List[Dict[str, str]] = [
39
  ]
40
 
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  def _load_fallback():
43
  for pair in _FALLBACK_MANUAL_QA:
44
  q = pair.get("q", "")
45
  a = pair.get("a", "")
46
- if not q or not a:
47
- continue
48
- norm_q = normalize_question(q)
49
- MANUAL_ANSWERS[norm_q] = a.strip()
50
 
51
 
52
  def _load_from_file():
@@ -65,39 +90,105 @@ def _load_from_file():
65
 
66
  q = obj.get("q", "")
67
  a = obj.get("a", "")
68
- if not q or not a:
69
- continue
70
 
71
- norm_q = normalize_question(q)
72
- # file values override fallback
73
- MANUAL_ANSWERS[norm_q] = a.strip()
74
 
 
 
 
 
 
75
 
76
- def add_manual_qa(question: str, answer: str) -> str:
 
77
  """
78
- Add new manual Q&A to in-memory index and append to JSONL file.
79
- Returns the normalized question key.
80
  """
81
- q = question.strip()
82
- a = answer.strip()
 
 
 
 
83
 
84
- if not q or not a:
 
 
 
 
 
 
 
 
85
  raise ValueError("Question and answer must not be empty.")
86
 
87
- norm_q = normalize_question(q)
88
- MANUAL_ANSWERS[norm_q] = a
 
 
89
 
90
- # ensure data directory exists
91
- os.makedirs(os.path.dirname(MANUAL_QA_PATH), exist_ok=True)
 
 
 
 
92
 
93
- # append to manual_qa.jsonl
94
- with open(MANUAL_QA_PATH, "a", encoding="utf-8") as f:
95
- json.dump({"q": q, "a": a}, f, ensure_ascii=False)
96
- f.write("\n")
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  return norm_q
99
 
100
 
101
- # Build MANUAL_ANSWERS at import time
102
- _load_fallback()
103
- _load_from_file()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  # data/manual_answers.py – manual teacher answers
 
2
  import os
3
  import json
4
+ from typing import Dict, List, Optional
5
 
6
  from .text_utils import normalize_question
7
 
8
  MANUAL_QA_PATH = "data/manual_qa.jsonl"
9
 
10
+ # Map: normalized question -> answer (used by chatbot)
11
  MANUAL_ANSWERS: Dict[str, str] = {}
12
 
13
+ # List used for UI (table)
14
+ # Each item: {"norm_q": ..., "q": ..., "a": ...}
15
+ MANUAL_LIST: List[Dict[str, str]] = []
16
 
17
+ # Fallback manual Q&A (built-in defaults)
18
  _FALLBACK_MANUAL_QA: List[Dict[str, str]] = [
19
  {
20
  "q": "ປະຫວັດສາດມີຄວາມສໍາຄັນຈັ່ງໃດ໋?",
 
41
  ]
42
 
43
 
44
+ # ---------- Internal helpers ----------
45
+
46
+ def _add_pair(q: str, a: str) -> str:
47
+ """
48
+ Add/overwrite a (q,a) pair into MANUAL_ANSWERS + MANUAL_LIST.
49
+ Returns normalized key.
50
+ """
51
+ q_clean = q.strip()
52
+ a_clean = a.strip()
53
+ if not q_clean or not a_clean:
54
+ return ""
55
+
56
+ norm_q = normalize_question(q_clean)
57
+
58
+ # Update dict
59
+ MANUAL_ANSWERS[norm_q] = a_clean
60
+
61
+ # Update list (remove old entry with same key, then append new)
62
+ global MANUAL_LIST
63
+ MANUAL_LIST = [row for row in MANUAL_LIST if row["norm_q"] != norm_q]
64
+ MANUAL_LIST.append({"norm_q": norm_q, "q": q_clean, "a": a_clean})
65
+
66
+ return norm_q
67
+
68
+
69
  def _load_fallback():
70
  for pair in _FALLBACK_MANUAL_QA:
71
  q = pair.get("q", "")
72
  a = pair.get("a", "")
73
+ if q and a:
74
+ _add_pair(q, a)
 
 
75
 
76
 
77
  def _load_from_file():
 
90
 
91
  q = obj.get("q", "")
92
  a = obj.get("a", "")
93
+ if q and a:
94
+ _add_pair(q, a)
95
 
 
 
 
96
 
97
+ def _load_all():
98
+ MANUAL_ANSWERS.clear()
99
+ MANUAL_LIST.clear()
100
+ _load_fallback()
101
+ _load_from_file()
102
 
103
+
104
+ def _save_to_file():
105
  """
106
+ Rewrite manual_qa.jsonl from MANUAL_LIST.
107
+ (Includes fallback entries once we start saving – that’s OK.)
108
  """
109
+ os.makedirs(os.path.dirname(MANUAL_QA_PATH), exist_ok=True)
110
+ with open(MANUAL_QA_PATH, "w", encoding="utf-8") as f:
111
+ for row in MANUAL_LIST:
112
+ json.dump({"q": row["q"], "a": row["a"]}, f, ensure_ascii=False)
113
+ f.write("\n")
114
+
115
 
116
+ # ---------- Public API (used by chatbot + UI) ----------
117
+
118
+ def add_manual_qa(question: str, answer: str) -> str:
119
+ """
120
+ Add new manual Q&A (or overwrite existing same question).
121
+ Updates in-memory index and rewrites file.
122
+ Returns normalized key.
123
+ """
124
+ if not question.strip() or not answer.strip():
125
  raise ValueError("Question and answer must not be empty.")
126
 
127
+ norm_q = _add_pair(question, answer)
128
+ _save_to_file()
129
+ return norm_q
130
+
131
 
132
+ def list_manual_qa() -> List[Dict[str, str]]:
133
+ """
134
+ Return a copy of all manual Q&A rows for displaying in UI.
135
+ Each row: { 'norm_q', 'q', 'a' }.
136
+ """
137
+ return list(MANUAL_LIST)
138
 
 
 
 
 
139
 
140
+ def get_manual_qa(norm_q: str) -> Optional[Dict[str, str]]:
141
+ """
142
+ Look up one Q&A by normalized key (for loading into edit boxes).
143
+ """
144
+ for row in MANUAL_LIST:
145
+ if row["norm_q"] == norm_q:
146
+ return row
147
+ return None
148
+
149
+
150
+ def update_manual_qa(old_norm_q: str, new_q: str, new_a: str) -> str:
151
+ """
152
+ Update an existing entry identified by old_norm_q.
153
+ Allows changing question text (so key may change).
154
+ Returns the new normalized key.
155
+ """
156
+ if not old_norm_q:
157
+ raise ValueError("No entry selected for update.")
158
+ if not new_q.strip() or not new_a.strip():
159
+ raise ValueError("Question and answer must not be empty.")
160
+
161
+ # Remove old entry (if exists)
162
+ global MANUAL_LIST
163
+ MANUAL_LIST = [row for row in MANUAL_LIST if row["norm_q"] != old_norm_q]
164
+ if old_norm_q in MANUAL_ANSWERS:
165
+ MANUAL_ANSWERS.pop(old_norm_q, None)
166
+
167
+ # Add as new pair
168
+ norm_q = _add_pair(new_q, new_a)
169
+ _save_to_file()
170
  return norm_q
171
 
172
 
173
+ def delete_manual_qa(norm_q: str) -> None:
174
+ """
175
+ Delete an entry by normalized key.
176
+ """
177
+ if not norm_q:
178
+ raise ValueError("No entry selected for deletion.")
179
+
180
+ global MANUAL_LIST
181
+ before = len(MANUAL_LIST)
182
+ MANUAL_LIST = [row for row in MANUAL_LIST if row["norm_q"] != norm_q]
183
+
184
+ if len(MANUAL_LIST) == before:
185
+ raise ValueError("Entry not found.")
186
+
187
+ if norm_q in MANUAL_ANSWERS:
188
+ MANUAL_ANSWERS.pop(norm_q, None)
189
+
190
+ _save_to_file()
191
+
192
+
193
+ # Load everything at import time
194
+ _load_all()