- URL 하드코딩 → .env APP_URL 기반 동적 URL로 변경 - DB 연결 하드코딩 → .env 기반으로 변경 - MySQL strict mode DATE 오류 수정
169 lines
5.0 KiB
PHP
169 lines
5.0 KiB
PHP
<?php
|
|
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
|
|
|
|
// 권한 체크
|
|
if ($level > 5) {
|
|
echo json_encode(['ok' => false, 'error' => '접근 권한이 없습니다.']);
|
|
exit;
|
|
}
|
|
|
|
// POST 데이터 받기
|
|
$input = file_get_contents('php://input');
|
|
$data = json_decode($input, true);
|
|
|
|
if (!isset($data['image'])) {
|
|
echo json_encode(['ok' => false, 'error' => '이미지 데이터가 없습니다.']);
|
|
exit;
|
|
}
|
|
|
|
$imageBase64 = $data['image'];
|
|
$rawText = isset($data['raw_text']) ? $data['raw_text'] : null; // OCR 텍스트는 선택사항
|
|
|
|
// API 키 읽기
|
|
$apiKeyFile = $_SERVER['DOCUMENT_ROOT'] . '/apikey/claude_api.txt';
|
|
if (!file_exists($apiKeyFile)) {
|
|
echo json_encode(['ok' => false, 'error' => 'API 키 파일이 존재하지 않습니다.']);
|
|
exit;
|
|
}
|
|
|
|
$apiKey = trim(file_get_contents($apiKeyFile));
|
|
|
|
// Claude API 요청
|
|
$promptText = "제공된 사업자등록증 이미지를 직접 분석하여 아래 필드를 정확하게 추출해주세요.\n\n";
|
|
|
|
if ($rawText) {
|
|
$promptText .= "참고: OCR 텍스트가 제공되었지만 부정확할 수 있으니, 이미지를 직접 읽어서 정확한 정보를 추출해주세요.\n";
|
|
$promptText .= "OCR 텍스트(참고용): {$rawText}\n\n";
|
|
}
|
|
|
|
$promptText .= <<<EOT
|
|
추출할 필드:
|
|
1. 사업자등록번호 (10자리 숫자, 형식: 000-00-00000)
|
|
2. 상호명 (법인명 또는 단체명)
|
|
3. 대표자명 (한글 이름)
|
|
4. 개업일자 (YYYY-MM-DD 형식)
|
|
5. 본점 소재지 (주소)
|
|
6. 업태
|
|
7. 종목
|
|
8. 발급일자 (YYYY-MM-DD 형식)
|
|
|
|
**중요 지침:**
|
|
- 이미지를 직접 읽어서 정확한 텍스트를 추출하세요.
|
|
- 사업자등록번호는 정확히 10자리 숫자여야 하며, 하이픈을 포함하여 000-00-00000 형식으로 반환하세요.
|
|
- 날짜는 YYYY-MM-DD 형식으로 변환하세요 (예: 2015년 06월 02일 → 2015-06-02).
|
|
- 대표자명은 2-4자의 한글 이름이어야 합니다.
|
|
- 이미지가 흐리거나 화질이 좋지 않아도 최대한 정확하게 읽어주세요.
|
|
- 특수문자나 공백을 정리해주세요.
|
|
|
|
**응답 형식 (JSON만 반환, 설명 없이):**
|
|
{
|
|
"biz_no": "123-45-67890",
|
|
"company_name": "주식회사 예시",
|
|
"representative": "홍길동",
|
|
"open_date": "2015-06-02",
|
|
"address": "서울특별시 강남구 ...",
|
|
"type": "제조업",
|
|
"item": "엘리베이터부장품",
|
|
"issue_date": "2024-01-15"
|
|
}
|
|
|
|
데이터를 찾을 수 없으면 빈 문자열("")로 반환하세요.
|
|
EOT;
|
|
|
|
// Claude API 호출
|
|
$apiUrl = 'https://api.anthropic.com/v1/messages';
|
|
|
|
// 이미지 데이터 준비 (base64에서 data:image/... 부분 제거)
|
|
$imageData = $imageBase64;
|
|
if (preg_match('/^data:image\/(\w+);base64,(.+)$/', $imageBase64, $matches)) {
|
|
$imageType = $matches[1]; // png, jpeg 등
|
|
$imageData = $matches[2]; // 순수 base64
|
|
$mediaType = "image/" . $imageType;
|
|
} else {
|
|
// data: 부분이 없으면 PNG로 가정
|
|
$mediaType = "image/png";
|
|
}
|
|
|
|
$requestBody = [
|
|
'model' => 'claude-3-haiku-20240307', // haiku 모델 사용 (이미지 직접 분석 가능)
|
|
'max_tokens' => 4096,
|
|
'messages' => [
|
|
[
|
|
'role' => 'user',
|
|
'content' => [
|
|
[
|
|
'type' => 'image',
|
|
'source' => [
|
|
'type' => 'base64',
|
|
'media_type' => $mediaType,
|
|
'data' => $imageData
|
|
]
|
|
],
|
|
[
|
|
'type' => 'text',
|
|
'text' => $promptText
|
|
]
|
|
]
|
|
]
|
|
]
|
|
];
|
|
|
|
$ch = curl_init($apiUrl);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_POST, true);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
'Content-Type: application/json',
|
|
'x-api-key: ' . $apiKey,
|
|
'anthropic-version: 2023-06-01'
|
|
]);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestBody));
|
|
|
|
$response = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
if ($httpCode !== 200) {
|
|
error_log("Claude API Error: HTTP {$httpCode} - {$response}");
|
|
echo json_encode([
|
|
'ok' => false,
|
|
'error' => 'Claude API 호출 실패 (HTTP ' . $httpCode . ')',
|
|
'details' => $response
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
$apiResponse = json_decode($response, true);
|
|
|
|
if (!isset($apiResponse['content'][0]['text'])) {
|
|
echo json_encode(['ok' => false, 'error' => 'Claude API 응답 형식 오류']);
|
|
exit;
|
|
}
|
|
|
|
// Claude가 반환한 JSON 파싱
|
|
$claudeText = $apiResponse['content'][0]['text'];
|
|
|
|
// JSON 부분만 추출 (코드블록이나 설명이 포함되어 있을 수 있음)
|
|
if (preg_match('/\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}/s', $claudeText, $matches)) {
|
|
$jsonText = $matches[0];
|
|
} else {
|
|
$jsonText = $claudeText;
|
|
}
|
|
|
|
$extractedData = json_decode($jsonText, true);
|
|
|
|
if (!$extractedData) {
|
|
echo json_encode([
|
|
'ok' => false,
|
|
'error' => 'Claude 응답 JSON 파싱 실패',
|
|
'raw_response' => $claudeText
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// 성공 응답
|
|
echo json_encode([
|
|
'ok' => true,
|
|
'data' => $extractedData,
|
|
'raw_response' => $claudeText
|
|
]);
|