VietCat commited on
Commit
f92231e
·
1 Parent(s): d75a3e0

quick fix timestamp

Browse files
Files changed (1) hide show
  1. app/sheets.py +49 -79
app/sheets.py CHANGED
@@ -17,19 +17,11 @@ from .constants import SHEET_RANGE
17
  SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
18
 
19
  def generate_conversation_id(user_id: str, page_id: str, timestamp: str) -> str:
20
- """
21
- Tạo conversation_id duy nhất dựa trên user_id, page_id và timestamp.
22
- """
23
  hash_input = f"{user_id}:{page_id}:{timestamp}"
24
  return hashlib.sha256(hash_input.encode()).hexdigest()[:32]
25
 
26
  class SheetsClient:
27
  def __init__(self, credentials_file: str, token_file: str, sheet_id: str):
28
- """
29
- Khởi tạo SheetsClient với thông tin xác thực và sheet_id.
30
- Input: credentials_file (str), token_file (str), sheet_id (str)
31
- Output: SheetsClient instance.
32
- """
33
  self.credentials_file = credentials_file
34
  self.token_file = token_file
35
  self.sheet_id = sheet_id
@@ -38,12 +30,6 @@ class SheetsClient:
38
 
39
  @timing_decorator_sync
40
  def authenticate(self) -> None:
41
- """
42
- Xác thực với Google Sheets API, tạo self.service.
43
- Đọc credentials từ biến môi trường GOOGLE_SHEETS_CREDENTIALS_JSON nếu có, nếu không thì dùng file.
44
- Input: None
45
- Output: None (raise exception nếu lỗi)
46
- """
47
  credentials_json = os.getenv("GOOGLE_SHEETS_CREDENTIALS_JSON")
48
  if credentials_json:
49
  info = json.loads(credentials_json)
@@ -53,7 +39,6 @@ class SheetsClient:
53
  if os.path.exists(self.token_file):
54
  with open(self.token_file, 'rb') as token:
55
  self.creds = pickle.load(token)
56
-
57
  if not self.creds or not self.creds.valid:
58
  if self.creds and self.creds.expired:
59
  self.creds.refresh(Request())
@@ -61,24 +46,15 @@ class SheetsClient:
61
  flow = InstalledAppFlow.from_client_secrets_file(
62
  self.credentials_file, SCOPES)
63
  self.creds = flow.run_local_server(port=0)
64
-
65
  with open(self.token_file, 'wb') as token:
66
  pickle.dump(self.creds, token)
67
-
68
  self.service = build('sheets', 'v4', credentials=self.creds)
69
 
70
  @timing_decorator_sync
71
  def get_conversation_history(self, user_id: str, page_id: str) -> List[Dict[str, Any]]:
72
- """
73
- Lấy lịch sử hội thoại chưa hoàn thành của user từ Google Sheets.
74
- Input: user_id (str), page_id (str)
75
- Output: list[dict] các dòng hội thoại chưa hoàn thành.
76
- """
77
  try:
78
  if not self.service:
79
  self.authenticate()
80
- if not self.service:
81
- raise RuntimeError("Google Sheets service not initialized")
82
  range_name = SHEET_RANGE
83
  result = self.service.spreadsheets().values().get(
84
  spreadsheetId=self.sheet_id,
@@ -90,10 +66,10 @@ class SheetsClient:
90
  row = row + [""] * (14 - len(row))
91
  try:
92
  timestamps = json.loads(row[12]) if row[12] else []
 
 
93
  except Exception:
94
  timestamps = []
95
- if not isinstance(timestamps, list):
96
- timestamps = [timestamps]
97
  if row[4] == user_id and row[5] == page_id:
98
  history.append({
99
  'conversation_id': row[0],
@@ -108,7 +84,7 @@ class SheetsClient:
108
  'originalpurpose': row[9],
109
  'originalquestion': row[10],
110
  'systemresponse': row[11],
111
- 'timestamp': row[12],
112
  'isdone': row[13].lower() == 'true'
113
  })
114
  return history
@@ -131,66 +107,57 @@ class SheetsClient:
131
  originalpurpose: str = "",
132
  originalquestion: str = "",
133
  systemresponse: str = "",
134
- timestamp: str = None,
135
  isdone: bool = False
136
  ) -> Optional[Dict[str, Any]]:
137
- """
138
- Ghi log hội thoại vào Google Sheets.
139
- Dùng các trường original* cho các cột tương ứng trong sheet và các logic liên quan.
140
- """
141
  try:
142
  if not self.service:
143
  self.authenticate()
144
- if not self.service:
145
- raise RuntimeError("Google Sheets service not initialized")
146
 
147
- # Get existing data to check for duplicates
148
  result = self.service.spreadsheets().values().get(
149
  spreadsheetId=self.sheet_id,
150
  range=SHEET_RANGE
151
  ).execute()
