From 8aa52ec639006864a0f48d7cac74d14aadcf859d Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Sat, 9 May 2026 01:52:09 +0200 Subject: [PATCH] asdasd --- modules/mining-checker/assets/js/app.js | 10 +- .../mining-checker/src/Domain/OcrService.php | 112 +++++++++++++----- 2 files changed, 84 insertions(+), 38 deletions(-) diff --git a/modules/mining-checker/assets/js/app.js b/modules/mining-checker/assets/js/app.js index 2a0b4eb..8d1301b 100644 --- a/modules/mining-checker/assets/js/app.js +++ b/modules/mining-checker/assets/js/app.js @@ -2268,17 +2268,15 @@ ]); })) : h('div', { className: 'mc-empty' }, 'Noch keine Wallet-Assets erkannt.')), - panel('Wallet-Historie', 'Erkannte Wallet-Snapshots mit allen aus dem Screenshot gelesenen Assets.', h('div', { className: 'mc-table-shell' }, [ + panel('Wallet-Historie', 'Die letzten 10 Wallet-Uploads mit allen aus dem Screenshot gelesenen Assets.', h('div', { className: 'mc-table-shell' }, [ h('table', { key: 'wallet-table', className: 'mc-table' }, [ h('thead', { key: 'thead' }, h('tr', null, [ - 'Zeit', 'Mining-Waehrung', 'Mining-Bestand', 'Quelle', 'Assets' + 'Zeit', 'Quelle', 'Assets' ].map((label) => h('th', { key: label }, label)))), h('tbody', { key: 'tbody' }, currentWalletSnapshots.length - ? currentWalletSnapshots.map((row) => h('tr', { key: row.id }, [ + ? currentWalletSnapshots.slice(0, 10).map((row) => h('tr', { key: row.id }, [ h('td', { key: 'measured' }, fmtDate(row.measured_at)), - h('td', { key: 'currency' }, row.wallet_currency || currentSettings.crypto_currency || 'DOGE'), - h('td', { key: 'balance' }, row.wallet_balance !== null && row.wallet_balance !== undefined ? `${fmtNumber(row.wallet_balance, 8)} ${row.wallet_currency || ''}`.trim() : 'n/a'), h('td', { key: 'source' }, row.source || 'manual'), h('td', { key: 'assets' }, h('div', { className: 'mc-asset-list' }, Object.entries(row.balances_json || {}).map(([code, asset]) => { const balance = asset && typeof asset === 'object' ? asset.balance : asset; @@ -2293,7 +2291,7 @@ ]); }))), ])) - : [h('tr', { key: 'empty' }, h('td', { colSpan: 5 }, 'Noch keine Wallet-Snapshots gespeichert.'))] + : [h('tr', { key: 'empty' }, h('td', { colSpan: 3 }, 'Noch keine Wallet-Snapshots gespeichert.'))] ), ]), ])), diff --git a/modules/mining-checker/src/Domain/OcrService.php b/modules/mining-checker/src/Domain/OcrService.php index f6ec371..2e8bc3d 100644 --- a/modules/mining-checker/src/Domain/OcrService.php +++ b/modules/mining-checker/src/Domain/OcrService.php @@ -491,47 +491,50 @@ final class OcrService $flags[] = 'wallet_total_missing'; } - preg_match_all( - '/([A-Z][A-Za-z0-9]+(?:\s+[A-Z][A-Za-z0-9]+)*)\s+(\d+(?:[.,]\d+)?)\s+([A-Z]{2,10})\s+(?:\d+(?:[.,]\d+)?)\s+USD\s+(\d+(?:[.,]\d+)?)\s+USD/u', - $normalizedText, - $assetRowMatches, - PREG_SET_ORDER - ); - foreach ($assetRowMatches as $match) { - $balanceAmount = round((float) str_replace(',', '.', $match[2]), 10); - $assetCurrency = strtoupper((string) $match[3]); - $priceAmount = round((float) str_replace(',', '.', $match[4]), 8); - if ($balanceAmount <= 0 || $assetCurrency === '') { + $assetRows = []; + foreach ($lines as $lineIndex => $line) { + if (!preg_match('/(\d+(?:[.,]\d+)?)\s*([A-Z]{2,10})\b/u', $line, $match)) { continue; } - - $balances[$assetCurrency] = [ - 'balance' => $balanceAmount, - 'price_amount' => $priceAmount > 0 ? $priceAmount : null, - 'price_currency' => $priceAmount > 0 ? 'USD' : null, - ]; - } - - preg_match_all('/(\d+(?:[.,]\d+)?)\s*([A-Z]{2,10})\b/u', $normalizedText, $balanceMatches, PREG_SET_ORDER); - foreach ($balanceMatches as $match) { $amount = round((float) str_replace(',', '.', $match[1]), 10); $currency = strtoupper((string) $match[2]); if ($amount <= 0 || $currency === '' || in_array($currency, ['USD', 'EUR'], true)) { continue; } - if (!isset($balances[$currency])) { - $balances[$currency] = [ - 'balance' => $amount, - 'price_amount' => null, - 'price_currency' => null, - ]; - continue; + + $assetRows[] = [ + 'index' => $lineIndex, + 'currency' => $currency, + 'balance' => $amount, + ]; + } + + foreach ($assetRows as $assetIndex => $assetRow) { + $currency = (string) $assetRow['currency']; + $balanceAmount = (float) $assetRow['balance']; + $startIndex = (int) $assetRow['index']; + $endIndex = isset($assetRows[$assetIndex + 1]['index']) + ? (int) $assetRows[$assetIndex + 1]['index'] + : count($lines); + + $usdCandidates = []; + for ($i = $startIndex; $i < $endIndex; $i++) { + if (!isset($lines[$i])) { + continue; + } + if (preg_match_all('/(\d+(?:[.,]\d+)?)\s*USD\b/u', $lines[$i], $usdMatches, PREG_SET_ORDER)) { + foreach ($usdMatches as $usdMatch) { + $usdCandidates[] = round((float) str_replace(',', '.', $usdMatch[1]), 8); + } + } } - $existingBalance = is_array($balances[$currency]) ? (float) ($balances[$currency]['balance'] ?? 0.0) : (float) $balances[$currency]; - if ($amount > $existingBalance) { - $balances[$currency]['balance'] = $amount; - } + $priceAmount = $this->pickWalletUnitPrice($balanceAmount, $usdCandidates); + $balances[$currency] = [ + 'balance' => $balanceAmount, + 'price_amount' => $priceAmount, + 'price_currency' => $priceAmount !== null ? 'USD' : null, + ]; } if ($walletCurrencyHint !== '' && array_key_exists($walletCurrencyHint, $balances)) { @@ -597,4 +600,49 @@ final class OcrService 'score' => $score, ]; } + + /** + * @param list $candidates + */ + private function pickWalletUnitPrice(float $balance, array $candidates): ?float + { + $candidates = array_values(array_filter(array_map( + static fn (mixed $value): float => round((float) $value, 8), + $candidates + ), static fn (float $value): bool => $value > 0)); + + if ($balance <= 0 || $candidates === []) { + return null; + } + if (count($candidates) === 1) { + return $candidates[0]; + } + + $bestPrice = null; + $bestError = null; + $candidateCount = count($candidates); + + for ($i = 0; $i < $candidateCount; $i++) { + $priceCandidate = $candidates[$i]; + for ($j = 0; $j < $candidateCount; $j++) { + if ($i === $j) { + continue; + } + $totalCandidate = $candidates[$j]; + $estimatedTotal = $balance * $priceCandidate; + $denominator = max(abs($totalCandidate), 0.00000001); + $error = abs($estimatedTotal - $totalCandidate) / $denominator; + if ($bestError === null || $error < $bestError) { + $bestError = $error; + $bestPrice = $priceCandidate; + } + } + } + + if ($bestPrice !== null && $bestError !== null && $bestError <= 0.2) { + return round($bestPrice, 8); + } + + return round($candidates[count($candidates) - 1], 8); + } }