Upload 11 files
Browse files- README.md +4 -5
- app.py +182 -1
- category.py +31 -0
- chatgpt_api.py +35 -0
- convert_chukan_fmt_1.py +140 -0
- kousei.py +73 -0
- manuscript_conversion.py +68 -0
- openai.py +12 -0
- select_question.py +92 -0
- translate.py +30 -0
- voice_create.py +113 -0
README.md
CHANGED
@@ -1,13 +1,12 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
-
emoji:
|
4 |
colorFrom: green
|
5 |
-
colorTo:
|
6 |
sdk: gradio
|
7 |
-
sdk_version: 4.
|
8 |
app_file: app.py
|
9 |
pinned: false
|
10 |
-
license: apache-2.0
|
11 |
---
|
12 |
|
13 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
1 |
---
|
2 |
+
title: English
|
3 |
+
emoji: 🏢
|
4 |
colorFrom: green
|
5 |
+
colorTo: blue
|
6 |
sdk: gradio
|
7 |
+
sdk_version: 4.27.0
|
8 |
app_file: app.py
|
9 |
pinned: false
|
|
|
10 |
---
|
11 |
|
12 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
CHANGED
@@ -1 +1,182 @@
|
|
1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import pandas as pd
|
3 |
+
import tempfile
|
4 |
+
import os
|
5 |
+
import re
|
6 |
+
from chatgpt_api import get_chatgpt_response
|
7 |
+
from voice_create import text_to_speech
|
8 |
+
from select_question import create_choice_question
|
9 |
+
from manuscript_conversion import manuscript_conversion
|
10 |
+
from category import check
|
11 |
+
from kousei import kousei2
|
12 |
+
from convert_chukan_fmt_1 import convert_chukan_fmt_1
|
13 |
+
|
14 |
+
def kousei(csv_file, input_text):
|
15 |
+
prompt_text = input_text + "指摘は、全ての問題において問題がない場合も含めて、必ず全問題、[id]に続けて結果を書くフォーマットで返してください。[id]の後は改行しないで。[id]はリクエストと完全一致の形式で。(必ず[問題ID]が5つ表示されるはずです)指摘方法は、問題ない場合は「問題なし」、指摘がある場合は「問題あり」\n「問題あり」の場合、問題のある箇所を具体的に指摘してください。\n#リスト"
|
16 |
+
|
17 |
+
# CSVファイルを読み込む
|
18 |
+
df = pd.read_csv(csv_file)
|
19 |
+
# 'id'列のデータ型を文字列に変換
|
20 |
+
df['id'] = df['id'].astype(str)
|
21 |
+
# DataFrameを5行ごとに処理するためのグループ化
|
22 |
+
df['group_id'] = df.index // 5
|
23 |
+
grouped = df.groupby('group_id')
|
24 |
+
|
25 |
+
# 各グループに対してフォーマットされたプロンプトを作成
|
26 |
+
def create_prompt(group, base_prompt):
|
27 |
+
prompt = base_prompt
|
28 |
+
for _, row in group.iterrows():
|
29 |
+
prompt += f"\n[{row['id']}]\n{row['原稿']}"
|
30 |
+
print(prompt)
|
31 |
+
return prompt
|
32 |
+
|
33 |
+
# 各グループごとのプロンプトを生成
|
34 |
+
prompts = grouped.apply(lambda g: create_prompt(g, prompt_text))
|
35 |
+
prompts = prompts.reset_index(name='prompt_after')
|
36 |
+
|
37 |
+
# 各プロンプトをAPIに送信(この部分は実装に応じて修正が必要です)
|
38 |
+
prompts['response'] = prompts['prompt_after'].apply(get_chatgpt_response)
|
39 |
+
print(prompts['response'])
|
40 |
+
|
41 |
+
# 各グループに対してフォーマットされたプロンプトを作成
|
42 |
+
def create_prompt(group, base_prompt):
|
43 |
+
prompt = base_prompt
|
44 |
+
for _, row in group.iterrows():
|
45 |
+
prompt += f"\n[{row['id']}]\n{row['原稿']}"
|
46 |
+
print(prompt)
|
47 |
+
return prompt
|
48 |
+
|
49 |
+
# 各グループごとのプロンプトを生成
|
50 |
+
prompts = grouped.apply(lambda g: create_prompt(g, prompt_text))
|
51 |
+
prompts = prompts.reset_index(name='prompt_after')
|
52 |
+
|
53 |
+
# 各プロンプトをAPIに送信(この部分は実装に応じて修正が必要です)
|
54 |
+
prompts['response'] = prompts['prompt_after'].apply(get_chatgpt_response)
|
55 |
+
print(prompts['response'])
|
56 |
+
|
57 |
+
|
58 |
+
|
59 |
+
# 応答を分割して元のDataFrameにマッピングする関数
|
60 |
+
def split_responses(grouped_df):
|
61 |
+
rows = []
|
62 |
+
for _, row in grouped_df.iterrows():
|
63 |
+
response = row['response']
|
64 |
+
split_response = re.split(r'\[([^\]]+)\]\s*', response)
|
65 |
+
ids_texts = list(zip(split_response[1::2], split_response[2::2]))
|
66 |
+
|
67 |
+
for id_text in ids_texts:
|
68 |
+
problem_id, correction_result = id_text
|
69 |
+
# フィルタリングされたDataFrameを安全に取得
|
70 |
+
filtered_df = df[df['id'] == problem_id]
|
71 |
+
original_content = filtered_df['原稿'].iloc[0] if not filtered_df.empty else "原稿が見つかりません"
|
72 |
+
rows.append({
|
73 |
+
'id': problem_id,
|
74 |
+
'contents': original_content,
|
75 |
+
'校正結果': correction_result.strip()
|
76 |
+
})
|
77 |
+
|
78 |
+
return pd.DataFrame(rows)
|
79 |
+
|
80 |
+
final_results = split_responses(prompts)
|
81 |
+
|
82 |
+
# ファイル出力
|
83 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix='.csv') as tmp:
|
84 |
+
final_results.to_csv(tmp.name, index=False, encoding='cp932', errors='ignore')
|
85 |
+
output_path = tmp.name
|
86 |
+
|
87 |
+
# ファイル名を変更
|
88 |
+
new_path = os.path.join(os.path.dirname(output_path), "output.csv")
|
89 |
+
os.rename(output_path, new_path)
|
90 |
+
return new_path
|
91 |
+
|
92 |
+
title = "英語生成ツール"
|
93 |
+
|
94 |
+
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
95 |
+
gr.Markdown(
|
96 |
+
f"""
|
97 |
+
# {title}
|
98 |
+
"""
|
99 |
+
)
|
100 |
+
with gr.Tab("問題生成(選択肢)"):
|
101 |
+
with gr.Column():
|
102 |
+
gr.Markdown("""
|
103 |
+
## 利用手順
|
104 |
+
1. こちらの[マスタ](https://drive.google.com/uc?export=download&id=1VyDBtVrnDUlddmITiXg7ybqyB0CTCPeu)を手元に置く
|
105 |
+
2. シート「input」に、生成したい問題パターンを書いてください(赤字の要素は固定。選択肢は可変。適宜行追加OK)
|
106 |
+
3. 完成したら、「ファイル>名前を付けて保存」から「CSV UTF-8(コンマ区切り)(*.csv)」形式で保存
|
107 |
+
4. 3のCSVを本サイトにアップロード
|
108 |
+
""")
|
109 |
+
|
110 |
+
with gr.Row():
|
111 |
+
inputs=gr.File(label="CSVファイルをアップロード")
|
112 |
+
outputs=gr.File(label="ダウンロード", file_count="singular")
|
113 |
+
gr.Button("問題生成").click(
|
114 |
+
create_choice_question,
|
115 |
+
inputs=[inputs],
|
116 |
+
outputs=[outputs]
|
117 |
+
)
|
118 |
+
with gr.Tab("原稿変換"):
|
119 |
+
with gr.Column():
|
120 |
+
with gr.Row():
|
121 |
+
inputs=gr.File(label="CSVファイルをアップロード")
|
122 |
+
outputs=gr.File(label="ダウンロード", file_count="singular")
|
123 |
+
gr.Button("変換").click(
|
124 |
+
manuscript_conversion,
|
125 |
+
inputs=[inputs],
|
126 |
+
outputs=[outputs]
|
127 |
+
)
|
128 |
+
with gr.Tab("校正"):
|
129 |
+
with gr.Column():
|
130 |
+
input_text_kousei = gr.Textbox(label="校正観点を入力してください。",value="英単語習得を目的として、以下2種類の問題を用意しています。\n1.英語の正しい日本語訳を選択する4択問題\n2.日本語の正しい英語訳を選択する4択問題\n「#リスト」の誤答選択肢の中に、正解選択肢の別解になってしまっているもの、または別解とは言えないが紛らわしすぎるものがないか、探して指摘してください。")
|
131 |
+
with gr.Row():
|
132 |
+
inputs=gr.File(label="CSVファイルをアップロード")
|
133 |
+
outputs=gr.File(label="ダウンロード", file_count="singular")
|
134 |
+
gr.Button("校正スタート").click(
|
135 |
+
kousei,
|
136 |
+
inputs=[inputs,input_text_kousei],
|
137 |
+
outputs=[outputs]
|
138 |
+
)
|
139 |
+
with gr.Tab("校正2"):
|
140 |
+
with gr.Column():
|
141 |
+
radio_options = ["英語", "日本語"]
|
142 |
+
radio_button = gr.Radio(choices=radio_options, label="選択してください",value="英語")
|
143 |
+
input_text_kousei = gr.Textbox(label="校正観点を入力してください。",value="If there are any typographical errors, omissions, missing or extra spaces and periods, or grammatical mistakes in the English text, please point them out.")
|
144 |
+
with gr.Row():
|
145 |
+
inputs=gr.File(label="CSVファイルをアップロード")
|
146 |
+
outputs=gr.File(label="ダウンロード", file_count="singular")
|
147 |
+
gr.Button("校正スタート").click(
|
148 |
+
kousei2,
|
149 |
+
inputs=[inputs,input_text_kousei,radio_button],
|
150 |
+
outputs=[outputs]
|
151 |
+
)
|
152 |
+
with gr.Tab("音声生成"):
|
153 |
+
with gr.Column():
|
154 |
+
# GradioのUIコンポーネントを定義
|
155 |
+
radio_options = ["ブレイクタイム有", "ブレイクタイム無"]
|
156 |
+
radio_button = gr.Radio(choices=radio_options, label="選択してください",value="ブレイクタイム有")
|
157 |
+
with gr.Row():
|
158 |
+
file_input = gr.File(label="CSVファイルをアップロード")
|
159 |
+
submit_button = gr.Button("音声ファイルを生成")
|
160 |
+
file_output = gr.File(label="ダウンロード")
|
161 |
+
submit_button.click(fn=text_to_speech, inputs=[file_input,radio_button], outputs=[file_output])
|
162 |
+
with gr.Tab("中間マスタ生成(意味理解)"):
|
163 |
+
with gr.Column():
|
164 |
+
with gr.Row():
|
165 |
+
file_input = gr.File(label="CSVアップロード")
|
166 |
+
submit_button = gr.Button("ファイルコンバート")
|
167 |
+
file_output = gr.File(label="ファイルをダウンロード")
|
168 |
+
submit_button.click(fn=convert_chukan_fmt_1, inputs=[file_input], outputs=[file_output])
|
169 |
+
with gr.Tab("カテゴリ分類"):
|
170 |
+
with gr.Column():
|
171 |
+
input_text_kousei = gr.Textbox(label="分類観点を入力してください。",value="xxxxxxxに関する内容の場合は「該当あり」と書いてください。")
|
172 |
+
with gr.Row():
|
173 |
+
inputs=gr.File(label="CSVファイルをアップロード")
|
174 |
+
outputs=gr.File(label="ダウンロード", file_count="singular")
|
175 |
+
gr.Button("分類スタート").click(
|
176 |
+
check,
|
177 |
+
inputs=[inputs,input_text_kousei],
|
178 |
+
outputs=[outputs]
|
179 |
+
)
|
180 |
+
|
181 |
+
demo.launch(share=True)
|
182 |
+
|
category.py
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import pandas as pd
|
3 |
+
import tempfile
|
4 |
+
import os
|
5 |
+
from chatgpt_api import get_chatgpt_response2
|
6 |
+
from voice_create import text_to_speech
|
7 |
+
from select_question import create_choice_question
|
8 |
+
from manuscript_conversion import manuscript_conversion
|
9 |
+
|
10 |
+
|
11 |
+
def check(csv_file, input_text):
|
12 |
+
prompt_text = input_text + "該当しない場合は「該当なし」、該当する場合は「該当あり」としてください\n"
|
13 |
+
# CSVファイルを読み込む
|
14 |
+
df = pd.read_csv(csv_file)
|
15 |
+
# 'id'列のデータ型を文字列に変換
|
16 |
+
df['id'] = df['id'].astype(str)
|
17 |
+
|
18 |
+
df["prompt"] = prompt_text + df["原稿"]
|
19 |
+
|
20 |
+
df["分類結果"] = df["prompt"].apply(get_chatgpt_response2)
|
21 |
+
|
22 |
+
|
23 |
+
# ファイル出力
|
24 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix='.csv') as tmp:
|
25 |
+
df.to_csv(tmp.name, index=False, encoding='cp932', errors='ignore')
|
26 |
+
output_path = tmp.name
|
27 |
+
|
28 |
+
# ファイル名を変更
|
29 |
+
new_path = os.path.join(os.path.dirname(output_path), "output.csv")
|
30 |
+
os.rename(output_path, new_path)
|
31 |
+
return new_path
|
chatgpt_api.py
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import requests
|
3 |
+
|
4 |
+
# OpenAI API キーを設定する
|
5 |
+
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "sk-proj-arrJA9XvKeo5nfYXLgmeT3BlbkFJNnqFQL9G8qTdYXsBvhJc")
|
6 |
+
|
7 |
+
def get_chatgpt_response(input_text):
|
8 |
+
headers = {
|
9 |
+
"Content-Type": "application/json",
|
10 |
+
"Authorization": f"Bearer {OPENAI_API_KEY}"
|
11 |
+
}
|
12 |
+
data = {
|
13 |
+
"model": "gpt-4o",
|
14 |
+
"messages": [{"role": "user", "content": input_text}]
|
15 |
+
}
|
16 |
+
response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=data)
|
17 |
+
response_json = response.json()
|
18 |
+
output_text = response_json["choices"][0]["message"]["content"]
|
19 |
+
|
20 |
+
return output_text
|
21 |
+
|
22 |
+
def get_chatgpt_response2(input_text):
|
23 |
+
headers = {
|
24 |
+
"Content-Type": "application/json",
|
25 |
+
"Authorization": f"Bearer {OPENAI_API_KEY}"
|
26 |
+
}
|
27 |
+
data = {
|
28 |
+
"model": "gpt-4o",
|
29 |
+
"messages": [{"role": "user", "content": input_text}]
|
30 |
+
}
|
31 |
+
response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=data)
|
32 |
+
response_json = response.json()
|
33 |
+
output_text = response_json["choices"][0]["message"]["content"]
|
34 |
+
|
35 |
+
return output_text
|
convert_chukan_fmt_1.py
ADDED
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import os
|
3 |
+
import tempfile
|
4 |
+
import re
|
5 |
+
import random
|
6 |
+
import gradio as gr
|
7 |
+
|
8 |
+
|
9 |
+
# id作成
|
10 |
+
def make_id(stage, order):
|
11 |
+
"""
|
12 |
+
指定された stage と order に基づいてIDを生成します。
|
13 |
+
|
14 |
+
Parameters:
|
15 |
+
stage (int): ステージ番号
|
16 |
+
order (int): オーダー番号
|
17 |
+
|
18 |
+
Returns:
|
19 |
+
str: 特定のフォーマットのID文字列
|
20 |
+
"""
|
21 |
+
# フォーマットに従ってIDを生成
|
22 |
+
id_str = f"EC03ST{stage:03d}L{order:03d}"
|
23 |
+
return id_str
|
24 |
+
|
25 |
+
def extract_correct_choice(text):
|
26 |
+
# Use a regular expression to find the content after "【正解選択肢】"
|
27 |
+
match = re.search(r'【正解選択肢】(.+)', text)
|
28 |
+
if match:
|
29 |
+
return match.group(1).strip()
|
30 |
+
else:
|
31 |
+
return None
|
32 |
+
|
33 |
+
# 選択肢シャッフルの関数
|
34 |
+
def shuffle_and_combine_options(text_a, text_b):
|
35 |
+
# 正規表現を使って各選択肢を抽出し、タグを除去する
|
36 |
+
def extract_and_clean_options(text):
|
37 |
+
matches = re.findall(r'【[^】]+】([^【]+)', text)
|
38 |
+
return [match.strip() for match in matches]
|
39 |
+
|
40 |
+
# 列Aと列Bの選択肢を抽出してクリーンアップ
|
41 |
+
options_a = extract_and_clean_options(text_a)
|
42 |
+
options_b = extract_and_clean_options(text_b)
|
43 |
+
|
44 |
+
# シャッフルのためのインデックスリストを作成
|
45 |
+
indices = list(range(len(options_a)))
|
46 |
+
random.shuffle(indices)
|
47 |
+
|
48 |
+
# シャッフルされた選択肢を作成
|
49 |
+
shuffled_a = [options_a[i] for i in indices]
|
50 |
+
shuffled_b = [options_b[i] for i in indices]
|
51 |
+
|
52 |
+
# 各選択肢を/で区切って結合
|
53 |
+
result_a = "/".join(shuffled_a)
|
54 |
+
result_b = "/".join(shuffled_b)
|
55 |
+
|
56 |
+
return result_a, result_b
|
57 |
+
|
58 |
+
# 解説作成
|
59 |
+
def create_explanation(script_english,script_japanese,choices_english, choices_japanese,question_english,question_japanese):
|
60 |
+
choices_english = choices_english.replace("/", "\n")
|
61 |
+
choices_japanese = choices_japanese.replace("/", "\n")
|
62 |
+
question_english = "" if question_english == "" or pd.isnull(question_english) else "\n\nQuestion:\n" + question_english
|
63 |
+
question_japanese = "" if question_japanese == "" or pd.isnull(question_japanese) else "\n\nQuestion:\n" + question_japanese
|
64 |
+
explanation = f"■英語\n{script_english}{question_english}\n\n選択肢:\n{choices_english}\n\n■日本語訳\n{script_japanese}{question_japanese}\n\n選択肢:\n{choices_japanese}"
|
65 |
+
return explanation
|
66 |
+
|
67 |
+
|
68 |
+
def convert_chukan_fmt_1(csv_file):
|
69 |
+
df_input = pd.read_csv(csv_file.name)
|
70 |
+
data = {
|
71 |
+
"問題ID": [],
|
72 |
+
"知識ID":[],
|
73 |
+
"出題形式ID":[],
|
74 |
+
"リード文":[],
|
75 |
+
"問題":[],
|
76 |
+
"問題_翻訳":[],
|
77 |
+
"正解文":[],
|
78 |
+
"解説テキスト":[],
|
79 |
+
"選択肢":[],
|
80 |
+
"正解":[],
|
81 |
+
"script":[],
|
82 |
+
"question":[],
|
83 |
+
"choices":[],
|
84 |
+
"eikenn":[],
|
85 |
+
}
|
86 |
+
for index, row in df_input.iterrows():
|
87 |
+
id = make_id(row["ステージ"], row["ステージ内表示順"])
|
88 |
+
try:
|
89 |
+
japanese_selection_1, english_selection_1 = shuffle_and_combine_options(row["日本語訳_問題1_選択肢"], row["問題1_選択肢"])
|
90 |
+
print(id)
|
91 |
+
data["問題ID"].append(id+"Q001")
|
92 |
+
data["知識ID"].append(id)
|
93 |
+
data["出題形式ID"].append(row["出題形式ID"])
|
94 |
+
data["リード文"].append(row["リード文"])
|
95 |
+
data["問題"].append("")
|
96 |
+
data["問題_翻訳"].append(extract_correct_choice(row["日本語訳_問題1_選択肢"]))
|
97 |
+
data["正解文"].append(extract_correct_choice(row["問題1_選択肢"]))
|
98 |
+
data["解説テキスト"].append(create_explanation(row["問題1_スクリプト"], row["日本語訳_問題1_スクリプト"], english_selection_1, japanese_selection_1, row["問題1_Question"], row["日本語訳_問題1_Question"]))
|
99 |
+
data["選択肢"].append(english_selection_1)
|
100 |
+
data["正解"].append(extract_correct_choice(row["問題1_選択肢"]))
|
101 |
+
data["script"].append(row["問題1_スクリプト"])
|
102 |
+
data["question"].append(row["問題1_Question"])
|
103 |
+
data["choices"].append(english_selection_1 if row["選択肢読み上げ有無"] == "有" else "")
|
104 |
+
data["eikenn"].append(row["レベル"])
|
105 |
+
|
106 |
+
japanese_selection_2, english_selection_2 = shuffle_and_combine_options(row["日本語訳_問題2_選択肢"], row["問題2_選択肢"])
|
107 |
+
id = make_id(row["ステージ"], row["ステージ内表示順"])
|
108 |
+
data["問題ID"].append(id+"Q002")
|
109 |
+
data["知識ID"].append(id)
|
110 |
+
data["出題形式ID"].append(row["出題形式ID"])
|
111 |
+
data["リード文"].append(row["リード文"])
|
112 |
+
data["問題"].append("")
|
113 |
+
data["問題_翻訳"].append(extract_correct_choice(row["日本語訳_問題2_選択肢"]))
|
114 |
+
data["正解文"].append(extract_correct_choice(row["問題2_選択肢"]))
|
115 |
+
data["解説テキス���"].append(create_explanation(row["問題2_スクリプト"], row["日本語訳_問題2_スクリプト"], english_selection_2, japanese_selection_2, row["問題2_Question"], row["日本語訳_問題2_Question"]))
|
116 |
+
data["選択肢"].append(english_selection_2)
|
117 |
+
data["正解"].append(extract_correct_choice(row["問題2_選択肢"]))
|
118 |
+
data["script"].append(row["問題2_スクリプト"])
|
119 |
+
data["question"].append(row["問題2_Question"])
|
120 |
+
data["choices"].append(english_selection_2 if row["選択肢読み上げ有無"] == "有" else "")
|
121 |
+
data["eikenn"].append(row["レベル"])
|
122 |
+
|
123 |
+
except Exception as e:
|
124 |
+
gr.Warning(f"次の問題でエラーが発生: {id} - {str(e)}")
|
125 |
+
return f"次の問題でエラーが発生: {id} - {str(e)}"
|
126 |
+
|
127 |
+
|
128 |
+
|
129 |
+
|
130 |
+
|
131 |
+
df_output = pd.DataFrame(data)
|
132 |
+
|
133 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix='.csv') as tmp:
|
134 |
+
df_output.to_csv(tmp.name, index=False, encoding='cp932', errors='ignore')
|
135 |
+
output_path = tmp.name
|
136 |
+
|
137 |
+
# ファイル名を変更
|
138 |
+
new_path = os.path.join(os.path.dirname(output_path), "output.csv")
|
139 |
+
os.rename(output_path, new_path)
|
140 |
+
return new_path
|
kousei.py
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import pandas as pd
|
3 |
+
import tempfile
|
4 |
+
import os
|
5 |
+
import re
|
6 |
+
from chatgpt_api import get_chatgpt_response2
|
7 |
+
from voice_create import text_to_speech
|
8 |
+
from select_question import create_choice_question
|
9 |
+
from manuscript_conversion import manuscript_conversion
|
10 |
+
|
11 |
+
def check_text(text, radio_option):
|
12 |
+
errors = []
|
13 |
+
error_details = []
|
14 |
+
|
15 |
+
# Split the text into sentences for individual checks
|
16 |
+
# This regex splits on punctuation but keeps the punctuation with the previous sentence
|
17 |
+
sentences = re.split(r'(?<=[。!??!.])\s*|\n', text)
|
18 |
+
|
19 |
+
for sentence in sentences:
|
20 |
+
sentence = sentence.strip()
|
21 |
+
if not sentence:
|
22 |
+
continue
|
23 |
+
|
24 |
+
if radio_option == "日本語":
|
25 |
+
if not re.search(r'[。!]$', sentence):
|
26 |
+
errors.append("文末に句点がありません。")
|
27 |
+
error_details.append(f"文末に「。」または「!」がない: '{sentence}'")
|
28 |
+
else:
|
29 |
+
# Check for multiple spaces
|
30 |
+
if re.search(r' +', sentence):
|
31 |
+
errors.append("半角スペースが2つ以上入っています。")
|
32 |
+
multiple_spaces_parts = re.findall(r'[^ ]* +[^ ]*', sentence)
|
33 |
+
for part in multiple_spaces_parts:
|
34 |
+
error_details.append(f"スペースが2つある部分: '{part.strip()}'")
|
35 |
+
|
36 |
+
# Check for punctuation at the end of the sentence
|
37 |
+
if not re.search(r'[.!?]$', sentence):
|
38 |
+
errors.append("文末にピリオドや?や!のいずれかがついていません。")
|
39 |
+
error_details.append(f"文末に「.」または「!」または「?」がない: '{sentence}'")
|
40 |
+
|
41 |
+
if errors:
|
42 |
+
return "チェック観点:\n" + "\n".join(errors) + "\n\n詳細:\n" + "\n".join(error_details)
|
43 |
+
else:
|
44 |
+
return "全てのチェックをクリアしました。"
|
45 |
+
|
46 |
+
|
47 |
+
|
48 |
+
|
49 |
+
|
50 |
+
def kousei2(csv_file, input_text,radio_option):
|
51 |
+
prompt_text = "#Instructions\n" + input_text +" If there is no problem, please reply with only 2 letters 'OK' and DON'T put any other extra words. \n #Target sentence\n"
|
52 |
+
# CSVファイルを読み込む
|
53 |
+
df = pd.read_csv(csv_file)
|
54 |
+
# 'id'列のデータ型を文字列に変換
|
55 |
+
df['id'] = df['id'].astype(str)
|
56 |
+
|
57 |
+
df["prompt"] = prompt_text + df["原稿"]
|
58 |
+
|
59 |
+
df["GPT校正結果"] = df["prompt"].apply(get_chatgpt_response2)
|
60 |
+
print("radio_option",radio_option)
|
61 |
+
df["タイプミス校正結果"] = df["原稿"].apply(check_text, args=(radio_option,))
|
62 |
+
|
63 |
+
|
64 |
+
|
65 |
+
# ファイル出力
|
66 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix='.csv') as tmp:
|
67 |
+
df.to_csv(tmp.name, index=False, encoding='cp932', errors='ignore')
|
68 |
+
output_path = tmp.name
|
69 |
+
|
70 |
+
# ファイル名を変更
|
71 |
+
new_path = os.path.join(os.path.dirname(output_path), "output.csv")
|
72 |
+
os.rename(output_path, new_path)
|
73 |
+
return new_path
|
manuscript_conversion.py
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import re
|
3 |
+
import os
|
4 |
+
import tempfile
|
5 |
+
|
6 |
+
|
7 |
+
# 新しいカラムを作成する関数
|
8 |
+
def process_text(row, column_name):
|
9 |
+
script_start_pattern = r"##\s*リスニングスクリプト"
|
10 |
+
question_start = "Question:"
|
11 |
+
choice_start = "##選択肢"
|
12 |
+
correct_choice = "【正解選択肢】"
|
13 |
+
|
14 |
+
# 【正解選択肢】の直前に ##選択肢 を挿入する処理
|
15 |
+
if correct_choice in row[column_name] and not choice_start in row[column_name]:
|
16 |
+
row[column_name] = row[column_name].replace(correct_choice, choice_start + correct_choice)
|
17 |
+
|
18 |
+
# 正規表現を使用してスクリプト開始部分を探す
|
19 |
+
script_parts = re.split(script_start_pattern, row[column_name], flags=re.IGNORECASE)
|
20 |
+
if len(script_parts) > 1:
|
21 |
+
script_part = script_parts[1]
|
22 |
+
if choice_start in script_part:
|
23 |
+
choice_part = script_part.split(choice_start, 1)[1]
|
24 |
+
script_text = script_part.split(choice_start)[0].strip()
|
25 |
+
choice_text = choice_part.strip()
|
26 |
+
|
27 |
+
if question_start in script_text:
|
28 |
+
question_text = script_text.split(question_start, 1)[1]
|
29 |
+
script_text = script_text.split(question_start)[0].strip()
|
30 |
+
else:
|
31 |
+
question_text = ""
|
32 |
+
|
33 |
+
return pd.Series({
|
34 |
+
f'{column_name}_スクリプト': script_text,
|
35 |
+
f'{column_name}_Question': question_text,
|
36 |
+
f'{column_name}_選択肢': choice_text
|
37 |
+
})
|
38 |
+
# 必要なセクションが存在しない場合、空の文字列を返す
|
39 |
+
return pd.Series({
|
40 |
+
f'{column_name}_スクリプト': "",
|
41 |
+
f'{column_name}_Question': "",
|
42 |
+
f'{column_name}_選択肢': ""
|
43 |
+
})
|
44 |
+
|
45 |
+
# 処理を行うカラムのリスト
|
46 |
+
columns_to_process = ['問題1', '問題2', '日本語訳_問題1', '日本語訳_問題2']
|
47 |
+
|
48 |
+
|
49 |
+
def manuscript_conversion(csv_file):
|
50 |
+
# CSVファイルを読み込む
|
51 |
+
df = pd.read_csv(csv_file.name)
|
52 |
+
|
53 |
+
# 各カラムに対して処理を適用し、新しいカラムをDataFrameに追加
|
54 |
+
for column in columns_to_process:
|
55 |
+
df = df.join(df.apply(lambda row: process_text(row, column), axis=1))
|
56 |
+
|
57 |
+
# 元の問題1と問題2、日本語訳_問題1と日本語訳_問題2のカラムを削除
|
58 |
+
df.drop(columns=columns_to_process, inplace=True)
|
59 |
+
|
60 |
+
# csvを書き出す
|
61 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix='.csv') as tmp:
|
62 |
+
# cp932で保存、エラーは無視(置換しても良い)
|
63 |
+
df.to_csv(tmp.name, index=False, encoding='cp932', errors='ignore')
|
64 |
+
output_path = tmp.name
|
65 |
+
# ファイル名を変更
|
66 |
+
new_path = os.path.join(os.path.dirname(output_path), "output.csv")
|
67 |
+
os.rename(output_path, new_path)
|
68 |
+
return new_path
|
openai.py
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# from openai import OpenAI
|
2 |
+
# client = OpenAI()
|
3 |
+
|
4 |
+
# def exec_gpt4(prompt):
|
5 |
+
# openai.api_key = 'sk-proj-arrJA9XvKeo5nfYXLgmeT3BlbkFJNnqFQL9G8qTdYXsBvhJc'
|
6 |
+
# response = client.chat.completions.create(
|
7 |
+
# model='gpt-4o',
|
8 |
+
# messages=[
|
9 |
+
# {"role": "user", "content": prompt},
|
10 |
+
# ],
|
11 |
+
# )
|
12 |
+
# return response.choices[0].message.content.strip()
|
select_question.py
ADDED
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from chatgpt_api import get_chatgpt_response
|
2 |
+
import pandas as pd
|
3 |
+
import re
|
4 |
+
import tempfile
|
5 |
+
import os
|
6 |
+
from translate import translate_text
|
7 |
+
|
8 |
+
|
9 |
+
# プロンプトを作成
|
10 |
+
def make_prompt(df):
|
11 |
+
rows = []
|
12 |
+
for index, row in df.iterrows():
|
13 |
+
theme_str = str(row["テーマ"])
|
14 |
+
if theme_str.lower() == 'nan':
|
15 |
+
continue
|
16 |
+
themes_list = theme_str.split(',')
|
17 |
+
|
18 |
+
questiontext = ""
|
19 |
+
if "Question" in row["サンプル"]:
|
20 |
+
questiontext = "・Questionがある場合は、「##リスニングスクリプト」の表現を真似しすぎず、what,why,how,when,whereなど、多様な角度から問う\n"
|
21 |
+
else:
|
22 |
+
questiontext = ""
|
23 |
+
|
24 |
+
for theme in themes_list:
|
25 |
+
new_prompt = "#条件\n"+ "・以下の「#サンプル」の形式([問題1]##リスニングスクリプト ... ##選択肢...[問題2]##リスニングスクリプト...##選択肢...)で、"+row['レベル']+"レベルのリスニング問題を生成\n"+"・[問題1]から[問題"+str(int(row["問題数"]))+"]まで必ず##リスニングスクリプトを"+str(int(row["問題数"]))+"種類作成\n"+ "・「##リスニングスクリプト」から「##選択肢」まですべて出力\n"+ "・「##リスニングスクリプト」は"+row['スクリプトパターン']+"\n"+"・問題の難易度、word数は「##リスニングスクリプト」と同等レベル\n"+ questiontext +"・各問題は、[問題1][問題2]という形式で始める\n"+"・ただし、スクリプトの内容は、"+theme+"に関するスクリプト\n"+"・[問題1]から[問題"+str(int(row["問題数"]))+"]までの誤答選択肢はすべて異なる内容・異なるパターン \n \n"+"#サンプル\n"+row["サンプル"]
|
26 |
+
print(new_prompt)
|
27 |
+
rows.append({
|
28 |
+
"形式":row["形式2"],
|
29 |
+
"レベル":row["レベル"],
|
30 |
+
"テーマ":theme,
|
31 |
+
"選択肢読み上げ有無":row["選択肢読み上げ有無"],
|
32 |
+
"複製パターン":row["複製パターン"],
|
33 |
+
"プロンプト":new_prompt
|
34 |
+
})
|
35 |
+
result_df = pd.DataFrame(rows)
|
36 |
+
return result_df
|
37 |
+
|
38 |
+
# 問題の分割と展開
|
39 |
+
def expand_problems(df):
|
40 |
+
temp_data = []
|
41 |
+
# テキスト全体を処理
|
42 |
+
for index, row in df.iterrows():
|
43 |
+
print("返却値",row['問題1'])
|
44 |
+
# 正規表現を用いて各問題を分割
|
45 |
+
problems = re.findall(r'\[(問題\d+)\](.*?)(?=\[問題\d+\]|$)', row['問題1'], re.DOTALL)
|
46 |
+
|
47 |
+
# 各問題のIDとともに新たな行を追加
|
48 |
+
for num, text in problems:
|
49 |
+
temp_data.append({
|
50 |
+
"形式": row["形式"],
|
51 |
+
"レベル": row["レベル"],
|
52 |
+
"テーマ":row["テーマ"],
|
53 |
+
"選択肢読み上げ有無": row["選択肢読み上げ有無"],
|
54 |
+
"複製パターン": row["複製パターン"],
|
55 |
+
"問題1": text.strip()
|
56 |
+
})
|
57 |
+
|
58 |
+
# 一時リストから新しいDataFrameを作成
|
59 |
+
return pd.DataFrame(temp_data)
|
60 |
+
|
61 |
+
def create_choice_question(csv_file):
|
62 |
+
# CSVファイルを読み込む
|
63 |
+
df = pd.read_csv(csv_file.name)
|
64 |
+
|
65 |
+
# プロンプトを作成する
|
66 |
+
df_prompt = make_prompt(df)
|
67 |
+
|
68 |
+
# 問題を生成する
|
69 |
+
## 問題1を生成する
|
70 |
+
df_prompt["問題1"] = df_prompt["プロンプト"].apply(get_chatgpt_response)
|
71 |
+
|
72 |
+
## 問題1を展開する
|
73 |
+
result_df = expand_problems(df_prompt)
|
74 |
+
|
75 |
+
## 問題2を生成する
|
76 |
+
result_df["プロンプト2"] = result_df["複製パターン"]+"\n"+result_df["問題1"]
|
77 |
+
result_df["問題2"] = result_df["プロンプト2"].apply(get_chatgpt_response)
|
78 |
+
|
79 |
+
# 翻訳する
|
80 |
+
result_df["翻訳_問題1"] = result_df["問題1"].apply(translate_text)
|
81 |
+
result_df["翻訳_問題2"] = result_df["問題2"].apply(translate_text)
|
82 |
+
|
83 |
+
|
84 |
+
# csvを書き出す
|
85 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix='.csv') as tmp:
|
86 |
+
# cp932で保存、エラーは無視(置換しても良い)
|
87 |
+
result_df.to_csv(tmp.name, index=False, encoding='cp932', errors='ignore')
|
88 |
+
output_path = tmp.name
|
89 |
+
# ファイル名を変更
|
90 |
+
new_path = os.path.join(os.path.dirname(output_path), "output.csv")
|
91 |
+
os.rename(output_path, new_path)
|
92 |
+
return new_path
|
translate.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import json
|
3 |
+
|
4 |
+
def translate_text(text, target_lang='ja', source_lang='en'):
|
5 |
+
api_key = "AIzaSyAEzK5_n6zKTimD9yoXS-C8O0xN_4LaVBQ"
|
6 |
+
# 元の改行を `<br>` で置き換え
|
7 |
+
text = text.replace('\n', '<br>')
|
8 |
+
url = f"https://translation.googleapis.com/language/translate/v2?key={api_key}"
|
9 |
+
payload = {
|
10 |
+
'q': text,
|
11 |
+
'source': source_lang,
|
12 |
+
'target': target_lang,
|
13 |
+
'format': 'html' # フォーマットを 'html' に変更
|
14 |
+
}
|
15 |
+
headers = {
|
16 |
+
'Content-Type': 'application/json'
|
17 |
+
}
|
18 |
+
|
19 |
+
response = requests.post(url, headers=headers, json=payload)
|
20 |
+
if response.status_code == 200:
|
21 |
+
translated_text = json.loads(response.text)['data']['translations'][0]['translatedText']
|
22 |
+
# 翻訳されたテキストの `<br>` を改行に戻す
|
23 |
+
translated_text = translated_text.replace('<br>', '\n')
|
24 |
+
|
25 |
+
# "##選択肢" と "【正解選択肢】" の間に改行を確実に挿入
|
26 |
+
translated_text = translated_text.replace("##選択肢【正解選択肢】", "##選択肢\n【正解選択肢】")
|
27 |
+
|
28 |
+
return translated_text
|
29 |
+
else:
|
30 |
+
return "Error: " + response.text
|
voice_create.py
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pandas as pd
|
2 |
+
import zipfile
|
3 |
+
import base64
|
4 |
+
import os
|
5 |
+
import requests
|
6 |
+
import re
|
7 |
+
|
8 |
+
def remove_quotes(text):
|
9 |
+
# ダブルクォートを空文字に置き換える
|
10 |
+
return text.replace('"', '')
|
11 |
+
|
12 |
+
def text_to_speech(input_file,selected_option):
|
13 |
+
# APIキーを直接コードに埋め込む(実際の運用では推奨されません)
|
14 |
+
api_key = 'AIzaSyAEzK5_n6zKTimD9yoXS-C8O0xN_4LaVBQ' # ここを実際のAPIキーに置き換えてください
|
15 |
+
data = pd.read_csv(input_file)
|
16 |
+
zip_path = 'output_audio_files.zip'
|
17 |
+
|
18 |
+
with zipfile.ZipFile(zip_path, 'w') as z:
|
19 |
+
for idx, row in data.iterrows():
|
20 |
+
# script列が文字列か確認し、文字列でない場合は空文字に置き換える
|
21 |
+
script = row.get('script', '')
|
22 |
+
if not isinstance(script, str):
|
23 |
+
script = str(script)
|
24 |
+
|
25 |
+
# テキストをA:やB:で分割
|
26 |
+
parts = re.split(r'(A:|B:)', script)
|
27 |
+
print(parts)
|
28 |
+
ssml_parts = []
|
29 |
+
print(parts)
|
30 |
+
# 交互に発言するAとBの内容を順に処理
|
31 |
+
for i in range(1, len(parts), 2):
|
32 |
+
if parts[i] == "A:":
|
33 |
+
voice_name = row["voiceA"]
|
34 |
+
print("A")
|
35 |
+
elif parts[i] == "B:":
|
36 |
+
voice_name = row["voiceB"]
|
37 |
+
else:
|
38 |
+
print("空白")
|
39 |
+
continue # A:またはB:で始まらない行は無視
|
40 |
+
|
41 |
+
text = parts[i + 1].strip()
|
42 |
+
text = remove_quotes(text)
|
43 |
+
print("テキスト",text)
|
44 |
+
|
45 |
+
|
46 |
+
# 1sに変換する前に除外するコード
|
47 |
+
text = text.replace("a.m.", 'AM')
|
48 |
+
text = text.replace("p.m.", 'PM')
|
49 |
+
text = text.replace("U.S.", 'US')
|
50 |
+
text = text.replace("U.K.", 'UK')
|
51 |
+
text = text.replace("Mr.", 'Mister')
|
52 |
+
text = text.replace("Ms.", 'MIZ')
|
53 |
+
text = text.replace("Mrs.", 'Misiz')
|
54 |
+
text = text.replace("Dr.", 'Doctor')
|
55 |
+
text = text.replace("Mt.", 'Mount')
|
56 |
+
|
57 |
+
|
58 |
+
# テキスト内の改行を1sの間に変換
|
59 |
+
text = text.replace("\n", '<break time="1s"/>')
|
60 |
+
text = text.replace(".", '.<break time="500ms"/>')
|
61 |
+
|
62 |
+
if selected_option == "ブレイクタイム有":
|
63 |
+
# 「,」で時間を空ける
|
64 |
+
if row["eikenn"] in ["5級","4級","3級","準2級","2級","準1級"]:
|
65 |
+
text = text.replace(",", '<break time="50ms"/>')
|
66 |
+
print("タグ処理")
|
67 |
+
else:
|
68 |
+
pass
|
69 |
+
|
70 |
+
ssml_parts.append(f'<voice name="{voice_name}"><prosody rate="{row["speed"]}"><p>{text}</p></prosody></voice>')
|
71 |
+
print(ssml_parts)
|
72 |
+
ssml = '<speak>' + ''.join(ssml_parts)
|
73 |
+
print(ssml)
|
74 |
+
|
75 |
+
if pd.notna(row.get('question')) and row['question'] != '':
|
76 |
+
ssml += f'<break time="1s"/><voice name="{row["voiceQuestion"]}"><prosody rate="{row["speed"]}"><p>Question</p><break time="1s"/><p>{row["question"]}</p></prosody></voice>'
|
77 |
+
# Choices部分の追加
|
78 |
+
if pd.notna(row.get('choices')) and row['choices'] != '':
|
79 |
+
choices_list = row['choices'].split('/')
|
80 |
+
choices_ssml = '<break time="1s"/>'.join(choices_list)
|
81 |
+
ssml += f'<break time="1s"/><voice name="{row["voiceB"]}"><prosody rate="{row["speed"]}"><p>{choices_ssml}</p></prosody></voice>'
|
82 |
+
ssml += '</speak>'
|
83 |
+
|
84 |
+
print(ssml)
|
85 |
+
# APIリクエスト用のボディ
|
86 |
+
body = {
|
87 |
+
"input": {"ssml": ssml},
|
88 |
+
"voice": {"languageCode": "en-US"}, # 基本的な言語設定(必要に応じて行ごとに変更可能)
|
89 |
+
"audioConfig": {"audioEncoding": "MP3"}
|
90 |
+
}
|
91 |
+
headers = {
|
92 |
+
"X-Goog-Api-Key": api_key,
|
93 |
+
"Content-Type": "application/json"
|
94 |
+
}
|
95 |
+
url = "https://texttospeech.googleapis.com/v1/text:synthesize"
|
96 |
+
response = requests.post(url, headers=headers, json=body)
|
97 |
+
print("レスポンス",response)
|
98 |
+
response_data = response.json()
|
99 |
+
print("レスポンスデータ",response_data)
|
100 |
+
|
101 |
+
# 音声コンテンツの取得とファイル保存
|
102 |
+
if 'audioContent' in response_data:
|
103 |
+
audio_content = base64.b64decode(response_data['audioContent'])
|
104 |
+
file_name = f"{row['id']}.mp3"
|
105 |
+
with open(file_name, "wb") as out:
|
106 |
+
out.write(audio_content)
|
107 |
+
|
108 |
+
z.write(file_name)
|
109 |
+
os.remove(file_name)
|
110 |
+
else:
|
111 |
+
print("ファイル不備")
|
112 |
+
|
113 |
+
return zip_path
|