Yoyo2004 commited on
Commit
e66fa0a
·
verified ·
1 Parent(s): 4c0264a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +28 -33
app.py CHANGED
@@ -17,9 +17,9 @@ custom_css = """
17
  @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&family=Noto+Serif+SC:wght@400;700&family=JetBrains+Mono:wght@400&family=Inter:wght@400;600&display=swap');
18
 
19
  :root {
20
- --primary-color: #4f46e5;
21
- --paper-bg: #fdf6e3;
22
- --glass-bg: rgba(255, 255, 255, 0.95);
23
  }
24
 
25
  body, .gradio-container {
@@ -32,7 +32,6 @@ body, .gradio-container {
32
  .header-box { text-align: center; padding: 25px; background: var(--glass-bg); border-radius: 16px; margin-bottom: 20px; box-shadow: 0 4px 20px rgba(0,0,0,0.08); backdrop-filter: blur(10px); }
33
  .title-text { font-size: 2.2rem; font-weight: 800; font-family: 'Noto Serif SC', serif; color: #1a202c; letter-spacing: -0.5px; }
34
  .subtitle-text { color: #718096; letter-spacing: 1.5px; text-transform: uppercase; font-size: 0.85rem; font-weight: 600; margin-top: 5px; }
35
- .title-badge { display: inline-block; background: #000; color: #fff; font-size: 0.7rem; padding: 2px 6px; border-radius: 4px; vertical-align: super; margin-left: 5px; }
36
 
37
  /* --- 左侧控制面板 --- */
38
  .control-panel {
@@ -43,7 +42,7 @@ body, .gradio-container {
43
  box-shadow: 0 8px 32px rgba(0,0,0,0.05);
44
  }
45
 
46
- /* 输入框与按钮美化 (保留之前的样式,此处略微精简以节省篇幅,功能不变) */
47
  .input-label { font-weight: 700; color: #4a5568; margin-bottom: 8px; display: flex; align-items: center; gap: 8px; }
48
  .input-box textarea { background: #f8fafc !important; border: 2px solid #e2e8f0 !important; border-radius: 12px !important; padding: 12px !important; }
49
  .input-box textarea:focus { border-color: var(--primary-color) !important; background: #fff !important; }
@@ -124,17 +123,13 @@ body, .gradio-container {
124
 
125
  .page-footer { height: 50px; display: flex; align-items: center; justify-content: center; font-size: 0.8rem; color: #999; border-top: 1px dashed rgba(0,0,0,0.05); z-index: 2; }
126
 
127
- /* =========================================
128
- Navigation Buttons (Refined)
129
- ========================================= */
130
-
131
- /* 1. 侧边箭头 (极简风格) */
132
  .arrow-btn {
133
  background: transparent !important;
134
  border: none !important;
135
  box-shadow: none !important;
136
- color: #cbd5e0 !important; /* 默认很浅的灰色 */
137
- font-size: 3rem !important; /* 字体加大 */
138
  font-weight: 200 !important;
139
  padding: 0 !important;
140
  height: 100% !important;
@@ -144,7 +139,7 @@ body, .gradio-container {
144
  justify-content: center !important;
145
  transition: all 0.2s ease !important;
146
  }
147
- /* Hover 时只变色,不加背景,保持清爽 */
148
  .arrow-btn:hover {
149
  color: var(--primary-color) !important;
150
  transform: scale(1.1);
@@ -188,12 +183,11 @@ def paginate_story(story_data, chars_per_page=600):
188
  return [], []
189
 
190
  flat_pages = []
191
- chapter_start_indices = [] # 记录 [Chapter 1起始页index, Chapter 2起始页index, ...]
192
 
193
  current_global_page_index = 0
194
 
195
  for chapter in story_data:
196
- # 记录当前章是从第几页开始的
197
  chapter_start_indices.append(current_global_page_index)
198
 
199
  title = chapter.get("title", "")
@@ -301,14 +295,13 @@ def render_book_page(flat_pages, page_index):
301
  # ==========================================
302
  def bridge_to_backend(premise):
303
  if not premise.strip():
304
- # yield error
305
  yield "⚠️ 请输入故事梗概...", None, None, None, [], [], render_book_page([], 0)
306
  return
307
 
308
  log_buffer = "🚀 初始化前端连接...\n"
309
  initial_html = render_book_page([], 0)
310
 
311
- # Yield 初始状态 [log, outline, plan, personas, pages, chap_indices, html]
312
  yield log_buffer, None, None, None, [], [], initial_html
313
 
314
  try:
@@ -342,15 +335,14 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo", neutral_hue="slate"),
342
  # --- 状态管理 ---
343
  story_pages_state = gr.State([]) # 所有的页面 List[Dict]
344
  chapter_indices_state = gr.State([]) # 每一章起始页的 index List[int]
345
- current_page_state = gr.State(0) # 当前在第几页
346
 
347
  # --- 顶部标题 ---
348
  with gr.Row(elem_classes=["header-box"]):
349
  gr.HTML("""
