convert_to_mealie.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import os
  2. from sys import stdin, stdout, argv
  3. from uuid import uuid4
  4. from json import dumps, load
  5. import psycopg
  6. from psycopg import Cursor
  7. import pandas as pd
  8. from app.data.QueryManager import QueryManager, display_mapper
  9. from app.parse_recipe import parse_recipe
  10. try:
  11. from db_credentials import HOST, PASSWORD
  12. host = f'host={HOST}'
  13. password = f'password={PASSWORD}'
  14. except:
  15. host = ''
  16. password = ''
  17. user = os.getenv('USER')
  18. conn = psycopg.connect(f"{host} dbname=grocery user={user} {password}")
  19. cur: Cursor = conn.cursor()
  20. query_manager = QueryManager(cur, display_mapper)
  21. with open(argv[1], 'rb') as f:
  22. units = { x['name']: x for x in load(f) }
  23. # {
  24. # "id": "7cb5a83d-268a-4898-b24e-08b4753039a5",
  25. # "userId": "d0f22cce-fa1c-420e-98ae-d85831c725b1",
  26. # "groupId": "c6229a83-ce82-4be1-9683-ff14f83025c9",
  27. # "name": "Another",
  28. # "slug": "another",
  29. # "image": null,
  30. # "recipeYield": null,
  31. # "totalTime": null,
  32. # "prepTime": null,
  33. # "cookTime": null,
  34. # "performTime": null,
  35. # "description": "",
  36. # "recipeCategory": [],
  37. # "tags": [],
  38. # "tools": [],
  39. # "rating": null,
  40. # "orgURL": null,
  41. # "dateAdded": "2024-04-14",
  42. # "dateUpdated": "2024-04-14T18:49:34.284815",
  43. # "createdAt": "2024-04-14T18:49:34.293412",
  44. # "updateAt": "2024-04-14T18:49:34.293418",
  45. # "lastMade": null,
  46. # "recipeIngredient": [
  47. # {
  48. # "quantity": 1.0,
  49. # "unit": null,
  50. # "food": null,
  51. # "note": "1 Cup Flour",
  52. # "isFood": false,
  53. # "disableAmount": true,
  54. # "display": "1 Cup Flour",
  55. # "title": null,
  56. # "originalText": null,
  57. # "referenceId": "2e4403e7-fbfb-42b6-b38b-adf38f09bf78"
  58. # }
  59. # ],
  60. # "recipeInstructions": [
  61. # {
  62. # "id": "f8c85a36-1044-45e7-b22b-e37764d892a9",
  63. # "title": "",
  64. # "text": "Recipe steps as well as other fields in the recipe page support markdown syntax.\n\n**Add a link**\n\n[My Link](https://demo.mealie.io)\n\n",
  65. # "ingredientReferences": []
  66. # }
  67. # ],
  68. # "nutrition": {
  69. # "calories": null,
  70. # "fatContent": null,
  71. # "proteinContent": null,
  72. # "carbohydrateContent": null,
  73. # "fiberContent": null,
  74. # "sodiumContent": null,
  75. # "sugarContent": null
  76. # },
  77. # "settings": {
  78. # "public": true,
  79. # "showNutrition": true,
  80. # "showAssets": true,
  81. # "landscapeView": false,
  82. # "disableComments": true,
  83. # "disableAmount": true,
  84. # "locked": false
  85. # },
  86. # "assets": [],
  87. # "notes": [],
  88. # "extras": {},
  89. # "comments": []
  90. # }
  91. cur.execute("BEGIN;")
  92. with open('units.sql') as f:
  93. to_exec = ''
  94. quote = False
  95. conn.add_notice_handler(lambda x: print(f"[{x.severity}] {x.message_primary}"))
  96. for line in filter(lambda x: x.strip() not in ('BEGIN;','ROLLBACK;'), f):
  97. if line.startswith("""$$"""):
  98. quote = True if not quote else False
  99. to_exec += line
  100. if not line.strip().endswith(';'):
  101. continue
  102. if quote:
  103. continue
  104. cur.execute(to_exec)
  105. try:
  106. data = pd.DataFrame(cur.fetchall(), columns=[
  107. x.name for x in cur.description
  108. ])
  109. if not data.empty:
  110. print()
  111. print(cur._last_query)
  112. print(data.to_string(index=False))
  113. except psycopg.ProgrammingError:
  114. pass
  115. to_exec = ''
  116. parsed = parse_recipe(stdin, query_manager)
  117. cur.execute('ROLLBACK')
  118. def unit_mapper(unit):
  119. if 'Cup' in unit:
  120. return 'cup'
  121. return unit.replace(' (metric)', '').replace(' (US)', '')
  122. mealie = {
  123. 'recipeYield': parsed['feeds'],
  124. 'recipeInstructions': [{
  125. "id": str(uuid4()),
  126. "title": "",
  127. "text": line,
  128. "ingredientReferences": [],
  129. } for line in parsed['instructions'].splitlines()],
  130. 'recipeIngredient': [{
  131. "quantity": quantity,
  132. "unit": units[unit_mapper(unit)],
  133. "food": None,
  134. "note": product,
  135. "isFood": False,
  136. "disableAmount": False,
  137. "display": product,
  138. "title": None,
  139. "originalText": o,
  140. "referenceId": str(uuid4())
  141. } for product, quantity, unit, o in map(
  142. lambda x: (*x, ' '.join([*x[1:], x[0]])),
  143. parsed['ingredients']
  144. )]
  145. }
  146. stdout.write(dumps(mealie))
  147. cur.close()
  148. conn.close()