Spaces:
Running
Running
File size: 7,296 Bytes
cd5d77c d403426 cd5d77c d403426 184d70e d403426 cd5d77c d403426 cd5d77c 184d70e cd5d77c 184d70e d403426 184d70e d403426 184d70e 312f42b 184d70e d403426 cd5d77c 184d70e d403426 184d70e cd5d77c d403426 184d70e d403426 cd5d77c 184d70e d403426 cd5d77c 184d70e d403426 f6b850a 184d70e d403426 cd5d77c 184d70e d403426 f6b850a 184d70e d403426 184d70e d403426 cd5d77c 184d70e d403426 184d70e cd5d77c 184d70e 312f42b cd5d77c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# cycles_chat_app.py
import os, math, numpy as np, matplotlib.pyplot as plt, gradio as gr
import openai
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# 0. OpenAI key
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
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. Wave-style chart utilities (โ NEW)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
CYCLES = {
"Tech Cycle (50 yr)": 50,
"Finance Cycle (80 yr)": 80,
"Hegemony Cycle (250 yr)": 250,
}
COLOR_MAP = {50: "#ff3333", 80: "#ffcc00", 250: "#66ccff"} # red / yellow / blue
AMPLITUDE_MAP = {50: 1.0, 80: 1.6, 250: 4.0} # taller tower for longer cycle
CENTER = 2025 # alignment reference
def _half_sine(xs, period, amp):
"""positive half-sine wave, aligned so peak at CENTER, 0 elsewhere"""
phase = np.mod(xs - CENTER, period)
y = amp * np.sin(np.pi * phase / period)
y[y < 0] = 0
return y
def build_wave_chart_and_summary(start: int, end: int):
"""return (matplotlib figure, text summary)"""
xs = np.linspace(start, end, (end - start) * 4) # 4 pts/yr โ smooth
fig, ax = plt.subplots(figsize=(10, 3))
summaries, align_years = [], None
# draw many stacked half-sine lines for each cycle โ โtowerโ ๋๋
for period in sorted(CYCLES.values()):
col, amp = COLOR_MAP[period], AMPLITUDE_MAP[period]
for frac in np.linspace(amp / 30, amp, 30): # 30 concentric lines
ax.plot(xs, _half_sine(xs, period, frac),
color=col, alpha=0.85, lw=0.6)
years = [CENTER + n * period for n in range(
math.ceil((start - CENTER) / period),
math.floor((end - CENTER) / period) + 1)]
summaries.append(f"{period}-yr cycle peaks: {years}")
align_years = set(years) if align_years is None else align_years & set(years)
# cosmeticโโโblack bg & white grid
ax.set_facecolor("black"); fig.patch.set_facecolor("black")
ax.set_xlim(start, end); ax.set_ylim(0, max(AMPLITUDE_MAP.values()) + .2)
ax.set_xlabel("Year", color="white"); ax.set_ylabel("Relative Amplitude", color="white")
ax.set_title("Technology ยท Finance ยท Hegemony Cycles", color="white", pad=20)
ax.tick_params(colors="white"); [s.set_color("white") for s in ax.spines.values()]
ax.grid(color="white", ls="--", lw=.3, alpha=.3)
# vertical dashed line at alignment year + 250-yr span arrow
ax.axvline(CENTER, color="white", ls="--", lw=1, alpha=.6)
arrow_y = AMPLITUDE_MAP[250] * 1.05
ax.annotate("", xy=(CENTER - 125, arrow_y), xytext=(CENTER + 125, arrow_y),
arrowprops=dict(arrowstyle="<|-|>", color="white", lw=1.2))
ax.text(CENTER, arrow_y + .15, "250 yr", color="white",
ha="center", va="bottom", fontsize=10, fontweight="bold")
summary = (f"Range {start}-{end}\n" +
"\n".join(summaries) +
f"\nAlignment year inside range: {', '.join(map(str, sorted(align_years))) if align_years else 'None'}")
return fig, summary
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# 2. GPT chat (์ฐจํธ ์์ฝ โ system ํ๋กฌํํธ์ ์๋ ์ฝ์
)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
BASE_PROMPT = (
"๋น์ ์ ๊ฐ๊ฒฐํ๊ณ ์ ํํ ํ๊ตญ์ด ์ด์์คํดํธ์
๋๋ค. "
"์ฌ์ฉ์์ ์ง๋ฌธ์ ๋ตํ ๋, ์ ๊ณต๋ [Chart summary] ๋ด์ฉ์ ๋ฐ๋์ ๋ฐ์ํ์ธ์."
)
def chat_with_gpt(history, user_msg, chart_summary):
msgs = [{"role": "system", "content": BASE_PROMPT}]
if chart_summary != "No chart yet.": # ์ฐจํธ๊ฐ ์ด๋ฏธ ๊ทธ๋ ค์ก๋ค๋ฉด
msgs.append({"role": "system", "content": f"[Chart summary]\n{chart_summary}"})
for u, a in history:
msgs += [{"role": "user", "content": u}, {"role": "assistant", "content": a}]
msgs.append({"role": "user", "content": user_msg})
answer = openai.chat.completions.create(
model="gpt-3.5-turbo", messages=msgs,
max_tokens=600, temperature=0.7).choices[0].message.content.strip()
return answer
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# 3. Gradio UI
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("## ๐ Wave-style Cycle Timeline & ๐ฌ GPT Chat")
chart_summary_state = gr.State(value="No chart yet.")
with gr.Tabs():
# โธ Tab 1 โ Chart
with gr.TabItem("Timeline Chart"):
start_year = gr.Number(label="Start Year", value=1500)
end_year = gr.Number(label="End Year", value=2500)
fig0, summ0 = build_wave_chart_and_summary(1500, 2500)
plot_out = gr.Plot(value=fig0)
def refresh_chart(s, e):
fig, summ = build_wave_chart_and_summary(int(s), int(e))
return fig, summ
start_year.change(refresh_chart, [start_year, end_year],
[plot_out, chart_summary_state])
end_year.change(refresh_chart, [start_year, end_year],
[plot_out, chart_summary_state])
# โธ Tab 2 โ GPT Chat
with gr.TabItem("GPT Chat"):
chatbot = gr.Chatbot(label="Assistant")
user_in = gr.Textbox(lines=3, placeholder="๋ฉ์์ง๋ฅผ ์
๋ ฅํ์ธ์โฆ")
send_btn = gr.Button("Send", variant="primary")
def respond(chat_hist, user_msg, summary):
reply = chat_with_gpt(chat_hist, user_msg, summary)
chat_hist.append((user_msg, reply))
return chat_hist, gr.Textbox(value="", interactive=True)
send_btn.click(respond, [chatbot, user_in, chart_summary_state],
[chatbot, user_in])
user_in.submit(respond, [chatbot, user_in, chart_summary_state],
[chatbot, user_in])
if __name__ == "__main__":
demo.launch()
|