Yoyo2004 commited on
Commit
0e89edd
·
verified ·
1 Parent(s): 9cbc975

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -17
app.py CHANGED
@@ -3,12 +3,15 @@ import time
3
  import gradio as gr
4
  from gradio_client import Client
5
 
 
 
 
6
  # 请确保这里的 Space ID 是你部署后端的真实 ID (格式: Username/SpaceName)
7
  PRIVATE_SPACE_ID = "Yoyo2004/Longstory-backend"
8
  HF_TOKEN = os.environ.get("HF_TOKEN")
9
 
10
  # ==========================================
11
- # 1. CSS 样式设计 (电子书风格)
12
  # ==========================================
13
  custom_css = """
14
  @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');
@@ -134,7 +137,7 @@ body, .gradio-container {
134
  box-shadow: none !important;
135
  }
136
 
137
- /* --- 右侧电子书 (保持原样微调) --- */
138
  .book-container {
139
  background-color: var(--paper-bg);
140
  padding: 60px 80px;
@@ -150,14 +153,32 @@ body, .gradio-container {
150
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 6px;
151
  background: linear-gradient(to right, rgba(0,0,0,0.1), transparent);
152
  }
153
- .chapter-title { font-size: 2.4em; font-weight: 700; color: #8b4513; margin-bottom: 10px; }
154
- .nav-btn { background: white !important; border: 1px solid #e2e8f0 !important; color: #4a5568 !important; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  .nav-btn:hover { background: #f7fafc !important; border-color: #cbd5e0 !important; }
156
 
157
  /* 移动端适配 */
158
  @media (max-width: 768px) {
159
  .book-container { padding: 30px 20px; min-height: 500px; }
160
  .control-panel { padding: 15px !important; }
 
161
  }
162
  """
163
 
@@ -175,7 +196,7 @@ def render_book_page(story_data, page_index):
175
  <div class='book-container' style='display:flex;align-items:center;justify-content:center;color:#999'>
176
  <div style='text-align:center;'>
177
  <h3>📖 等待故事生成...</h3>
178
- <p>Wait for content generation...</p>
179
  </div>
180
  </div>
