feat(摘要生成): 升级摘要生成模型至Qwen2.5并优化提示工程
Browse files- 将摘要生成模型从Falconsai/text_summarization替换为Qwen/Qwen2.5-0.5B-Instruct
- 重构摘要生成逻辑,使用更灵活的提示模板和生成参数
- 修复app.py中commit消息显示格式问题
- 优化score_titles端点的代码格式
- app.py +13 -10
- utils/summarization.py +38 -13
app.py
CHANGED
|
@@ -66,7 +66,7 @@ def check_hf_token(token):
|
|
| 66 |
# 构建消息内容
|
| 67 |
message = f"你好,{user_info.get('name')},我已启动"
|
| 68 |
if commit_message:
|
| 69 |
-
message += f"\n\
|
| 70 |
|
| 71 |
webhook_headers = {"Content-Type": "application/json"}
|
| 72 |
webhook_data = {
|
|
@@ -515,7 +515,11 @@ async def text_to_speech(
|
|
| 515 |
|
| 516 |
|
| 517 |
@app.post("/text/score")
|
| 518 |
-
async def score_titles(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 519 |
"""
|
| 520 |
为文章标题列表打分,返回标题和对应的分数。
|
| 521 |
|
|
@@ -524,19 +528,18 @@ async def score_titles(request_data: Dict[str, List[str]] = Body(..., descriptio
|
|
| 524 |
try:
|
| 525 |
# 获取标题列表
|
| 526 |
titles = request_data.get("titles", [])
|
| 527 |
-
|
| 528 |
# 调用打分函数
|
| 529 |
scores = score_article_titles(titles)
|
| 530 |
-
|
| 531 |
# 组合标题和分数
|
| 532 |
results = [
|
| 533 |
-
{"title": title, "score": score}
|
| 534 |
-
for title, score in zip(titles, scores)
|
| 535 |
]
|
| 536 |
-
|
| 537 |
# 按分数倒序排序
|
| 538 |
results.sort(key=lambda x: x["score"], reverse=True)
|
| 539 |
-
|
| 540 |
return {"results": results}
|
| 541 |
except Exception as e:
|
| 542 |
logger.error(f"Title scoring error: {e}")
|
|
@@ -547,7 +550,7 @@ async def score_titles(request_data: Dict[str, List[str]] = Body(..., descriptio
|
|
| 547 |
async def generate_summary(
|
| 548 |
text: str = Body(..., description="Text to summarize"),
|
| 549 |
max_length: int = Body(300, description="Maximum length of the summary"),
|
| 550 |
-
min_length: int = Body(50, description="Minimum length of the summary")
|
| 551 |
):
|
| 552 |
"""
|
| 553 |
生成文本摘要。
|
|
@@ -559,7 +562,7 @@ async def generate_summary(
|
|
| 559 |
try:
|
| 560 |
# 调用摘要函数
|
| 561 |
summary = summarize_text(text, max_length=max_length, min_length=min_length)
|
| 562 |
-
|
| 563 |
return {"summary": summary}
|
| 564 |
except Exception as e:
|
| 565 |
logger.error(f"Summarization error: {e}")
|
|
|
|
| 66 |
# 构建消息内容
|
| 67 |
message = f"你好,{user_info.get('name')},我已启动"
|
| 68 |
if commit_message:
|
| 69 |
+
message += f"\n\{commit_message}"
|
| 70 |
|
| 71 |
webhook_headers = {"Content-Type": "application/json"}
|
| 72 |
webhook_data = {
|
|
|
|
| 515 |
|
| 516 |
|
| 517 |
@app.post("/text/score")
|
| 518 |
+
async def score_titles(
|
| 519 |
+
request_data: Dict[str, List[str]] = Body(
|
| 520 |
+
..., description="Object containing titles list"
|
| 521 |
+
)
|
| 522 |
+
):
|
| 523 |
"""
|
| 524 |
为文章标题列表打分,返回标题和对应的分数。
|
| 525 |
|
|
|
|
| 528 |
try:
|
| 529 |
# 获取标题列表
|
| 530 |
titles = request_data.get("titles", [])
|
| 531 |
+
|
| 532 |
# 调用打分函数
|
| 533 |
scores = score_article_titles(titles)
|
| 534 |
+
|
| 535 |
# 组合标题和分数
|
| 536 |
results = [
|
| 537 |
+
{"title": title, "score": score} for title, score in zip(titles, scores)
|
|
|
|
| 538 |
]
|
| 539 |
+
|
| 540 |
# 按分数倒序排序
|
| 541 |
results.sort(key=lambda x: x["score"], reverse=True)
|
| 542 |
+
|
| 543 |
return {"results": results}
|
| 544 |
except Exception as e:
|
| 545 |
logger.error(f"Title scoring error: {e}")
|
|
|
|
| 550 |
async def generate_summary(
|
| 551 |
text: str = Body(..., description="Text to summarize"),
|
| 552 |
max_length: int = Body(300, description="Maximum length of the summary"),
|
| 553 |
+
min_length: int = Body(50, description="Minimum length of the summary"),
|
| 554 |
):
|
| 555 |
"""
|
| 556 |
生成文本摘要。
|
|
|
|
| 562 |
try:
|
| 563 |
# 调用摘要函数
|
| 564 |
summary = summarize_text(text, max_length=max_length, min_length=min_length)
|
| 565 |
+
|
| 566 |
return {"summary": summary}
|
| 567 |
except Exception as e:
|
| 568 |
logger.error(f"Summarization error: {e}")
|
utils/summarization.py
CHANGED
|
@@ -1,22 +1,47 @@
|
|
| 1 |
-
from transformers import
|
|
|
|
| 2 |
|
| 3 |
def summarize_text(text, max_length=300, min_length=50):
|
| 4 |
"""
|
| 5 |
-
使用
|
| 6 |
-
:param text: 输入的文章内容(
|
| 7 |
-
:param max_length: 摘要最大长度(
|
| 8 |
-
:param min_length: 摘要最小长度
|
| 9 |
:return: 生成的摘要
|
| 10 |
"""
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
# 生成摘要
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
)
|
| 21 |
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 2 |
+
import torch
|
| 3 |
|
| 4 |
def summarize_text(text, max_length=300, min_length=50):
|
| 5 |
"""
|
| 6 |
+
使用 Qwen2.5-0.5B-Instruct 生成摘要
|
| 7 |
+
:param text: 输入的文章内容(支持中英文)
|
| 8 |
+
:param max_length: 摘要最大长度(汉字数)
|
| 9 |
+
:param min_length: 摘要最小长度(汉字数)
|
| 10 |
:return: 生成的摘要
|
| 11 |
"""
|
| 12 |
+
model_name = "Qwen/Qwen2.5-0.5B-Instruct"
|
| 13 |
+
|
| 14 |
+
# 加载模型和分词器
|
| 15 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 16 |
+
model_name,
|
| 17 |
+
torch_dtype="auto",
|
| 18 |
+
device_map="auto"
|
| 19 |
+
)
|
| 20 |
+
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
| 21 |
+
|
| 22 |
+
# 构建提示
|
| 23 |
+
prompt = f"请将以下文章总结为{max_length}字以内的摘要:\n\n{text}"
|
| 24 |
+
messages = [{"role": "user", "content": prompt}]
|
| 25 |
+
|
| 26 |
+
# 应用聊天模板
|
| 27 |
+
text = tokenizer.apply_chat_template(
|
| 28 |
+
messages,
|
| 29 |
+
tokenize=False,
|
| 30 |
+
add_generation_prompt=True
|
| 31 |
+
)
|
| 32 |
|
| 33 |
# 生成摘要
|
| 34 |
+
model_inputs = tokenizer([text], return_tensors="pt").to(model.device)
|
| 35 |
+
generated_ids = model.generate(
|
| 36 |
+
**model_inputs,
|
| 37 |
+
max_new_tokens=max_length + 50,
|
| 38 |
+
temperature=0.3
|
| 39 |
)
|
| 40 |
|
| 41 |
+
# 处理生成结果
|
| 42 |
+
generated_ids = [
|
| 43 |
+
output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
|
| 44 |
+
]
|
| 45 |
+
|
| 46 |
+
response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
|
| 47 |
+
return response
|