tomo2chin2 commited on
Commit
d7da753
·
verified ·
1 Parent(s): 62a0bc6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +55 -34
app.py CHANGED
@@ -5,17 +5,22 @@ from pathlib import Path
5
  import google.generativeai as genai
6
  import tempfile
7
  import base64
8
- from concurrent.futures import ThreadPoolExecutor
9
  import logging
10
  import time
11
 
12
  # ロギング設定
13
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
14
 
15
- # Gemini APIの設定 (環境変数から取得)
16
  GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")
 
 
17
  if not GOOGLE_API_KEY:
18
  raise ValueError("環境変数 'GOOGLE_API_KEY' が設定されていません。")
 
 
 
19
  genai.configure(api_key=GOOGLE_API_KEY)
20
 
21
 
@@ -41,7 +46,7 @@ def split_pdf(pdf_path, output_dir, pages_per_chunk=5):
41
  output_pdf.save(output_path)
42
  output_pdf.close()
43
 
44
- split_pdfs.append(output_path)
45
 
46
  pdf_document.close()
47
  return split_pdfs
@@ -53,32 +58,44 @@ def encode_pdf_to_base64(pdf_path):
53
  return base64.b64encode(pdf_file.read()).decode('utf-8')
54
 
55
 
56
- def ocr_pdf_with_gemini(pdf_path):
57
  """GeminiモデルでPDFをOCRしてマークダウンに変換する関数"""
58
  # PDFをbase64エンコード
59
  pdf_base64 = encode_pdf_to_base64(pdf_path)
60
 
61
  # Geminiモデルの設定
62
- model = genai.GenerativeModel('gemini-2.0-flash') # または利用可能な他のモデル
63
 
64
  # プロンプトの設定
65
  prompt = """
66
- このPDFに含まれるテキストをOCRで読み取り、整形されたマークダウン形式に変換してください。
67
- 以下の点に注意してください:
68
- - 見出しは適切なマークダウン見出し記法(#, ##, ###など)を使用
69
- - 箇条書きリストは適切に変換
70
- - 表はマークダウン表形式に変換
71
- - 段落構造を維持
72
- - 余分な改行やスペースは整理
73
- - 画像の内容は[画像: 内容の説明]と表記
 
 
 
74
  """
75
 
76
  # PDFをGeminiに送信
77
  try:
78
- response = model.generate_content([
79
- prompt,
80
- {"mime_type": "application/pdf", "data": pdf_base64}
81
- ])
 
 
 
 
 
 
 
 
 
82
  # 結果を返す
83
  return response.text
84
  except Exception as e:
@@ -86,6 +103,7 @@ def ocr_pdf_with_gemini(pdf_path):
86
  return f"エラーが発生しました: {e}"
87
 
88
 
 
89
  def process_pdf(pdf_file, progress=gr.Progress()):
90
  """PDFファイルを処理するメイン関数"""
91
  logging.info(f"Received file: {pdf_file.name if hasattr(pdf_file, 'name') else pdf_file}")
@@ -96,30 +114,33 @@ def process_pdf(pdf_file, progress=gr.Progress()):
96
  logging.info(f"Temporary PDF path: {temp_pdf_path}")
97
 
98
  # PDFを分割
99
- split_pdf_paths = split_pdf(temp_pdf_path, temp_dir)
100
  logging.info(f"Split PDF paths: {split_pdf_paths}")
101
- progress(0.2, desc="PDFを分割中...") # 進捗更新
102
 
103
  # 並列処理でOCR変換
104
- markdown_results = []
105
  with ThreadPoolExecutor() as executor:
106
- # futureオブジェクトのリストを作成し、進捗を追跡
107
- futures = [executor.submit(ocr_pdf_with_gemini, path) for path in split_pdf_paths]
108
- for i, future in enumerate(futures):
 
109
  try:
110
  result = future.result()
111
- markdown_results.append(result)
112
- progress(0.2 + 0.6 * (i + 1) / len(futures), desc="OCR処理中...") # 進捗更新
 
113
  except Exception as e:
114
  logging.error(f"Error processing split PDF: {e}")
115
- markdown_results.append(f"分割PDFの処理中にエラーが発生しました: {e}")
116
 
117
  logging.info(f"Markdown results length: {len(markdown_results)}")
118
- progress(0.8, desc="結果を結合中...") # 進捗更新
119
- # 結果を結合
120
- combined_markdown = "\n\n".join(markdown_results)
121
- progress(1.0, desc="完了") # 進捗更新
122
- time.sleep(0.5) # 完了表示のため少し待つ
 
123
 
124
  return combined_markdown
125
 
@@ -135,11 +156,11 @@ def create_interface():
135
 
136
  with gr.Row():
137
  convert_btn = gr.Button("変換開始", variant="primary",
138
- elem_id="convert-button") # variantとelem_idを追加
139
 
140
  with gr.Row():
141
  markdown_output = gr.Textbox(label="変換結果", lines=10,
142
- max_lines=20) # MarkdownからTextboxに変更、行数を指定
143
 
144
  with gr.Row():
145
  copy_btn = gr.Button("クリップボードにコピー")
@@ -154,7 +175,7 @@ def create_interface():
154
  }
155
  </script>