350
  <div style="display:flex; flex-direction:column; align-items:center;">
351
  <div class="title-wrapper">
352
- <span class="title-text">LongStory AI</span>
353
- <span class="title-badge">PRO</span>
354
  </div>
355
  <div class="subtitle-text">Deep Persona-Driven Recursive Novel Generation</div>
356
  </div>
@@ -369,7 +361,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo", neutral_hue="slate"),
369
  """)
370
  premise_input = gr.Textbox(label="Premise", show_label=False, lines=5, elem_classes=["input-box"], placeholder="输入故事创意...")
371
 
372
- # 2. 灵感卡片
373
  gr.HTML('<div class="examples-container"><div class="examples-label">⚡ 快速开始 (Quick Inspirations)</div></div>')
374
 
375
  example_prompts = [
@@ -395,19 +387,15 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo", neutral_hue="slate"),
395
  with gr.Column(scale=8):
396
  with gr.Tabs(elem_classes=["tabs-container"]):
397
 
398
- # Tab 1: 电子书 (核心修改区域)
399
  with gr.TabItem("📖 正文阅读", id="tab-story"):
400
-
401
- # 1. 阅读区:[左箭] [书] [右箭]
402
- # equal_height=True 保证高度对其
403
- # gap=0 去除列间隙,让箭头紧贴
404
  with gr.Row(elem_classes=["book-reader-row"], equal_height=True):
405
 
406
- # 左侧箭头:缩小宽度 (min_width=40),去掉间距
407
  with gr.Column(scale=1, min_width=40, elem_classes=["arrow-col"]):
408
  btn_prev_page = gr.Button("‹", elem_classes=["arrow-btn"])
409
 
410
- # 书本核心
411
  with gr.Column(scale=15):
412
  story_display = gr.HTML(label="Book View", value=render_book_page([], 0))
413
 
@@ -415,17 +403,24 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo", neutral_hue="slate"),
415
  with gr.Column(scale=1, min_width=40, elem_classes=["arrow-col"]):
416
  btn_next_page = gr.Button("›", elem_classes=["arrow-btn"])
417
 
418
- # 2. 章节导航区:放在书本下方
419
  with gr.Row(elem_classes=["chapter-nav-row"]):
420
  btn_prev_chap = gr.Button("⏮️ 上一章", elem_classes=["chapter-nav-btn"])
421
  # 占位符,把按钮挤到两边或中间
422
  # gr.Spacer()
423
  btn_next_chap = gr.Button("⏭️ 下一章", elem_classes=["chapter-nav-btn"])
424
 
425
- # Tab 2-4
426
- with gr.TabItem("🗺️ 大纲"): outline_output = gr.JSON(label="Structure")
427
- with gr.TabItem("📅 规划"): plan_output = gr.JSON(label="Plan")
428
- with gr.TabItem("👥 人设"): persona_output = gr.HTML(label="Personas")
 
 
 
 
 
 
 
429
 
430
  # ==========================================
431
  # 5. 事件交互
 
17
  @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&family=Noto+Serif+SC:wght@400;700&family=JetBrains+Mono:wght@400&family=Inter:wght@400;600&display=swap');
18
 
19
  :root {
20
+ --primary-color: #4f46e5; /* indigo 靛蓝色 */
21
+ --paper-bg: #fdf6e3; /* 米黄色 */
22
+ --glass-bg: rgba(255, 255, 255, 0.95); /* 半透明白 */
23
  }
24
 
25
  body, .gradio-container {
 
32
  .header-box { text-align: center; padding: 25px; background: var(--glass-bg); border-radius: 16px; margin-bottom: 20px; box-shadow: 0 4px 20px rgba(0,0,0,0.08); backdrop-filter: blur(10px); }
33
  .title-text { font-size: 2.2rem; font-weight: 800; font-family: 'Noto Serif SC', serif; color: #1a202c; letter-spacing: -0.5px; }
34
  .subtitle-text { color: #718096; letter-spacing: 1.5px; text-transform: uppercase; font-size: 0.85rem; font-weight: 600; margin-top: 5px; }
 
35
 
36
  /* --- 左侧控制面板 --- */
37
  .control-panel {
 
42
  box-shadow: 0 8px 32px rgba(0,0,0,0.05);
43
  }
44
 
45
+ /* 输入框与按钮 */
46
  .input-label { font-weight: 700; color: #4a5568; margin-bottom: 8px; display: flex; align-items: center; gap: 8px; }
47
  .input-box textarea { background: #f8fafc !important; border: 2px solid #e2e8f0 !important; border-radius: 12px !important; padding: 12px !important; }
48
  .input-box textarea:focus { border-color: var(--primary-color) !important; background: #fff !important; }
 
123
 
124
  .page-footer { height: 50px; display: flex; align-items: center; justify-content: center; font-size: 0.8rem; color: #999; border-top: 1px dashed rgba(0,0,0,0.05); z-index: 2; }
125
 
126
+ /* 1. 侧边箭头*/
 
 
 
 
127
  .arrow-btn {
128
  background: transparent !important;
129
  border: none !important;
130
  box-shadow: none !important;
131
+ color: #cbd5e0 !important;
132
+ font-size: 3rem !important;
133
  font-weight: 200 !important;
134
  padding: 0 !important;
135
  height: 100% !important;
 
139
  justify-content: center !important;
140
  transition: all 0.2s ease !important;
141
  }
142
+ /* Hover */
143
  .arrow-btn:hover {
144
  color: var(--primary-color) !important;
145
  transform: scale(1.1);
 
183
  return [], []
184
 
185
  flat_pages = []
186
+ chapter_start_indices = [] # 记录 Chapter i 的起始页 index
187
 
188
  current_global_page_index = 0
189
 
190
  for chapter in story_data:
 
191
  chapter_start_indices.append(current_global_page_index)
192
 
193
  title = chapter.get("title", "")
 
295
  # ==========================================
296
  def bridge_to_backend(premise):
297
  if not premise.strip():
 
298
  yield "⚠️ 请输入故事梗概...", None, None, None, [], [], render_book_page([], 0)
299
  return
300
 
301
  log_buffer = "🚀 初始化前端连接...\n"
302
  initial_html = render_book_page([], 0)
303
 
304
+ # 初始状态 [log, outline, plan, personas, pages, chap_indices, html]
305
  yield log_buffer, None, None, None, [], [], initial_html
306
 
307
  try:
 
335
  # --- 状态管理 ---
336
  story_pages_state = gr.State([]) # 所有的页面 List[Dict]
337
  chapter_indices_state = gr.State([]) # 每一章起始页的 index List[int]
338
+ current_page_state = gr.State(0) # 当前页面
339
 
340
  # --- 顶部标题 ---
341
  with gr.Row(elem_classes=["header-box"]):
342
  gr.HTML("""
