Yoyo2004 commited on
Commit
132536a
·
verified ·
1 Parent(s): 18a81b7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +163 -0
app.py CHANGED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ PRIVATE_SPACE_ID = "Yoyo2004/Longstory-backend"
3
+
4
+ HF_TOKEN = os.environ.get("HF_TOKEN")
5
+
6
+ custom_css = """
7
+ @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;700&family=Noto+Serif+SC:wght@400;700&display=swap');
8
+
9
+ body { font-family: 'Noto Sans SC', sans-serif !important; }
10
+
11
+ .container { max-width: 1200px; margin: 0 auto; }
12
+
13
+ /* 标题样式 */
14
+ .header-title {
15
+ font-family: 'Noto Serif SC', serif;
16
+ font-weight: 700;
17
+ font-size: 2.5rem;
18
+ color: #2d3436;
19
+ margin-bottom: 0.5rem;
20
+ }
21
+ .header-subtitle {
22
+ color: #636e72;
23
+ font-size: 1.1rem;
24
+ margin-bottom: 2rem;
25
+ }
26
+
27
+ /* 输入框美化 */
28
+ textarea {
29
+ border: 2px solid #dfe6e9 !important;
30
+ border-radius: 12px !important;
31
+ transition: all 0.3s ease;
32
+ font-size: 16px !important;
33
+ }
34
+ textarea:focus {
35
+ border-color: #74b9ff !important;
36
+ box-shadow: 0 0 10px rgba(116, 185, 255, 0.2) !important;
37
+ }
38
+
39
+ /* 按钮美化 */
40
+ #generate-btn {
41
+ background: linear-gradient(135deg, #6c5ce7, #a29bfe) !important;
42
+ border: none;
43
+ color: white;
44
+ font-weight: bold;
45
+ font-size: 18px;
46
+ padding: 12px 24px;
47
+ border-radius: 30px;
48
+ box-shadow: 0 4px 15px rgba(108, 92, 231, 0.4);
49
+ transition: transform 0.2s;
50
+ }
51
+ #generate-btn:hover {
52
+ transform: translateY(-2px);
53
+ box-shadow: 0 6px 20px rgba(108, 92, 231, 0.6);
54
+ }
55
+
56
+ /* 输出区域卡片化 */
57
+ .output-card {
58
+ background: white;
59
+ border: 1px solid #f1f2f6;
60
+ border-radius: 16px;
61
+ padding: 20px;
62
+ box-shadow: 0 4px 20px rgba(0,0,0,0.03);
63
+ }
64
+
65
+ /* 小说正文阅读模式 */
66
+ .story-content {
67
+ font-family: 'Noto Serif SC', serif;
68
+ line-height: 1.8;
69
+ font-size: 18px;
70
+ color: #2d3436;
71
+ background-color: #fafafa;
72
+ padding: 40px;
73
+ border-radius: 8px;
74
+ border-left: 5px solid #6c5ce7;
75
+ }
76
+ """
77
+
78
+ # ==========================================
79
+ # 客户端连接逻辑
80
+ # ==========================================
81
+ def bridge_to_backend(premise):
82
+ """
83
+ 连接到私有 Space 并流式传输结果
84
+ """
85
+ if not HF_TOKEN:
86
+ yield "⚠️ Error: HF_TOKEN not found in Secrets.", None, None, None, None
87
+ return
88
+
89
+ try:
90
+ # 连接私有 Space
91
+ client = Client(PRIVATE_SPACE_ID, hf_token=HF_TOKEN)
92
+
93
+ # 提交任务 (使用 generate_novel 函数)
94
+ # 注意:这里的 fn_index 或 api_name 取决于后端 Gradio 的自动命名,
95
+ # 通常如果后端只有一个函数,可以直接用 submit
96
+ job = client.submit(premise, api_name="/generate_novel")
97
+
98
+ # 迭代获取生成器产生的数据
99
+ for result in job:
100
+ # result 是一个元组,对应后端的 outputs
101
+ # (log, outline, plan, persona, story)
102
+ yield result
103
+
104
+ except Exception as e:
105
+ yield f"❌ Connection Error: {str(e)}", None, None, None, None
106
+
107
+
108
+ # ==========================================
109
+ # 构建前端界面
110
+ # ==========================================
111
+ with gr.Blocks(theme=gr.themes.Soft(), css=custom_css, title="LongStory AI") as demo:
112
+
113
+ with gr.Row(elem_classes=["container"]):
114
+ with gr.Column(scale=1):
115
+ gr.Markdown("# 🖊️ LongStory AI", elem_classes=["header-title"])
116
+ gr.Markdown("智能长篇小说辅助创作系统 · Deep Layout & Persona Driven", elem_classes=["header-subtitle"])
117
+
118
+ with gr.Row(elem_classes=["container"]):
119
+ # 左侧控制栏
120
+ with gr.Column(scale=1, min_width=300):
121
+ with gr.Group():
122
+ premise_input = gr.Textbox(
123
+ label="💡 小说核心梗概 (Premise)",
124
+ placeholder="例如:构造一个长篇青春校园小说, 事件覆盖从刚刚入学报道到高考之前...",
125
+ lines=6
126
+ )
127
+ submit_btn = gr.Button("✨ 开始创作 (Generate)", elem_id="generate-btn")
128
+
129
+ # 日志区
130
+ with gr.Accordion("构建日志 (System Logs)", open=True):
131
+ log_output = gr.Textbox(label="实时进度", lines=10, interactive=False, show_label=False)
132
+
133
+ # 右侧展示栏
134
+ with gr.Column(scale=2, min_width=500):
135
+ with gr.Tabs():
136
+ # Tab 1: 最终正文
137
+ with gr.TabItem("📖 正文草稿 (Draft)"):
138
+ story_output = gr.Markdown(
139
+ value="等待生成...",
140
+ elem_classes=["story-content"]
141
+ )
142
+
143
+ # Tab 2: 大纲
144
+ with gr.TabItem("🗺️ 故事大纲 (Outline)"):
145
+ outline_output = gr.JSON(label="事件流 (Event Flow)")
146
+
147
+ # Tab 3: 细纲
148
+ with gr.TabItem("📅 详细规划 (Planning)"):
149
+ plan_output = gr.JSON(label="子事件 (Sub-events)")
150
+
151
+ # Tab 4: 人物
152
+ with gr.TabItem("👥 人物设定 (Personas)"):
153
+ persona_output = gr.JSON(label="人物弧光 (Character Arc)")
154
+
155
+ # 事件绑定
156
+ submit_btn.click(
157
+ bridge_to_backend,
158
+ inputs=[premise_input],
159
+ outputs=[log_output, outline_output, plan_output, persona_output, story_output]
160
+ )
161
+
162
+ if __name__ == "__main__":
163
+ demo.queue().launch()