app/Http/Controllers/RegularContractCreateController.php を更新
All checks were successful
Deploy so-manager (auto) / deploy (push) Successful in 22s
All checks were successful
Deploy so-manager (auto) / deploy (push) Successful in 22s
自動本人確認テストコード削除
This commit is contained in:
parent
5ba63ace77
commit
00ae084aad
@ -16,7 +16,7 @@ use function redirect;
|
|||||||
class RegularContractCreateController extends Controller
|
class RegularContractCreateController extends Controller
|
||||||
{
|
{
|
||||||
// 新規作成画面表示
|
// 新規作成画面表示
|
||||||
public function show(Request $request)
|
public function show()
|
||||||
{
|
{
|
||||||
$user_id = session('user_id');
|
$user_id = session('user_id');
|
||||||
if (!$user_id) {
|
if (!$user_id) {
|
||||||
@ -111,24 +111,12 @@ class RegularContractCreateController extends Controller
|
|||||||
->get()
|
->get()
|
||||||
->groupBy('park_id');
|
->groupBy('park_id');
|
||||||
|
|
||||||
// ルート名で画面表示を切り替え(新規定期契約 or 駐輪場検索)
|
|
||||||
$isRegularContract = $request->route()->getName() === 'regular_contract.create';
|
|
||||||
|
|
||||||
// ヘッダーの選択状態を分岐
|
|
||||||
$active_menu = $isRegularContract ? 'SWC-8-1' : 'SWC-10-1';
|
|
||||||
|
|
||||||
if ($isRegularContract) {
|
|
||||||
\Log::info('新規定期契約-駐輪場選択画面にアクセス', [
|
\Log::info('新規定期契約-駐輪場選択画面にアクセス', [
|
||||||
'user_id' => $user_id,
|
'user_id' => $user_id,
|
||||||
]);
|
]);
|
||||||
} else {
|
|
||||||
\Log::info('駐輪場検索-駐輪場選択画面にアクセス', [
|
|
||||||
'user_id' => $user_id,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('regular_contract.create', [
|
return view('regular_contract.create', [
|
||||||
'active_menu' => $active_menu, // この画面のID
|
'active_menu' => 'SWC-8-1', // この画面のID
|
||||||
'user_name' => $user ? $user->user_name : '', // ユーザー名(ヘッダー用)
|
'user_name' => $user ? $user->user_name : '', // ユーザー名(ヘッダー用)
|
||||||
'cities' => $cities,
|
'cities' => $cities,
|
||||||
'stations' => $stations,
|
'stations' => $stations,
|
||||||
@ -140,7 +128,6 @@ class RegularContractCreateController extends Controller
|
|||||||
'zones' => $zones,
|
'zones' => $zones,
|
||||||
'city_grace_periods' => $city_grace_periods,
|
'city_grace_periods' => $city_grace_periods,
|
||||||
'reserve' => $reserve,
|
'reserve' => $reserve,
|
||||||
'isRegularContract' => $isRegularContract
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -699,34 +686,7 @@ class RegularContractCreateController extends Controller
|
|||||||
'park_id' => $park_id
|
'park_id' => $park_id
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 処理結果に基づいて遷移先を決定
|
|
||||||
if ($exitCode === 0) {
|
|
||||||
// 成功の場合
|
|
||||||
return redirect("/regular-contract/upload_identity_success?contract_id={$contract_id}");
|
|
||||||
// return view('regular_contract.create_confirm', [
|
|
||||||
// 'contract_id' => $request->contract_id,
|
|
||||||
// 'user' => $user,
|
|
||||||
// 'park' => $park,
|
|
||||||
// 'psection' => $psection,
|
|
||||||
// 'usertype' => $usertype,
|
|
||||||
// 'user_name' => $user->user_name,
|
|
||||||
// 'active_menu' => 'SWC-8-1'
|
|
||||||
// ]);
|
|
||||||
} else {
|
|
||||||
// 失敗の場合 または、学生証 と その他 の場合
|
|
||||||
return redirect("/regular-contract/upload_identity_fail?contract_id={$contract_id}");
|
|
||||||
|
|
||||||
// return view('regular_contract.create_confirm', [
|
|
||||||
// 'contract_id' => $request->contract_id,
|
|
||||||
// 'user' => $user,
|
|
||||||
// 'park' => $park,
|
|
||||||
// 'psection' => $psection,
|
|
||||||
// 'usertype' => $usertype,
|
|
||||||
// 'user_name' => $user->user_name,
|
|
||||||
// 'active_menu' => 'SWC-8-1'
|
|
||||||
// ]);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::error('SHJ-1バッチ処理でエラー発生', [
|
\Log::error('SHJ-1バッチ処理でエラー発生', [
|
||||||
@ -735,8 +695,20 @@ class RegularContractCreateController extends Controller
|
|||||||
'park_id' => $park_id
|
'park_id' => $park_id
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return redirect("/regular-contract/upload_identity_fail?contract_id={$contract_id}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 処理結果に基づいて遷移
|
||||||
|
return view('regular_contract.create_confirm', [
|
||||||
|
'contract_id' => $request->contract_id,
|
||||||
|
'user' => $user,
|
||||||
|
'park' => $park,
|
||||||
|
'psection' => $psection,
|
||||||
|
'usertype' => $usertype,
|
||||||
|
'user_name' => $user->user_name,
|
||||||
|
'active_menu' => 'SWC-8-1'
|
||||||
|
]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createConfirmNext($contract_id)
|
public function createConfirmNext($contract_id)
|
||||||
@ -856,553 +828,8 @@ class RegularContractCreateController extends Controller
|
|||||||
return redirect()->route('wellnet.payment');
|
return redirect()->route('wellnet.payment');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* SHJ-1本人確認処理成功ページ表示!!!!テスト後に削除して!!!!viewも!!!!!
|
|
||||||
*/
|
|
||||||
public function showUploadIdentitySuccess(Request $request)
|
|
||||||
{
|
|
||||||
$contractId = $request->get('contract_id');
|
|
||||||
$userId = Session::get('user_id');
|
|
||||||
|
|
||||||
// 詳細情報を取得
|
|
||||||
$debugInfo = $this->getShjDebugInfo($userId, $contractId);
|
|
||||||
|
|
||||||
return view('regular_contract.upload_identity_success', compact('debugInfo', 'contractId'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SHJ-1本人確認処理失敗ページ表示!!!!テスト後に削除して!!!!viewも!!!!!
|
|
||||||
*/
|
|
||||||
public function showUploadIdentityFail(Request $request)
|
|
||||||
{
|
|
||||||
$contractId = $request->get('contract_id');
|
|
||||||
$userId = Session::get('user_id');
|
|
||||||
|
|
||||||
// 詳細情報を取得
|
|
||||||
$debugInfo = $this->getShjDebugInfo($userId, $contractId);
|
|
||||||
|
|
||||||
return view('regular_contract.upload_identity_fail', compact('debugInfo', 'contractId'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SHJ-1デバッグ情報取得!!!!テスト後に削除して!!!!
|
|
||||||
*/
|
|
||||||
private function getShjDebugInfo($userId, $contractId)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
// ユーザー情報取得
|
|
||||||
$user = DB::table('user')->where('user_id', $userId)->first();
|
|
||||||
|
|
||||||
// 契約情報取得
|
|
||||||
$contract = DB::table('regular_contract')->where('user_id', $user->user_id ?? 0)->first();
|
|
||||||
|
|
||||||
// 駐輪場情報取得
|
|
||||||
$park = null;
|
|
||||||
if ($contract) {
|
|
||||||
$park = DB::table('park')->where('park_id', $contract->park_id)->first();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 最新のSHJ-1バッチログ取得
|
|
||||||
$batchLog = DB::table('batch_log')
|
|
||||||
->where('process_name', 'SHJ-1本人確認自動処理')
|
|
||||||
->orderBy('created_at', 'desc')
|
|
||||||
->first();
|
|
||||||
|
|
||||||
// 最新のログファイルから詳細ログを取得
|
|
||||||
$logContent = $this->getRecentShjLogs();
|
|
||||||
|
|
||||||
// ログからAPI結果情報を解析
|
|
||||||
$apiResults = $this->parseApiResultsFromLogs($logContent);
|
|
||||||
|
|
||||||
return [
|
|
||||||
'user' => $user,
|
|
||||||
'contract' => $contract,
|
|
||||||
'park' => $park,
|
|
||||||
'batch_log' => $batchLog,
|
|
||||||
'detailed_logs' => $logContent,
|
|
||||||
'recent_logs' => $logContent, // 为调试页面提供日志内容访问
|
|
||||||
'timestamp' => now()->format('Y-m-d H:i:s'),
|
|
||||||
// API結果情報
|
|
||||||
'ocr_text_length' => $apiResults['ocr_text_length'],
|
|
||||||
'ocr_text_preview' => $apiResults['ocr_text_preview'],
|
|
||||||
'ocr_full_text' => $apiResults['ocr_full_text'],
|
|
||||||
'ocr_threshold' => $apiResults['ocr_threshold'],
|
|
||||||
'name_similarity' => $apiResults['name_similarity'],
|
|
||||||
'address_similarity' => $apiResults['address_similarity'],
|
|
||||||
'name_passed' => $apiResults['name_passed'],
|
|
||||||
'address_passed' => $apiResults['address_passed'],
|
|
||||||
'matched_address_type' => $apiResults['matched_address_type'] ?? null, // 新增:匹配成功的地址类型
|
|
||||||
'name_match_attempts' => $apiResults['name_match_attempts'],
|
|
||||||
'address_match_attempts' => $apiResults['address_match_attempts'],
|
|
||||||
'best_name_match' => $apiResults['best_name_match'],
|
|
||||||
'best_address_match' => $apiResults['best_address_match'],
|
|
||||||
'name_match_details' => $apiResults['name_match_details'],
|
|
||||||
'address_match_details' => $apiResults['address_match_details'],
|
|
||||||
'ocr_debug_info' => $apiResults['ocr_debug_info'] ?? null,
|
|
||||||
// 移除重复分析逻辑,只显示SHJ-1的结果
|
|
||||||
'calculated_distance' => $apiResults['calculated_distance'],
|
|
||||||
'distance_text' => $apiResults['distance_text'] ?? null,
|
|
||||||
'distance_limit' => $apiResults['distance_limit'] ?? null,
|
|
||||||
'distance_start_address' => $apiResults['distance_start_address'] ?? null,
|
|
||||||
'distance_end_address' => $apiResults['distance_end_address'] ?? null,
|
|
||||||
'distance_passed' => $apiResults['distance_passed'],
|
|
||||||
'maps_api_status' => $apiResults['maps_api_status'],
|
|
||||||
'maps_api_error' => $apiResults['maps_api_error']
|
|
||||||
];
|
|
||||||
|
|
||||||
} catch (Exception $e) {
|
|
||||||
\Log::error('Debug info error: ' . $e->getMessage());
|
|
||||||
return [
|
|
||||||
'error' => 'デバッグ情報の取得に失敗しました: ' . $e->getMessage(),
|
|
||||||
'timestamp' => now()->format('Y-m-d H:i:s')
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 最新のSHJ-1関連ログを取得!!!!テスト後に削除して!!!!
|
|
||||||
*/
|
|
||||||
private function getRecentShjLogs()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$logPath = storage_path('logs/laravel.log');
|
|
||||||
if (!file_exists($logPath)) {
|
|
||||||
return '日志文件未找到';
|
|
||||||
}
|
|
||||||
|
|
||||||
$logs = file_get_contents($logPath);
|
|
||||||
$lines = explode("\n", $logs);
|
|
||||||
|
|
||||||
// 最新の1000行からSHJ-1関連ログを抽出(さらに範囲拡大)
|
|
||||||
$recentLines = array_slice($lines, -1000);
|
|
||||||
$shjLogs = [];
|
|
||||||
|
|
||||||
foreach ($recentLines as $line) {
|
|
||||||
if (strpos($line, 'SHJ-1') !== false ||
|
|
||||||
strpos($line, 'GoogleVision') !== false ||
|
|
||||||
strpos($line, 'Google Maps') !== false ||
|
|
||||||
strpos($line, 'バッチ処理') !== false) {
|
|
||||||
$shjLogs[] = $line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return implode("\n", array_slice($shjLogs, -200)); // 最新200行(さらに拡大)
|
|
||||||
|
|
||||||
} catch (Exception $e) {
|
|
||||||
return 'ログ取得エラー: ' . $e->getMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ログからAPI結果情報を解析!!!!テスト後に削除して!!!!
|
|
||||||
*/
|
|
||||||
private function parseApiResultsFromLogs($logContent)
|
|
||||||
{
|
|
||||||
$results = [
|
|
||||||
'ocr_text_length' => 'N/A',
|
|
||||||
'ocr_text_preview' => 'N/A',
|
|
||||||
'ocr_threshold' => 'N/A',
|
|
||||||
'name_similarity' => 'N/A',
|
|
||||||
'address_similarity' => 'N/A',
|
|
||||||
'name_passed' => false,
|
|
||||||
'address_passed' => false,
|
|
||||||
'calculated_distance' => 'N/A',
|
|
||||||
'distance_passed' => false,
|
|
||||||
'maps_api_status' => '成功',
|
|
||||||
'maps_api_error' => 'なし',
|
|
||||||
// 新增详细OCR信息
|
|
||||||
'ocr_full_text' => 'N/A',
|
|
||||||
'name_match_attempts' => [],
|
|
||||||
'address_match_attempts' => [],
|
|
||||||
'best_name_match' => 'N/A',
|
|
||||||
'best_address_match' => 'N/A',
|
|
||||||
'match_details' => 'N/A'
|
|
||||||
];
|
|
||||||
|
|
||||||
try {
|
|
||||||
// OCR処理完了ログから文字数とプレビューを抽取(清理格式)
|
|
||||||
if (preg_match('/GoogleVision OCR処理完了.*"text_length":(\d+).*"text_preview":"([^"]*)"/', $logContent, $matches)) {
|
|
||||||
$results['ocr_text_length'] = $matches[1];
|
|
||||||
// 清理OCR文本,移除可能的日志污染
|
|
||||||
$cleanText = $matches[2];
|
|
||||||
// 移除可能混入的日志时间戳和标记
|
|
||||||
$cleanText = preg_replace('/\[\d{4}-\d{2}-\d{2}.*?\].*?local\.INFO.*?$/', '', $cleanText);
|
|
||||||
// 移除末尾的不完整JSON片段
|
|
||||||
$cleanText = preg_replace('/\s*\{?\s*$/', '', $cleanText);
|
|
||||||
// 清理换行和多余空格
|
|
||||||
$cleanText = trim($cleanText);
|
|
||||||
$results['ocr_text_preview'] = $cleanText;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试从GoogleVision日志提取完整的OCR文本
|
|
||||||
if (preg_match('/GoogleVision OCR処理完了.*"text_full":"([^"]*)"/', $logContent, $matches)) {
|
|
||||||
$fullText = $matches[1];
|
|
||||||
// 解码JSON转义字符
|
|
||||||
$fullText = str_replace('\n', "\n", $fullText);
|
|
||||||
$fullText = str_replace('\r', "\r", $fullText);
|
|
||||||
$fullText = str_replace('\"', '"', $fullText);
|
|
||||||
$fullText = str_replace('\\\\', '\\', $fullText);
|
|
||||||
$results['ocr_full_text'] = $fullText;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试从SHJ-1日志提取完整的OCR文本(多种模式匹配)
|
|
||||||
$patterns = [
|
|
||||||
'/SHJ-1 完全OCR認識結果.*"ocr_full_text":"([^"]*)"/', // 原始日文版本
|
|
||||||
'/螳悟・OCR隱崎ュ倡オ先棡.*"ocr_full_text":"([^"]*)"/', // 日文编码版本
|
|
||||||
'/OCR認識結果.*"ocr_full_text":"([^"]*)"/', // 简化匹配
|
|
||||||
'/"ocr_full_text":"([^"]*)"/', // 最宽泛匹配
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($patterns as $pattern) {
|
|
||||||
if (empty($results['ocr_full_text']) && preg_match($pattern, $logContent, $matches)) {
|
|
||||||
$encodedText = $matches[1];
|
|
||||||
// Base64解码
|
|
||||||
$fullText = base64_decode($encodedText);
|
|
||||||
if ($fullText !== false && strlen($fullText) > 10) {
|
|
||||||
$results['ocr_full_text'] = $fullText;
|
|
||||||
|
|
||||||
// 简化OCR信息显示 - 只显示基本信息
|
|
||||||
$results['ocr_debug_info'] = [
|
|
||||||
'decoded_length' => strlen($fullText),
|
|
||||||
'preview' => substr($fullText, 0, 200)
|
|
||||||
];
|
|
||||||
break; // 找到后停止尝试其他模式
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试从OCR认识内容详细日志提取(备选方案,适配日文编码)
|
|
||||||
if (empty($results['ocr_full_text']) && preg_match('/OCR隱崎ュ伜・螳ケ隧ウ邏ー.*"raw_text":"OCR_TEXT_START>([^<]*)<OCR_TEXT_END"/', $logContent, $matches)) {
|
|
||||||
$results['ocr_full_text'] = $matches[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提取氏名匹配详细信息(适配日文编码)
|
|
||||||
$nameMatchDetails = [];
|
|
||||||
if (preg_match_all('/豌丞錐繝槭ャ繝√Φ繧ー隧ウ邏ー.*"target_name":"([^"]*)".*"similarity_score":([^,}]*).*"ocr_contains_name":"([^"]*)"/', $logContent, $nameMatches, PREG_SET_ORDER)) {
|
|
||||||
foreach ($nameMatches as $match) {
|
|
||||||
$nameMatchDetails[] = [
|
|
||||||
'target' => $match[1],
|
|
||||||
'score' => round(floatval($match[2]), 2),
|
|
||||||
'found_in_ocr' => $match[3]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$results['name_match_details'] = $nameMatchDetails;
|
|
||||||
|
|
||||||
// 提取住所匹配详细信息(适配日文编码)
|
|
||||||
$addressMatchDetails = [];
|
|
||||||
if (preg_match_all('/菴乗園繝槭ャ繝√Φ繧ー隧ウ邏ー.*"target_address":"([^"]*)".*"address_type":"([^"]*)".*"similarity_score":([^,}]*).*"ocr_contains_address":"([^"]*)"/', $logContent, $addressMatches, PREG_SET_ORDER)) {
|
|
||||||
foreach ($addressMatches as $match) {
|
|
||||||
$addressMatchDetails[] = [
|
|
||||||
'target' => $match[1],
|
|
||||||
'type' => $match[2],
|
|
||||||
'score' => round(floatval($match[3]), 2),
|
|
||||||
'found_in_ocr' => $match[4]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$results['address_match_details'] = $addressMatchDetails;
|
|
||||||
|
|
||||||
// 从新的SHJ-1日志格式中提取信息
|
|
||||||
|
|
||||||
// 提取OCR抽出结果
|
|
||||||
if (preg_match('/SHJ-1 OCR抽出成功.*"extracted_name":"([^"]*)".*"extracted_address":"([^"]*)".*"ocr_value":"([^"]*)"/', $logContent, $matches)) {
|
|
||||||
$results['extracted_name'] = $matches[1];
|
|
||||||
$results['extracted_address'] = $matches[2];
|
|
||||||
$results['extracted_ocr_value'] = $matches[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提取居住住所照合结果
|
|
||||||
if (preg_match('/SHJ-1 居住住所照合.*"resident_address":"([^"]*)".*"similarity":([^,}]*)/', $logContent, $matches)) {
|
|
||||||
$results['resident_address'] = $matches[1];
|
|
||||||
$results['resident_similarity'] = round(floatval($matches[2]), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提取関連住所照合结果
|
|
||||||
if (preg_match('/SHJ-1 関連住所照合.*"related_address":"([^"]*)".*"similarity":([^,}]*)/', $logContent, $matches)) {
|
|
||||||
$results['related_address'] = $matches[1];
|
|
||||||
$results['related_similarity'] = round(floatval($matches[2]), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提取最終OCR結果
|
|
||||||
if (preg_match('/SHJ-1 OCR照合(成功|失敗)/', $logContent, $matches)) {
|
|
||||||
$results['final_ocr_result'] = $matches[1];
|
|
||||||
$results['address_passed'] = ($matches[1] === '成功');
|
|
||||||
$results['name_passed'] = ($matches[1] === '成功'); // 新SHJ-1逻辑中,成功表示整体成功
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果OCR文本为空或太短,提供说明
|
|
||||||
if (empty($results['ocr_text_preview']) || strlen($results['ocr_text_preview']) < 5) {
|
|
||||||
$results['ocr_text_preview'] = '(OCR認識内容が短いか、表示できない文字が含まれています)';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 表面画像処理完了の詳細結果を抽取
|
|
||||||
if (preg_match('/SHJ-1 表面画像処理完了.*"front_result":\{"name_matches":\[([^\]]*)\],"address_matches":\[([^\]]*)\]\}/', $logContent, $matches)) {
|
|
||||||
$nameMatches = explode(',', $matches[1]);
|
|
||||||
$addressMatches = explode(',', $matches[2]);
|
|
||||||
|
|
||||||
$results['name_match_attempts'] = array_map(function($val) {
|
|
||||||
return round(floatval($val), 2);
|
|
||||||
}, $nameMatches);
|
|
||||||
|
|
||||||
$results['address_match_attempts'] = array_map(function($val) {
|
|
||||||
return round(floatval($val), 2);
|
|
||||||
}, $addressMatches);
|
|
||||||
}
|
|
||||||
|
|
||||||
// OCR類似度計算結果の詳細情報を抽取
|
|
||||||
if (preg_match('/SHJ-1 OCR類似度計算結果.*"best_name_match":([^,}]*).*"best_address_match":([^,}]*).*"all_name_matches":\[([^\]]*)\].*"all_address_matches":\[([^\]]*)\]/', $logContent, $matches)) {
|
|
||||||
$results['best_name_match'] = round(floatval($matches[1]), 2);
|
|
||||||
$results['best_address_match'] = round(floatval($matches[2]), 2);
|
|
||||||
|
|
||||||
$allNameMatches = explode(',', $matches[3]);
|
|
||||||
$allAddressMatches = explode(',', $matches[4]);
|
|
||||||
|
|
||||||
$results['name_match_attempts'] = array_map(function($val) {
|
|
||||||
return round(floatval($val), 2);
|
|
||||||
}, $allNameMatches);
|
|
||||||
|
|
||||||
$results['address_match_attempts'] = array_map(function($val) {
|
|
||||||
return round(floatval($val), 2);
|
|
||||||
}, $allAddressMatches);
|
|
||||||
}
|
|
||||||
|
|
||||||
// OCR閾値チェックログから類似度情報を抽出(新しい順序匹配対応)
|
|
||||||
if (preg_match('/SHJ-1 OCR閾値チェック.*"threshold":"?([^",}]*)"?.*"name_match":([^,}]*).*"address_match":([^,}]*).*"name_passed":([^,}]*).*"address_passed":([^,}]*).*"matched_address_type":"?([^",}]*)"?/', $logContent, $matches)) {
|
|
||||||
$results['ocr_threshold'] = $matches[1];
|
|
||||||
$results['name_similarity'] = round(floatval($matches[2]), 2);
|
|
||||||
$results['address_similarity'] = round(floatval($matches[3]), 2);
|
|
||||||
$results['name_passed'] = $matches[4] === 'true';
|
|
||||||
$results['address_passed'] = $matches[5] === 'true';
|
|
||||||
$results['matched_address_type'] = $matches[6] ?: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Google Maps API エラーチェック
|
|
||||||
if (strpos($logContent, 'Google Maps distance calculation error') !== false) {
|
|
||||||
$results['maps_api_status'] = 'エラー';
|
|
||||||
if (preg_match('/Google Maps distance calculation error.*"error":"([^"]*)"/', $logContent, $matches)) {
|
|
||||||
$results['maps_api_error'] = $matches[1];
|
|
||||||
}
|
|
||||||
} else if (strpos($logContent, 'Distance calculation failed') !== false) {
|
|
||||||
$results['maps_api_status'] = 'アドレス未発見';
|
|
||||||
$results['maps_api_error'] = 'NOT_FOUND';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 距離計算結果を抽取(最新の詳細ログから)
|
|
||||||
if (preg_match_all('/SHJ-1 距離計算完了.*"calculated_distance_meters":(\d+).*"distance_text":"([^"]*)".*"limit_meters":"?([^",}]*)"?.*"within_limit":([^,}]*)/', $logContent, $allMatches, PREG_SET_ORDER)) {
|
|
||||||
// 最後の(最新の)マッチを使用
|
|
||||||
$matches = end($allMatches);
|
|
||||||
$results['calculated_distance'] = $matches[1]; // 距離メートル
|
|
||||||
$results['distance_text'] = $matches[2]; // Google Mapsテキスト
|
|
||||||
$results['distance_limit'] = $matches[3]; // 制限値
|
|
||||||
$results['distance_passed'] = $matches[4] === 'true';
|
|
||||||
} else {
|
|
||||||
// ログから具体的な結果が取得できない場合はデフォルト値を設定
|
|
||||||
// ※重要:API成功≠距離制限内ではないため、明示的にfalseにする
|
|
||||||
$results['distance_passed'] = false;
|
|
||||||
if (strpos($logContent, 'Distance check error') === false &&
|
|
||||||
strpos($logContent, 'Google Maps distance calculation error') === false) {
|
|
||||||
$results['calculated_distance'] = '計算成功(制限値詳細はログで確認)';
|
|
||||||
$results['maps_api_status'] = '成功(但制限確認要)';
|
|
||||||
} else {
|
|
||||||
$results['calculated_distance'] = '計算失敗';
|
|
||||||
$results['maps_api_status'] = 'エラー';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 距離計算開始ログから起点・終点住所を抽取
|
|
||||||
if (preg_match('/SHJ-1 距離計算開始.*"user_address":"([^"]*)".*"park_address":"([^"]*)"/', $logContent, $matches)) {
|
|
||||||
$results['distance_start_address'] = $matches[1];
|
|
||||||
$results['distance_end_address'] = $matches[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception $e) {
|
|
||||||
\Log::error('API結果解析エラー: ' . $e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不再需要的分析方法已移除 - 只显示SHJ-1的结果
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 废弃的方法(已不再使用)
|
|
||||||
*/
|
|
||||||
private function manualOcrAnalysis($logContent, $user = null)
|
|
||||||
{
|
|
||||||
$analysis = [
|
|
||||||
'found_base64' => false,
|
|
||||||
'decoded_success' => false,
|
|
||||||
'decoded_text' => '',
|
|
||||||
'contains_yamada' => false,
|
|
||||||
'contains_taro' => false,
|
|
||||||
'contains_tokyo' => false,
|
|
||||||
'contains_osaka' => false,
|
|
||||||
'full_analysis' => 'Analysis failed',
|
|
||||||
'corrected_matching' => null
|
|
||||||
];
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 分割日志内容为行数组,按时间倒序搜索最新的OCR结果
|
|
||||||
$logLines = explode("\n", $logContent);
|
|
||||||
$logLines = array_reverse($logLines); // 从最新的开始搜索
|
|
||||||
|
|
||||||
// 查找最新的Base64编码OCR结果
|
|
||||||
$patterns = [
|
|
||||||
'/SHJ-1 完全OCR認識結果.*"ocr_full_text":"([^"]*)"/',
|
|
||||||
'/SHJ-1.*OCR.*結果.*"ocr_full_text":"([^"]*)"/',
|
|
||||||
'/"ocr_full_text":"([^"]*)"/'
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($logLines as $line) {
|
|
||||||
foreach ($patterns as $pattern) {
|
|
||||||
if (preg_match($pattern, $line, $matches)) {
|
|
||||||
$analysis['found_base64'] = true;
|
|
||||||
$base64Text = $matches[1];
|
|
||||||
|
|
||||||
// Base64解码
|
|
||||||
$decodedText = base64_decode($base64Text);
|
|
||||||
if ($decodedText !== false && strlen($decodedText) > 10) {
|
|
||||||
$analysis['decoded_success'] = true;
|
|
||||||
$analysis['decoded_text'] = $decodedText;
|
|
||||||
|
|
||||||
// 内容分析
|
|
||||||
$analysis['contains_yamada'] = strpos($decodedText, '山田') !== false;
|
|
||||||
$analysis['contains_taro'] = strpos($decodedText, '太郎') !== false;
|
|
||||||
$analysis['contains_tokyo'] = strpos($decodedText, '東京') !== false;
|
|
||||||
$analysis['contains_osaka'] = strpos($decodedText, '大阪') !== false;
|
|
||||||
|
|
||||||
// ユーザー提案:空白と改行を除去して比較
|
|
||||||
$analysis['corrected_matching'] = $this->performCorrectedMatching($decodedText, $user);
|
|
||||||
|
|
||||||
// 詳細分析(実際のユーザーデータから期待値を取得)
|
|
||||||
if ($user) {
|
|
||||||
$expectedName = $user->user_name ?? "";
|
|
||||||
$expectedAddress = ($user->user_regident_pre ?? '') .
|
|
||||||
($user->user_regident_city ?? '') .
|
|
||||||
($user->user_regident_add ?? '') ?: "";
|
|
||||||
} else {
|
|
||||||
$expectedName = "";
|
|
||||||
$expectedAddress = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
$analysis['full_analysis'] =
|
|
||||||
"OCR認識テキスト長: " . strlen($decodedText) . "文字\n" .
|
|
||||||
"期待氏名: '$expectedName'\n" .
|
|
||||||
"期待住所: '$expectedAddress'\n" .
|
|
||||||
"山田を含む: " . ($analysis['contains_yamada'] ? 'YES' : 'NO') . "\n" .
|
|
||||||
"太郎を含む: " . ($analysis['contains_taro'] ? 'YES' : 'NO') . "\n" .
|
|
||||||
"東京を含む: " . ($analysis['contains_tokyo'] ? 'YES' : 'NO') . "\n" .
|
|
||||||
"大阪を含む: " . ($analysis['contains_osaka'] ? 'YES' : 'NO') . "\n" .
|
|
||||||
"認識完全内容: " . substr($decodedText, 0, 200) . "...";
|
|
||||||
|
|
||||||
// 成功解码最新OCR结果后立即返回
|
|
||||||
return $analysis;
|
|
||||||
}
|
|
||||||
// 解码失败时,继续搜索其他条目
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$analysis['full_analysis'] = 'OCR分析エラー: ' . $e->getMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $analysis;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修正マッチングアルゴリズム実行(空白・改行除去)
|
|
||||||
*/
|
|
||||||
private function performCorrectedMatching($ocrText, $user = null)
|
|
||||||
{
|
|
||||||
// ユーザー情報から期待値を取得、デフォルトはテスト用
|
|
||||||
if ($user) {
|
|
||||||
$expectedName = $user->user_name ?? "";
|
|
||||||
$expectedAddress = ($user->user_regident_pre ?? '') .
|
|
||||||
($user->user_regident_city ?? '') .
|
|
||||||
($user->user_regident_add ?? '') ?: "";
|
|
||||||
} else {
|
|
||||||
$expectedName = "";
|
|
||||||
$expectedAddress = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 統一的テキスト正規化関数
|
|
||||||
$normalize = function($text) {
|
|
||||||
// 全空白文字と改行を除去(全角スペース含む)
|
|
||||||
$text = preg_replace('/[\s\x{3000}]+/u', '', $text); // \x{3000}は全角スペース
|
|
||||||
// 一般的な空白文字を明示的に除去
|
|
||||||
$text = str_replace([' ', ' ', "\t", "\n", "\r"], '', $text);
|
|
||||||
// 全角→半角変換
|
|
||||||
$text = mb_convert_kana($text, 'rnask', 'UTF-8');
|
|
||||||
// 住所統一
|
|
||||||
$text = str_replace(['東京市', '東京府'], '東京都', $text);
|
|
||||||
$text = str_replace(['の'], '', $text);
|
|
||||||
// 数字統一
|
|
||||||
$text = str_replace(['1','2','3','4','5','6','7','8','9','0'],
|
|
||||||
['1','2','3','4','5','6','7','8','9','0'], $text);
|
|
||||||
return $text;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 正規化処理
|
|
||||||
$normalizedOcr = $normalize($ocrText);
|
|
||||||
$normalizedExpectedName = $normalize($expectedName);
|
|
||||||
$normalizedExpectedAddr = $normalize($expectedAddress);
|
|
||||||
|
|
||||||
// 使用"住所"分割OCR文本
|
|
||||||
$addressKeyword = '住所';
|
|
||||||
$ocrParts = explode($addressKeyword, $normalizedOcr, 2);
|
|
||||||
|
|
||||||
$personalInfoSection = $ocrParts[0] ?? ''; // "住所"前の個人情報欄
|
|
||||||
$addressSection = isset($ocrParts[1]) ? $addressKeyword . $ocrParts[1] : ''; // "住所"後の住所欄
|
|
||||||
|
|
||||||
// 分区マッチング計算
|
|
||||||
$nameMatch = $this->calculateSimpleMatch($normalizedExpectedName, $personalInfoSection);
|
|
||||||
$addrMatch = $this->calculateSimpleMatch($normalizedExpectedAddr, $addressSection);
|
|
||||||
|
|
||||||
return [
|
|
||||||
'original_ocr' => substr($ocrText, 0, 100) . '...',
|
|
||||||
'normalized_ocr' => substr($normalizedOcr, 0, 100) . '...',
|
|
||||||
'normalized_expected_name' => $normalizedExpectedName,
|
|
||||||
'normalized_expected_addr' => $normalizedExpectedAddr,
|
|
||||||
'personal_info_section' => substr($personalInfoSection, 0, 80) . '...',
|
|
||||||
'address_section' => substr($addressSection, 0, 80) . '...',
|
|
||||||
'name_match_score' => $nameMatch,
|
|
||||||
'addr_match_score' => $addrMatch,
|
|
||||||
'name_passed' => $nameMatch >= 70,
|
|
||||||
'addr_passed' => $addrMatch >= 70,
|
|
||||||
'overall_result' => ($nameMatch >= 70 && $addrMatch >= 70) ? 'PASS' : 'FAIL'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* シンプルマッチング計算
|
|
||||||
*/
|
|
||||||
private function calculateSimpleMatch($expected, $haystack)
|
|
||||||
{
|
|
||||||
if (empty($expected)) return 0;
|
|
||||||
|
|
||||||
// 1. 完全包含チェック
|
|
||||||
if (strpos($haystack, $expected) !== false) {
|
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 文字包含率
|
|
||||||
$expectedChars = mb_str_split($expected, 1, 'UTF-8');
|
|
||||||
$foundChars = 0;
|
|
||||||
|
|
||||||
foreach ($expectedChars as $char) {
|
|
||||||
if (mb_strpos($haystack, $char, 0, 'UTF-8') !== false) {
|
|
||||||
$foundChars++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$charRate = ($foundChars / count($expectedChars)) * 100;
|
|
||||||
|
|
||||||
// 3. 類似度計算
|
|
||||||
similar_text($expected, $haystack, $similarRate);
|
|
||||||
|
|
||||||
// 最高スコアを返す
|
|
||||||
return max($charRate, $similarRate);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user