343
  <div style="display:flex; flex-direction:column; align-items:center;">
344
  <div class="title-wrapper">
345
+ <span class="title-text">LongStory Agent</span>
 
346
  </div>
347
  <div class="subtitle-text">Deep Persona-Driven Recursive Novel Generation</div>
348
  </div>
 
361
  """)
362
  premise_input = gr.Textbox(label="Premise", show_label=False, lines=5, elem_classes=["input-box"], placeholder="输入故事创意...")
363
 
364
+ # Examples
365
  gr.HTML('<div class="examples-container"><div class="examples-label">⚡ 快速开始 (Quick Inspirations)</div></div>')
366
 
367
  example_prompts = [
 
387
  with gr.Column(scale=8):
388
  with gr.Tabs(elem_classes=["tabs-container"]):
389
 
390
+ # Tab 1: 正文
391
  with gr.TabItem("📖 正文阅读", id="tab-story"):
 
 
 
 
392
  with gr.Row(elem_classes=["book-reader-row"], equal_height=True):
393
 
394
+ # 左侧箭头
395
  with gr.Column(scale=1, min_width=40, elem_classes=["arrow-col"]):
396
  btn_prev_page = gr.Button("‹", elem_classes=["arrow-btn"])
397
 
398
+ # 核心内容
399
  with gr.Column(scale=15):
400
  story_display = gr.HTML(label="Book View", value=render_book_page([], 0))
401
 
 
403
  with gr.Column(scale=1, min_width=40, elem_classes=["arrow-col"]):
404
  btn_next_page = gr.Button("›", elem_classes=["arrow-btn"])
405
 
406
+ # 2. 章节导航
407
  with gr.Row(elem_classes=["chapter-nav-row"]):
408
  btn_prev_chap = gr.Button("⏮️ 上一章", elem_classes=["chapter-nav-btn"])
409
  # 占位符,把按钮挤到两边或中间
410
  # gr.Spacer()
411
  btn_next_chap = gr.Button("⏭️ 下一章", elem_classes=["chapter-nav-btn"])
412
 
413
+ # Tab 2: 大纲
414
+ with gr.TabItem("🗺️ 故事大纲", id="tab-outline"):
415
+ outline_output = gr.JSON(label="Structure Data")
416
+
417
+ # Tab 3: 规划
418
+ with gr.TabItem("📅 剧情规划", id="tab-planning"):
419
+ plan_output = gr.JSON(label="Event Planning")
420
+
421
+ # Tab 4: 人设
422
+ with gr.TabItem("👥 人物档案", id="tab-persona"):
423
+ persona_output = gr.HTML(label="Character Cards")
424
 
425
  # ==========================================
426
  # 5. 事件交互