Update app.py
Browse files
app.py
CHANGED
|
@@ -613,13 +613,20 @@ def display_historical_glossary_for_reporter(scenario_key, vocab_level):
|
|
| 613 |
st.sidebar.markdown(f"**{term}:** {definition}")
|
| 614 |
st.sidebar.markdown("---")
|
| 615 |
|
| 616 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 617 |
if 'game_mode' not in st.session_state: st.session_state.game_mode = 'scenario_select'
|
| 618 |
if 'current_scenario_key' not in st.session_state: st.session_state.current_scenario_key = None
|
| 619 |
if 'game_state' not in st.session_state: st.session_state.game_state = None
|
| 620 |
if 'current_assignment_data' not in st.session_state: st.session_state.current_assignment_data = None
|
| 621 |
if 'actions_taken_this_turn' not in st.session_state: st.session_state.actions_taken_this_turn = 0
|
| 622 |
if 'desk_feedback_message' not in st.session_state: st.session_state.desk_feedback_message = None
|
|
|
|
| 623 |
|
| 624 |
# --- 메인 게임 로직 (기자 컨셉) ---
|
| 625 |
def reporter_simulation_main():
|
|
@@ -630,6 +637,7 @@ def reporter_simulation_main():
|
|
| 630 |
|
| 631 |
st.title(get_text_main("game_title"))
|
| 632 |
|
|
|
|
| 633 |
if st.session_state.game_mode == 'scenario_select':
|
| 634 |
st.header(get_text_main("scenario_select_title"))
|
| 635 |
scenario_descriptions = {
|
|
@@ -649,94 +657,161 @@ def reporter_simulation_main():
|
|
| 649 |
st.session_state.actions_taken_this_turn = 0
|
| 650 |
st.session_state.desk_feedback_message = None
|
| 651 |
st.session_state.game_mode = 'assignment_briefing'
|
|
|
|
| 652 |
st.rerun()
|
| 653 |
st.stop()
|
| 654 |
|
|
|
|
| 655 |
if st.session_state.game_mode != 'scenario_select' and st.session_state.game_state:
|
| 656 |
game_state = st.session_state.game_state
|
| 657 |
scenario_key = st.session_state.current_scenario_key
|
| 658 |
vocab_level = SCENARIOS[scenario_key]["vocab_level"]
|
| 659 |
get_text_main = lambda key: get_text(key, vocab_level)
|
| 660 |
|
| 661 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 662 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 663 |
if st.session_state.game_mode == 'assignment_over':
|
| 664 |
st.balloons()
|
| 665 |
st.header(get_text_main("assignment_over_title"))
|
| 666 |
st.subheader(get_text_main("assignment_over_subtitle"))
|
| 667 |
-
|
| 668 |
-
|
| 669 |
st.subheader("송고한 주요 기사 목록")
|
| 670 |
if game_state['submitted_articles']:
|
| 671 |
-
for article in game_state['submitted_articles']:
|
| 672 |
tone_text_key = f"article_tone_{article['tone']}"
|
| 673 |
tone_display_text = get_text_main(tone_text_key)
|
| 674 |
-
|
|
|
|
|
|
|
| 675 |
else:
|
| 676 |
st.caption("이번 취재 기간 동안 송고한 기사가 없습니다.")
|
| 677 |
|
| 678 |
-
st.
|
| 679 |
-
|
| 680 |
-
|
| 681 |
-
|
| 682 |
-
|
| 683 |
-
|
| 684 |
-
|
| 685 |
-
|
| 686 |
-
|
| 687 |
-
|
| 688 |
-
|
| 689 |
-
|
| 690 |
-
st.rerun()
|
| 691 |
-
with col_btn2:
|
| 692 |
-
if st.button(get_text_main("button_back_to_scenario_select"), use_container_width=True):
|
| 693 |
-
st.session_state.game_mode = 'scenario_select'
|
| 694 |
-
keys_to_clear = ['current_scenario_key', 'game_state', 'current_assignment_data', 'actions_taken_this_turn', 'desk_feedback_message']
|
| 695 |
-
for k_to_clear in keys_to_clear:
|
| 696 |
-
if k_to_clear in st.session_state: del st.session_state[k_to_clear]
|
| 697 |
-
st.rerun()
|
| 698 |
st.stop()
|
| 699 |
|
| 700 |
-
col_dashboard, col_main_content, col_actions_notebook = st.columns([1.2, 1.8, 1.5])
|
| 701 |
|
| 702 |
-
|
| 703 |
-
|
| 704 |
-
|
| 705 |
-
|
| 706 |
-
|
| 707 |
-
|
| 708 |
-
|
| 709 |
-
|
| 710 |
-
|
| 711 |
-
|
| 712 |
-
|
| 713 |
-
|
| 714 |
-
|
| 715 |
-
|
| 716 |
-
|
| 717 |
-
|
| 718 |
-
|
| 719 |
-
|
| 720 |
-
|
| 721 |
-
|
| 722 |
-
|
| 723 |
-
|
| 724 |
-
|
| 725 |
-
|
| 726 |
-
|
| 727 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 728 |
|
|
|
|
|
|
|
| 729 |
if st.session_state.game_mode == 'reporter_action' and st.session_state.current_assignment_data:
|
| 730 |
assignment_data = st.session_state.current_assignment_data
|
| 731 |
-
st.header(get_text_main("current_assignment_title"))
|
| 732 |
-
st.subheader(assignment_data['assignment_text'])
|
| 733 |
-
if assignment_data.get('source_text'):
|
| 734 |
-
st.info(f"**{get_text_main('historical_source_title')}:** {assignment_data['source_text']}")
|
| 735 |
-
|
| 736 |
-
st.divider()
|
| 737 |
-
st.subheader(get_text_main("reporter_actions_title"))
|
| 738 |
-
|
| 739 |
if st.session_state.actions_taken_this_turn < ACTIONS_PER_TURN_LIMIT:
|
|
|
|
| 740 |
for i, opt in enumerate(assignment_data['options']):
|
| 741 |
risk_info = []
|
| 742 |
if opt.get('cost_freedom_risk',0) > 0: risk_info.append(f"자유도↓{opt['cost_freedom_risk']}%")
|
|
@@ -746,89 +821,69 @@ def reporter_simulation_main():
|
|
| 746 |
|
| 747 |
if st.button(button_label, key=f"rep_action_{game_state['current_turn']}_{i}_{scenario_key}", use_container_width=True):
|
| 748 |
process_reporter_action(opt, game_state)
|
|
|
|
|
|
|
| 749 |
st.rerun()
|
| 750 |
else:
|
| 751 |
st.info(get_text_main("status_actions_taken"))
|
| 752 |
-
if assignment_data.get("article_writing_phase"):
|
| 753 |
-
|
| 754 |
-
|
| 755 |
-
|
|
|
|
| 756 |
|
| 757 |
-
if st.session_state.game_mode == 'article_writing' and st.session_state.current_assignment_data:
|
| 758 |
-
assignment_data = st.session_state.current_assignment_data
|
| 759 |
-
submitted_article = generate_article_interface(game_state, vocab_level)
|
| 760 |
-
if submitted_article:
|
| 761 |
-
feedback = evaluate_article_and_get_feedback_openai(submitted_article, game_state, assignment_data)
|
| 762 |
-
st.session_state.desk_feedback_message = feedback
|
| 763 |
-
st.session_state.game_mode = 'reporter_action' # 피드백 표시 후 다음날로 넘어갈 수 있도록
|
| 764 |
-
st.rerun()
|
| 765 |
-
|
| 766 |
-
if st.session_state.desk_feedback_message and st.session_state.game_mode == 'reporter_action':
|
| 767 |
-
st.divider()
|
| 768 |
-
st.subheader(get_text_main("desk_feedback_title"))
|
| 769 |
-
st.warning(st.session_state.desk_feedback_message) # AI 피드백 표시
|
| 770 |
-
|
| 771 |
-
with col_actions_notebook: # 오른쪽 컬럼
|
| 772 |
-
st.header("활동 기록 및 다음 단계")
|
| 773 |
-
can_proceed_to_next_day = False
|
| 774 |
-
if st.session_state.game_mode == 'reporter_action' and st.session_state.current_assignment_data:
|
| 775 |
-
assignment_data = st.session_state.current_assignment_data
|
| 776 |
-
if st.session_state.actions_taken_this_turn >= ACTIONS_PER_TURN_LIMIT:
|
| 777 |
-
if not assignment_data.get("article_writing_phase"): # 기사 작성 없는 턴
|
| 778 |
-
can_proceed_to_next_day = True
|
| 779 |
-
elif st.session_state.desk_feedback_message: # 기사 작성 후 피드백까지 받은 상태
|
| 780 |
-
can_proceed_to_next_day = True
|
| 781 |
-
|
| 782 |
-
if can_proceed_to_next_day:
|
| 783 |
-
if st.button(get_text_main("button_next_day"), use_container_width=True, key="next_day_button"):
|
| 784 |
-
current_turn = game_state['current_turn']
|
| 785 |
-
max_turns_for_scenario = SCENARIOS[scenario_key]['max_turns']
|
| 786 |
|
| 787 |
-
|
| 788 |
-
|
| 789 |
-
if game_state.get('event_log') is not None:
|
| 790 |
-
game_state['event_log'].append(get_text_main("log_assignment_over").format(scenario_name=SCENARIOS[scenario_key]['display_name']))
|
| 791 |
-
else:
|
| 792 |
-
game_state['current_turn'] += 1
|
| 793 |
-
if game_state.get('event_log') is not None:
|
| 794 |
-
game_state['event_log'].append(get_text_main("log_next_day_start").format(year=game_state['game_year'], turn=game_state['current_turn']))
|
| 795 |
-
st.session_state.game_mode = 'assignment_briefing'
|
| 796 |
-
|
| 797 |
-
st.session_state.current_assignment_data = None
|
| 798 |
-
st.session_state.actions_taken_this_turn = 0
|
| 799 |
-
# desk_feedback_message는 다음 턴 시작 시 assignment_briefing에서 초기화
|
| 800 |
-
st.rerun()
|
| 801 |
-
|
| 802 |
-
st.divider()
|
| 803 |
-
st.subheader(get_text_main("term_event_log"))
|
| 804 |
-
log_text = "\n".join(game_state.get('event_log', [])[::-1])
|
| 805 |
-
st.text_area(get_text_main("term_event_log"), log_text, height=300, disabled=True, key="event_log_area_reporter")
|
| 806 |
|
| 807 |
-
with st.sidebar:
|
| 808 |
-
st.header(get_text_main("sidebar_title"))
|
| 809 |
-
display_historical_glossary_for_reporter(scenario_key, vocab_level)
|
| 810 |
-
|
| 811 |
-
st.subheader(get_text_main("sidebar_current_source_title"))
|
| 812 |
-
if st.session_state.current_assignment_data and st.session_state.current_assignment_data.get('source_text'):
|
| 813 |
-
st.sidebar.info(st.session_state.current_assignment_data.get('source_text'))
|
| 814 |
-
else:
|
| 815 |
-
st.sidebar.caption(get_text_main("sidebar_no_source"))
|
| 816 |
|
| 817 |
-
|
| 818 |
-
|
| 819 |
-
st.session_state.game_mode
|
| 820 |
-
|
| 821 |
-
|
| 822 |
-
|
| 823 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 824 |
|
| 825 |
elif st.session_state.game_mode != 'scenario_select' and not st.session_state.game_state:
|
| 826 |
st.warning("게임 상태 정보가 유실되었습니다. 시나리오 선택 화면으로 돌아갑니다.")
|
| 827 |
st.session_state.game_mode = 'scenario_select'
|
| 828 |
-
keys_to_clear = ['current_scenario_key', 'game_state', 'current_assignment_data', 'actions_taken_this_turn', 'desk_feedback_message']
|
| 829 |
for k_to_clear in keys_to_clear:
|
| 830 |
if k_to_clear in st.session_state: del st.session_state[k_to_clear]
|
| 831 |
-
time.sleep(1)
|
| 832 |
st.rerun()
|
| 833 |
|
| 834 |
if __name__ == "__main__":
|
|
|
|
| 613 |
st.sidebar.markdown(f"**{term}:** {definition}")
|
| 614 |
st.sidebar.markdown("---")
|
| 615 |
|
| 616 |
+
# (상단 import 및 설정, 함수 정의 등은 기존 코드 유지)
|
| 617 |
+
# ... (initialize_reporter_scenario_state, get_next_assignment, process_reporter_action,
|
| 618 |
+
# generate_article_interface, evaluate_article_and_get_feedback_openai,
|
| 619 |
+
# display_reporter_dashboard, display_reporter_notebook,
|
| 620 |
+
# display_historical_glossary_for_reporter 등 함수 정의는 그대로 사용) ...
|
| 621 |
+
|
| 622 |
+
# --- 세션 상태 초기화 (기존과 동일) ---
|
| 623 |
if 'game_mode' not in st.session_state: st.session_state.game_mode = 'scenario_select'
|
| 624 |
if 'current_scenario_key' not in st.session_state: st.session_state.current_scenario_key = None
|
| 625 |
if 'game_state' not in st.session_state: st.session_state.game_state = None
|
| 626 |
if 'current_assignment_data' not in st.session_state: st.session_state.current_assignment_data = None
|
| 627 |
if 'actions_taken_this_turn' not in st.session_state: st.session_state.actions_taken_this_turn = 0
|
| 628 |
if 'desk_feedback_message' not in st.session_state: st.session_state.desk_feedback_message = None
|
| 629 |
+
if 'active_main_tab' not in st.session_state: st.session_state.active_main_tab = "취재 브리핑" # 기본 활성 탭
|
| 630 |
|
| 631 |
# --- 메인 게임 로직 (기자 컨셉) ---
|
| 632 |
def reporter_simulation_main():
|
|
|
|
| 637 |
|
| 638 |
st.title(get_text_main("game_title"))
|
| 639 |
|
| 640 |
+
# --- 시나리오 선택 (기존과 동일) ---
|
| 641 |
if st.session_state.game_mode == 'scenario_select':
|
| 642 |
st.header(get_text_main("scenario_select_title"))
|
| 643 |
scenario_descriptions = {
|
|
|
|
| 657 |
st.session_state.actions_taken_this_turn = 0
|
| 658 |
st.session_state.desk_feedback_message = None
|
| 659 |
st.session_state.game_mode = 'assignment_briefing'
|
| 660 |
+
st.session_state.active_main_tab = "취재 브리핑" # 탭 초기화
|
| 661 |
st.rerun()
|
| 662 |
st.stop()
|
| 663 |
|
| 664 |
+
# --- 게임 진행 ---
|
| 665 |
if st.session_state.game_mode != 'scenario_select' and st.session_state.game_state:
|
| 666 |
game_state = st.session_state.game_state
|
| 667 |
scenario_key = st.session_state.current_scenario_key
|
| 668 |
vocab_level = SCENARIOS[scenario_key]["vocab_level"]
|
| 669 |
get_text_main = lambda key: get_text(key, vocab_level)
|
| 670 |
|
| 671 |
+
# --- 사이드바 구성 ---
|
| 672 |
+
with st.sidebar:
|
| 673 |
+
st.header(get_text_main("dashboard_title"))
|
| 674 |
+
st.caption(f"시나리오: {SCENARIOS[scenario_key]['display_name']}")
|
| 675 |
+
st.caption(f"역할: {game_state['player_role']}")
|
| 676 |
+
st.markdown(f"**{get_text_main('dashboard_term').format(year=game_state['game_year'], turn=game_state['current_turn'])}**")
|
| 677 |
+
display_reporter_dashboard(game_state) # 핵심 지표 표시
|
| 678 |
+
st.markdown("---")
|
| 679 |
+
|
| 680 |
+
if st.button(get_text_main("button_next_day"), use_container_width=True, key="next_day_button_sidebar",
|
| 681 |
+
disabled=(st.session_state.game_mode == 'article_writing' or
|
| 682 |
+
(st.session_state.game_mode == 'reporter_action' and
|
| 683 |
+
st.session_state.actions_taken_this_turn < ACTIONS_PER_TURN_LIMIT and
|
| 684 |
+
st.session_state.current_assignment_data and
|
| 685 |
+
len(st.session_state.current_assignment_data.get("options", [])) > 0
|
| 686 |
+
) # 아직 할 수 있는 액션이 남았거나 기사 작성 중이면 비활성화
|
| 687 |
+
)
|
| 688 |
+
):
|
| 689 |
+
current_turn = game_state['current_turn']
|
| 690 |
+
max_turns_for_scenario = SCENARIOS[scenario_key]['max_turns']
|
| 691 |
+
|
| 692 |
+
if current_turn >= max_turns_for_scenario or \
|
| 693 |
+
(st.session_state.current_assignment_data and st.session_state.current_assignment_data.get("is_final_turn_event", False)):
|
| 694 |
+
st.session_state.game_mode = 'assignment_over'
|
| 695 |
+
if game_state.get('event_log') is not None:
|
| 696 |
+
game_state['event_log'].append(get_text_main("log_assignment_over").format(scenario_name=SCENARIOS[scenario_key]['display_name']))
|
| 697 |
+
else:
|
| 698 |
+
game_state['current_turn'] += 1
|
| 699 |
+
if game_state.get('event_log') is not None:
|
| 700 |
+
game_state['event_log'].append(get_text_main("log_next_day_start").format(year=game_state['game_year'], turn=game_state['current_turn']))
|
| 701 |
+
st.session_state.game_mode = 'assignment_briefing'
|
| 702 |
+
|
| 703 |
+
st.session_state.current_assignment_data = None
|
| 704 |
+
st.session_state.actions_taken_this_turn = 0
|
| 705 |
+
st.session_state.desk_feedback_message = None # 피드백 초기화
|
| 706 |
+
st.session_state.active_main_tab = "취재 브리핑" # 탭 초기화
|
| 707 |
+
st.rerun()
|
| 708 |
+
|
| 709 |
+
st.markdown("---")
|
| 710 |
+
display_historical_glossary_for_reporter(scenario_key, vocab_level)
|
| 711 |
+
|
| 712 |
+
st.subheader(get_text_main("sidebar_current_source_title"))
|
| 713 |
+
if st.session_state.current_assignment_data and st.session_state.current_assignment_data.get('source_text'):
|
| 714 |
+
st.sidebar.info(st.session_state.current_assignment_data.get('source_text'))
|
| 715 |
+
else:
|
| 716 |
+
st.sidebar.caption(get_text_main("sidebar_no_source"))
|
| 717 |
|
| 718 |
+
st.markdown("---")
|
| 719 |
+
if st.button(get_text_main("button_back_to_scenario_select") + " (다른 시대 취재)", use_container_width=True):
|
| 720 |
+
st.session_state.game_mode = 'scenario_select'
|
| 721 |
+
keys_to_clear = ['current_scenario_key', 'game_state', 'current_assignment_data', 'actions_taken_this_turn', 'desk_feedback_message', 'active_main_tab']
|
| 722 |
+
for k_to_clear in keys_to_clear:
|
| 723 |
+
if k_to_clear in st.session_state: del st.session_state[k_to_clear]
|
| 724 |
+
st.rerun()
|
| 725 |
+
|
| 726 |
+
# --- 취재 기간 종료 처리 ---
|
| 727 |
if st.session_state.game_mode == 'assignment_over':
|
| 728 |
st.balloons()
|
| 729 |
st.header(get_text_main("assignment_over_title"))
|
| 730 |
st.subheader(get_text_main("assignment_over_subtitle"))
|
| 731 |
+
# 최종 대시보드는 사이드바에 이미 표시됨
|
| 732 |
+
|
| 733 |
st.subheader("송고한 주요 기사 목록")
|
| 734 |
if game_state['submitted_articles']:
|
| 735 |
+
for article_idx, article in enumerate(game_state['submitted_articles']):
|
| 736 |
tone_text_key = f"article_tone_{article['tone']}"
|
| 737 |
tone_display_text = get_text_main(tone_text_key)
|
| 738 |
+
# AI 점수는 article 딕셔너리에 저장해야 함 (evaluate 함수에서)
|
| 739 |
+
ai_score = article.get('ai_score', 'N/A') # 'ai_score' 키로 저장했다고 가정
|
| 740 |
+
st.markdown(f"- **{article['headline']}** (논조: {tone_display_text}) - {article['turn']}일차 송고 (AI 점수: {ai_score}점)")
|
| 741 |
else:
|
| 742 |
st.caption("이번 취재 기간 동안 송고한 기사가 없습니다.")
|
| 743 |
|
| 744 |
+
with st.expander(get_text_main("term_event_log"), expanded=False):
|
| 745 |
+
log_text = "\n".join(game_state.get('event_log', [])[::-1])
|
| 746 |
+
st.text_area("로그 내용", log_text, height=250, disabled=True, key="final_log_reporter_main")
|
| 747 |
+
|
| 748 |
+
if st.button(get_text_main("button_restart_assignment"), key="restart_assignment_main_btn"):
|
| 749 |
+
st.session_state.game_state = initialize_reporter_scenario_state(scenario_key)
|
| 750 |
+
st.session_state.current_assignment_data = None
|
| 751 |
+
st.session_state.actions_taken_this_turn = 0
|
| 752 |
+
st.session_state.desk_feedback_message = None
|
| 753 |
+
st.session_state.game_mode = 'assignment_briefing'
|
| 754 |
+
st.session_state.active_main_tab = "취재 브리핑"
|
| 755 |
+
st.rerun()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 756 |
st.stop()
|
| 757 |
|
|
|
|
| 758 |
|
| 759 |
+
# --- 메인 콘텐츠 영역 ---
|
| 760 |
+
# 탭 대신 단계별 UI 전환 또는 주요 정보만 표시하는 방식으로 변경 가능
|
| 761 |
+
# 여기서는 주요 정보를 먼저 표시하고, 액션은 버튼으로 유도
|
| 762 |
+
|
| 763 |
+
# 1. 오늘의 취재 지시 로드 (assignment_briefing 모드에서 처리)
|
| 764 |
+
if st.session_state.game_mode == 'assignment_briefing':
|
| 765 |
+
if st.session_state.current_assignment_data is None:
|
| 766 |
+
spinner_text = get_text_main('status_loading_assignment').format(year=game_state['game_year'], turn=game_state['current_turn'])
|
| 767 |
+
with st.spinner(spinner_text):
|
| 768 |
+
time.sleep(0.5)
|
| 769 |
+
assignment = get_next_assignment(scenario_key, game_state['current_turn'], game_state)
|
| 770 |
+
if assignment:
|
| 771 |
+
st.session_state.current_assignment_data = assignment
|
| 772 |
+
st.session_state.actions_taken_this_turn = 0
|
| 773 |
+
st.session_state.desk_feedback_message = None # 이전 피드백 초기화
|
| 774 |
+
st.session_state.game_mode = 'reporter_action' # 바로 취재 활동으로
|
| 775 |
+
st.session_state.active_main_tab = "취재 활동" # 탭 전환
|
| 776 |
+
st.rerun()
|
| 777 |
+
else:
|
| 778 |
+
st.session_state.game_mode = 'assignment_over'
|
| 779 |
+
if game_state.get('event_log') is not None:
|
| 780 |
+
game_state['event_log'].append(get_text_main("log_assignment_over").format(scenario_name=SCENARIOS[scenario_key]['display_name']))
|
| 781 |
+
st.rerun()
|
| 782 |
+
|
| 783 |
+
# 메인 화면에 현재 취재 지시 표시
|
| 784 |
+
if st.session_state.current_assignment_data:
|
| 785 |
+
assignment_data = st.session_state.current_assignment_data
|
| 786 |
+
st.header(get_text_main("current_assignment_title"))
|
| 787 |
+
st.subheader(f"{assignment_data['assignment_text']}")
|
| 788 |
+
# 배경 정보는 사이드바로 이동했으므로 여기서는 생략 가능
|
| 789 |
+
st.markdown("---")
|
| 790 |
+
|
| 791 |
+
# 탭으로 주요 활동 구분
|
| 792 |
+
tab_titles = ["🎤 취재 활동"]
|
| 793 |
+
if st.session_state.current_assignment_data and st.session_state.current_assignment_data.get("article_writing_phase"):
|
| 794 |
+
tab_titles.append("🖋️ 기사 작성")
|
| 795 |
+
if st.session_state.desk_feedback_message:
|
| 796 |
+
tab_titles.append("📢 AI 편집장 평가")
|
| 797 |
+
|
| 798 |
+
# 탭 상태 관리 (선택된 탭 유지)
|
| 799 |
+
if 'active_main_tab' not in st.session_state or st.session_state.active_main_tab not in tab_titles:
|
| 800 |
+
st.session_state.active_main_tab = tab_titles[0] # 기본값 또는 유효한 값으로 설정
|
| 801 |
+
|
| 802 |
+
# 현재 활성화된 탭을 selected_tab으로 사용
|
| 803 |
+
# selected_tab = st.radio("메인 활동 선택:", tab_titles, horizontal=True, key="main_activity_radio", index=tab_titles.index(st.session_state.active_main_tab))
|
| 804 |
+
# st.session_state.active_main_tab = selected_tab # 선택된 탭 업데이트
|
| 805 |
+
# radio 대신 st.tabs 사용
|
| 806 |
+
|
| 807 |
+
tabs_ui = st.tabs(tab_titles)
|
| 808 |
|
| 809 |
+
with tabs_ui[0]: # 취재 활동 탭
|
| 810 |
+
# st.header(get_text_main("reporter_actions_title")) # 탭 이름으로 대체
|
| 811 |
if st.session_state.game_mode == 'reporter_action' and st.session_state.current_assignment_data:
|
| 812 |
assignment_data = st.session_state.current_assignment_data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 813 |
if st.session_state.actions_taken_this_turn < ACTIONS_PER_TURN_LIMIT:
|
| 814 |
+
st.write(f"남은 활동 횟수: {ACTIONS_PER_TURN_LIMIT - st.session_state.actions_taken_this_turn}")
|
| 815 |
for i, opt in enumerate(assignment_data['options']):
|
| 816 |
risk_info = []
|
| 817 |
if opt.get('cost_freedom_risk',0) > 0: risk_info.append(f"자유도↓{opt['cost_freedom_risk']}%")
|
|
|
|
| 821 |
|
| 822 |
if st.button(button_label, key=f"rep_action_{game_state['current_turn']}_{i}_{scenario_key}", use_container_width=True):
|
| 823 |
process_reporter_action(opt, game_state)
|
| 824 |
+
# 취재 활동 후 바로 기사 작성 탭으로 이동할지, 아니면 현재 탭 유지할지 결정 필요
|
| 825 |
+
# 여기서는 현재 탭 유지하고, 모든 활동 끝나면 기사 작성 버튼 활성화
|
| 826 |
st.rerun()
|
| 827 |
else:
|
| 828 |
st.info(get_text_main("status_actions_taken"))
|
| 829 |
+
if assignment_data.get("article_writing_phase") and "🖋️ 기사 작성" in tab_titles:
|
| 830 |
+
st.success("모든 취재 활동을 마쳤습니다. '기사 작성' 탭으로 이동하여 기사를 작성하세요.")
|
| 831 |
+
# 자동으로 탭 이동은 어려우므로 사용자에게 안내
|
| 832 |
+
elif not assignment_data.get("article_writing_phase"):
|
| 833 |
+
st.success("오늘의 모든 취재 활동을 마쳤습니다. 사이드바에서 '다음 날로' 버튼을 눌러 진행하세요.")
|
| 834 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 835 |
|
| 836 |
+
with st.expander("📝 나의 취재 노트 보기", expanded=False):
|
| 837 |
+
display_reporter_notebook(game_state, vocab_level)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 838 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 839 |
|
| 840 |
+
if "🖋️ 기사 작성" in tab_titles:
|
| 841 |
+
with tabs_ui[tab_titles.index("🖋️ 기사 작성")]:
|
| 842 |
+
if st.session_state.game_mode in ['reporter_action', 'article_writing'] and \
|
| 843 |
+
st.session_state.current_assignment_data and \
|
| 844 |
+
st.session_state.current_assignment_data.get("article_writing_phase") and \
|
| 845 |
+
st.session_state.actions_taken_this_turn >= ACTIONS_PER_TURN_LIMIT: # 모든 취재 활동을 마친 후
|
| 846 |
+
|
| 847 |
+
# 기사 작성 중이 아니면, 작성 모드로 변경
|
| 848 |
+
if st.session_state.game_mode != 'article_writing':
|
| 849 |
+
st.session_state.game_mode = 'article_writing'
|
| 850 |
+
# st.rerun() # generate_article_interface를 바로 호출하므로 rerun 불필요
|
| 851 |
+
|
| 852 |
+
assignment_data = st.session_state.current_assignment_data
|
| 853 |
+
submitted_article = generate_article_interface(game_state, vocab_level)
|
| 854 |
+
if submitted_article:
|
| 855 |
+
feedback = evaluate_article_and_get_feedback_openai(submitted_article, game_state, assignment_data)
|
| 856 |
+
st.session_state.desk_feedback_message = feedback
|
| 857 |
+
st.session_state.game_mode = 'reporter_action' # 피드백 표시 및 다음날로 진행 가능하도록
|
| 858 |
+
st.session_state.active_main_tab = "📢 AI 편집장 평가" if "📢 AI 편집장 평가" in tab_titles else "🎤 취재 활동"
|
| 859 |
+
st.rerun()
|
| 860 |
+
elif not (st.session_state.current_assignment_data and st.session_state.current_assignment_data.get("article_writing_phase")):
|
| 861 |
+
st.info("이번 턴에는 기사 작성이 예정되어 있지 않습니다.")
|
| 862 |
+
elif st.session_state.actions_taken_this_turn < ACTIONS_PER_TURN_LIMIT:
|
| 863 |
+
st.info(f"아직 오늘의 취재 활동이 남았습니다. (남은 활동: {ACTIONS_PER_TURN_LIMIT - st.session_state.actions_taken_this_turn}회)")
|
| 864 |
+
|
| 865 |
+
|
| 866 |
+
if "📢 AI 편집장 평가" in tab_titles:
|
| 867 |
+
with tabs_ui[tab_titles.index("📢 AI 편집장 평가")]:
|
| 868 |
+
if st.session_state.desk_feedback_message:
|
| 869 |
+
st.subheader(get_text_main("desk_feedback_title"))
|
| 870 |
+
st.warning(st.session_state.desk_feedback_message)
|
| 871 |
+
st.info("평가를 확인했으면 사이드바에서 '다음 날로' 버튼을 눌러 진행하세요.")
|
| 872 |
+
else:
|
| 873 |
+
st.info("아직 평가된 기사가 없습니다. 기사를 먼저 작성하고 송고해주세요.")
|
| 874 |
+
|
| 875 |
+
st.markdown("---")
|
| 876 |
+
with st.expander(get_text_main("term_event_log") + " (최근 10개)", expanded=False):
|
| 877 |
+
log_text = "\n".join(game_state.get('event_log', [])[-10:][::-1]) # 최근 10개만 표시
|
| 878 |
+
st.text_area("로그 내용", log_text, height=200, disabled=True, key="event_log_area_reporter_main")
|
| 879 |
|
| 880 |
elif st.session_state.game_mode != 'scenario_select' and not st.session_state.game_state:
|
| 881 |
st.warning("게임 상태 정보가 유실되었습니다. 시나리오 선택 화면으로 돌아갑니다.")
|
| 882 |
st.session_state.game_mode = 'scenario_select'
|
| 883 |
+
keys_to_clear = ['current_scenario_key', 'game_state', 'current_assignment_data', 'actions_taken_this_turn', 'desk_feedback_message', 'active_main_tab']
|
| 884 |
for k_to_clear in keys_to_clear:
|
| 885 |
if k_to_clear in st.session_state: del st.session_state[k_to_clear]
|
| 886 |
+
time.sleep(1)
|
| 887 |
st.rerun()
|
| 888 |
|
| 889 |
if __name__ == "__main__":
|