openfree commited on
Commit
2aef962
ยท
verified ยท
1 Parent(s): 4fb7e13

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +25 -28
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # cycles_chat_app.py
2
  import os, math, numpy as np, matplotlib.pyplot as plt, gradio as gr
3
  import openai
4
 
@@ -13,30 +13,29 @@ openai.api_key = os.environ["OPENAI_API_KEY"]
13
  # 1. Wave-style chart utilities
14
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
15
  CYCLES = {
16
- "Tech Cycle (50 yr)": 50,
17
- "Finance Cycle (80 yr)": 80,
18
- "Hegemony Cycle (250 yr)": 250,
 
19
  }
20
- COLOR_MAP = {50: "#ff3333", 80: "#ffcc00", 250: "#66ccff"}
21
- AMPLITUDE_MAP = {50: 1.0, 80: 1.6, 250: 4.0}
22
- CENTER = 2025 # alignment reference
23
 
24
  def _half_sine(xs, period, amp):
25
- """positive half-sine wave centred on CENTER"""
26
  phase = np.mod(xs - CENTER, period)
27
  y = amp * np.sin(np.pi * phase / period)
28
  y[y < 0] = 0
29
  return y
30
 
31
  def build_wave_chart_and_summary(start: int, end: int):
32
- xs = np.linspace(start, end, (end - start) * 4) # 4 pts per year
33
  fig, ax = plt.subplots(figsize=(14, 6))
34
- fig.subplots_adjust(top=0.9) # spare margin for labels
35
 
36
  summaries, align_years, all_year_labels = [], None, set()
37
 
38
- # draw half-sine โ€œtowersโ€
39
- for period in sorted(CYCLES.values()):
40
  col, amp = COLOR_MAP[period], AMPLITUDE_MAP[period]
41
  for frac in np.linspace(amp / 30, amp, 30):
