Enoch commited on
Commit
0780b55
·
1 Parent(s): fbe33c3

更新了应用程序代码

Browse files
Files changed (1) hide show
  1. app.py +238 -161
app.py CHANGED
@@ -1,9 +1,9 @@
1
  import os
2
- from openai import OpenAI
3
  import gradio as gr
4
- from dotenv import load_dotenv
5
  import tempfile
6
  import atexit
 
 
7
 
8
  # 加载环境变量
9
  load_dotenv()
@@ -17,26 +17,28 @@ client = OpenAI(
17
  def call_openai_api(prompt, temperature=0.7):
18
  """调用OpenAI API生成内容"""
19
  try:
 
20
  chat_completion = client.chat.completions.create(
21
  messages=[
22
  {
23
  "role": "system",
24
- "content": "你是一个专业的专利代理人,擅长撰写专利文档。",
25
  },
26
  {
27
  "role": "user",
28
  "content": prompt,
29
  },
30
  ],
31
- model="qwen2.5-1.5b-instruct",
32
  temperature=temperature,
33
  max_tokens=3000,
34
  n=1
35
  )
 
36
  return chat_completion.choices[0].message.content.strip()
37
  except Exception as e:
38
- print(f"API调用出错:{str(e)}")
39
- return f"生成失败:{str(e)}"
40
 
41
  # 定义每个部分的Agent Prompt模板
42
  BACKGROUND_PROMPT = """
@@ -73,9 +75,9 @@ SHORTCOMING_PROMPT = """
73
 
74
  PROBLEM_PROMPT = """
75
  请根据以下信息编写第三部分内容:
76
- 三、本发明决的技术问题是:
77
  要求:
78
- - 对第二分所列出的缺点和不足,描述本发明试图解决的具体技术问题。
79
  - 内容应与本发明拟解决的问题相呼应。
80
 
81
  已有输出:
@@ -90,7 +92,7 @@ PROBLEM_PROMPT = """
90
  """
91
 
92
  SOLUTION_PROMPT = """
93
- 请根以下信息撰写第四部分内容:
94
  四、本发明技术方案的详细阐述:
95
  要求:
96
  - 详细描述本发明的技术方案,包括各功能模块/步骤的技术实现方式、结构图(可文字描述)和原理说明。
@@ -126,9 +128,9 @@ KEYPOINT_PROMPT = """
126
  ADVANTAGE_PROMPT = """
127
  请根据以下信息撰写第六部分内容:
128
  六、与第二条所述最好的现有技术相比,本发明的优:
129
- 求:
130
  - 简要介绍本发明相对现有技术的有益效果和优势。
131
- - 结技术方案来描述,做到有理有据。
132
 
133
  已有输出:
134
  第二部分(现有技术的缺点):
@@ -156,129 +158,157 @@ ALTERNATIVE_PROMPT = """
156
  用户提供的需求:
157
  {user_input}
158
  """
159
- def generate_patent_document(
160
- bg_input,
161
- shortcoming_input,
162
- problem_input,
163
- solution_input,
164
- keypoint_input,
165
- advantage_input,
166
- alternative_input,
167
- progress=gr.Progress()
168
- ):
169
- progress(0, desc="正在生成背景技术部分...")
170
- bg_prompt = BACKGROUND_PROMPT.format(user_input=bg_input)
171
- background_content = call_openai_api(bg_prompt)
172
-
173
- progress(0.15, desc="正在生成现有技术缺点部分...")
174
- short_prompt = SHORTCOMING_PROMPT.format(
175
- previous_content=background_content,
176
- user_input=shortcoming_input
177
- )
178
- shortcoming_content = call_openai_api(short_prompt)
179
 
180
- progress(0.3, desc="正在生成技术问题部分...")
181
- problem_prompt_full = PROBLEM_PROMPT.format(
182
- background_content=background_content,
183
- shortcoming_content=shortcoming_content,
184
- user_input=problem_input
185
- )
186
- problem_content = call_openai_api(problem_prompt_full)
187
-
188
- progress(0.45, desc="正在生成技术方案部分...")
189
- solution_prompt_full = SOLUTION_PROMPT.format(
190
- background_content=background_content,
191
- shortcoming_content=shortcoming_content,
192
- problem_content=problem_content,
193
- user_input=solution_input
194
- )
195
- solution_content = call_openai_api(solution_prompt_full)
196
 
197
- progress(0.6, desc="正在生成关键点部分...")
198
- keypoint_prompt_full = KEYPOINT_PROMPT.format(
199
- solution_content=solution_content,
200
- user_input=keypoint_input
201
- )
202
- keypoint_content = call_openai_api(keypoint_prompt_full)
203
-
204
- progress(0.75, desc="正在生成优点部分...")
205
- advantage_prompt_full = ADVANTAGE_PROMPT.format(
206
- shortcoming_content=shortcoming_content,
207
- problem_content=problem_content,
208
- solution_content=solution_content,
209
- user_input=advantage_input
210
- )
211
- advantage_content = call_openai_api(advantage_prompt_full)
212
-
213
- progress(0.9, desc="正在生成替代方案部分...")
214
- alternative_prompt_full = ALTERNATIVE_PROMPT.format(
215
- solution_content=solution_content,
216
- user_input=alternative_input
217
- )
218
- alternative_content = call_openai_api(alternative_prompt_full)
219
-
220
- progress(1.0, desc="生成完成!")
221
 
222
- final_document = (
223
- f"{background_content}\n\n"
224
- f"{shortcoming_content}\n\n"
225
- f"{problem_content}\n\n"
226
- f"{solution_content}\n\n"
227
- f"{keypoint_content}\n\n"
228
- f"{advantage_content}\n\n"
229
- f"{alternative_content}"
230
- )
231
- return final_document
232
-
233
- def gradio_interface(
234
- bg_input,
235
- shortcoming_input,
236
- problem_input,
237
- solution_input,
238
- keypoint_input,
239
- advantage_input,
240
- alternative_input,
241
- progress=gr.Progress()
242
- ):
243
- progress_output = gr.Textbox() # 用于显示进度的临时输出
244
- doc = generate_patent_document(
245
- bg_input,
246
- shortcoming_input,
247
- problem_input,
248
- solution_input,
249
- keypoint_input,
250
- advantage_input,
251
- alternative_input,
252
- progress=progress
253
- )
254
- return progress_output, doc
255
-
256
- # ... existing code ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
 
258
  def generate_filename(text):
259
  """根据专利交底书内容生成合适的文件名"""
260
  try:
261
- prompt = """
262
  请根据以下专利交底书内容,生成一个简短的文件名(不超过50个字符)。
263
  文件名应该能反映出发明的核心内容和技术领域。
264
  只需要返回文件名,不需要其他解释。
265
 
266
  专利交底书内容:
267
- {text}
268
- """.format(text=text[:1000]) # 只取前1000个字符用于生成文件名
269
-
270
  filename = call_openai_api(prompt).strip()
271
  # 确保文件名合法
272
  filename = "".join(c for c in filename if c not in r'\/:*?"<>|')
273
  return filename + ".txt"
274
  except Exception as e:
275
  print(f"生成文件名失败:{str(e)}")
276
- return "专利交底书.txt" # 默认文件名
277
 
278
  def download_text(text):
279
  """将文本保存为临时文件并返回文件路径"""
280
  filename = generate_filename(text)
281
- # 创建临时文件,使用生成的文件名
282
  temp_dir = tempfile.gettempdir()
283
  file_path = os.path.join(temp_dir, filename)
284
 
@@ -286,16 +316,14 @@ def download_text(text):
286
  f.write(text)
287
  return file_path
288
 
289
- # ... existing code ...
290
  def clear_all():
291
  """清空所有输入和输出"""
292
  try:
293
- # 清空下载文件组件前,先将其值设为None
294
- return [""] * 9 + [None] # 7个输入框 + 2个输出框 + 1个下载文件框(None)
295
  except Exception as e:
296
  print(f"清空过程中出错:{str(e)}")
297
- return [""] * 9 + [None]
298
-
299
  def cleanup_temp_files():
300
  """清理临时文件"""
301
  temp_dir = tempfile.gettempdir()
@@ -309,61 +337,110 @@ def cleanup_temp_files():
309
  print(f"删除临时文件失败:{str(e)}")
310
  continue
311
 
 
312
 
313
- with gr.Blocks() as demo:
314
- gr.Markdown("## 专利交底书生成系统 (基于大模型的Agent生成)")
315
-
316
- with gr.Column():
317
- bg = gr.Textbox(label="一、背景技术与现有技术方案输入")
318
- sh = gr.Textbox(label="二、现有技术缺点输入")
319
- pr = gr.Textbox(label="三、本发明解决的技术问题输入")
320
- so = gr.Textbox(label="四、本发明技术方案输入")
321
- kp = gr.Textbox(label="五、关键点输入")
322
- adv = gr.Textbox(label="六、本发明优点输入")
323
- alt = gr.Textbox(label="七、替代方案输入")
324
-
325
- with gr.Row():
326
- generate_button = gr.Button("开始生成", variant="primary")
327
- clear_button = gr.Button("清空所有", variant="secondary")
328
-
329
- progress_output = gr.Textbox(label="生成进度", lines=2)
330
- final_output = gr.Markdown(label="生成的专利交底书文本")
331
-
332
- with gr.Row():
333
- download_button = gr.Button("创建下载文件", variant="secondary")
334
- download_file = gr.File(label="点击下载文件", visible=True)
335
-
336
- # 设置下载按钮
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
  download_button.click(
338
  fn=download_text,
339
  inputs=[final_output],
340
  outputs=[download_file]
341
  )
342
-
343
- # 设置生成按钮
344
  generate_button.click(
345
- fn=gradio_interface,
346
  inputs=[bg, sh, pr, so, kp, adv, alt],
347
- outputs=[progress_output, final_output]
 
 
 
 
 
348
  )
349
-
350
- # 设置清空按钮
351
  clear_button.click(
352
  fn=clear_all,
353
  inputs=[],
354
- outputs=[bg, sh, pr, so, kp, adv, alt, progress_output, final_output, download_file]
355
  )
356
 
357
- # 在程序退出时清理临时文件
358
- def cleanup_temp_files():
359
- temp_dir = tempfile.gettempdir()
360
- for file in os.listdir(temp_dir):
361
- if file.endswith(".txt"):
362
- try:
363
- os.remove(os.path.join(temp_dir, file))
364
- except:
365
- pass
366
-
367
- atexit.register(cleanup_temp_files)
368
-
369
- demo.launch()
 
1
  import os
 
2
  import gradio as gr
 
3
  import tempfile
4
  import atexit
5
+ from dotenv import load_dotenv
6
+ from openai import OpenAI
7
 
8
  # 加载环境变量
9
  load_dotenv()
 
17
  def call_openai_api(prompt, temperature=0.7):
18
  """调用OpenAI API生成内容"""
19
  try:
20
+ print(f"开始调用API,prompt长度: {len(prompt)}") # 添加日志
21
  chat_completion = client.chat.completions.create(
22
  messages=[
23
  {
24
  "role": "system",
25
+ "content": "你是一个专业的专利代理人,正在完成一份专利文档的撰写。",
26
  },
27
  {
28
  "role": "user",
29
  "content": prompt,
30
  },
31
  ],
32
+ model="qwen-max-latest",
33
  temperature=temperature,
34
  max_tokens=3000,
35
  n=1
36
  )
37
+ print("API调用成功") # 添加日志
38
  return chat_completion.choices[0].message.content.strip()
39
  except Exception as e:
40
+ print(f"API调用详细错误:{type(e).__name__}: {str(e)}") # 增强错误信息
41
+ return f"生成失败:{type(e).__name__}: {str(e)}"
42
 
43
  # 定义每个部分的Agent Prompt模板
44
  BACKGROUND_PROMPT = """
 
75
 
76
  PROBLEM_PROMPT = """
77
  请根据以下信息编写第三部分内容:
78
+ 三、本发明解决的技术问题是:
79
  要求:
80
+ - 对第二部分所列出的缺点和不足,描述本发明试图解决的具体技术问题。
81
  - 内容应与本发明拟解决的问题相呼应。
82
 
83
  已有输出:
 
92
  """
93
 
94
  SOLUTION_PROMPT = """
95
+ 请根据以下信息撰写第四部分内容:
96
  四、本发明技术方案的详细阐述:
97
  要求:
98
  - 详细描述本发明的技术方案,包括各功能模块/步骤的技术实现方式、结构图(可文字描述)和原理说明。
 
128
  ADVANTAGE_PROMPT = """
129
  请根据以下信息撰写第六部分内容:
130
  六、与第二条所述最好的现有技术相比,本发明的优:
131
+ 要求:
132
  - 简要介绍本发明相对现有技术的有益效果和优势。
133
+ - 结合技术方案来描述,做到有理有据。
134
 
135
  已有输出:
136
  第二部分(现有技术的缺点):
 
158
  用户提供的需求:
159
  {user_input}
160
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
163
+ # 验证函数示例
164
+ def validate_content(content, expected_keywords=None):
165
+ """
166
+ 自动化验证内容是否合理。
167
+ - 检查内容是否包含预期的关键词。
168
+ - 确保内容长度合理。
169
+ - 其他自定义验证规则。
170
+ """
171
+ if expected_keywords:
172
+ for keyword in expected_keywords:
173
+ if keyword.lower() not in content.lower():
174
+ raise ValidationError(f"内容缺少关键词: {keyword}")
175
+ if len(content) < 100:
176
+ raise ValidationError("内容过短,可能不够详实。")
177
+ # 添加更多验证规则
178
+ return True
179
+
180
+ class ValidationError(Exception):
181
+ """自定义验证错误"""
182
+ def __init__(self, message):
183
+ self.message = message
184
+ super().__init__(self.message)
 
 
185
 
186
+ def get_retry_prompt(self):
187
+ return f"请根据反馈修改内容: {self.message}"
188
+
189
+ def generate_with_hitl(prompt_template, user_input, previous_contents=None, max_retries=3):
190
+ """通用的生成函数,包含HITL流程"""
191
+ print(f"开始生成内容,用户输入长度: {len(user_input)}") # 添加日志
192
+ retry_prompt = ""
193
+ retries = 0
194
+ success = False
195
+ final_content = ""
196
+
197
+ while retries < max_retries and not success:
198
+ try:
199
+ # 生成内容
200
+ if previous_contents:
201
+ prompt = prompt_template.format(
202
+ user_input=user_input,
203
+ **previous_contents
204
+ )
205
+ else:
206
+ prompt = prompt_template.format(user_input=user_input)
207
+
208
+ print(f"第{retries + 1}次尝试生成") # 添加日志
209
+ content = call_openai_api(prompt)
210
+
211
+ # 检查返回内容是否包含错误信息
212
+ if content.startswith("生成失败"):
213
+ print(f"生成返回错误: {content}") # 添加日志
214
+ raise Exception(content)
215
+
216
+ # 自动化验证
217
+ validate_content(content, expected_keywords=["技术", "方案"])
218
+ success = True
219
+ final_content = content
220
+ print("内容生成成功") # 添加日志
221
+
222
+ except ValidationError as e:
223
+ print(f"验证失败: {str(e)}") # 添加日志
224
+ retry_prompt = e.get_retry_prompt()
225
+ retries += 1
226
+ except Exception as e:
227
+ print(f"生成过程中发生错误: {type(e).__name__}: {str(e)}") # 增强错误信息
228
+ retries += 1
229
+
230
+ if not success:
231
+ final_content = "生成失败,请检查输入或稍后重试。"
232
+
233
+ return final_content
234
+ def generate_patent_document(bg_input, sh_input, pr_input, so_input, kp_input, adv_input, alt_input, progress=gr.Progress()):
235
+ """
236
+ 生成完整的专利交底书,包含HITL流程的每个模块。
237
+ """
238
+ final_document = ""
239
+ try:
240
+ # 生成第一部分:背景技术
241
+ progress(0.14, desc="生成背景技术部分...")
242
+ background_content = generate_with_hitl(BACKGROUND_PROMPT, bg_input)
243
+ final_document += f"{background_content}\n\n"
244
+
245
+ # 生成第二部分:现有技术缺点
246
+ progress(0.28, desc="生成现有技术缺点部分...")
247
+ shortcoming_content = generate_with_hitl(SHORTCOMING_PROMPT, sh_input, {"background_content": background_content})
248
+ final_document += f"{shortcoming_content}\n\n"
249
+
250
+ # 生成第三部分:技术问题
251
+ progress(0.42, desc="生成技术问题部分...")
252
+ problem_content = generate_with_hitl(PROBLEM_PROMPT, pr_input, {
253
+ "background_content": background_content,
254
+ "shortcoming_content": shortcoming_content
255
+ })
256
+ final_document += f"{problem_content}\n\n"
257
+
258
+ # 生成第四部分:技术方案
259
+ progress(0.56, desc="生成技术方案部分...")
260
+ solution_content = generate_with_hitl(SOLUTION_PROMPT, so_input, {
261
+ "background_content": background_content,
262
+ "shortcoming_content": shortcoming_content,
263
+ "problem_content": problem_content
264
+ })
265
+ final_document += f"{solution_content}\n\n"
266
+
267
+ # 生成第五部分:关键点
268
+ progress(0.70, desc="生成关键点部分...")
269
+ keypoint_content = generate_with_hitl(KEYPOINT_PROMPT, kp_input, {"solution_content": solution_content})
270
+ final_document += f"{keypoint_content}\n\n"
271
+
272
+ # 生成第六部分:优点
273
+ progress(0.84, desc="生成优点部分...")
274
+ advantage_content = generate_with_hitl(ADVANTAGE_PROMPT, adv_input, {
275
+ "shortcoming_content": shortcoming_content,
276
+ "problem_content": problem_content,
277
+ "solution_content": solution_content
278
+ })
279
+ final_document += f"{advantage_content}\n\n"
280
+
281
+ # 生成第七部分:替代方案
282
+ progress(1.0, desc="生成替代方案部分...")
283
+ alternative_content = generate_with_hitl(ALTERNATIVE_PROMPT, alt_input, {"solution_content": solution_content})
284
+ final_document += f"{alternative_content}"
285
+
286
+ return final_document
287
+ except Exception as e:
288
+ return f"生成过程中发生错误:{str(e)}"
289
 
290
  def generate_filename(text):
291
  """根据专利交底书内容生成合适的文件名"""
292
  try:
293
+ prompt = f"""
294
  请根据以下专利交底书内容,生成一个简短的文件名(不超过50个字符)。
295
  文件名应该能反映出发明的核心内容和技术领域。
296
  只需要返回文件名,不需要其他解释。
297
 
298
  专利交底书内容:
299
+ {text[:1000]}
300
+ """
 
301
  filename = call_openai_api(prompt).strip()
302
  # 确保文件名合法
303
  filename = "".join(c for c in filename if c not in r'\/:*?"<>|')
304
  return filename + ".txt"
305
  except Exception as e:
306
  print(f"生成文件名失败:{str(e)}")
307
+ return "专利交底书.txt"
308
 
309
  def download_text(text):
310
  """将文本保存为临时文件并返回文件路径"""
311
  filename = generate_filename(text)
 
312
  temp_dir = tempfile.gettempdir()
313
  file_path = os.path.join(temp_dir, filename)
314
 
 
316
  f.write(text)
317
  return file_path
318
 
 
319
  def clear_all():
320
  """清空所有输入和输出"""
321
  try:
322
+ return [""] * 7 + ["", "", None] # 7个输入框 + 2个输出框 + 1个下载文件框(None)
 
323
  except Exception as e:
324
  print(f"清空过程中出错:{str(e)}")
325
+ return [""] * 7 + ["", "", None]
326
+
327
  def cleanup_temp_files():
328
  """清理临时文件"""
329
  temp_dir = tempfile.gettempdir()
 
337
  print(f"删除临时文件失败:{str(e)}")
338
  continue
339
 
340
+ atexit.register(cleanup_temp_files)
341
 
342
+ custom_css = """
343
+ .gradio-container {
344
+ background-color: #f0f2f6;
345
+ padding: 20px;
346
+ }
347
+ .gradio-container h2 {
348
+ color: #333333;
349
+ }
350
+ .gr-button-primary {
351
+ background-color: #4B6CB7;
352
+ color: white;
353
+ }
354
+ .gr-button-secondary {
355
+ background-color: #A5A5A5;
356
+ color: white;
357
+ }
358
+ .gr-textbox, .gr-markdown {
359
+ border-radius: 5px;
360
+ padding: 10px;
361
+ border: 1px solid #ccc;
362
+ }
363
+ """
364
+
365
+ with gr.Blocks(theme=gr.themes.Soft(
366
+ primary_hue="blue",
367
+ secondary_hue="indigo",
368
+ neutral_hue="slate"
369
+ )) as demo:
370
+ gr.Markdown("## 📝 专利交底书生成系统\n**基于先进的语言模型技术,为您自动生成高质量的专利文档。**\n\n请按顺序填写下列所有部分的信息,然后点击\"🚀 开始生成\"按钮。")
371
+
372
+ with gr.Accordion("📥 输入信息", open=True):
373
+ bg = gr.Textbox(
374
+ label="一、背景技术与现有技术方案输入",
375
+ placeholder="请输入背景技术和现有技术方案...",
376
+ lines=4
377
+ )
378
+ sh = gr.Textbox(
379
+ label="二、现有技术缺点输入",
380
+ placeholder="请输入现有技术的缺点...",
381
+ lines=4
382
+ )
383
+ pr = gr.Textbox(
384
+ label="三、本发明解决的技术问题输入",
385
+ placeholder="请输入本发明解决的技术问题...",
386
+ lines=4
387
+ )
388
+ so = gr.Textbox(
389
+ label="四、本发明技术方案输入",
390
+ placeholder="请输入本发明的技术方案...",
391
+ lines=4
392
+ )
393
+ kp = gr.Textbox(
394
+ label="五、关键点输入",
395
+ placeholder="请输入本发明的关键点...",
396
+ lines=3
397
+ )
398
+ adv = gr.Textbox(
399
+ label="六、本发明优点输入",
400
+ placeholder="请输入本发明的优点...",
401
+ lines=3
402
+ )
403
+ alt = gr.Textbox(
404
+ label="七、替代方案输入",
405
+ placeholder="请输入替代方案...",
406
+ lines=3
407
+ )
408
+
409
+ with gr.Row():
410
+ generate_button = gr.Button("🚀 开始生成", variant="primary")
411
+ clear_button = gr.Button("🧹 清空所有", variant="secondary")
412
+
413
+ progress_bar = gr.Progress()
414
+ status_box = gr.Textbox(label="生成状态", interactive=False) # 添加标签和设置为只读
415
+
416
+ final_output = gr.Markdown(label="生成的专利交底书文本")
417
+ with gr.Row():
418
+ download_button = gr.Button("⬇️ 创建下载文件", variant="secondary")
419
+ download_file = gr.File(label="点击下载文件", visible=False)
420
+
421
+ # 设置下载按钮行为
422
  download_button.click(
423
  fn=download_text,
424
  inputs=[final_output],
425
  outputs=[download_file]
426
  )
427
+
428
+ # 设置生成按钮行为
429
  generate_button.click(
430
+ fn=generate_patent_document,
431
  inputs=[bg, sh, pr, so, kp, adv, alt],
432
+ outputs=[final_output]
433
+ ).then(
434
+ # 修改 lambda 函数,添加输入参数
435
+ fn=lambda x: gr.update(visible=True),
436
+ inputs=[final_output],
437
+ outputs=[download_file]
438
  )
439
+
 
440
  clear_button.click(
441
  fn=clear_all,
442
  inputs=[],
443
+ outputs=[bg, sh, pr, so, kp, adv, alt, final_output, download_file]
444
  )
445
 
446
+ demo.launch()