From 8085a9a7233f5acacdb0ba33cb79078bfea28d34 Mon Sep 17 00:00:00 2001 From: jinye_huang Date: Mon, 12 May 2025 09:55:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E6=9B=BE=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E6=8F=90=E5=8F=96=E5=A4=B1=E8=B4=A5=E7=9A=84=E5=AE=A1?= =?UTF-8?q?=E6=A0=B8=E5=99=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../content_judger.cpython-312.pyc | Bin 19140 -> 25257 bytes .../output_handler.cpython-312.pyc | Bin 13579 -> 13692 bytes .../tweet_generator.cpython-312.pyc | Bin 37847 -> 38150 bytes utils/content_judger.py | 144 ++++++++++++++++-- utils/resource_loader.py | 23 +-- utils/tweet_generator.py | 41 +++-- 6 files changed, 169 insertions(+), 39 deletions(-) diff --git a/utils/__pycache__/content_judger.cpython-312.pyc b/utils/__pycache__/content_judger.cpython-312.pyc index 1820624678e78c5c77d4f38b4358e23a32d2d718..3262b115f6c9eb68b1b26f39876b01dba7edccac 100644 GIT binary patch delta 7013 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 Y?L(Ft%IT(>>lHi2c*P?Ol`PSJ0R)!Qg#Z8m delta 1365 zcmYjQYfw{16yCj;OLIxW!|({<70NT9jU#Q944@(418X{hEhVBf$qf>qiF0!^s11dw zATYIqvQ(5u-yLtPFRFlas-(rdFxctCRkS}aRrq#h}s zMC|D8!>k1YkF*AGxGGLMO4WcYAS9A&A(9RFly(^>I<}H z(C9T(fD!CMt1a-H)#(sy4k6?xj(-yT*cbM5C*i=bVRfcw<;Hu=~e40ULy!E7a}h+bMzF(wn15B1og_ z#f349djs2})SH5es$WKz=vXGK2t<@OyPS>y)9N&HuFz!g3LMUp zi`UTM@sK`KMY!eU!f>fPc?$e4v4W}V7=});9xq{)i>jPoRfTh^!W&ids@*;~ zr_%Kv{zn4hl|#DAx~nboiUPl^;L#G928vZK$rSxZ`i}Thi+!0sgej&KU>J#ZHr9O_n7sp_#p^Qd+OesK#<~S%t`R1aGB62A58u)DlbOf{n zb`dB=9p+S6f=10dt9CH;aN{J5VQCecMymU0XSPc)9 zugxevd98Gy(Jj9GqRjNnyu_UNlFX8v)LQ~@esX?ZNoronExxSMl=Rg2M4+0=;>_aB z|D>%M8Ivbl$<{GGoV-)ENAZD10e#C%j&+Krd_ z7%wZ3eN2?qO^*GT6gyDmF-1;ye&%CZ((YW$$GKSD`8Pk1pT)$OG`U*oFk|y(d*wb( zAm^M;Gh_DTAYDJkw8;x~cQW>Ej@AoeVLZEeoskZsp*m|grN&IpumbZJLaQytU&fLHdZ%&_G8@aK$XXYINceTk4a0rSu-EAW_4%S9H=mhi7|fi8>PdH z^_w>+_i+L__PWiC8Iup|`Y|R?7Sh|v*tPkLUJwi8$<6Y{I*f+Otl^9+fmdQ4z`hp2ejJz{)zcPU6B0*r#0|3yR BY9ast diff --git a/utils/__pycache__/tweet_generator.cpython-312.pyc b/utils/__pycache__/tweet_generator.cpython-312.pyc index 6d44fd5629bbcf4428d5c5c54e30808070e0ddda..982c6ac9160e3acd6c775ba2c6ab54b8487a689c 100644 GIT binary patch delta 3184 zcmZve3se;6702h>*%{dPDy;0n@>uY}^40}GgcT52u?iY66=REJcfd8vF8Ov5sw*JT zq@H6E_4c$FHL;J=Vse^CCuyqHHnvHVG^Zy^APHG>dOU5cF-?<=+C231@!cU0;>p1N z=0Eq|?=kb;x!=6`3)Q`ks*JA~3|fvIXWAUw#b=%}`n9?wcFD8fH9dhb?a*SM80B{o zD)_i4?-Og7C(5^Td0a$fQaKiKv>c2&hbt+nKF0ZyPwqUtYv zKHjH0F2H78W}&`yS8`2hWV=6jmz&~znrQ_iUCt0U>=^L%N?qXruU86(;jk{#oyP1% zIq#hN{pBA_T>0(zyO00u@~JbI?%jXs@zZoE^L01{x(qvTA-?R2Hn2-)61=QiBET|YWz1R z8jLp+Nv!RSa26YIte&qIx$~l?f#=Vgob_)0d=)|MRtxL|S*CKRF@#9~o-{m2)q0n#<%q?yAZl^pLAriv;7< zRwC=oJu1=+;rSZqzm)y~2B z>THWCDzFvSMny(*RPUR2OzoQwqn7=o6vPD%L&_X~DwJ7L)z|^7UEm-VIk2FCq&7R% zx2{bCoJ}hh+i}_*@L^hc+a{FCvaMn&&IhC*y&aVh4oFgeT%_GWU#O3M8{>))U)_Bz z#%ZJ>uhbv$hl0*|v=gW`FMSJ!-GSJOs6>1h(FIRfd$oN`{*e8`2O-C{h-`yq+qfyV zVbf&F?Xk_?Sc*5M_rew181n?uosBOwO`2|tb#%o{U9Ts1-Ao87VH>#-E?_;Jur*q_ zXB%{kf8^^^+39(!rpe4d?^xKR<6jU6(=X_RCbRrT`ma?>B-Vt@H#pEI(e8*87udb^ zN)+c47rXoWrJ&C_pWTC;=^GMkVnv<#*neE;3;CpgGD6%$rMm~DaHK2Z?~_6Ukt>+@ zYc7>oOE3920~$JHV2xS!D)$$pO1{sn06w*n)wpE z9EA@`Gst1kmX(qRpt|gr!c)v_k>4-N=1C{$%a@slFm6sJKx=uaDyUUb|EJ||sY$E6 zXN8NT{3xnDMCih(fzc7wGiI^$m&qv@SeZTVsIM@Zvy-E{e8tLnC%zi+{K^BWXbw!S zv=qC1;$tc{6g#4sJ{Q(ZU%3+Mj^_BvZL{_YvxKi%fG0KtYV5^vHYi zLy5~B&ShiCtOZkpWRM%;JGnvPTrD4VR|q5oFRrd5UPx~INKlHm{8{7wNScpL$C*Lh z>_nAP@nci~CQqg9cTC3T1w!4vt{#6t!gP&D!3b@JE>AY0FygV9Z^!T+L@%NbCOidX zJ4|`vD1SihCeu&}jSKW?pC z|7P9B$-0fP+qz@k?NfFBllqCS$(&l4-I>Hf_Ii zrlx*;-9+}JeZ{8M)xH?J2# zOWUT#{0_D1FH2UZwVPEjcY}dlO_?>U`zc#idyOzvDWIiBV3ujZGd-==bd(Fz275=T zFkLDzO$Xp_ZTAt7cWn56w)t6ncBzQpAWqAw{wbnUO4&PTxCbuY{Tg{umg&2M`~i+f zPLbE;=7EQa{bO|JAwFRU<13kyL+xm|ab$2A`50V-i^)ycGFYKIgVwW%bMixjCPMbf zj}8qH5|ZF9?Q5y1xBjLC@#A-NgR2-O> zbP@w!Lxd5y#ZjzransuNw$?_;%W7y7r6D?7{=O`VRN`P_&u+3B77pi=pTPRzH1Y~a z!{hAB;J?H65lrT|!Am8!jdb;g!V!r&J+pZ{fMa}9GS7L67;*{m55#4}yND}@_Yi>i zC*pm?zYrfFltL_ih;ko1GGZgcaC)SV%)pY-tz-}E8;yz=(0LBTy{AbEJh!(})Z;7Q zf$o;YU>;itp0Qlv4rZ#BgJUNRBgZh@i+Gs9$zOIU$JDCchmPX$)~Z>DnqJ4Ct*j-* z7GX;_+VYrUk1s@}l5V*F(7GHO z8q{c@$rzA%xoh8vKw)N!GQt$ie}zB3dG zP%Ht|iQNm4f&PF*@y=%xH49ysp*NCi*k(EqklfVIyzHL~SF&47@Pv?S$sEyM;B*(@ zvBMtwYC_UK;*i(YsjMU|QN{I=9poBc!oF7YN7_dkcw(KfCOACL6jvvB6c?Sv3HGf? ztn9OOu``jR$YidtB*8vPnN`b`tW4+>Y2@+?6DCEPxx%urAT}xBs8Zji0oQZPy>ygj?58`oUNdN!< delta 2910 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 diff --git a/utils/content_judger.py b/utils/content_judger.py index 436f4df..86ead85 100644 --- a/utils/content_judger.py +++ b/utils/content_judger.py @@ -51,9 +51,9 @@ class ContentJudger: 3. 重点审查对象:请你着重检查以下关键字词前后的内容是否符合产品资料,如不符必须严格按照资料修改;如产品资料中未提及,必须修改为符合上下文情境、资料中明确提及的内容。 关键字词:价、元、r、人民币、rmb、优惠、活动、福利、赠、免费、折、DIY、跟拍、送、摄影、兑、服务、¥、包、课、提供、选、专业、补、差 4. 字数控制:每个文案的标题字数都必须少于19个字(计数包括文字、符号、数字和emoji)。如果标题超过19个字,请在符合文案风格和背景资料的前提下修改标题到19个字以内,尽量保留emoji,必须保证标题流畅通顺。 -5. 敏感字词替换:请删去标题中的数字后面的“元”和“r”,并将正文中数字后面的“元”字修改为“r”。例如:标题中的399元修改为399,正文中的399元修改为399r -6. 特征语句保留:请保留文案中原本的引流语句,不要修改或删除,例如“先关zhu+留下99看到会回复” -7. 面向人群保留:请尽量保留文案原本的面向人群和风格,这是同一产品面向多种人群营销的策略。例如产品资料中写明亲子游时,文案写“为情侣定制的山水秘境”是可以接受的。 +5. 敏感字词替换:请删去标题中的数字后面的"元"和"r",并将正文中数字后面的"元"字修改为"r"。例如:标题中的399元修改为399,正文中的399元修改为399r +6. 特征语句保留:请保留文案中原本的引流语句,不要修改或删除,例如"先关zhu+留下99看到会回复" +7. 面向人群保留:请尽量保留文案原本的面向人群和风格,这是同一产品面向多种人群营销的策略。例如产品资料中写明亲子游时,文案写"为情侣定制的山水秘境"是可以接受的。 8. 案例如下,请参考案例评判真假信息的尺度,逐行逐句仔细分析不符点和修改思路,并按照分析思路落实对每一处不符的修改措施,严格审查每一篇文案: { "产品资料": @@ -126,7 +126,7 @@ class ContentJudger: 输出结果: { "不良内容分析" : " 1、观察文案标题和内容,可以看出此文案主要面向亲子出游人群,因此修改后的文案也应该围绕亲子出游这一主题。 - 2、文章标题字数为28个字,超过19个字,因此属于不符内容。由于要求中提到尽量保留emoji,并且标题中数字后面的“元”字应删去,所以修改为:五一遛娃👶必囤!喜来登1088景观房 + 2、文章标题字数为28个字,超过19个字,因此属于不符内容。由于要求中提到尽量保留emoji,并且标题中数字后面的"元"字应删去,所以修改为:五一遛娃👶必囤!喜来登1088景观房 3、产品资料中未提及儿童乐园开放时间和儿童乐园配置,但文案中提到儿童乐园10:00-20:00全程开放,滑梯/积木/绘本一应俱全,因此属于不符内容。应修改为:儿童乐园:免费儿童乐园和丰富的游乐设施,让孩子们可以尽情玩耍。 4、产品材料中未提及户外泳池开放时间和消毒频次,但文案中提到户外泳池:9:00-18:00恒温开放(五一期间每日消毒3次),因此属于不符内容。应修改为:户外泳池:酒店配有户外无边泳池,供大人小孩一同享受清凉时光。 5、产品材料中未提及健身房开放时间与具体细节,但文案中提到健身房:8:00-22:00配备亲子瑜伽课程(需提前预约),因此属于不符内容。应修改为:健身房:酒店提供免费健身中心,方便您和家人一起强身健体。 @@ -174,7 +174,7 @@ class ContentJudger: presence_penalty: 存在惩罚参数 Returns: - dict: 审核后的结果JSON,包含修改后的title和content + dict: 审核后的结果JSON,包含修改后的title和content以及judge_success状态 """ logging.info("开始内容审核流程") # 构建用户提示词 @@ -198,16 +198,43 @@ class ContentJudger: end_time = time.time() logging.info(f"AI模型响应完成,耗时:{end_time - start_time:.2f}秒") + # 保存原始响应用于调试 + response_log_dir = "/root/autodl-tmp/TravelContentCreator/log/judge_responses" + os.makedirs(response_log_dir, exist_ok=True) + response_log_file = f"{response_log_dir}/response_{int(time.time())}.txt" + with open(response_log_file, "w", encoding="utf-8") as f: + f.write(result) + logging.info(f"原始响应已保存到: {response_log_file}") + # 提取修改后的内容 modified_content = self._extract_modified_content(result) if modified_content: logging.info("成功提取修改后的内容") + # 添加judge_success字段 + modified_content["judge_success"] = True return modified_content else: - return {"title": "提取失败", "content": "无法从响应中提取有效内容"} + logging.error("无法从响应中提取有效内容") + # 尝试使用原始内容并标记审核失败 + if isinstance(content, dict) and "title" in content and "content" in content: + return { + "title": content.get("title", "提取失败"), + "content": content.get("content", "无法从响应中提取有效内容"), + "judge_success": False + } + return { + "title": "提取失败", + "content": "无法从响应中提取有效内容", + "judge_success": False + } except Exception as e: - return {"title": "审核失败", "content": f"审核过程中出错: {str(e)}"} + logging.exception(f"审核过程中出错: {e}") + return { + "title": "审核失败", + "content": f"审核过程中出错: {str(e)}", + "judge_success": False + } def _build_user_prompt(self, product_info, content_gen): """ @@ -229,21 +256,106 @@ class ContentJudger: """ def _extract_modified_content(self, result_text): + """从检测结果文本中提取修改后的文案内容""" + try: + processed_text = result_text # Work on a copy of the input text + # 记录原始文本前100个字符用于调试 + logging.debug(f"原始响应文本前100字符: {result_text[:100]}") + + if "" in processed_text: + processed_text = processed_text.split("", 1)[1].strip() + logging.debug("检测到标签并分离内容") + + # Attempt 1: Parse as JSON from the processed text + json_start = processed_text.find('{') + json_end = processed_text.rfind('}') + 1 + if json_start >= 0 and json_end > json_start: + json_str = processed_text[json_start:json_end] + logging.debug(f"找到JSON字符串,长度: {len(json_str)},前100字符: {json_str[:100]}") + + # Clean control characters that might break JSON parsing + json_str_cleaned = re.sub(r'[\x00-\x1F\x7F]', '', json_str) + try: + content_json = json.loads(json_str_cleaned) + if "title" in content_json and "content" in content_json: + logging.info("Successfully parsed JSON content from AI response.") + return { + "title": content_json["title"].strip(), + "content": content_json["content"].strip() + } + except json.JSONDecodeError as e: + logging.warning(f"JSON parsing failed for substring: '{json_str_cleaned[:100]}...'. Error: {e}. Will attempt regex extraction.") + + # Attempt 2: Regex on the processed_text (which might have had stripped) + # 修复正则表达式,移除多余的反斜杠 + logging.debug("尝试使用正则表达式提取") + title_match = re.search(r'"title":\s*"([^"]*)"', processed_text) + content_match = re.search(r'"content":\s*"([^"]*)"', processed_text) + + if title_match and content_match: + logging.info("Successfully extracted title/content using regex.") + return { + "title": title_match.group(1).strip(), + "content": content_match.group(1).strip() + } + + # Attempt 3: Try finding content with single quotes + logging.debug("尝试查找使用单引号的内容") + title_match = re.search(r'"title":\s*\'([^\']*)\'', processed_text) + content_match = re.search(r'"content":\s*\'([^\']*)\'', processed_text) + + if title_match and content_match: + logging.info("Successfully extracted title/content using single-quote regex.") + return { + "title": title_match.group(1).strip(), + "content": content_match.group(1).strip() + } + + # Final attempt: Look for key-value pairs without standard JSON formatting + logging.debug("尝试非标准格式提取") + title_pattern = re.compile(r'["""]?title["""]?[::]\s*["""]([^"""]+)["""]', re.IGNORECASE) + content_pattern = re.compile(r'["""]?content["""]?[::]\s*["""]([^"""]+)["""]', re.IGNORECASE) + + title_match = title_pattern.search(processed_text) + content_match = content_pattern.search(processed_text) + + if title_match and content_match: + logging.info("提取到标题和内容(使用灵活模式匹配)") + return { + "title": title_match.group(1).strip(), + "content": content_match.group(1).strip() + } + + logging.warning(f"所有提取方法失败,响应前300字符: {processed_text[:300]}...") + return None # Fallback if all extraction methods fail + + except Exception as e: + logging.error(f"Unexpected error during content extraction: {e}\n{traceback.format_exc()}") + return None + + def test_extraction_from_file(self, response_file_path): """ - 从检测结果文本中提取修改后的文案内容 + 从文件中读取响应并测试提取功能 Args: - result_text: AI响应的文本 + response_file_path: 响应文件路径 Returns: - dict or None: 提取的内容JSON,提取失败则返回None + dict: 提取结果 """ try: - result_text = result_text.split("")[1] + logging.info(f"从文件测试提取: {response_file_path}") + with open(response_file_path, 'r', encoding='utf-8') as f: + response_text = f.read() - ## 舍弃 - - return json.loads(result_text) + result = self._extract_modified_content(response_text) + if result: + logging.info(f"成功从文件提取内容: {result.get('title', '')[:30]}...") + return {"success": True, "result": result} + else: + logging.error(f"从文件中提取内容失败") + return {"success": False, "error": "提取失败"} + except Exception as e: - logging.error(f"提取内容时发生错误: {e}") - return None \ No newline at end of file + logging.exception(f"测试提取时发生错误: {e}") + return {"success": False, "error": str(e)} \ No newline at end of file diff --git a/utils/resource_loader.py b/utils/resource_loader.py index 4cb4ef3..0decd0c 100644 --- a/utils/resource_loader.py +++ b/utils/resource_loader.py @@ -1,6 +1,7 @@ import os import random import json +import logging class ResourceLoader: """资源加载器,用于加载提示词和参考资料""" @@ -13,11 +14,11 @@ class ResourceLoader: content = f.read() return content else: - print(f"文件不存在: {file_path}") + logging.warning(f"文件不存在: {file_path}") # Return None for non-existent file to distinguish from empty file return None except Exception as e: - print(f"加载文件 '{file_path}' 内容失败: {e}") + logging.warning(f"加载文件 '{file_path}' 内容失败: {e}") # Return None on error as well return None @@ -26,10 +27,10 @@ class ResourceLoader: """加载Refer目录下的指定文件内容""" refer_content = "" if not file_path or not os.path.isfile(file_path): - print(f"Warning: Refer directory '{file_path}' not found or invalid.") + logging.warning(f"Warning: Refer directory '{file_path}' not found or invalid.") return "" try: - if True: # print(file_path) + if True: if os.path.isfile(file_path) and file_path.endswith(".txt"): # Use the updated load_file_content content = ResourceLoader.load_file_content(file_path) @@ -49,7 +50,7 @@ class ResourceLoader: # 检查必要的键是否存在 if "title" not in file_content or "description" not in file_content or "examples" not in file_content: - print(f"Warning: JSON文件 '{file_path}' 缺少必要的键(title/description/examples)") + logging.warning(f"Warning: JSON文件 '{file_path}' 缺少必要的键(title/description/examples)") title_content = file_content["title"] description_content = file_content["description"] @@ -66,12 +67,12 @@ class ResourceLoader: refer_content += f"## {file_path}\n{content}\n\n" else: - print(f"Warning: JSON文件 '{file_path}' 的examples不是有效列表") + logging.warning(f"Warning: JSON文件 '{file_path}' 的examples不是有效列表") except Exception as json_err: - print(f"处理JSON文件 '{file_path}' 失败: {json_err}") + logging.warning(f"处理JSON文件 '{file_path}' 失败: {json_err}") return refer_content except Exception as e: - print(f"加载Refer目录文件失败: {e}") + logging.warning(f"加载Refer目录文件失败: {e}") return "" @staticmethod @@ -98,7 +99,7 @@ class ResourceLoader: return None except Exception as e: - print(f"查找文件 '{file_name}' 在 '{directory}' 失败: {e}") + logging.warning(f"查找文件 '{file_name}' 在 '{directory}' 失败: {e}") return None @staticmethod @@ -125,7 +126,7 @@ class ResourceLoader: f.write(f"```\n{result}\n```\n\n") f.write("--------------------------------\n\n") except Exception as e: - print(f"更新汇总文件时出错: {e}") + logging.warning(f"更新汇总文件时出错: {e}") @staticmethod def save_article(result, prompt, output_dir, run_id, article_index, variant_index): @@ -145,5 +146,5 @@ class ResourceLoader: return filepath except Exception as e: - print(f"保存文章时出错: {e}") + logging.warning(f"保存文章时出错: {e}") return None \ No newline at end of file diff --git a/utils/tweet_generator.py b/utils/tweet_generator.py index cd1a28b..85146ed 100644 --- a/utils/tweet_generator.py +++ b/utils/tweet_generator.py @@ -88,14 +88,22 @@ class tweetContent: json_data = json.loads(processed_result) json_data["error"] = False json_data["raw_result"] = None + # 确保judge_success字段存在 + if "judge_success" not in json_data: + json_data["judge_success"] = None return json_data # --- End Existing Logic --- except Exception as e: - logging.warning(f"解析内容时出错: {e}, 返回空字符串") - json_data["error"] = True - json_data["raw_result"] = e - return json_data + logging.warning(f"解析内容时出错: {e}, 使用默认空内容") + # 创建一个新的json_data而不是使用未定义的变量 + return { + "title": "", + "content": "", + "error": True, + "raw_result": str(e), + "judge_success": False + } def get_json_data(self): """Returns the generated JSON data dictionary.""" @@ -159,7 +167,7 @@ def generate_single_content(ai_agent, system_prompt, user_prompt, item, run_id, if result is None: # Check if AI call failed logging.error(f"AI agent work failed for {article_index}_{variant_index}. No result returned.") - return {"title": "", "content": "", "error": True}, user_prompt # 返回空字段而不是None + return {"title": "", "content": "", "error": True, "judge_success": False}, user_prompt # 添加judge_success字段 logging.info(f"Content generation for {article_index}_{variant_index} completed in {time_cost:.2f}s. Estimated tokens: {tokens}") @@ -185,13 +193,13 @@ def generate_single_content(ai_agent, system_prompt, user_prompt, item, run_id, except Exception as e: logging.exception(f"Error generating single content for {article_index}_{variant_index}:") - return {"title": "", "content": "", "error": True}, user_prompt # 返回空字段而不是None + return {"title": "", "content": "", "error": True, "judge_success": False}, user_prompt # 添加judge_success字段 def generate_content(ai_agent, system_prompt, topics, output_dir, run_id, prompts_dir, resource_dir, variants=2, temperature=0.3, start_index=0, end_index=None): """根据选题生成内容""" if not topics: - print("没有选题,无法生成内容") + logging.warning("没有选题,无法生成内容") return # 确定处理范围 @@ -199,7 +207,7 @@ def generate_content(ai_agent, system_prompt, topics, output_dir, run_id, prompt end_index = len(topics) topics_to_process = topics[start_index:end_index] - print(f"准备处理{len(topics_to_process)}个选题...") + logging.info(f"准备处理{len(topics_to_process)}个选题...") # 创建汇总文件 # summary_file = ResourceLoader.create_summary_file(output_dir, run_id, len(topics_to_process)) @@ -207,11 +215,11 @@ def generate_content(ai_agent, system_prompt, topics, output_dir, run_id, prompt # 处理每个选题 processed_results = [] for i, item in enumerate(topics_to_process): - print(f"处理第 {i+1}/{len(topics_to_process)} 篇文章") + logging.info(f"处理第 {i+1}/{len(topics_to_process)} 篇文章") # 为每个选题生成多个变体 for j in range(variants): - print(f"正在生成变体 {j+1}/{variants}") + logging.info(f"正在生成变体 {j+1}/{variants}") # 调用单篇文章生成函数 tweet_content, result = generate_single_content( @@ -225,7 +233,7 @@ def generate_content(ai_agent, system_prompt, topics, output_dir, run_id, prompt # if j == 0: # ResourceLoader.update_summary(summary_file, i+1, user_prompt, result) - print(f"完成{len(processed_results)}篇文章生成") + logging.info(f"完成{len(processed_results)}篇文章生成") return processed_results @@ -520,15 +528,24 @@ content: {content_json.get('content', '')} content_json["content"] = judged_result["content"] # 添加审核标记 content_json["judged"] = True + # 添加judge_success状态 + content_json["judge_success"] = judged_result.get("judge_success", False) # 可选:保存审核分析结果 if "不良内容分析" in judged_result: content_json["judge_analysis"] = judged_result["不良内容分析"] else: logging.warning(f" 审核结果缺少title或content字段,保留原内容") + content_json["judge_success"] = False else: logging.warning(f" 内容审核返回无效结果,保留原内容") + content_json["judge_success"] = False except Exception as judge_err: logging.exception(f" 内容审核过程出错: {judge_err},保留原内容") + content_json["judge_success"] = False + else: + # 未启用内容审核时,添加相应标记 + content_json["judged"] = False + content_json["judge_success"] = None # Use the output handler to process/save the result output_handler.handle_content_variant( @@ -859,7 +876,7 @@ def generate_posters_for_topic(topic_item: dict, collage_img = collage_images[0] # 获取第一个 PIL Image used_image_files = used_image_filenames[0] if used_image_filenames else [] # 获取使用的图片文件名 logging.info(f"Collage image generated successfully (in memory). Used images: {used_image_files}") - print(f"拼贴图使用的图片文件: {used_image_files}") + logging.info(f"拼贴图使用的图片文件: {used_image_files}") # --- 使用 Handler 保存 Collage 图片和使用的图片文件信息 --- output_handler.handle_generated_image(