Update app.py
Browse files
app.py
CHANGED
@@ -209,110 +209,97 @@ async def move_file_to_folder(file_id, current_parents, new_parents):
|
|
209 |
logging.error(f"Failed to move file {file_id} to new folders: {e}")
|
210 |
|
211 |
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
no_of_cols = len(data[0])
|
217 |
-
|
218 |
-
if is_reset:
|
219 |
-
# sheet_name = f"{sheet_name} {datetime.now(kst).strftime("%Y-%m-%d %H:%M:%S")}"
|
220 |
-
sheet_name = f"{sheet_name} {datetime.now(kst).strftime('%Y-%m-%d %H:%M')}"
|
221 |
-
duplicate_requests = [{
|
222 |
-
"duplicateSheet": {
|
223 |
-
"sourceSheetId": contacts_ss,
|
224 |
-
"newSheetName": sheet_name
|
225 |
-
}
|
226 |
-
}]
|
227 |
-
duplicate_response = sheet_service.spreadsheets().batchUpdate(
|
228 |
-
spreadsheetId=spreadsheet_id,
|
229 |
-
body={
|
230 |
-
'requests': duplicate_requests
|
231 |
-
}
|
232 |
-
).execute()
|
233 |
-
sheet_id = duplicate_response['replies'][0]['duplicateSheet']['properties']['sheetId']
|
234 |
-
|
235 |
-
# Insert new rows
|
236 |
-
requests = [
|
237 |
-
{
|
238 |
-
"updateSheetProperties": {
|
239 |
-
"properties": {
|
240 |
-
"sheetId": sheet_id,
|
241 |
-
"hidden": False
|
242 |
-
},
|
243 |
-
"fields": "hidden"
|
244 |
-
}
|
245 |
-
},
|
246 |
-
{
|
247 |
-
"insertDimension": {
|
248 |
-
"range": {
|
249 |
-
"sheetId": sheet_id,
|
250 |
-
"dimension": "ROWS",
|
251 |
-
"startIndex": 1,
|
252 |
-
"endIndex": no_of_rows + 1
|
253 |
-
},
|
254 |
-
"inheritFromBefore": False,
|
255 |
-
}
|
256 |
-
}]
|
257 |
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
'
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
279 |
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
color = {"red": 0, "green": 0, "blue": 1} # Blue for hyperlinks
|
285 |
else:
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
316 |
|
317 |
async def copy_sms_sheet(phone_no: str, spreadsheet_id: str):
|
318 |
requests = [
|
@@ -396,7 +383,13 @@ template_sheet_id = '1i5mrmlTs5sPWtx2mBtc_f-zm1D3x21r1T_77guki8_8'
|
|
396 |
async def edit_spreadsheet(target_sheet_id: str = Form(...)):
|
397 |
try:
|
398 |
# Retrieve the target spreadsheet's metadata
|
399 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
400 |
|
401 |
# Collect all sheet IDs in the target spreadsheet
|
402 |
target_sheet_ids = [sheet['properties']['sheetId'] for sheet in target_spreadsheet.get('sheets', [])]
|
@@ -411,214 +404,76 @@ async def edit_spreadsheet(target_sheet_id: str = Form(...)):
|
|
411 |
})
|
412 |
|
413 |
# Retrieve the template spreadsheet's metadata
|
414 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
415 |
|
416 |
# Iterate through each sheet in the template spreadsheet
|
417 |
for sheet in template_spreadsheet.get('sheets', []):
|
418 |
sheet_id = sheet['properties']['sheetId']
|
419 |
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
"
|
436 |
-
"
|
437 |
-
|
438 |
-
|
439 |
-
|
|
|
|
|
440 |
}
|
441 |
-
}
|
442 |
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
|
449 |
-
|
|
|
|
|
|
|
450 |
|
451 |
if requests:
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
|
|
|
|
|
|
|
|
459 |
|
460 |
logging.info(f"All sheets from template {template_sheet_id} copied to {target_sheet_id}.")
|
461 |
return {"message": "Spreadsheet copied successfully"}
|
462 |
|
|
|
|
|
|
|
463 |
except Exception as e:
|
464 |
-
logging.error(f"
|
465 |
-
|
466 |
-
|
467 |
-
# image upload
|
468 |
-
# receive image id and user_id
|
469 |
-
# check if they have enough credits
|
470 |
-
# post to gpt4o with the user credit info
|
471 |
-
# identify the sheet_id to update by checking in user_id
|
472 |
-
# update user sheet
|
473 |
-
# update firebase transaction
|
474 |
-
# privatize the image and move the image to appropriate folder(s)
|
475 |
-
# @app.post("/process-image")
|
476 |
-
# async def process_photo(image_id: str = Form(...), user_id: str = Form(...)):
|
477 |
-
# transaction_ref = transactions_collection_ref.document(user_id)
|
478 |
-
# transaction = transaction_ref.get()
|
479 |
-
# # If transaction does not exist, create a new one
|
480 |
-
# if not transaction.exists:
|
481 |
-
# transaction_ref.set({
|
482 |
-
# "no_sms": 0,
|
483 |
-
# "no_contacts": 0,
|
484 |
-
# "no_receipts": 0,
|
485 |
-
# "no_business_cards": 0,
|
486 |
-
# "purchased_credit": {
|
487 |
-
# "image_detection": 100,
|
488 |
-
# "sync_data": 500,
|
489 |
-
# }
|
490 |
-
# })
|
491 |
-
# transaction = transaction_ref.get()
|
492 |
-
|
493 |
-
# transaction_data = transaction.to_dict()
|
494 |
-
|
495 |
-
# # check if any of the limits have been reached
|
496 |
-
# if transaction_data['no_receipts'] + transaction_data['no_business_cards'] >= transaction_data['purchased_credit']['image_detection']:
|
497 |
-
# return {"error": "You have reached the limit of the number of items you can process. Please upgrade your plan."}
|
498 |
-
|
499 |
-
# user_ref = users_collection_ref.document(user_id)
|
500 |
-
# user = user_ref.get()
|
501 |
-
# user_data = user.to_dict()
|
502 |
|
503 |
-
|
504 |
-
# try:
|
505 |
-
# parent_folders = [user_data['gDrive_metadata']['yungsoogi'], user_data['gDrive_metadata']['uploaded']]
|
506 |
-
# dataJson = await request_gpt4o_completion(image_id, transaction_data['purchased_credit']['image_detection'])
|
507 |
-
# if dataJson is None:
|
508 |
-
# return {"error": "An error occurred while processing the image"}
|
509 |
-
|
510 |
-
# data = json.loads(dataJson)
|
511 |
-
# # Check if 'receipts' key exists and the length
|
512 |
-
# found_receipt_no = len(data['receipts']) if 'receipts' in data else 0
|
513 |
-
# found_business_cards_no = len(data['busi_cards']) if 'busi_cards' in data else 0
|
514 |
-
# new_folders = []
|
515 |
-
# timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
516 |
-
# # https://drive.google.com/file/d/1cFIA09PBqFjM8YvIz1D60p7HMGk1uBvo/view?usp=sharing
|
517 |
-
# download_image_url = f"https://drive.google.com/uc?id={image_id}&export=download"
|
518 |
-
# image_url = f"https://drive.google.com/file/d/{image_id}/view?usp=sharing"
|
519 |
-
# # 이미지를 보여주어야 할때 =image({image_url})를 사용하고 갈 수 있는 경로를 만들때는 =HYPERLINK({image_url}, '바로가기')를 사용하세요.
|
520 |
-
# if found_receipt_no > 0:
|
521 |
-
# new_folders.append(user_data['gDrive_metadata']['receipts'])
|
522 |
-
# receipts_data = convert_dicts_to_list(
|
523 |
-
# data['receipts'],
|
524 |
-
# add_link=True,
|
525 |
-
# image_id=image_id,
|
526 |
-
# link_text="바로가기",
|
527 |
-
# link_position=1 # Link third
|
528 |
-
# )
|
529 |
-
# print(receipts_data)
|
530 |
-
# await update_user_sheet(user_data['gDrive_metadata']['spreadsheet'], receipts_ss, "영수증", receipts_data)
|
531 |
-
# if found_business_cards_no > 0:
|
532 |
-
# new_folders.append(user_data['gDrive_metadata']['business_cards'])
|
533 |
-
# business_cards_data = convert_dicts_to_list(
|
534 |
-
# data['busi_cards'],
|
535 |
-
# add_link=True,
|
536 |
-
# image_id=image_id,
|
537 |
-
# link_text="명함보기",
|
538 |
-
# link_position=-1 # Link at the end
|
539 |
-
# )
|
540 |
-
# await update_user_sheet(user_data['gDrive_metadata']['spreadsheet'], business_cards_ss, "명함", business_cards_data)
|
541 |
-
|
542 |
-
# print(f"{found_receipt_no}, {found_business_cards_no}")
|
543 |
-
|
544 |
-
# status = await update_fb_transaction(
|
545 |
-
# transaction_ref,
|
546 |
-
# no_receipts=found_receipt_no,
|
547 |
-
# no_business_cards=found_business_cards_no
|
548 |
-
# )
|
549 |
-
|
550 |
-
|
551 |
-
# if status['status'] == "Success":
|
552 |
-
# await move_file_to_folder(image_id, parent_folders, new_folders)
|
553 |
-
# return {"success": True}
|
554 |
-
# else:
|
555 |
-
# logging.error(f"Transaction update failed with status: {status['status']}")
|
556 |
-
# return {"error": "An error has occurred while updating the transaction"}
|
557 |
-
# except Exception as e:
|
558 |
-
# logging.error(f"An error occurred: {e}")
|
559 |
-
# # Move the image file to the error folder
|
560 |
-
# await move_file_to_folder(image_id, parent_folders, user_data['gDrive_metadata']['error'])
|
561 |
-
# return {"error": str(e)}
|
562 |
-
|
563 |
-
# async def update_user_sheets_and_folders(user_data, transaction_ref, transaction_data, image_id):
|
564 |
-
# try:
|
565 |
-
# parent_folders = [user_data['gDrive_metadata']['yungsoogi'], user_data['gDrive_metadata']['uploaded']]
|
566 |
-
# dataJson = await request_gpt4o_completion(image_id, transaction_data['purchased_credit']['image_detection'])
|
567 |
-
# if dataJson is None:
|
568 |
-
# return {"error": "An error occurred while processing the image"}
|
569 |
-
|
570 |
-
# data = json.loads(dataJson)
|
571 |
-
# # Check if 'receipts' key exists and the length
|
572 |
-
# found_receipt_no = len(data['receipts']) if 'receipts' in data else 0
|
573 |
-
# found_business_cards_no = len(data['busi_cards']) if 'busi_cards' in data else 0
|
574 |
-
# new_folders = []
|
575 |
-
# timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
576 |
-
# # https://drive.google.com/file/d/1cFIA09PBqFjM8YvIz1D60p7HMGk1uBvo/view?usp=sharing
|
577 |
-
# download_image_url = f"https://drive.google.com/uc?id={image_id}&export=download"
|
578 |
-
# image_url = f"https://drive.google.com/file/d/{image_id}/view?usp=sharing"
|
579 |
-
# # 이미지를 보여주어야 할때 =image({image_url})를 사용하고 갈 수 있는 경로를 만들때는 =HYPERLINK({image_url}, '바로가기')를 사용하세요.
|
580 |
-
# if found_receipt_no > 0:
|
581 |
-
# new_folders.append(user_data['gDrive_metadata']['receipts'])
|
582 |
-
# receipts_data = convert_dicts_to_list(
|
583 |
-
# data['receipts'],
|
584 |
-
# add_link=True,
|
585 |
-
# image_id=image_id,
|
586 |
-
# link_text="바로가기",
|
587 |
-
# link_position=1 # Link third
|
588 |
-
# )
|
589 |
-
# print(receipts_data)
|
590 |
-
# await update_user_sheet(user_data['gDrive_metadata']['spreadsheet'], receipts_ss, "영수증", receipts_data)
|
591 |
-
# if found_business_cards_no > 0:
|
592 |
-
# new_folders.append(user_data['gDrive_metadata']['business_cards'])
|
593 |
-
# business_cards_data = convert_dicts_to_list(
|
594 |
-
# data['busi_cards'],
|
595 |
-
# add_link=True,
|
596 |
-
# image_id=image_id,
|
597 |
-
# link_text="명함보기",
|
598 |
-
# link_position=-1 # Link at the end
|
599 |
-
# )
|
600 |
-
# await update_user_sheet(user_data['gDrive_metadata']['spreadsheet'], business_cards_ss, "명함", business_cards_data)
|
601 |
-
|
602 |
-
# print(f"{found_receipt_no}, {found_business_cards_no}")
|
603 |
-
|
604 |
-
# status = await update_fb_transaction(
|
605 |
-
# transaction_ref,
|
606 |
-
# no_receipts=found_receipt_no,
|
607 |
-
# no_business_cards=found_business_cards_no
|
608 |
-
# )
|
609 |
-
|
610 |
-
|
611 |
-
# if status['status'] == "Success":
|
612 |
-
# await move_file_to_folder(image_id, parent_folders, new_folders)
|
613 |
-
# return {"success": True}
|
614 |
-
# else:
|
615 |
-
# logging.error(f"Transaction update failed with status: {status['status']}")
|
616 |
-
# return {"error": "An error has occurred while updating the transaction"}
|
617 |
-
# except Exception as e:
|
618 |
-
# logging.error(f"An error occurred: {e}")
|
619 |
-
# # Move the image file to the error folder
|
620 |
-
# await move_file_to_folder(image_id, parent_folders, user_data['gDrive_metadata']['error'])
|
621 |
-
# return {"error": str(e)}
|
622 |
async def create_shortcut(file_id, parent_folder_id, name):
|
623 |
try:
|
624 |
file_metadata = {
|
@@ -709,113 +564,182 @@ async def update_user_sheets_and_folders(user_data, transaction_ref, transaction
|
|
709 |
|
710 |
@app.post("/process-image")
|
711 |
async def process_photo(background_tasks: BackgroundTasks, image_id: str = Form(...), user_id: str = Form(...)):
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
"no_receipts": 0,
|
720 |
-
"no_business_cards": 0,
|
721 |
-
"purchased_credit": {
|
722 |
-
"image_detection": 100,
|
723 |
-
"sync_data": 500,
|
724 |
-
}
|
725 |
-
})
|
726 |
-
transaction = transaction_ref.get()
|
727 |
-
|
728 |
-
transaction_data = transaction.to_dict()
|
729 |
-
|
730 |
-
if transaction_data['no_receipts'] + transaction_data['no_business_cards'] >= transaction_data['purchased_credit']['image_detection']:
|
731 |
-
return {"error": "You have reached the limit of the number of items you can process. Please upgrade your plan."}
|
732 |
-
|
733 |
-
user_ref = users_collection_ref.document(user_id)
|
734 |
-
user = user_ref.get()
|
735 |
-
user_data = user.to_dict()
|
736 |
-
|
737 |
-
background_tasks.add_task(update_user_sheets_and_folders, user_data, transaction_ref, transaction_data, image_id)
|
738 |
-
return {"success": True}
|
739 |
-
|
740 |
-
@app.post("/sync-data")
|
741 |
-
async def process_photo(data_json: str = Form(...), user_id: str = Form(...)):
|
742 |
-
# print(data_json)
|
743 |
-
data: Dict[str, Any] = json.loads(data_json)
|
744 |
-
transaction_ref = transactions_collection_ref.document(user_id)
|
745 |
-
transaction = transaction_ref.get()
|
746 |
-
|
747 |
-
if not transaction.exists:
|
748 |
-
transaction_ref.set({
|
749 |
-
"no_sms": 0,
|
750 |
-
"no_contacts": 0,
|
751 |
-
"no_receipts": 0,
|
752 |
-
"no_business_cards": 0,
|
753 |
-
"purchased_credit": {
|
754 |
-
"image_detection": 100,
|
755 |
-
"sync_data": 500,
|
756 |
-
}
|
757 |
-
})
|
758 |
transaction = transaction_ref.get()
|
759 |
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
768 |
|
|
|
|
|
|
|
769 |
try:
|
770 |
-
|
771 |
-
|
772 |
-
|
773 |
-
|
774 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
775 |
else:
|
776 |
if 'sms_ids' not in user_data:
|
777 |
-
print('No sms_ids')
|
778 |
user_data['sms_ids'] = {}
|
779 |
|
780 |
existing_phones = set(user_data.get('sms_ids', {}).keys())
|
781 |
new_phones = [phone['address'] for phone in data['data'] if phone['address'] not in existing_phones]
|
782 |
-
|
783 |
-
print(f"Existing phones: {existing_phones}")
|
784 |
-
|
785 |
for phone_address in new_phones:
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
|
|
|
|
791 |
updated_sms_count = 0
|
792 |
for phone in data['data']:
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
802 |
continue
|
803 |
-
|
804 |
-
sheet_id = user_data['sms_ids'][phone['address']]['sheet_id']
|
805 |
-
print(f"Sheet ID: {sheet_id}")
|
806 |
|
807 |
-
|
808 |
-
|
809 |
-
|
810 |
-
|
|
|
|
|
|
|
|
|
811 |
|
812 |
-
|
813 |
-
user_ref.update({'sms_ids': user_data['sms_ids']})
|
814 |
-
transaction_data['no_sms'] += updated_sms_count
|
815 |
-
transaction_ref.update({'no_sms': transaction_data['no_sms']})
|
816 |
|
817 |
-
|
818 |
-
|
|
|
819 |
except Exception as e:
|
820 |
-
logging.error(f"
|
821 |
-
|
|
|
209 |
logging.error(f"Failed to move file {file_id} to new folders: {e}")
|
210 |
|
211 |
|
212 |
+
# Update the update_user_sheets_and_folders function for better error handling
|
213 |
+
async def update_user_sheets_and_folders(user_data, transaction_ref, transaction_data, image_id):
|
214 |
+
try:
|
215 |
+
parent_folders = [user_data['gDrive_metadata']['yungsoogi'], user_data['gDrive_metadata']['uploaded']]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
216 |
|
217 |
+
# Request GPT-4 completion
|
218 |
+
dataJson = await request_gpt4o_completion(image_id, transaction_data['purchased_credit']['image_detection'])
|
219 |
+
if dataJson is None:
|
220 |
+
raise Exception("Failed to process the image with GPT-4")
|
221 |
+
|
222 |
+
data = json.loads(dataJson)
|
223 |
+
|
224 |
+
# Process receipts and business cards
|
225 |
+
found_receipt_no = len(data.get('receipts', []))
|
226 |
+
found_business_cards_no = len(data.get('busi_cards', []))
|
227 |
+
|
228 |
+
new_folder = None
|
229 |
+
secondary_folder = None
|
230 |
+
timestamp = datetime.now(kst).strftime("%Y-%m-%d %H:%M:%S")
|
231 |
+
|
232 |
+
# Process receipts
|
233 |
+
if found_receipt_no > 0:
|
234 |
+
new_folder = user_data['gDrive_metadata']['receipts']
|
235 |
+
receipts_data = convert_dicts_to_list(
|
236 |
+
data['receipts'],
|
237 |
+
receipt_sheet_headers,
|
238 |
+
add_link=True,
|
239 |
+
image_id=image_id,
|
240 |
+
link_text="바로가기",
|
241 |
+
link_position=1
|
242 |
+
)
|
243 |
+
try:
|
244 |
+
await update_user_sheet(user_data['gDrive_metadata']['spreadsheet'], receipts_ss, "영수증", receipts_data)
|
245 |
+
except HttpError as e:
|
246 |
+
logging.error(f"Failed to update receipt sheet: {str(e)}")
|
247 |
+
raise Exception("Failed to update receipt data in spreadsheet")
|
248 |
|
249 |
+
# Process business cards
|
250 |
+
if found_business_cards_no > 0:
|
251 |
+
if new_folder is None:
|
252 |
+
new_folder = user_data['gDrive_metadata']['business_cards']
|
|
|
253 |
else:
|
254 |
+
secondary_folder = user_data['gDrive_metadata']['business_cards']
|
255 |
+
business_cards_data = convert_dicts_to_list(
|
256 |
+
data['busi_cards'],
|
257 |
+
business_card_sheet_headers,
|
258 |
+
add_link=True,
|
259 |
+
image_id=image_id,
|
260 |
+
link_text="명함보기",
|
261 |
+
link_position=-1
|
262 |
+
)
|
263 |
+
try:
|
264 |
+
await update_user_sheet(user_data['gDrive_metadata']['spreadsheet'], business_cards_ss, "명함", business_cards_data)
|
265 |
+
except HttpError as e:
|
266 |
+
logging.error(f"Failed to update business card sheet: {str(e)}")
|
267 |
+
raise Exception("Failed to update business card data in spreadsheet")
|
268 |
+
|
269 |
+
# Update Firebase transaction
|
270 |
+
status = await update_fb_transaction(
|
271 |
+
transaction_ref,
|
272 |
+
no_receipts=found_receipt_no,
|
273 |
+
no_business_cards=found_business_cards_no
|
274 |
+
)
|
275 |
+
|
276 |
+
if status['status'] != "Success":
|
277 |
+
logging.error(f"Transaction update failed with status: {status['status']}")
|
278 |
+
raise Exception("Failed to update transaction in Firebase")
|
279 |
+
|
280 |
+
# Move file to appropriate folder
|
281 |
+
if new_folder:
|
282 |
+
try:
|
283 |
+
await move_file_to_folder(image_id, parent_folders, [new_folder])
|
284 |
+
if secondary_folder:
|
285 |
+
await create_shortcut(image_id, secondary_folder, f"Shortcut to {image_id}")
|
286 |
+
except HttpError as e:
|
287 |
+
logging.error(f"Failed to move file or create shortcut: {str(e)}")
|
288 |
+
raise Exception("Failed to organize processed image in Google Drive")
|
289 |
+
|
290 |
+
logging.info(f"Successfully processed image {image_id} for user {user_data['uid']}")
|
291 |
+
|
292 |
+
except Exception as e:
|
293 |
+
logging.error(f"Error processing image {image_id} for user {user_data['uid']}: {str(e)}")
|
294 |
+
try:
|
295 |
+
# Move the image file to the error folder
|
296 |
+
await move_file_to_folder(image_id, parent_folders, [user_data['gDrive_metadata']['error']])
|
297 |
+
logging.info(f"Moved image {image_id} to error folder for user {user_data['uid']}")
|
298 |
+
except Exception as move_error:
|
299 |
+
logging.error(f"Failed to move image {image_id} to error folder: {str(move_error)}")
|
300 |
+
|
301 |
+
# You might want to update the transaction or user document to indicate the error
|
302 |
+
# This depends on your error handling strategy
|
303 |
|
304 |
async def copy_sms_sheet(phone_no: str, spreadsheet_id: str):
|
305 |
requests = [
|
|
|
383 |
async def edit_spreadsheet(target_sheet_id: str = Form(...)):
|
384 |
try:
|
385 |
# Retrieve the target spreadsheet's metadata
|
386 |
+
try:
|
387 |
+
target_spreadsheet = sheet_service.spreadsheets().get(spreadsheetId=target_sheet_id).execute()
|
388 |
+
except HttpError as e:
|
389 |
+
if e.resp.status == 404:
|
390 |
+
raise HTTPException(status_code=404, detail="Target spreadsheet not found")
|
391 |
+
else:
|
392 |
+
raise HTTPException(status_code=e.resp.status, detail=f"Error accessing target spreadsheet: {e.error_details}")
|
393 |
|
394 |
# Collect all sheet IDs in the target spreadsheet
|
395 |
target_sheet_ids = [sheet['properties']['sheetId'] for sheet in target_spreadsheet.get('sheets', [])]
|
|
|
404 |
})
|
405 |
|
406 |
# Retrieve the template spreadsheet's metadata
|
407 |
+
try:
|
408 |
+
template_spreadsheet = sheet_service.spreadsheets().get(spreadsheetId=template_sheet_id).execute()
|
409 |
+
except HttpError as e:
|
410 |
+
if e.resp.status == 404:
|
411 |
+
raise HTTPException(status_code=404, detail="Template spreadsheet not found")
|
412 |
+
else:
|
413 |
+
raise HTTPException(status_code=e.resp.status, detail=f"Error accessing template spreadsheet: {e.error_details}")
|
414 |
|
415 |
# Iterate through each sheet in the template spreadsheet
|
416 |
for sheet in template_spreadsheet.get('sheets', []):
|
417 |
sheet_id = sheet['properties']['sheetId']
|
418 |
|
419 |
+
try:
|
420 |
+
# Use the copyTo method to copy the sheet to the target spreadsheet
|
421 |
+
copy_request = sheet_service.spreadsheets().sheets().copyTo(
|
422 |
+
spreadsheetId=template_sheet_id,
|
423 |
+
sheetId=sheet_id,
|
424 |
+
body={"destinationSpreadsheetId": target_sheet_id}
|
425 |
+
)
|
426 |
+
copy_response = copy_request.execute()
|
427 |
+
|
428 |
+
# Get the copied sheet ID
|
429 |
+
copied_sheet_id = copy_response['sheetId']
|
430 |
+
|
431 |
+
# Rename the copied sheet to remove "Copy of"
|
432 |
+
copied_sheet_title = sheet['properties']['title'].replace("Copy of ", "")
|
433 |
+
rename_request = {
|
434 |
+
"updateSheetProperties": {
|
435 |
+
"properties": {
|
436 |
+
"sheetId": copied_sheet_id,
|
437 |
+
"title": copied_sheet_title
|
438 |
+
},
|
439 |
+
"fields": "title"
|
440 |
+
}
|
441 |
}
|
|
|
442 |
|
443 |
+
# Execute rename request
|
444 |
+
sheet_service.spreadsheets().batchUpdate(
|
445 |
+
spreadsheetId=target_sheet_id,
|
446 |
+
body={"requests": [rename_request]}
|
447 |
+
).execute()
|
448 |
|
449 |
+
logging.info(f"Sheet {sheet['properties']['title']} copied and renamed to {copied_sheet_title} in {target_sheet_id}.")
|
450 |
+
except HttpError as e:
|
451 |
+
logging.error(f"Error copying or renaming sheet {sheet['properties']['title']}: {e}")
|
452 |
+
raise HTTPException(status_code=e.resp.status, detail=f"Error copying or renaming sheet: {e.error_details}")
|
453 |
|
454 |
if requests:
|
455 |
+
try:
|
456 |
+
# Execute batch update to delete sheets
|
457 |
+
batch_update_request = {"requests": requests}
|
458 |
+
sheet_service.spreadsheets().batchUpdate(
|
459 |
+
spreadsheetId=target_sheet_id,
|
460 |
+
body=batch_update_request
|
461 |
+
).execute()
|
462 |
+
logging.info(f"Deleted existing sheets in target spreadsheet {target_sheet_id}.")
|
463 |
+
except HttpError as e:
|
464 |
+
logging.error(f"Error deleting existing sheets: {e}")
|
465 |
+
raise HTTPException(status_code=e.resp.status, detail=f"Error deleting existing sheets: {e.error_details}")
|
466 |
|
467 |
logging.info(f"All sheets from template {template_sheet_id} copied to {target_sheet_id}.")
|
468 |
return {"message": "Spreadsheet copied successfully"}
|
469 |
|
470 |
+
except HTTPException as he:
|
471 |
+
# Re-raise HTTP exceptions
|
472 |
+
raise he
|
473 |
except Exception as e:
|
474 |
+
logging.error(f"Unexpected error in edit_spreadsheet: {e}")
|
475 |
+
raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
476 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
477 |
async def create_shortcut(file_id, parent_folder_id, name):
|
478 |
try:
|
479 |
file_metadata = {
|
|
|
564 |
|
565 |
@app.post("/process-image")
|
566 |
async def process_photo(background_tasks: BackgroundTasks, image_id: str = Form(...), user_id: str = Form(...)):
|
567 |
+
try:
|
568 |
+
# Validate input
|
569 |
+
if not image_id or not user_id:
|
570 |
+
raise HTTPException(status_code=400, detail="Both image_id and user_id are required")
|
571 |
+
|
572 |
+
# Get transaction data
|
573 |
+
transaction_ref = transactions_collection_ref.document(user_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
574 |
transaction = transaction_ref.get()
|
575 |
|
576 |
+
if not transaction.exists:
|
577 |
+
# Initialize new transaction if it doesn't exist
|
578 |
+
try:
|
579 |
+
transaction_ref.set({
|
580 |
+
"no_sms": 0,
|
581 |
+
"no_contacts": 0,
|
582 |
+
"no_receipts": 0,
|
583 |
+
"no_business_cards": 0,
|
584 |
+
"purchased_credit": {
|
585 |
+
"image_detection": 100,
|
586 |
+
"sync_data": 500,
|
587 |
+
}
|
588 |
+
})
|
589 |
+
transaction = transaction_ref.get()
|
590 |
+
except Exception as e:
|
591 |
+
logging.error(f"Failed to initialize new transaction for user {user_id}: {str(e)}")
|
592 |
+
raise HTTPException(status_code=500, detail="Failed to initialize user transaction")
|
593 |
+
|
594 |
+
transaction_data = transaction.to_dict()
|
595 |
+
|
596 |
+
# Check credit limit
|
597 |
+
if transaction_data['no_receipts'] + transaction_data['no_business_cards'] >= transaction_data['purchased_credit']['image_detection']:
|
598 |
+
raise HTTPException(status_code=403, detail="You have reached the limit of the number of items you can process. Please upgrade your plan.")
|
599 |
+
|
600 |
+
# Get user data
|
601 |
+
user_ref = users_collection_ref.document(user_id)
|
602 |
+
user = user_ref.get()
|
603 |
+
if not user.exists:
|
604 |
+
raise HTTPException(status_code=404, detail="User not found")
|
605 |
+
user_data = user.to_dict()
|
606 |
+
|
607 |
+
# Validate user data
|
608 |
+
if 'gDrive_metadata' not in user_data:
|
609 |
+
raise HTTPException(status_code=400, detail="User Google Drive metadata not found")
|
610 |
+
|
611 |
+
# Add task to background
|
612 |
+
try:
|
613 |
+
background_tasks.add_task(update_user_sheets_and_folders, user_data, transaction_ref, transaction_data, image_id)
|
614 |
+
except Exception as e:
|
615 |
+
logging.error(f"Failed to add background task for user {user_id}, image {image_id}: {str(e)}")
|
616 |
+
raise HTTPException(status_code=500, detail="Failed to start image processing")
|
617 |
+
|
618 |
+
return {"success": True, "message": "Image processing started"}
|
619 |
+
|
620 |
+
except HTTPException as he:
|
621 |
+
# Re-raise HTTP exceptions
|
622 |
+
raise he
|
623 |
+
except Exception as e:
|
624 |
+
logging.error(f"Unexpected error in process_photo for user {user_id}, image {image_id}: {str(e)}")
|
625 |
+
raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {str(e)}")
|
626 |
|
627 |
+
|
628 |
+
@app.post("/sync-data")
|
629 |
+
async def sync_data(data_json: str = Form(...), user_id: str = Form(...)):
|
630 |
try:
|
631 |
+
# Validate input
|
632 |
+
if not data_json or not user_id:
|
633 |
+
raise HTTPException(status_code=400, detail="Both data_json and user_id are required")
|
634 |
+
|
635 |
+
# Parse JSON data
|
636 |
+
try:
|
637 |
+
data: Dict[str, Any] = json.loads(data_json)
|
638 |
+
except json.JSONDecodeError as e:
|
639 |
+
logging.error(f"Invalid JSON data for user {user_id}: {str(e)}")
|
640 |
+
raise HTTPException(status_code=400, detail="Invalid JSON data")
|
641 |
+
|
642 |
+
# Get transaction data
|
643 |
+
transaction_ref = transactions_collection_ref.document(user_id)
|
644 |
+
try:
|
645 |
+
transaction = transaction_ref.get()
|
646 |
+
if not transaction.exists:
|
647 |
+
transaction_ref.set({
|
648 |
+
"no_sms": 0,
|
649 |
+
"no_contacts": 0,
|
650 |
+
"no_receipts": 0,
|
651 |
+
"no_business_cards": 0,
|
652 |
+
"purchased_credit": {
|
653 |
+
"image_detection": 100,
|
654 |
+
"sync_data": 500,
|
655 |
+
}
|
656 |
+
})
|
657 |
+
transaction = transaction_ref.get()
|
658 |
+
except GoogleAPICallError as e:
|
659 |
+
logging.error(f"Firebase error for user {user_id}: {str(e)}")
|
660 |
+
raise HTTPException(status_code=500, detail="Error accessing user transaction data")
|
661 |
+
|
662 |
+
transaction_data = transaction.to_dict()
|
663 |
+
|
664 |
+
# Check credit limit
|
665 |
+
if transaction_data['no_contacts'] + transaction_data['no_sms'] >= transaction_data['purchased_credit']['sync_data']:
|
666 |
+
raise HTTPException(status_code=403, detail="You have reached the limit of the number of items you can process. Please upgrade your plan.")
|
667 |
+
|
668 |
+
# Get user data
|
669 |
+
user_ref = users_collection_ref.document(user_id)
|
670 |
+
try:
|
671 |
+
user = user_ref.get()
|
672 |
+
if not user.exists:
|
673 |
+
raise HTTPException(status_code=404, detail="User not found")
|
674 |
+
user_data = user.to_dict()
|
675 |
+
except GoogleAPICallError as e:
|
676 |
+
logging.error(f"Firebase error fetching user data for user {user_id}: {str(e)}")
|
677 |
+
raise HTTPException(status_code=500, detail="Error accessing user data")
|
678 |
+
|
679 |
+
# Process contacts
|
680 |
+
if data.get('isContacts', False):
|
681 |
+
try:
|
682 |
+
await update_user_sheet(user_data['gDrive_metadata']['spreadsheet'], contacts_ss, "연락처", data['data'], True)
|
683 |
+
new_contacts_count = len(data['data'])
|
684 |
+
transaction_data['no_contacts'] += new_contacts_count
|
685 |
+
transaction_ref.update({'no_contacts': transaction_data['no_contacts']})
|
686 |
+
logging.info(f"Updated {new_contacts_count} contacts for user {user_id}")
|
687 |
+
except HttpError as e:
|
688 |
+
logging.error(f"Google Sheets API error updating contacts for user {user_id}: {str(e)}")
|
689 |
+
raise HTTPException(status_code=500, detail="Error updating contact data")
|
690 |
+
except KeyError as e:
|
691 |
+
logging.error(f"Missing key in user data for user {user_id}: {str(e)}")
|
692 |
+
raise HTTPException(status_code=500, detail="Error accessing user Google Drive data")
|
693 |
+
|
694 |
+
# Process SMS
|
695 |
else:
|
696 |
if 'sms_ids' not in user_data:
|
|
|
697 |
user_data['sms_ids'] = {}
|
698 |
|
699 |
existing_phones = set(user_data.get('sms_ids', {}).keys())
|
700 |
new_phones = [phone['address'] for phone in data['data'] if phone['address'] not in existing_phones]
|
701 |
+
|
|
|
|
|
702 |
for phone_address in new_phones:
|
703 |
+
try:
|
704 |
+
new_sheet_id = await copy_sms_sheet(phone_address, user_data['gDrive_metadata']['spreadsheet'])
|
705 |
+
user_data['sms_ids'][phone_address] = {'sheet_id': new_sheet_id, 'last_updated': "1970-01-01T00:00:00.000"}
|
706 |
+
except HttpError as e:
|
707 |
+
logging.error(f"Google Sheets API error creating new SMS sheet for user {user_id}, phone {phone_address}: {str(e)}")
|
708 |
+
raise HTTPException(status_code=500, detail=f"Error creating new SMS sheet for phone {phone_address}")
|
709 |
+
|
710 |
updated_sms_count = 0
|
711 |
for phone in data['data']:
|
712 |
+
try:
|
713 |
+
last_updated = user_data['sms_ids'][phone['address']]['last_updated']
|
714 |
+
last_updated_dt = datetime.fromisoformat(last_updated)
|
715 |
+
update_message = [sms for sms in phone['sms'] if datetime.fromisoformat(sms[0]) > last_updated_dt]
|
716 |
+
|
717 |
+
if update_message:
|
718 |
+
sheet_id = user_data['sms_ids'][phone['address']]['sheet_id']
|
719 |
+
await update_user_sheet(user_data['gDrive_metadata']['spreadsheet'], sheet_id, 'SMS ' + phone['address'], update_message, False)
|
720 |
+
user_data['sms_ids'][phone['address']]['last_updated'] = phone['sms'][0][0]
|
721 |
+
updated_sms_count += len(update_message)
|
722 |
+
except KeyError as e:
|
723 |
+
logging.error(f"Missing key in SMS data for user {user_id}, phone {phone['address']}: {str(e)}")
|
724 |
+
continue
|
725 |
+
except HttpError as e:
|
726 |
+
logging.error(f"Google Sheets API error updating SMS for user {user_id}, phone {phone['address']}: {str(e)}")
|
727 |
continue
|
|
|
|
|
|
|
728 |
|
729 |
+
try:
|
730 |
+
user_ref.update({'sms_ids': user_data['sms_ids']})
|
731 |
+
transaction_data['no_sms'] += updated_sms_count
|
732 |
+
transaction_ref.update({'no_sms': transaction_data['no_sms']})
|
733 |
+
logging.info(f"Updated {updated_sms_count} SMS messages for user {user_id}")
|
734 |
+
except GoogleAPICallError as e:
|
735 |
+
logging.error(f"Firebase error updating user data for user {user_id}: {str(e)}")
|
736 |
+
raise HTTPException(status_code=500, detail="Error updating user data")
|
737 |
|
738 |
+
return {"success": True, "updated_count": new_contacts_count if data.get('isContacts', False) else updated_sms_count}
|
|
|
|
|
|
|
739 |
|
740 |
+
except HTTPException as he:
|
741 |
+
# Re-raise HTTP exceptions
|
742 |
+
raise he
|
743 |
except Exception as e:
|
744 |
+
logging.error(f"Unexpected error in sync_data for user {user_id}: {str(e)}")
|
745 |
+
raise HTTPException(status_code=500, detail=f"An unexpected error occurred: {str(e)}")
|