42
  ax.plot(xs, _half_sine(xs, period, frac),
@@ -45,29 +44,28 @@ def build_wave_chart_and_summary(start: int, end: int):
45
  years = [CENTER + n * period for n in range(
46
  math.ceil((start - CENTER) / period),
47
  math.floor((end - CENTER) / period) + 1)]
48
- summaries.append(f"{period}-yr cycle peaks: {years}")
 
49
  align_years = set(years) if align_years is None else align_years & set(years)
50
  all_year_labels.update(years)
51
 
52
- # baseline small year labels (duplicates removed)
53
  for y in sorted(all_year_labels):
54
  if start <= y <= end:
55
  ax.text(y, -0.1, str(y), ha="center", va="top",
56
  fontsize=6, color="white", rotation=90)
57
 
58
- # styling
59
  ax.set_facecolor("black"); fig.patch.set_facecolor("black")
60
  ax.set_xlim(start, end)
61
  ax.set_ylim(-0.2, max(AMPLITUDE_MAP.values()) + 0.2)
62
  ax.set_xlabel("Year", color="white")
63
  ax.set_ylabel("Relative Amplitude", color="white")
64
- # (no chart title per request)
65
  ax.tick_params(colors="white")
66
  for spine in ax.spines.values():
67
  spine.set_color("white")
68
  ax.grid(axis="y", color="white", ls="--", lw=.3, alpha=.3)
69
 
70
- # alignment marker (CENTER) and 250-yr arrow
71
  ax.axvline(CENTER, color="white", ls="--", lw=1, alpha=.6)
72
  arrow_y = AMPLITUDE_MAP[250] * 1.05
73
  ax.annotate("", xy=(CENTER - 125, arrow_y), xytext=(CENTER + 125, arrow_y),
@@ -115,14 +113,17 @@ custom_css = """
115
  """
116
 
117
  with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
118
- # Service title and descriptions
119
- gr.Markdown("## ๐Ÿš€ **TriPulse Navigator**")
 
 
120
  gr.Markdown(
121
- """
122
- **Tech Cycle (50 yr)** โ€“ Innovation booms and busts about every half-century.
123
- **Finance Cycle (80 yr)** โ€“ Credit expansions and crises roughly once per lifetime.
124
- **Hegemony Cycle (250 yr)** โ€“ Rise and decline of world-leading powers across centuries.
125
- """
 
126
  )
127
 
128
  chart_summary_state = gr.State(value="No chart yet.")
@@ -130,18 +131,15 @@ with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
130
  with gr.Tabs():
131
  # โ–ธ Tab 1 โ€” Timeline Chart
132
  with gr.TabItem("Timeline Chart"):
133
- # initial chart
134
  fig0, summ0 = build_wave_chart_and_summary(1500, 2500)
135
  plot_out = gr.Plot(value=fig0, elem_id="wave_plot")
136
 
137
- # inputs and zoom buttons
138
  with gr.Row():
139
  start_year = gr.Number(label="Start Year", value=1500)
140
  end_year = gr.Number(label="End Year", value=2500)
141
  zoom_in_btn = gr.Button("๐Ÿ” Zoom In")
142
  zoom_out_btn = gr.Button("๐Ÿ”Ž Zoom Out")
143
 
144
- # refresh on manual year change
145
  def refresh_chart(s, e):
146
  fig, summ = build_wave_chart_and_summary(int(s), int(e))
147
  return fig, summ
@@ -151,7 +149,6 @@ with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
151
  end_year.change(refresh_chart, [start_year, end_year],
152
  [plot_out, chart_summary_state])
153
 
154
- # zoom helpers
155
  def zoom(s, e, factor):
156
  mid = (s + e) / 2
157
  span = (e - s) * factor / 2
 
1
+ # cycles_chat_app.py โ€” CycleNavigator (4-Cycle ๋ฒ„์ „)
2
  import os, math, numpy as np, matplotlib.pyplot as plt, gradio as gr
3
  import openai
4
 
 
13
  # 1. Wave-style chart utilities
14
  # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
15
  CYCLES = {
16
+ "K-Wave (50 yr)": 50, # ์žฅ๊ธฐ ์ฝ˜๋“œ๋ผํ‹ฐ์—ํ”„ ํŒŒ๋™
17
+ "Business Cycle (Juglar 9 yr)": 9, # ์„ค๋น„ํˆฌ์žยท์‹ ์šฉ ๊ฒฝ๊ธฐ์ˆœํ™˜
18
+ "Finance Cycle (80 yr)": 80, # ์‹ ์šฉยท๊ธˆ์œต ์žฅ์ฃผ๊ธฐ
19
+ "Hegemony Cycle (250 yr)": 250, # ํŒจ๊ถŒ ํฅ๋ง
20
  }
21
+ COLOR_MAP = {50: "#ff3333", 9: "#66ff66", 80: "#ffcc00", 250: "#66ccff"}
22
+ AMPLITUDE_MAP = {50: 1.0, 9: 0.6, 80: 1.6, 250: 4.0}
23
+ CENTER = 2025 # alignment reference
24
 
25
  def _half_sine(xs, period, amp):
 
26
  phase = np.mod(xs - CENTER, period)
27
  y = amp * np.sin(np.pi * phase / period)
28
  y[y < 0] = 0
29
  return y
30
 
31
  def build_wave_chart_and_summary(start: int, end: int):
32
+ xs = np.linspace(start, end, (end - start) * 4)
33
  fig, ax = plt.subplots(figsize=(14, 6))
34
+ fig.subplots_adjust(top=0.9)
35
 
36
  summaries, align_years, all_year_labels = [], None, set()
37
 
38
+ for period in sorted(set(CYCLES.values())): # iterate periods in ascending order
 
39
  col, amp = COLOR_MAP[period], AMPLITUDE_MAP[period]
40
  for frac in np.linspace(amp / 30, amp, 30):
41
  ax.plot(xs, _half_sine(xs, period, frac),
 
44
  years = [CENTER + n * period for n in range(
45
  math.ceil((start - CENTER) / period),
46
  math.floor((end - CENTER) / period) + 1)]
47
+ name = [k for k, v in CYCLES.items() if v == period][0]
48
+ summaries.append(f"{name} peaks: {years}")
49
  align_years = set(years) if align_years is None else align_years & set(years)
50
  all_year_labels.update(years)
51
 
52
+ # small baseline labels
53
  for y in sorted(all_year_labels):
54
  if start <= y <= end:
55
  ax.text(y, -0.1, str(y), ha="center", va="top",
56
  fontsize=6, color="white", rotation=90)
57
 
 
58
  ax.set_facecolor("black"); fig.patch.set_facecolor("black")
59
  ax.set_xlim(start, end)
60
  ax.set_ylim(-0.2, max(AMPLITUDE_MAP.values()) + 0.2)
61
  ax.set_xlabel("Year", color="white")
62
  ax.set_ylabel("Relative Amplitude", color="white")
 
63
  ax.tick_params(colors="white")
64
  for spine in ax.spines.values():
65
  spine.set_color("white")
66
  ax.grid(axis="y", color="white", ls="--", lw=.3, alpha=.3)
67
 
68
+ # alignment marker
69
  ax.axvline(CENTER, color="white", ls="--", lw=1, alpha=.6)
70
  arrow_y = AMPLITUDE_MAP[250] * 1.05
71
  ax.annotate("", xy=(CENTER - 125, arrow_y), xytext=(CENTER + 125, arrow_y),
 
113
  """
114
 
115
  with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
116
+ # โ”€โ”€ ์„œ๋น„์Šค ์ œ๋ชฉ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
117
+ gr.Markdown("## ๐Ÿ”ญ **CycleNavigator**")
118
+
119
+ # โ”€โ”€ ๋„ค ์‚ฌ์ดํด ๊ฐ„๋‹จ ์„ค๋ช… (์ž‘์€ ๊ธ€์”จ) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
120
  gr.Markdown(
121
+ "<sub>"
122
+ "**K-Wave (50 yr)** โ€“ Long-wave industrial & technological shifts.โ€ƒ"
123
+ "**Business (Juglar 9 yr)** โ€“ Credit-driven capital investment booms & busts.โ€ƒ"
124
+ "**Finance (80 yr)** โ€“ Extended credit cycles culminating in crises.โ€ƒ"
125
+ "**Hegemony (250 yr)** โ€“ Rise & decline of world powers."
126
+ "</sub>"
127
  )
128
 
129
  chart_summary_state = gr.State(value="No chart yet.")
 
131
  with gr.Tabs():
132
  # โ–ธ Tab 1 โ€” Timeline Chart
133
  with gr.TabItem("Timeline Chart"):
 
134
  fig0, summ0 = build_wave_chart_and_summary(1500, 2500)
135
  plot_out = gr.Plot(value=fig0, elem_id="wave_plot")
136
 
 
137
  with gr.Row():
138
  start_year = gr.Number(label="Start Year", value=1500)
139
  end_year = gr.Number(label="End Year", value=2500)
140
  zoom_in_btn = gr.Button("๐Ÿ” Zoom In")
141
  zoom_out_btn = gr.Button("๐Ÿ”Ž Zoom Out")
142
 
 
143
  def refresh_chart(s, e):
144
  fig, summ = build_wave_chart_and_summary(int(s), int(e))
145
  return fig, summ
 
149
  end_year.change(refresh_chart, [start_year, end_year],
150
  [plot_out, chart_summary_state])
151
 
 
152
  def zoom(s, e, factor):
153
  mid = (s + e) / 2
154
  span = (e - s) * factor / 2