bootstrap-industry-evidence.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. """Recheck existing eight-shop pages and delivered review originals into the auxiliary registry."""
  2. import argparse
  3. import csv
  4. import hashlib
  5. import json
  6. from pathlib import Path
  7. import sys
  8. ROOT = Path(__file__).resolve().parents[1]
  9. sys.path.insert(0, str(ROOT / 'server/voc-library'))
  10. from monitoring_store import import_run, projection, read_state, need
  11. def load(path):
  12. return json.loads(path.read_text('utf-8-sig'))
  13. def run(store, historical, reviews, generation):
  14. imported = []
  15. groups = {}
  16. for path in sorted([*(historical / 'originals').glob('*.json'), *(historical / 'competitors/originals').glob('*.json')]):
  17. doc = load(path)
  18. shop = str(doc['params']['shopId'])
  19. groups.setdefault(shop, []).append(path)
  20. need(len(groups) == 8, 'EIGHT_STORE_BASELINE_REQUIRED')
  21. for shop, paths in groups.items():
  22. pages = []
  23. for path in paths:
  24. doc = load(path)
  25. body = doc['result']['data']
  26. pages.append({'page': int(doc['params']['page']), 'requestKey': body['requestId'], 'status': 'success',
  27. 'rawFile': path.relative_to(historical).as_posix(), 'rawSha256': hashlib.sha256(path.read_bytes()).hexdigest(),
  28. 'mapping': {'itemsPointer': '/result/data/data/ItemList', 'idPointer': '/itemId', 'titlePointer': '/title',
  29. 'pagePointer': '/result/data/requestParams/query/page', 'requestIdPointer': '/result/data/requestId',
  30. 'scopePointers': {'shopId': '/result/data/data/shopId'},
  31. 'observedAtPointer': '/result/data/recordTime', 'totalPointer': '/result/data/data/totalResults',
  32. 'pageCountPointer': '/result/data/data/TotalPage',
  33. 'successChecks': [{'pointer': '/httpStatus', 'equals': 200}, {'pointer': '/status', 'equals': 'ok'},
  34. {'pointer': '/result/code', 'equals': 200}, {'pointer': '/result/data/code', 'equals': 0}]}})
  35. manifest = {'schema': 'ksf.monitoring-run.v1', 'kind': 'listings', 'platform': 'jd',
  36. 'scope': {'shopId': shop}, 'scopeName': body['data']['shopName'], 'window': 'historical-20261104-selected-pass',
  37. 'endpointId': 'jd.get_shop_item_list_v1', 'generation': generation, 'termination': 'exhausted', 'pages': sorted(pages, key=lambda p: p['page'])}
  38. imported.append(import_run(store, manifest, historical))
  39. with (reviews / 'manifest.csv').open(encoding='utf-8-sig', newline='') as stream:
  40. for item in csv.DictReader(stream):
  41. product = item['productId']
  42. path = reviews / 'originals' / (product.split(':')[1] + '.json')
  43. need(hashlib.sha256(path.read_bytes()).hexdigest() == item['sha256'], 'DELIVERED_REVIEW_SHA_MISMATCH')
  44. body = load(path)['data']
  45. page = {'page': int(item['page']), 'requestKey': body['requestId'], 'status': 'success',
  46. 'rawFile': path.relative_to(reviews).as_posix(), 'rawSha256': item['sha256'],
  47. 'mapping': {'itemsPointer': '/data/data/data', 'idPointer': '/commentId',
  48. 'pagePointer': '/data/requestParams/query/page', 'requestIdPointer': '/data/requestId',
  49. 'scopePointers': {'productId': '/data/requestParams/query/itemId'},
  50. 'rowScopePointers': {'productId': '/productId'},
  51. 'totalPointer': '/data/data/pageInfo/count', 'pageCountPointer': '/data/data/pageInfo/maxPage',
  52. 'observedAtPointer': '/data/recordTime',
  53. 'successChecks': [{'pointer': '/code', 'equals': 200}, {'pointer': '/data/code', 'equals': 0}]}}
  54. manifest = {'schema': 'ksf.monitoring-run.v1', 'kind': 'reviews', 'platform': 'jd', 'scope': {'productId': product, 'mode': 'interface_default'},
  55. 'scopeName': product, 'window': 'g2g3-20261106', 'generation': generation, 'endpointId': 'jd.get_item_comments_v1',
  56. 'termination': 'stopped', 'pages': [page]}
  57. imported.append(import_run(store, manifest, reviews))
  58. return {'ok': True, 'registered': len(imported), 'newRegistrations': sum(not r['alreadyRegistered'] for r in imported),
  59. 'collectionCalls': 0, 'productionWrites': 0, **projection(read_state(store), {}, set())}
  60. if __name__ == '__main__':
  61. p = argparse.ArgumentParser(description=__doc__)
  62. p.add_argument('--store', required=True)
  63. p.add_argument('--historical', type=Path, default=ROOT / 'work/jd-historical-baseline-20261106-r2')
  64. p.add_argument('--reviews', type=Path, default=ROOT / 'work/voc-g2g3-final-readback-20261107-r1/originals-package')
  65. p.add_argument('--generation', required=True)
  66. args = p.parse_args()
  67. try:
  68. print(json.dumps(run(args.store, args.historical, args.reviews, args.generation), ensure_ascii=False))
  69. except Exception as error:
  70. print(json.dumps({'ok': False, 'error': str(error)}, ensure_ascii=False))
  71. sys.exit(1)