Spaces:
Sleeping
Sleeping
| 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 | |
| ) |