File size: 10,082 Bytes
48ed049
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
import gradio as gr
import google.generativeai as genai
from PIL import Image
import io
import base64
import json
from typing import Optional, Tuple

class KoreanOCRApp:
    def __init__(self):
        self.model = None
        self.api_key = None
    
    def configure_api(self, api_key: str) -> str:
        """API 키를 설정하고 모델을 초기화합니다."""
        try:
            if not api_key or api_key.strip() == "":
                return "❌ API 키를 입력해주세요."
            
            genai.configure(api_key=api_key.strip())
            self.model = genai.GenerativeModel('gemini-2.5-flash')
            self.api_key = api_key.strip()
            return "✅ API 키가 성공적으로 설정되었습니다."
        except Exception as e:
            return f"❌ API 키 설정 중 오류가 발생했습니다: {str(e)}"
    
    def extract_korean_text(self, image: Image.Image, api_key: str) -> Tuple[str, Image.Image]:
        """이미지에서 한국어 텍스트를 추출합니다."""
        try:
            # API 키가 변경되었거나 처음 설정하는 경우
            if not self.model or self.api_key != api_key.strip():
                config_result = self.configure_api(api_key)
                if "❌" in config_result:
                    return config_result, image
            
            if not image:
                return "❌ 이미지를 업로드해주세요.", None
            
            # 이미지 전처리 (선택사항)
            if image.mode != 'RGB':
                image = image.convert('RGB')
            
            # 이미지 크기 최적화 (너무 큰 경우)
            max_size = 1024
            if max(image.size) > max_size:
                ratio = max_size / max(image.size)
                new_size = tuple(int(dim * ratio) for dim in image.size)
                image = image.resize(new_size, Image.Resampling.LANCZOS)
            
            # 한국어 텍스트 추출을 위한 프롬프트
            prompt = """
            이 이미지에서 모든 한국어 텍스트를 추출해주세요. 
            다음 규칙을 따라주세요:
            1. 이미지에 있는 모든 한국어 텍스트를 정확하게 읽어주세요
            2. 텍스트의 위치나 순서를 고려하여 자연스럽게 배열해주세요
            3. 줄바꿈이나 문단 구분이 있다면 그대로 유지해주세요
            4. 영어나 숫자가 함께 있다면 그것도 포함해주세요
            5. 읽을 수 없거나 불분명한 부분이 있다면 [불분명]으로 표시해주세요
            
            추출된 텍스트만 출력해주세요:
            """
            
            # Gemini API 호출
            response = self.model.generate_content([prompt, image])
            
            if response.text:
                extracted_text = response.text.strip()
                success_message = f"✅ 텍스트 추출 완료:\n\n{extracted_text}"
                return success_message, image
            else:
                return "❌ 텍스트를 추출할 수 없습니다.", image
                
        except Exception as e:
            error_message = f"❌ 오류가 발생했습니다: {str(e)}"
            return error_message, image
    
    def verify_image_display(self, image: Image.Image) -> Tuple[str, Image.Image]:
        """업로드된 이미지와 출력창의 이미지가 같은지 확인합니다."""
        if image is None:
            return "❌ 이미지를 먼저 업로드해주세요.", None
        
        try:
            # 이미지 정보 확인
            width, height = image.size
            format_info = image.format if hasattr(image, 'format') else "Unknown"
            mode = image.mode
            
            verification_text = f"""
            ✅ 이미지 검증 완료
            
            📊 이미지 정보:
            - 크기: {width} x {height} 픽셀
            - 포맷: {format_info}
            - 색상 모드: {mode}
            - 파일 크기: 약 {width * height * (3 if mode == 'RGB' else 1)} 바이트
            
            🔍 이미지가 올바르게 표시되고 있습니다.
            """
            
            return verification_text, image
            
        except Exception as e:
            return f"❌ 이미지 검증 중 오류가 발생했습니다: {str(e)}", image