156
  """,
157
- visible=False, # 非表示にしておく
158
  )
159
 
160
  # js_code が読み込まれた後に styleButton 関数を実行
 
5
  import google.generativeai as genai
6
  import tempfile
7
  import base64
8
+ from concurrent.futures import ThreadPoolExecutor, as_completed # as_completed を追加
9
  import logging
10
  import time
11
 
12
  # ロギング設定
13
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
14
 
15
+ # 環境変数から設定を読み込む
16
  GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")
17
+ MODEL_NAME = os.environ.get("MODEL_NAME", "gemini-1.5-pro") # デフォルトモデルも設定
18
+
19
  if not GOOGLE_API_KEY:
20
  raise ValueError("環境変数 'GOOGLE_API_KEY' が設定されていません。")
21
+ if not MODEL_NAME:
22
+ raise ValueError("環境変数 'MODEL_NAME' が設定されていません。")
23
+
24
  genai.configure(api_key=GOOGLE_API_KEY)
25
 
26
 
 
46
  output_pdf.save(output_path)
47
  output_pdf.close()
48
 
49
+ split_pdfs.append((start_page, output_path)) # (開始ページ, パス) のタプルで保存
50
 
51
  pdf_document.close()
52
  return split_pdfs
 
58
  return base64.b64encode(pdf_file.read()).decode('utf-8')
59
 
60
 
61
+ def ocr_pdf_with_gemini(pdf_path, model_name):
62
  """GeminiモデルでPDFをOCRしてマークダウンに変換する関数"""
63
  # PDFをbase64エンコード
64
  pdf_base64 = encode_pdf_to_base64(pdf_path)
65
 
66
  # Geminiモデルの設定
67
+ model = genai.GenerativeModel(model_name)
68
 
69
  # プロンプトの設定
70
  prompt = """
71
+ Extract the text content from this PDF using OCR and output it in a well-structured Markdown format.
72
+ Focus solely on the text extraction; do not include any conversational elements, greetings, or additional explanations.
73
+ Only provide the extracted text in Markdown.
74
+
75
+ Pay attention to the following:
76
+ - Use appropriate Markdown heading syntax (#, ##, ###, etc.) for headings.
77
+ - Convert bulleted lists correctly.
78
+ - Convert tables to Markdown table format.
79
+ - Maintain the paragraph structure.
80
+ - Clean up any extra line breaks or spaces.
81
+ - For images, use the format [Image: Description of the content].
82
  """
83
 
84
  # PDFをGeminiに送信
85
  try:
86
+ response = model.generate_content(
87
+ [
88
+ prompt,
89
+ {"mime_type": "application/pdf", "data": pdf_base64}
90
+ ],
91
+ # generation_configで不要な応答を抑制 (モデルによっては効かない場合あり)
92
+ generation_config=genai.types.GenerationConfig(
93
+ candidate_count=1, # 候補を1つに絞る
94
+ max_output_tokens=8192, # 必要に応じてトークン数を調整
95
+ # stop_sequences=["."], # 句点で生成を停止 (モデルによっては無効)
96
+ )
97
+
98
+ )
99
  # 結果を返す
100
  return response.text
101
  except Exception as e:
 
103
  return f"エラーが発生しました: {e}"
104
 
105
 
106
+
107
  def process_pdf(pdf_file, progress=gr.Progress()):
108
  """PDFファイルを処理するメイン関数"""
109
  logging.info(f"Received file: {pdf_file.name if hasattr(pdf_file, 'name') else pdf_file}")
 
114
  logging.info(f"Temporary PDF path: {temp_pdf_path}")
115
 
116
  # PDFを分割
117
+ split_pdf_paths = split_pdf(temp_pdf_path, temp_dir) # [(start_page, path), ...]
118
  logging.info(f"Split PDF paths: {split_pdf_paths}")
119
+ progress(0.2, desc="PDFを分割中...")
120
 
121
  # 並列処理でOCR変換
122
+ markdown_results = {} # {start_page: markdown_text, ...} 辞書に変更
123
  with ThreadPoolExecutor() as executor:
124
+ futures = {executor.submit(ocr_pdf_with_gemini, path, MODEL_NAME): start_page for start_page, path in split_pdf_paths}
125
+ completed_count = 0
126
+ for future in as_completed(futures):
127
+ start_page = futures[future]
128
  try:
129
  result = future.result()
130
+ markdown_results[start_page] = result
131
+ completed_count += 1
132
+ progress(0.2 + 0.6 * (completed_count) / len(futures), desc="OCR処理中...")
133
  except Exception as e:
134
  logging.error(f"Error processing split PDF: {e}")
135
+ markdown_results[start_page] = f"分割PDFの処理中にエラーが発生しました: {e}"
136
 
137
  logging.info(f"Markdown results length: {len(markdown_results)}")
138
+ progress(0.8, desc="結果を結合中...")
139
+
140
+ # 結果を結合 (開始ページ番号でソート)
141
+ combined_markdown = "\n\n".join(markdown_results[page] for page in sorted(markdown_results.keys()))
142
+ progress(1.0, desc="完了")
143
+ time.sleep(0.5)
144
 
145
  return combined_markdown
146
 
 
156
 
157
  with gr.Row():
158
  convert_btn = gr.Button("変換開始", variant="primary",
159
+ elem_id="convert-button")
160
 
161
  with gr.Row():
162
  markdown_output = gr.Textbox(label="変換結果", lines=10,
163
+ max_lines=20)
164
 
165
  with gr.Row():
166
  copy_btn = gr.Button("クリップボードにコピー")
 
175
  }
176
  </script>
177
  """,
178
+ visible=False,
179
  )
180
 
181
  # js_code が読み込まれた後に styleButton 関数を実行