ryo2's picture
Upload 3 files
f477594 verified
import gradio as gr
import tempfile
class MarkdownGenerator:
@staticmethod
def generate_from_shot_data(shot_data):
markdown = ""
for i in range(0, len(shot_data), 3):
if i + 2 < len(shot_data):
title, content, visible = shot_data[i], shot_data[i + 1], shot_data[i + 2]
if visible and content.strip():
markdown += f"# {title}\n{content}\n\n"
return markdown.strip()
@staticmethod
def create_temporary_file(markdown_content):
with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False, encoding='utf-8') as f:
f.write(markdown_content)
return f.name
class ShotManager:
def __init__(self):
self.default_titles = ["命令書", "制約条件", "入力", "出力"]
self.max_shots = 12
def add_shot(self, *shot_data):
shot_data = list(shot_data)
for i in range(12, len(shot_data), 3):
if i + 2 < len(shot_data) and not shot_data[i + 2]:
shot_data[i] = f"新しいショット {(i // 3) - 3}"
shot_data[i + 2] = True
break
return shot_data + self._create_accordion_updates(shot_data)
def delete_shot(self, shot_index, *shot_data):
shot_data = list(shot_data)
visible_count = sum(1 for i in range(2, len(shot_data), 3) if i < len(shot_data) and shot_data[i])
if visible_count > 1:
data_index = shot_index * 3
if data_index + 2 < len(shot_data):
shot_data[data_index:data_index + 3] = ["", "", False]
return shot_data + self._create_accordion_updates(shot_data)
def move_shot_up(self, shot_index, *shot_data):
shot_data = list(shot_data)
if shot_index > 0:
self._swap_shots(shot_data, shot_index, shot_index - 1)
return shot_data + self._create_accordion_updates(shot_data)
def move_shot_down(self, shot_index, *shot_data):
shot_data = list(shot_data)
next_index = (shot_index + 1) * 3
if next_index + 2 < len(shot_data) and shot_data[next_index + 2]:
self._swap_shots(shot_data, shot_index, shot_index + 1)
return shot_data + self._create_accordion_updates(shot_data)
def clear_all_shots(self, *shot_data):
shot_data = list(shot_data)
for i, title in enumerate(self.default_titles):
data_index = i * 3
if data_index + 2 < len(shot_data):
shot_data[data_index:data_index + 3] = [title, "", True]
for i in range(4, len(shot_data) // 3):
data_index = i * 3
if data_index + 2 < len(shot_data):
shot_data[data_index:data_index + 3] = ["", "", False]
return shot_data + self._create_accordion_updates(shot_data)
def _swap_shots(self, shot_data, index1, index2):
start1, start2 = index1 * 3, index2 * 3
if start1 + 2 < len(shot_data) and start2 + 2 < len(shot_data):
for offset in range(3):
shot_data[start1 + offset], shot_data[start2 + offset] = \
shot_data[start2 + offset], shot_data[start1 + offset]
def _create_accordion_updates(self, shot_data):
updates = []
for i in range(self.max_shots):
data_index = i * 3
if data_index + 2 < len(shot_data):
updates.append(gr.update(visible=shot_data[data_index + 2]))
else:
updates.append(gr.update())
return updates
class PromptEngineering:
def __init__(self):
self.shot_manager = ShotManager()
self.markdown_generator = MarkdownGenerator()
def update_preview_and_stats(self, *shot_data):
markdown = self.markdown_generator.generate_from_shot_data(shot_data)
total_shots, filled_shots = self._calculate_stats(shot_data)
stats = f"ショット数: {total_shots} | 入力済み: {filled_shots}"
if markdown:
temp_file = self.markdown_generator.create_temporary_file(markdown)
return markdown, stats, markdown, gr.update(visible=True, value=temp_file)
else:
return "ショットに内容を入力すると、プレビューが表示されます。", stats, "", gr.update(visible=False)
def _calculate_stats(self, shot_data):
total_shots = filled_shots = 0
for i in range(0, len(shot_data), 3):
if i + 2 < len(shot_data):
title, content, visible = shot_data[i], shot_data[i + 1], shot_data[i + 2]
if visible:
total_shots += 1
if content.strip():
filled_shots += 1
return total_shots, filled_shots
def create_interface(self):
with gr.Blocks(title="🔧 プロンプトエンジニアリングツール", theme=gr.themes.Soft()) as demo:
gr.Markdown("# 🔧 プロンプトエンジニアリングツール")
gr.Markdown("各ショットを入力して、統合されたプロンプトを生成しましょう!")
with gr.Row():
shot_components, shot_data_components = self._create_shot_input_section()
preview_components = self._create_preview_section()
self._setup_event_handlers(shot_components, shot_data_components, preview_components)
return demo
def _create_shot_input_section(self):
with gr.Column(scale=2):
gr.Markdown("## 📝 ショット入力")
with gr.Row():
add_shot_btn = gr.Button("➕ ショットを追加", variant="primary")
clear_all_btn = gr.Button("🗑️ 全てクリア", variant="stop")
shot_components = []
shot_data_components = []
for i in range(12):
component_data = self._create_single_shot(i)
shot_components.append(component_data['components'])
shot_data_components.extend(component_data['data'])
return {'components': shot_components, 'add_btn': add_shot_btn, 'clear_btn': clear_all_btn}, shot_data_components
def _create_single_shot(self, index):
default_values = self._get_default_shot_values(index)
with gr.Accordion(default_values['accordion_title'],
open=(index == 0),
visible=default_values['visible']) as accordion:
with gr.Row():
with gr.Column(scale=3):
title_input = gr.Textbox(
label="ショットタイトル",
value=default_values['title'],
placeholder="ショットのタイトルを入力してください..."
)
content_input = gr.Textbox(
label="内容",
value="",
lines=5,
placeholder="ショットの内容を入力してください..."
)
with gr.Column(scale=1):
gr.Markdown("**操作**")
with gr.Row():
up_btn = gr.Button("⬆️", size="sm", variant="secondary")
down_btn = gr.Button("⬇️", size="sm", variant="secondary")
with gr.Row():
delete_btn = gr.Button("🗑️ 削除", size="sm", variant="stop")
visible_state = gr.Checkbox(value=default_values['visible'], visible=False)
return {
'components': {
'accordion': accordion,
'title': title_input,
'content': content_input,
'visible': visible_state,
'up': up_btn,
'down': down_btn,
'delete': delete_btn
},
'data': [title_input, content_input, visible_state]
}
def _get_default_shot_values(self, index):
if index < 4:
titles = ["命令書", "制約条件", "入力", "出力"]
return {
'title': titles[index],
'visible': True,
'accordion_title': f"📋 {titles[index]}"
}
else:
return {
'title': "",
'visible': False,
'accordion_title': f"📋 追加ショット {index - 3}"
}
def _create_preview_section(self):
with gr.Column(scale=1):
gr.Markdown("## 📄 生成されたプロンプト")
stats_display = gr.Textbox(
label="📊 統計",
value="ショット数: 4 | 入力済み: 0",
interactive=False
)
gr.Markdown("### 👀 プレビュー")
preview_area = gr.Textbox(
label="生成されたMarkdown",
value="ショットに内容を入力すると、プレビューが表示されます。",
lines=15,
max_lines=20,
interactive=False
)
gr.Markdown("### 📥 ダウンロード")
download_file = gr.File(label="Markdownファイル", visible=False)
gr.Markdown("### 📋 コピー用")
copy_area = gr.Textbox(
label="テキスト形式",
lines=8,
interactive=False,
info="このテキストをコピーして使用できます"
)
return [preview_area, stats_display, copy_area, download_file]
def _setup_event_handlers(self, shot_components, shot_data_components, preview_components):
accordion_components = [comp['accordion'] for comp in shot_components['components']]
all_outputs = shot_data_components + accordion_components
shot_components['add_btn'].click(
fn=self.shot_manager.add_shot,
inputs=shot_data_components,
outputs=all_outputs
)
shot_components['clear_btn'].click(
fn=self.shot_manager.clear_all_shots,
inputs=shot_data_components,
outputs=all_outputs
)
for i, component in enumerate(shot_components['components']):
component['up'].click(
fn=lambda *args, idx=i: self.shot_manager.move_shot_up(idx, *args),
inputs=shot_data_components,
outputs=all_outputs
)
component['down'].click(
fn=lambda *args, idx=i: self.shot_manager.move_shot_down(idx, *args),
inputs=shot_data_components,
outputs=all_outputs
)
component['delete'].click(
fn=lambda *args, idx=i: self.shot_manager.delete_shot(idx, *args),
inputs=shot_data_components,
outputs=all_outputs
)
for component in shot_data_components:
component.change(
fn=self.update_preview_and_stats,
inputs=shot_data_components,
outputs=preview_components
)
def launch(self):
demo = self.create_interface()
demo.launch()
if __name__ == "__main__":
app = PromptEngineering()
app.launch()