def create_app():
    """그라디오 앱을 생성합니다."""
    ocr_app = KoreanOCRApp()
    
    with gr.Blocks(
        title="한국어 OCR 텍스트 추출기",
        theme=gr.themes.Soft(),
        css="""
        .container {
            max-width: 1200px;
            margin: auto;
        }
        .header {
            text-align: center;
            padding: 20px;
            background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
            color: white;
            border-radius: 10px;
            margin-bottom: 20px;
        }
        """
    ) as app:
        
        # 헤더
        gr.HTML("""
        <div class="header">
            <h1>🔤 한국어 OCR 텍스트 추출기</h1>
            <p>Google Gemini를 사용한 고성능 한국어 텍스트 인식</p>
        </div>
        """)
        
        with gr.Row():
            with gr.Column(scale=1):
                # API 키 입력 섹션
                gr.Markdown("## 🔑 API 키 설정")
                api_key_input = gr.Textbox(
                    label="Google Gemini API 키",
                    placeholder="여기에 API 키를 입력하세요...",
                    type="password",
                    info="https://makersuite.google.com에서 API 키를 발급받으세요"
                )
                
                api_status = gr.Textbox(
                    label="API 상태",
                    value="API 키를 입력하고 설정하세요",
                    interactive=False
                )
                
                # API 키 설정 버튼
                api_config_btn = gr.Button("🔧 API 키 설정", variant="primary")
                
                gr.Markdown("---")
                
                # 이미지 업로드 섹션
                gr.Markdown("## 📤 이미지 업로드")
                image_input = gr.Image(
                    label="한국어 텍스트가 포함된 이미지를 업로드하세요",
                    type="pil",
                    height=300
                )
                
                # 버튼들
                with gr.Row():
                    extract_btn = gr.Button("📖 텍스트 추출", variant="primary")
                    verify_btn = gr.Button("🔍 이미지 검증", variant="secondary")
                
            with gr.Column(scale=1):
                # 결과 출력 섹션
                gr.Markdown("## 📄 추출 결과")
                
                text_output = gr.Textbox(
                    label="추출된 텍스트",
                    lines=10,
                    placeholder="여기에 추출된 한국어 텍스트가 표시됩니다...",
                    interactive=False
                )
                
                gr.Markdown("## 🖼️ 이미지 확인")
                image_output = gr.Image(
                    label="업로드된 이미지 (검증용)",
                    height=300
                )
                
                # 이미지 정보
                image_info = gr.Textbox(
                    label="이미지 정보",
                    lines=5,
                    interactive=False
                )
        
        # 사용법 안내
        with gr.Accordion("📋 사용법 안내", open=False):
            gr.Markdown("""
            ### 🔧 설정 방법
            1. **API 키 발급**: [Google AI Studio](https://makersuite.google.com)에서 무료 API 키를 발급받으세요
            2. **API 키 입력**: 위의 입력창에 발급받은 API 키를 입력하고 '설정' 버튼을 클릭하세요
            
            ### 📖 텍스트 추출 방법
            1. **이미지 업로드**: 한국어 텍스트가 포함된 이미지를 업로드하세요
            2. **텍스트 추출**: '텍스트 추출' 버튼을 클릭하여 OCR을 실행하세요
            3. **결과 확인**: 오른쪽 결과창에서 추출된 텍스트를 확인하세요
            
            ### 📋 지원 형식
            - **이미지 형식**: PNG, JPEG, WEBP, HEIC, HEIF
            - **최대 크기**: 20MB (자동으로 최적화됩니다)
            - **언어**: 한국어 중심 (영어, 숫자도 인식 가능)
            
            ### 💡 팁
            - 선명하고 해상도가 높은 이미지를 사용하세요
            - 텍스트가 잘 보이도록 조명이 충분한 사진을 촬영하세요
            - 기울어진 이미지는 자동으로 보정을 시도합니다
            """)
        
        # 이벤트 핸들러 등록
        api_config_btn.click(
            fn=ocr_app.configure_api,
            inputs=[api_key_input],
            outputs=[api_status]
        )
        
        extract_btn.click(
            fn=ocr_app.extract_korean_text,
            inputs=[image_input, api_key_input],
            outputs=[text_output, image_output]
        )
        
        verify_btn.click(
            fn=ocr_app.verify_image_display,
            inputs=[image_input],
            outputs=[image_info, image_output]
        )
        
        # 이미지 업로드 시 자동으로 출력창에 표시
        image_input.change(
            fn=lambda img: (img, "이미지가 업로드되었습니다. 텍스트 추출을 실행하세요." if img else ""),
            inputs=[image_input],
            outputs=[image_output, image_info]
        )
    
    return app

if __name__ == "__main__":
    app = create_app()
    app.launch(
        server_name="0.0.0.0",
        server_port=7860,
        share=True,
        debug=True,
        show_error=True
    )