公開前の確認用サイト
日常訳NICHIJOYAKUEnglish ↗

SOURCE EXPLORER / 資料ブラウザー

recover-session-usage.py

実装と資料を、行ごとに確かめる。

日常訳はAIを用いて作成された翻訳です。人間の聖書学・原語の専門家による全訳の検証は確認されていません。既存の翻訳や原語資料と照らし合わせてお読みください。

recover-session-usage.py79 行原本を保存 ↓

site extraction script · web/nichijoyaku-com/scripts/recover-session-usage.py

出典とハッシュ

資料取得日: 2026-10-03. 取得元の詳細は資料インデックスを参照。

SHA-256 9533811bdbd2ce54a7168332f7faeffddc9c086dacd955a3556da96752096e73

index.json ↗

関数・クラスへ移動 (1)

行番号は、その行へのリンクです。ページ内検索は ⌘F / Ctrl+F。

1"""Aggregate a project-scoped Claude session archive without exporting messages."""2import argparse3import hashlib4import json5from collections import Counter6from pathlib import Path78FIELDS = ('input_tokens', 'cache_creation_input_tokens', 'cache_read_input_tokens', 'output_tokens')91011def summarize(directory):12    requests = {}13    errors = set()14    duplicate_records = 015    synthetic_records = 016    inventory = hashlib.sha256()17    files = sorted(directory.rglob('*.jsonl'))18    for path in files:19        raw = path.read_bytes()20        inventory.update(str(path.relative_to(directory)).encode() + b'\0' + hashlib.sha256(raw).digest())21        for line in raw.splitlines():22            record = json.loads(line)23            if record.get('type') != 'assistant':24                continue25            message = record['message']26            if record.get('isApiErrorMessage') and record.get('error') == 'rate_limit':27                errors.add(record['uuid'])28            if message.get('model') == '<synthetic>':29                synthetic_records += 130                continue31            if not message.get('usage'):32                continue33            key = message['id']34            if not key or not record.get('requestId'):35                raise ValueError('Usage record lacks stable message/request identity')36            usage = {field: message['usage'][field] for field in FIELDS}37            if any(not isinstance(n, int) or n < 0 for n in usage.values()):38                raise ValueError('Invalid token counter')39            item = {'request_id': record['requestId'], 'model': message['model'], 'tokens': usage}40            if key in requests:41                if requests[key]['identity'] != item:42                    raise ValueError('Conflicting usage snapshots; reconcile before publishing')43                duplicate_records += 144                requests[key]['timestamp'] = min(requests[key]['timestamp'], record['timestamp'])45            else:46                requests[key] = {'identity': item, 'timestamp': record['timestamp']}47    models = {}48    for request in requests.values():49        item = request['identity']50        model = item['model']51        if model not in models:52            models[model] = {'tokens': Counter(), 'requests': 0, 'first_timestamp': request['timestamp'], 'last_timestamp': request['timestamp']}53        row = models[model]54        row['tokens'].update(item['tokens'])55        row['requests'] += 156        row['first_timestamp'] = min(row['first_timestamp'], request['timestamp'])57        row['last_timestamp'] = max(row['last_timestamp'], request['timestamp'])58    for row in models.values():59        row['total_tokens'] = sum(row['tokens'].values())60    return {'schema': 1, 'captured_at': '2026-10-03',61        'scope': 'Local Claude session archive for the historical cli-tool/translate-bible project directory only. Not a complete project history or a provider quota statement.',62        'archive_files': len(files), 'archive_inventory_sha256': inventory.hexdigest(),63        'unique_requests': len(requests), 'duplicate_usage_records_removed': duplicate_records,64        'synthetic_records_excluded': synthetic_records, 'distinct_rate_limit_error_records': len(errors),65        'models': models, 'total_tokens': sum(row['total_tokens'] for row in models.values()),66        'counting': 'Deduplicate by assistant message ID; require identical request ID, model and top-level counters across repeated records. Sum input + cache creation + cache read + output once. Do not add nested iterations, thinking details, or modelUsage.',67        'limits': ['Only the recovered local archive is covered; other dates, machines, deleted logs and unrecorded calls are absent.',68                   'Haiku records include CLI session-labeling work; this is not evidence that every Haiku call translated or reviewed scripture.',69                   'Rate-limit error entries are not distinct quota-exhaustion episodes and carry no measured consumed-token estimate.',70                   'Cache token counts and nominal token totals are not a measurement of subscription quota consumed.',71                   'The separate 38-call release audit is not included in this total.'],72        'whole_project_total_tokens': None}737475if __name__ == '__main__':76    parser = argparse.ArgumentParser()77    parser.add_argument('--sessions', type=Path, required=True)78    print(json.dumps(summarize(parser.parse_args().sessions), ensure_ascii=False, indent=2))79