181
  """
@@ -192,7 +213,6 @@ def render_book_page(story_data, page_index):
192
  content = chapter.get("content", "")
193
 
194
  # 4. 格式化正文 (将换行符 \n 转为 HTML 段落 <p>)
195
- # 过滤掉空行,给每段加上 <p>
196
  paragraphs = [p.strip() for p in content.split('\n') if p.strip()]
197
  content_html = "".join([f"<p>{p}</p>" for p in paragraphs])
198
 
@@ -218,7 +238,7 @@ def render_book_page(story_data, page_index):
218
  # ==========================================
219
  def bridge_to_backend(premise):
220
  if not premise.strip():
221
- yield "⚠️ 请输入故事梗概...", None, None, None, [], None
222
  return
223
 
224
  # 初始化日志
@@ -240,10 +260,9 @@ def bridge_to_backend(premise):
240
  start_time = time.time()
241
  for result in job:
242
  elapsed = int(time.time() - start_time)
243
- current_log = log_buffer + f"\n[+{elapsed}s] 后端处理中... (Processing)"
244
-
245
- # 解析后端返回的 Tuple (对应后端 app.py 的 return)
246
  # [0]Log, [1]Outline, [2]Plan, [3]Personas(HTML), [4]Story(List[Dict])
 
247
  backend_log = result[0]
248
  outline = result[1]
249
  plan = result[2]
@@ -254,19 +273,15 @@ def bridge_to_backend(premise):
254
  book_html = render_book_page(story_list, 0)
255
 
256
  # 更新所有组件
257
- # story_state 存原始数据,story_display 存渲染后的 HTML
258
  yield backend_log, outline, plan, personas_html, story_list, book_html
259
 
260
  except Exception as e:
261
  error_msg = f"❌ 前端连接错误: {str(e)}"
262
  yield error_msg, None, None, None, [], render_book_page([], 0)
263
 
264
-
265
  # ==========================================
266
  # 4. 前端 UI 布局 (Blocks)
267
  # ==========================================
268
- # ... (前面的 imports 和 rendering 函数保持不变)
269
-
270
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo", neutral_hue="slate"), css=custom_css, title="LongStory Agent") as demo:
271
 
272
  # --- 状态管理 ---
@@ -310,7 +325,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo", neutral_hue="slate"),
310
  # 2. 灵感卡片 (Examples)
311
  gr.HTML('<div class="examples-container"><div class="examples-label">⚡ Quick Inspirations</div></div>')
312
 
313
- # 定义 Examples,注意这里只放 text,不放 label,CSS 会把它变成卡片
314
  example_prompts = [
315
  ["高中时互相看不顺眼的死对头,十年后在公司并购案谈判桌上重逢,一个是冷血收购方,一个是绝境求生的CEO。"],
316
  ["天生'废灵根'的宗门弃徒,在被逐出师门当晚,意外捡到一个能听见万物心声的黑色小鼎。"],
@@ -374,15 +389,25 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo", neutral_hue="slate"),
374
  persona_output = gr.HTML(label="Character Cards")
375
 
376
  # ==========================================
377
- # 事件交互 (保持不变)
378
  # ==========================================
 
 
379
  submit_btn.click(
380
  fn=bridge_to_backend,
381
  inputs=[premise_input],
382
- outputs=[log_output, outline_output, plan_output, persona_output, story_state, story_display],
 
 
 
 
 
 
 
383
  concurrency_limit=1
384
  )
385
 
 
386
  def go_prev(story_data, current_page):
387
  new_page = max(0, current_page - 1)
388
  return new_page, render_book_page(story_data, new_page)
@@ -392,6 +417,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo", neutral_hue="slate"),
392
  new_page = min(len(story_data) - 1, current_page + 1)
393
  return new_page, render_book_page(story_data, new_page)
394
 
 
395
  prev_btn.click(fn=go_prev, inputs=[story_state, page_state], outputs=[page_state, story_display])
396
  next_btn.click(fn=go_next, inputs=[story_state, page_state], outputs=[page_state, story_display])
397
 
 
3
  import gradio as gr
4
  from gradio_client import Client
5
 
6
+ # ==========================================
7
+ # 配置区域
8
+ # ==========================================
9
  # 请确保这里的 Space ID 是你部署后端的真实 ID (格式: Username/SpaceName)
10
  PRIVATE_SPACE_ID = "Yoyo2004/Longstory-backend"
11
  HF_TOKEN = os.environ.get("HF_TOKEN")
12
 
13
  # ==========================================
14
+ # 1. CSS 样式设计 (科技与人文融合风格)
15
  # ==========================================
16
  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');
 
137
  box-shadow: none !important;
138
  }
139
 
140
+ /* --- 右侧电子书 --- */
141
  .book-container {
142
  background-color: var(--paper-bg);
143
  padding: 60px 80px;
 
153
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 6px;
154
  background: linear-gradient(to right, rgba(0,0,0,0.1), transparent);
155
  }
156
+ .chapter-header {
157
+ text-align: center; margin-bottom: 40px; padding-bottom: 20px;
158
+ border-bottom: 2px solid rgba(139, 69, 19, 0.2);
159
+ }
160
+ .chapter-subtitle { font-size: 0.9em; color: #8b4513; opacity: 0.6; font-style: italic; margin-bottom: 5px; }
161
+ .chapter-title {
162
+ font-size: 2.4em;
163
+ font-weight: 700;
164
+ color: #8b4513;
165
+ text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
166
+ }
167
+ .chapter-content { font-size: 1.2em; text-align: justify; }
168
+ .chapter-content p {
169
+ margin-bottom: 1.5em;
170
+ text-indent: 2em;
171
+ }
172
+ .page-footer { text-align: center; margin-top: 60px; font-size: 0.9em; color: #a0aec0; font-family: sans-serif; }
173
+ .nav-row { margin-top: 20px; display: flex; justify-content: center; gap: 20px; }
174
+ .nav-btn { background: white !important; border: 1px solid #e2e8f0 !important; color: #4a5568 !important; width: 150px !important; }
175
  .nav-btn:hover { background: #f7fafc !important; border-color: #cbd5e0 !important; }
176
 
177
  /* 移动端适配 */
178
  @media (max-width: 768px) {
179
  .book-container { padding: 30px 20px; min-height: 500px; }
180
  .control-panel { padding: 15px !important; }
181
+ .chapter-title { font-size: 1.8em; }
182
  }
183
  """