152
  values = result.get('values', [])
153
- logger.info(f"[DEBUG] Gsheet values {values}")
154
- # Đảm bảo timestamp str
155
- ts = datetime.now().isoformat()
156
- # Đảm bảo timestamp luôn là list
157
- if timestamp is None:
158
- timestamp = []
159
- elif not isinstance(timestamp, list):
160
- timestamp = [timestamp]
161
- # Chống trùng bản ghi dựa trên sender_id, page_id, timestamp
162
  for row in values:
163
- if len(row) >= 13:
164
- try:
165
- row_timestamps = json.loads(row[12]) if row[12] else []
166
- except Exception:
167
- row_timestamps = []
168
- if not isinstance(row_timestamps, list):
169
- row_timestamps = [row_timestamps]
170
  if not isinstance(row_timestamps, list):
171
  row_timestamps = [row_timestamps]
172
- row_recipient_id = row[4]
173
- row_page_id = row[5]
174
- if (str(timestamp) in [str(ts) for ts in row_timestamps] and str(row_recipient_id) == str(recipient_id) and str(row_page_id) == str(page_id)):
175
- logger.info(f"Found duplicate conversation for user {recipient_id}, page {page_id}, timestamp {timestamp}")
176
- return {
177
- 'conversation_id': row[0],
178
- 'originalcommand': row[1],
179
- 'originalcontent': row[2],
180
- 'originalattachments': json.loads(row[3]) if row[3] else [],
181
- 'recipient_id': row[4],
182
- 'page_id': row[5],
183
- 'originaltext': row[6],
184
- 'originalvehicle': row[7],
185
- 'originalaction': row[8],
186
- 'originalpurpose': row[9],
187
- 'originalquestion': row[10],
188
- 'systemresponse': row[11],
189
- 'timestamp': row[12],
190
- 'isdone': row[13].lower() == 'true' if len(row) > 13 else False
191
- }
192
- # Nếu không trùng thì thêm mới bản ghi
193
- conversation_id = generate_conversation_id(recipient_id, page_id, timestamp)
 
 
 
 
 
 
194
  new_row = [
195
  conversation_id,
196
  originalcommand,
@@ -204,20 +171,23 @@ class SheetsClient:
204
  originalpurpose,
205
  originalquestion,
206
  systemresponse,
207
- json.dumps(timestamp),
208
  str(isdone).lower()
209
  ]
 
210
  body = {
211
  'values': [new_row]
212
  }
213
- range_name = SHEET_RANGE
214
  self.service.spreadsheets().values().append(
215
  spreadsheetId=self.sheet_id,
216
- range=range_name,
217
  valueInputOption='RAW',
218
  body=body
219
  ).execute()
220
- logger.info(f"Thêm mới conversation: {conversation_id} | Giá trị: {{dict(zip(['conversation_id','originalcommand','originalcontent','originalattachments','recipient_id','page_id','originaltext','originalvehicle','originalaction','originalpurpose','originalquestion','systemresponse','timestamp','isdone'], new_row))}}")
 
 
221
  return {
222
  'conversation_id': conversation_id,
223
  'originalcommand': originalcommand,
@@ -231,9 +201,9 @@ class SheetsClient:
231
  'originalpurpose': originalpurpose,
232
  'originalquestion': originalquestion,
233
  'systemresponse': systemresponse,
234
- 'timestamp': timestamp,
235
  'isdone': isdone
236
  }
237
  except Exception as e:
238
  logger.error(f"Error logging conversation: {e}")
239
- return None
 
17
  SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
18
 
19
  def generate_conversation_id(user_id: str, page_id: str, timestamp: str) -> str:
 
 
 
20
  hash_input = f"{user_id}:{page_id}:{timestamp}"
21
  return hashlib.sha256(hash_input.encode()).hexdigest()[:32]
22
 
23
  class SheetsClient:
24
  def __init__(self, credentials_file: str, token_file: str, sheet_id: str):
 
 
 
 
 
25
  self.credentials_file = credentials_file
26
  self.token_file = token_file
27
  self.sheet_id = sheet_id
 
30
 
31
  @timing_decorator_sync
32
  def authenticate(self) -> None:
 
 
 
 
 
 
33
  credentials_json = os.getenv("GOOGLE_SHEETS_CREDENTIALS_JSON")
34
  if credentials_json:
35
  info = json.loads(credentials_json)
 
39
  if os.path.exists(self.token_file):
40
  with open(self.token_file, 'rb') as token:
41
  self.creds = pickle.load(token)
 
42
  if not self.creds or not self.creds.valid:
43
  if self.creds and self.creds.expired:
44
  self.creds.refresh(Request())
 
