# cycles_chat_app.py import os, math, numpy as np, matplotlib.pyplot as plt, gradio as gr import openai ### 0.โ€†OpenAI ํ‚ค ์„ค์ • --------------------------------------------------------- if "OPENAI_API_KEY" not in os.environ: os.environ["OPENAI_API_KEY"] = input("๐Ÿ”‘ Enter your OpenAI API key: ").strip() openai.api_key = os.environ["OPENAI_API_KEY"] ### 1.โ€†์ฃผ๊ธฐ ์ฐจํŠธ ํ•จ์ˆ˜ ---------------------------------------------------------- CYCLES = { "ํ…Œํฌ ์‚ฌ์ดํด (50 ๋…„)": 50, "์žฌ๋ฌด ์‚ฌ์ดํด (80 ๋…„)": 80, "ํŒจ๊ถŒ ์‚ฌ์ดํด (250 ๋…„)": 250, } CENTER = 2025 # ๊ธฐ์ค€์  def make_cycle_points(period, start, end): n_min = math.floor((start - CENTER) / period) n_max = math.ceil((end - CENTER) / period) return [CENTER + n * period for n in range(n_min, n_max + 1)] def plot_cycles(range_start, range_end): plt.figure(figsize=(10, 4)) y_positions = np.arange(len(CYCLES)) align_years = None for i, (name, period) in enumerate(CYCLES.items()): years = make_cycle_points(period, range_start, range_end) plt.scatter(years, [y_positions[i]] * len(years), label=name, s=60) for y in years: plt.text(y, y_positions[i] + 0.1, str(y), ha="center", fontsize=7) align_years = set(years) if align_years is None else align_years & set(years) if align_years: for y in sorted(align_years): plt.axvline(y, color="black", linestyle="--") plt.text(y, y_positions[-1] + 0.35, f"๊ณต๋™ ์ •๋ ฌ โ†’ {y}", ha="center", va="bottom", fontsize=9, fontweight="bold") plt.yticks(y_positions, list(CYCLES.keys())) plt.ylim(-0.5, len(CYCLES) - 0.2) plt.grid(axis="x", alpha=0.3) plt.xlabel("Year") plt.title("์ฃผ๊ธฐ๋ณ„ ๋ฐœ์ƒ ์—ฐ๋„์™€ ๊ณต๋™ ์ •๋ ฌ ์ง€์ ") plt.tight_layout() return plt.gcf() ### 2.โ€†GPT ์ฑ„ํŒ… ํ•จ์ˆ˜ ----------------------------------------------------------- SYSTEM_PROMPT = ( "๋‹น์‹ ์€ ์นœ์ ˆํ•˜๊ณ  ๋ถ„์„์ ์ธ ์–ด์‹œ์Šคํ„ดํŠธ์ž…๋‹ˆ๋‹ค. " "์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์— ํ•œ๊ตญ์–ด๋กœ ๊ฐ„๊ฒฐํ•˜๊ณ  ์ •ํ™•ํ•˜๊ฒŒ ๋‹ต๋ณ€ํ•˜์„ธ์š”." ) def chat_with_gpt(history, user_message): messages = [{"role": "system", "content": SYSTEM_PROMPT}] for u, a in history: messages.append({"role": "user", "content": u}) messages.append({"role": "assistant", "content": a}) messages.append({"role": "user", "content": user_message}) response = openai.chat.completions.create( model="gpt-3.5-turbo", messages=messages, max_tokens=600, temperature=0.7, ) assistant_reply = response.choices[0].message.content.strip() return assistant_reply ### 3.โ€†Gradio ์ธํ„ฐํŽ˜์ด์Šค ------------------------------------------------------- with gr.Blocks(theme=gr.themes.Soft()) as demo: gr.Markdown("## ๐Ÿ“Š 3-Cycle Timeline & ๐Ÿ’ฌ GPT Chat") with gr.Tabs(): ## Tab 1โ€Šโ€”โ€ŠChart with gr.TabItem("๐Ÿ—“๏ธ ์ฃผ๊ธฐ ์ฐจํŠธ"): start_year = gr.Number(label="๋ฒ”์œ„ ์‹œ์ž‘(Year)", value=1500) end_year = gr.Number(label="๋ฒ”์œ„ ๋(Year)", value=2500) plot_out = gr.Plot() def update_chart(s, e): return plot_cycles(int(s), int(e)) start_year.change(update_chart, [start_year, end_year], plot_out) end_year.change(update_chart, [start_year, end_year], plot_out) plot_out.render() # ์ดˆ๊ธฐ ํ‘œ์‹œ ## Tab 2โ€Šโ€”โ€ŠGPT Chat with gr.TabItem("๐Ÿ’ฌ GPT ์ฑ„ํŒ…"): chatbot = gr.Chatbot(label="GPT Assistant") user_in = gr.Textbox(placeholder="๋ฉ”์‹œ์ง€๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”...", lines=3) send_btn = gr.Button("Send", variant="primary") def respond(chat_history, user_msg): assistant_msg = chat_with_gpt(chat_history, user_msg) chat_history.append((user_msg, assistant_msg)) return chat_history, gr.Textbox(value="", interactive=True) send_btn.click( respond, inputs=[chatbot, user_in], outputs=[chatbot, user_in], ) user_in.submit( respond, inputs=[chatbot, user_in], outputs=[chatbot, user_in], ) if __name__ == "__main__": demo.launch()