184
 
 
196
  <div class='book-container' style='display:flex;align-items:center;justify-content:center;color:#999'>
197
  <div style='text-align:center;'>
198
  <h3>📖 等待故事生成...</h3>
199
+ <p>Waiting for generation...</p>
200
  </div>
201
  </div>
202
  """
 
213
  content = chapter.get("content", "")
214
 
215
  # 4. 格式化正文 (将换行符 \n 转为 HTML 段落 <p>)
 
216
  paragraphs = [p.strip() for p in content.split('\n') if p.strip()]
217
  content_html = "".join([f"<p>{p}</p>" for p in paragraphs])
218
 
 
238
  # ==========================================
239
  def bridge_to_backend(premise):
240
  if not premise.strip():
241
+ yield "⚠️ 请输入故事梗概...", None, None, None, [], render_book_page([], 0)
242
  return
243
 
244
  # 初始化日志
 
260
  start_time = time.time()
261
  for result in job:
262
  elapsed = int(time.time() - start_time)
263
+ # 这里的 result 是一个 tuple,对应后端的返回值
 
 
264
  # [0]Log, [1]Outline, [2]Plan, [3]Personas(HTML), [4]Story(List[Dict])
265
+
266
  backend_log = result[0]
267
  outline = result[1]
268
  plan = result[2]
 
273
  book_html = render_book_page(story_list, 0)
274
 
275
  # 更新所有组件
 
276
  yield backend_log, outline, plan, personas_html, story_list, book_html
277
 
278
  except Exception as e:
279
  error_msg = f"❌ 前端连接错误: {str(e)}"
280
  yield error_msg, None, None, None, [], render_book_page([], 0)
281
 
 
282
  # ==========================================
283
  # 4. 前端 UI 布局 (Blocks)
284
  # ==========================================
 
 
285
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo", neutral_hue="slate"), css=custom_css, title="LongStory Agent") as demo:
286
 
287
  # --- 状态管理 ---
 
325
  # 2. 灵感卡片 (Examples)
326
  gr.HTML('<div class="examples-container"><div class="examples-label">⚡ Quick Inspirations</div></div>')
327
 
328
+ # 定义 Examples
329
  example_prompts = [
330
  ["高中时互相看不顺眼的死对头,十年后在公司并购案谈判桌上重逢,一个是冷血收购方,一个是绝境求生的CEO。"],
331
  ["天生'废灵根'的宗门弃徒,在被逐出师门当晚,意外捡到一个能听见万物心声的黑色小鼎。"],
 
389
  persona_output = gr.HTML(label="Character Cards")
390
 
391
  # ==========================================
392
+ # 5. 事件交互逻辑
393
  # ==========================================
394
+
395
+ # A. 提交生成
396
  submit_btn.click(
397
  fn=bridge_to_backend,
398
  inputs=[premise_input],
399
+ outputs=[
400
+ log_output, # [0] 日志
401
+ outline_output, # [1] 大纲
402
+ plan_output, # [2] 规划
403
+ persona_output, # [3] 人设HTML
404
+ story_state, # [4] 故事状态 (List)
405
+ story_display # [5] 故事显示 (HTML)
406
+ ],
407
  concurrency_limit=1
408
  )
409
 
410
+ # B. 翻页逻辑
411
  def go_prev(story_data, current_page):
412
  new_page = max(0, current_page - 1)
413
  return new_page, render_book_page(story_data, new_page)
 
417
  new_page = min(len(story_data) - 1, current_page + 1)
418
  return new_page, render_book_page(story_data, new_page)
419
 
420
+ # C. 绑定翻页
421
  prev_btn.click(fn=go_prev, inputs=[story_state, page_state], outputs=[page_state, story_display])
422
  next_btn.click(fn=go_next, inputs=[story_state, page_state], outputs=[page_state, story_display])
423