46
  flow = InstalledAppFlow.from_client_secrets_file(
47
  self.credentials_file, SCOPES)
48
  self.creds = flow.run_local_server(port=0)
 
49
  with open(self.token_file, 'wb') as token:
50
  pickle.dump(self.creds, token)
 
51
  self.service = build('sheets', 'v4', credentials=self.creds)
52
 
53
  @timing_decorator_sync
54
  def get_conversation_history(self, user_id: str, page_id: str) -> List[Dict[str, Any]]:
 
 
 
 
 
55
  try:
56
  if not self.service:
57
  self.authenticate()
 
 
58
  range_name = SHEET_RANGE
59
  result = self.service.spreadsheets().values().get(
60
  spreadsheetId=self.sheet_id,
 
66
  row = row + [""] * (14 - len(row))
67
  try:
68
  timestamps = json.loads(row[12]) if row[12] else []
69
+ if not isinstance(timestamps, list):
70
+ timestamps = [str(timestamps)]
71
  except Exception:
72
  timestamps = []
 
 
73
  if row[4] == user_id and row[5] == page_id:
74
  history.append({
75
  'conversation_id': row[0],
 
84
  'originalpurpose': row[9],
85
  'originalquestion': row[10],
86
  'systemresponse': row[11],
87
+ 'timestamp': timestamps,
88
  'isdone': row[13].lower() == 'true'
89
  })
90
  return history
 
107
  originalpurpose: str = "",
108
  originalquestion: str = "",
109
  systemresponse: str = "",
110
+ timestamp: Optional[str] = None,
111
  isdone: bool = False
112
  ) -> Optional[Dict[str, Any]]:
 
 
 
 
113
  try:
114
  if not self.service:
115
  self.authenticate()
 
 
116
 
 
117
  result = self.service.spreadsheets().values().get(
118
  spreadsheetId=self.sheet_id,
119
  range=SHEET_RANGE
120
  ).execute()
121
  values = result.get('values', [])
122
+
123
+ current_ts = timestamp or datetime.now().isoformat()
124
+ timestamps_list = [current_ts]
125
+
126
+ # Check duplicate
 
 
 
 
127
  for row in values:
128
+ row = row + [""] * 14
129
+ try:
130
+ row_timestamps = json.loads(row[12]) if row[12] else []
 
 
 
 
131
  if not isinstance(row_timestamps, list):
132
  row_timestamps = [row_timestamps]
133
+ except Exception:
134
+ row_timestamps = []
135
+
136
+ row_recipient_id = row[4]
137
+ row_page_id = row[5]
138
+
139
+ if current_ts in [str(ts) for ts in row_timestamps] and \
140
+ str(row_recipient_id) == str(recipient_id) and \
141
+ str(row_page_id) == str(page_id):
142
+ logger.info(f"Found duplicate conversation for user {recipient_id}, page {page_id}, timestamp {current_ts}")
143
+ return {
144
+ 'conversation_id': row[0],
145
+ 'originalcommand': row[1],
146
+ 'originalcontent': row[2],
147
+ 'originalattachments': json.loads(row[3]) if row[3] else [],
148
+ 'recipient_id': row[4],
149
+ 'page_id': row[5],
150
+ 'originaltext': row[6],
151
+ 'originalvehicle': row[7],
152
+ 'originalaction': row[8],
153
+ 'originalpurpose': row[9],
154
+ 'originalquestion': row[10],
155
+ 'systemresponse': row[11],
156
+ 'timestamp': row_timestamps,
157
+ 'isdone': row[13].lower() == 'true' if len(row) > 13 else False
158
+ }
159
+
160
+ conversation_id = generate_conversation_id(recipient_id, page_id, current_ts)
161
  new_row = [
162
  conversation_id,
163
  originalcommand,
 
171
  originalpurpose,
172
  originalquestion,
173
  systemresponse,
174
+ json.dumps(timestamps_list),
175
  str(isdone).lower()
176
  ]
177
+
178
  body = {
179
  'values': [new_row]
180
  }
181
+
182
  self.service.spreadsheets().values().append(
183
  spreadsheetId=self.sheet_id,
184
+ range=SHEET_RANGE,
185
  valueInputOption='RAW',
186
  body=body
187
  ).execute()
188
+
189
+ logger.info(f"Thêm mới conversation: {conversation_id}")
190
+
191
  return {
192
  'conversation_id': conversation_id,
193
  'originalcommand': originalcommand,
 
201
  'originalpurpose': originalpurpose,
202
  'originalquestion': originalquestion,
203
  'systemresponse': systemresponse,
204
+ 'timestamp': timestamps_list,
205
  'isdone': isdone
206
  }
207
  except Exception as e:
208
  logger.error(f"Error logging conversation: {e}")
209
+ return None