diff --git a/app.py b/app.py index 5318af9..b2416cb 100644 --- a/app.py +++ b/app.py @@ -195,21 +195,47 @@ class OutlineRequest(BaseModel): prompt: Optional[str] = None -def length_convert(length: Optional[str]) -> str: +def length_convert(length: Optional[str]): + """将篇幅解析为 {target, max}:target 为建议目标字数,max 为硬上限。""" if length == "短": - return "1000字" + return {"target": 700, "max": 1000} if length == "中": - return "1000-2000字" + return {"target": 2500, "max": 3000} if length == "长": - return "2000-5000字" + return {"target": 4500, "max": 5000} + # 兜底:从自定义篇幅字符串里解析出最大字数 + if length: + nums = re.findall(r"\d+", length) + if nums: + max_chars = int(nums[-1]) + return {"target": int(max_chars * 0.8), "max": max_chars} + return None + + +def length_display(length: Optional[str]) -> str: + """模板 {length} 占位符用的字符串。""" + info = length_convert(length) + if info: + return f"{info['target']}字左右(不超过{info['max']}字)" return length or "" +def build_length_instruction(length: Optional[str]) -> str: + """把 target/max 写进提示词:建议目标 + 硬上限 + 优先级。""" + info = length_convert(length) + if not info: + return "" + return ( + f"全文建议写到{info['target']}字左右,绝对不得超过{info['max']}字;" + "字数为硬性要求,不得注水或重复凑字数。" + ) + + def build_write_prompt(request: WriteRequest) -> str: prompt = request.prompt or "" - length = length_convert(request.length) template = request.template or "" - content = f"请生成一篇字数在{length}的{template},字数严格遵守该规则,并且不能超过给定字数范围。{prompt}" + length_instruction = build_length_instruction(request.length) + content = f"请撰写一篇{template}。{length_instruction}{prompt}" prompt_template = TEMPLATE_DICT.get(template) if not prompt_template: raise HTTPException(status_code=400, detail=f"不支持的写作模板: {template}") @@ -221,7 +247,7 @@ def build_write_prompt(request: WriteRequest) -> str: return content+prompt_template.format( role=request.role or "", title=title, - length=length_convert(request.length), + length=length_display(request.length), requirement=request.requirement or "", references=request.references or "", outline=request.outline or "", @@ -267,7 +293,7 @@ def build_outline_prompt(request: OutlineRequest) -> str: role=request.role or "", template=template, title=title, - length=length_convert(request.length), + length=length_display(request.length), requirement=request.requirement or "", references=request.references or "", ) diff --git a/requirements.txt b/requirements.txt index 1b7a7e6..820171f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,41 +4,103 @@ langchain langchain-core langchain-openai +langchain-protocol langgraph langgraph-checkpoint langgraph-checkpoint-postgres +langgraph-prebuilt +langgraph-sdk +langsmith # HTTP客户端 httpx +httpcore +httptools +h11 requests +requests-toolbelt +urllib3 # 数据处理 pydantic -typing-extensions +pydantic_core +typing_extensions +typing-inspection numpy +scipy # 其他工具 python-dotenv +python-dateutil +pytz +PyYAML +types-PyYAML +tenacity +tqdm +click +json_repair +jsonpatch +jsonpointer +orjson +ormsgpack +xxhash +zstandard +uuid_utils +packaging +regex +six +anyio +sniffio +certifi +charset-normalizer +idna +distro +exceptiongroup +fsspec +runlike +pyahocorasick # FastAPI 相关 fastapi -uvicorn[standard] +starlette +uvicorn +uvloop +watchfiles +websockets +python-multipart # Neo4j 图数据库 neo4j +neo4j-graphrag # PostgreSQL 支持 -psycopg[binary] +psycopg +psycopg-binary psycopg-pool # OpenAI API openai tiktoken +jiter # Word 文档生成 python-docx +lxml +# LaTeX 公式转 Word 原生公式(OMML),缺失时会回退成模糊图片 +latex2mathml # PDF 生成相关 matplotlib Pillow +contourpy +cycler +fonttools +kiwisolver +pyparsing +pymupdf +pypdf +# 其他依赖 +aiofiles +annotated-doc +annotated-types