From ae9b2f2fcf669ff95ba11515e1c9ee14da02fa45 Mon Sep 17 00:00:00 2001 From: liao Date: Wed, 2 Apr 2025 17:38:26 +0800 Subject: [PATCH] commit; --- src/app.py | 23 +- src/fundamentals_llm/fundamental_analysis.py | 402 +++++++++++-------- 2 files changed, 267 insertions(+), 158 deletions(-) diff --git a/src/app.py b/src/app.py index 4ea3c6b..840d279 100644 --- a/src/app.py +++ b/src/app.py @@ -1,6 +1,8 @@ import sys import os +from src.fundamentals_llm.fundamental_analysis_database import get_analysis_result, get_db + # 添加项目根目录到 Python 路径 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) @@ -25,6 +27,9 @@ CORS(app) # 启用跨域请求支持 # 创建企业筛选器实例 screener = EnterpriseScreener() +# 获取数据库连接 +db = next(get_db()) + @app.route('/api/health', methods=['GET']) def health_check(): """健康检查接口""" @@ -752,9 +757,25 @@ def comprehensive_analysis(): # 筛选出传入列表中符合条件的股票 for code, name in all_stocks: if code in input_stock_codes: + # 获取各个维度的分析结果 + investment_advice_result = get_analysis_result(db, code, "investment_advice") + industry_competition_result = get_analysis_result(db, code, "industry_competition") + financial_report_result = get_analysis_result(db, code, "financial_report") + valuation_level_result = get_analysis_result(db, code, "valuation_level") + + # 从ai_response和extra_info中提取所需的值 + investment_advice = investment_advice_result.ai_response if investment_advice_result else None + industry_space = industry_competition_result.extra_info.get("industry_space") if industry_competition_result else 0 + financial_report_level = financial_report_result.extra_info.get("financial_report_level") if financial_report_result else 0 + pe_industry = valuation_level_result.extra_info.get("pe_industry") if valuation_level_result else 0 + filtered_stocks.append({ "code": code, - "name": name + "name": name, + "investment_advice": investment_advice, # 投资建议(从ai_response获取) + "industry_space": industry_space, # 行业发展空间(2:高速增长, 1:稳定经营, 0:不确定性大, -1:不利经营) + "financial_report_level": financial_report_level, # 经营质量(2:优秀, 1:较好, 0:一般, -1:存在隐患,-2:较大隐患) + "pe_industry": pe_industry # 个股在行业的PE水平(-1:高于行业, 0:接近行业, 1:低于行业) }) logger.info(f"筛选出 {len(filtered_stocks)} 个符合条件的股票") diff --git a/src/fundamentals_llm/fundamental_analysis.py b/src/fundamentals_llm/fundamental_analysis.py index 90fa198..845917b 100644 --- a/src/fundamentals_llm/fundamental_analysis.py +++ b/src/fundamentals_llm/fundamental_analysis.py @@ -66,7 +66,7 @@ class FundamentalAnalyzer: # 使用联网模型进行基本面分析 self.chat_bot = ChatBot(model_type="online_bot") # 使用离线模型进行其他分析 - self.offline_bot = OfflineChatBot(platform="volc", model_type="offline_model") + self.offline_bot = OfflineChatBot(platform="tl_private", model_type="ds-v1") # 千问打杂 self.offline_bot_tl_qw = OfflineChatBot(platform="tl_qw_private", model_type="qwq") self.db = next(get_db()) @@ -366,25 +366,25 @@ class FundamentalAnalyzer: try: prompt = f"""请对{stock_name}({stock_code})的财报情况进行简要分析,严格要求最新财报情况200字以内,最新业绩预告情况100字以内,近三年变化趋势150字以内,请严格按照以下格式输出: -1. 最新财报情况 -- 营业收入及同比变化 -- 主要成本构成及变化 -- 净利润及同比变化 -- 毛利率和净利率变化 -- 其他重要财务指标(如ROE、资产负债率等) - -2. 最新业绩预告情况(没有就不要提) -- 预告类型(预增/预减/扭亏/续亏) -- 预计业绩区间 -- 变动原因 - -3. 近三年变化趋势 -- 收入增长趋势 -- 利润变化趋势 -- 盈利能力变化 -- 经营质量变化 - -请提供专业、客观的分析,突出关键信息,避免冗长描述。""" + 1. 最新财报情况 + - 营业收入及同比变化 + - 主要成本构成及变化 + - 净利润及同比变化 + - 毛利率和净利率变化 + - 其他重要财务指标(如ROE、资产负债率等) + + 2. 最新业绩预告情况(没有就不要提) + - 预告类型(预增/预减/扭亏/续亏) + - 预计业绩区间 + - 变动原因 + + 3. 近三年变化趋势 + - 收入增长趋势 + - 利润变化趋势 + - 盈利能力变化 + - 经营质量变化 + + 请提供专业、客观的分析,突出关键信息,避免冗长描述。""" # 获取AI分析结果 result = self.chat_bot.chat(prompt) @@ -425,16 +425,16 @@ class FundamentalAnalyzer: # 使用在线模型分析财报水平 prompt = f"""请对{stock_name}({stock_code})的财报水平进行专业分析,并返回对应的数值评级: -- 如果财报水平边际向好,最新财报没有任何风险,返回数值"2" -- 如果边际变化波动不高较为稳定,并且风险很小,返回数值"1" -- 如果波动不高较为稳定,但其中存在一定财报隐患,返回数值"0" -- 如果财报波动较大(亏损或者盈利),并且存在一定财报隐患,返回数值"-1" -- 如果财报波动较大(亏损或者盈利),并且存在较大财报隐患,返回数值"-2" - -财报分析内容: -{report_text} - -请仅返回一个数值:2、1、0、-1或-2,不要包含任何解释或说明。""" + - 如果财报水平边际向好,最新财报没有任何风险,返回数值"2" + - 如果边际变化波动不高较为稳定,并且风险很小,返回数值"1" + - 如果波动不高较为稳定,但其中存在一定财报隐患,返回数值"0" + - 如果财报波动较大(亏损或者盈利),并且存在一定财报隐患,返回数值"-1" + - 如果财报波动较大(亏损或者盈利),并且存在较大财报隐患,返回数值"-2" + + 财报分析内容: + {report_text} + + 请仅返回一个数值:2、1、0、-1或-2,不要包含任何解释或说明。""" # 使用在线模型进行分析 response = self.chat_bot.chat(prompt) @@ -484,26 +484,26 @@ class FundamentalAnalyzer: try: prompt = f"""请对{stock_name}({stock_code})所在行业的发展趋势和竞争格局进行简要分析,要求输出控制在400字以内,请严格按照以下格式输出: -1. 市场需求: -- 主要下游应用领域 -- 需求增长驱动因素 -- 市场规模和增速 - -2. 竞争格局: -- 主要竞争对手及特点 -- 行业集中度 -- 竞争壁垒 - -3. 行业环境: -- 行业平均利润率 -- 政策环境影响 -- 技术发展趋势 -- 市场阶段结论:新兴市场、成熟市场、衰退市场 - -4. 小结: -- 简要说明当前市场是否有利于企业经营 - -请提供专业、客观的分析,突出关键信息,避免冗长描述。""" + 1. 市场需求: + - 主要下游应用领域 + - 需求增长驱动因素 + - 市场规模和增速 + + 2. 竞争格局: + - 主要竞争对手及特点 + - 行业集中度 + - 竞争壁垒 + + 3. 行业环境: + - 行业平均利润率 + - 政策环境影响 + - 技术发展趋势 + - 市场阶段结论:新兴市场、成熟市场、衰退市场 + + 4. 小结: + - 简要说明当前市场是否有利于企业经营 + + 请提供专业、客观的分析,突出关键信息,避免冗长描述。""" # 获取AI分析结果 result = self.chat_bot.chat(prompt) @@ -543,15 +543,15 @@ class FundamentalAnalyzer: try: # 使用离线模型分析行业发展空间 prompt = f"""请分析以下{stock_name}({stock_code})的行业发展趋势和竞争格局文本,评估当前市场环境、阶段和竞争格局对企业未来的影响,并返回对应的数值: -- 如果当前市场环境、阶段和竞争格局符合未来企业高速增长,返回数值"2" -- 如果当前市场环境、阶段和竞争格局符合未来企业稳定经营,返回数值"1" -- 如果当前市场环境、阶段和竞争格局存在较大不确定性,返回数值"0" -- 如果当前市场环境、阶段和竞争格局不利于企业正常经营,返回数值"-1" - -行业发展趋势和竞争格局文本: -{industry_text} - -请仅返回一个数值:2、1、0或-1,不要包含任何解释或说明。""" + - 如果当前市场环境、阶段和竞争格局符合未来企业高速增长,返回数值"2" + - 如果当前市场环境、阶段和竞争格局符合未来企业稳定经营,返回数值"1" + - 如果当前市场环境、阶段和竞争格局存在较大不确定性,返回数值"0" + - 如果当前市场环境、阶段和竞争格局不利于企业正常经营,返回数值"-1" + + 行业发展趋势和竞争格局文本: + {industry_text} + + 请仅返回一个数值:2、1、0或-1,不要包含任何解释或说明。""" self.offline_bot_tl_qw.clear_history() # 使用离线模型进行分析 space_value_str = self.offline_bot_tl_qw.chat(prompt) @@ -702,17 +702,17 @@ class FundamentalAnalyzer: try: prompt = f"""请对{stock_name}({stock_code})的股吧讨论内容进行简要分析,要求输出控制在300字以内,请严格按照以下格式输出: -1. 主要讨论话题(150字左右): -- 近期热点事件 -- 投资者关注焦点 -- 市场情绪倾向 - -2. 重要信息汇总(150字左右): -- 公司相关动态 -- 行业政策变化 -- 市场预期变化 - -请提供专业、客观的分析,突出关键信息,避免冗长描述。重点关注投资者普遍关注的话题和重要市场信息。""" + 1. 主要讨论话题(150字左右): + - 近期热点事件 + - 投资者关注焦点 + - 市场情绪倾向 + + 2. 重要信息汇总(150字左右): + - 公司相关动态 + - 行业政策变化 + - 市场预期变化 + + 请提供专业、客观的分析,突出关键信息,避免冗长描述。重点关注投资者普遍关注的话题和重要市场信息。""" # 获取AI分析结果 result = self.chat_bot.chat(prompt) @@ -752,14 +752,14 @@ class FundamentalAnalyzer: try: # 使用离线模型分析市场情绪 prompt = f"""请分析以下{stock_name}({stock_code})的股吧讨论内容分析,判断整体市场情绪倾向,并返回对应的数值: -- 如果股吧讨论情绪偏乐观,返回数值"1" -- 如果股吧讨论情绪偏中性,返回数值"0" -- 如果股吧讨论情绪偏悲观,返回数值"-1" - -股吧讨论内容分析: -{discussion_text} - -请仅返回一个数值:1、0或-1,不要包含任何解释或说明。""" + - 如果股吧讨论情绪偏乐观,返回数值"1" + - 如果股吧讨论情绪偏中性,返回数值"0" + - 如果股吧讨论情绪偏悲观,返回数值"-1" + + 股吧讨论内容分析: + {discussion_text} + + 请仅返回一个数值:1、0或-1,不要包含任何解释或说明。""" self.offline_bot_tl_qw.clear_history() # 使用离线模型进行分析 emotion_value_str = self.offline_bot_tl_qw.chat(prompt) @@ -807,17 +807,17 @@ class FundamentalAnalyzer: try: prompt = f"""请对{stock_name}({stock_code})最近半年内的产业链上下游合作动态进行简要分析,要求输出控制在400字以内,请严格按照以下格式输出: -1. 重要客户合作(200字左右): -- 主要客户合作进展 -- 产品供应情况 -- 合作深度和规模 - -2. 产业链布局(200字左右): -- 上下游合作动态 -- 新业务领域拓展 -- 战略合作项目 - -请提供专业、客观的分析,突出关键信息,避免冗长描述。重点关注最近半年内的合作动态,如果没有相关动态,请直接说明。""" + 1. 重要客户合作(200字左右): + - 主要客户合作进展 + - 产品供应情况 + - 合作深度和规模 + + 2. 产业链布局(200字左右): + - 上下游合作动态 + - 新业务领域拓展 + - 战略合作项目 + + 请提供专业、客观的分析,突出关键信息,避免冗长描述。重点关注最近半年内的合作动态,如果没有相关动态,请直接说明。""" # 获取AI分析结果 result = self.chat_bot.chat(prompt) @@ -858,15 +858,15 @@ class FundamentalAnalyzer: # 使用在线模型分析合作动态质量 prompt = f"""请评估{stock_name}({stock_code})的产业链上下游合作动态质量,并返回相应数值: -- 如果企业近期有较多且质量高的新合作动态(具备新业务拓展能力,以及可以体现在近一年财报中),返回数值"2" -- 如果企业半年内合作动态频率低或质量一般(在原有业务上合作关系的衍生,对财报影响一般),返回数值"1" -- 如果企业没有合作动态或质量低,返回数值"0" -- 如果企业有负面合作关系(解除合作,或业务被其他厂商瓜分),返回数值"-1" - -以下是合作动态相关信息: -{cooperation_text} - -请仅返回一个数值:2、1、0或-1,不要包含任何解释或说明。""" + - 如果企业近期有较多且质量高的新合作动态(具备新业务拓展能力,以及可以体现在近一年财报中),返回数值"2" + - 如果企业半年内合作动态频率低或质量一般(在原有业务上合作关系的衍生,对财报影响一般),返回数值"1" + - 如果企业没有合作动态或质量低,返回数值"0" + - 如果企业有负面合作关系(解除合作,或业务被其他厂商瓜分),返回数值"-1" + + 以下是合作动态相关信息: + {cooperation_text} + + 请仅返回一个数值:2、1、0或-1,不要包含任何解释或说明。""" # 使用在线模型进行分析 response = self.chat_bot.chat(prompt) @@ -1084,15 +1084,13 @@ class FundamentalAnalyzer: prompt = f"""请对{stock_name}({stock_code})的估值水平进行简要分析,要求输出控制在300字以内,请严格按照以下格式输出: 1. 历史估值水平(150字左右): -- 当前PE和PB值 -- PE在历史分位水平的位置(高于/接近/低于历史平均分位) -- PB在历史分位水平的位置(高于/接近/低于历史平均分位) +- 当前PE值及其在历史分位水平的位置(高于/接近/低于历史平均分位) +- 当前PB值及其在历史分位水平的位置(高于/接近/低于历史平均分位) - 历史估值变化趋势简要分析 2. 行业估值对比(150字左右): -- 所在行业平均PE和PB -- PE与行业平均的比较(高于/接近/低于行业平均) -- PB与行业平均的比较(高于/接近/低于行业平均) +- 当前PE值与行业平均水平的比较(高于/接近/低于行业平均) +- 当前PB值与行业平均水平的比较(高于/接近/低于行业平均) - 与可比公司估值的简要对比 请提供专业、客观的分析,突出关键信息,避免冗长描述。如果无法获取某项数据,请直接说明。""" @@ -1130,14 +1128,18 @@ class FundamentalAnalyzer: stock_name: 股票名称 Returns: - Dict[str, int]: 包含历史估值和行业估值分类的字典 + Dict[str, int]: 包含四个分类值的字典: + - pe_historical: PE历史分位分类 (-1:高于历史, 0:接近历史, 1:低于历史) + - pb_historical: PB历史分位分类 (-1:高于历史, 0:接近历史, 1:低于历史) + - pe_industry: PE行业对比分类 (-1:高于行业, 0:接近行业, 1:低于行业) + - pb_industry: PB行业对比分类 (-1:高于行业, 0:接近行业, 1:低于行业) """ try: - # 提取历史估值分类 - historical_classification = self._extract_historical_valuation(valuation_text) - - # 提取行业估值分类 - industry_classification = self._extract_industry_valuation(valuation_text) + # 直接提取四个分类值 + pe_historical = self._extract_pe_historical(valuation_text) + pb_historical = self._extract_pb_historical(valuation_text) + pe_industry = self._extract_pe_industry(valuation_text) + pb_industry = self._extract_pb_industry(valuation_text) # 更新数据库中的记录 result = get_analysis_result(self.db, stock_code, "valuation_level") @@ -1150,103 +1152,189 @@ class FundamentalAnalyzer: reasoning_process=result.reasoning_process, references=result.references, extra_info={ - "historical_valuation": historical_classification, - "industry_valuation": industry_classification + "pe_historical": pe_historical, + "pb_historical": pb_historical, + "pe_industry": pe_industry, + "pb_industry": pb_industry } ) - logger.info(f"已更新估值分类到数据库: historical_valuation={historical_classification}, industry_valuation={industry_classification}") + logger.info(f"已更新估值分类到数据库: pe_historical={pe_historical}, pb_historical={pb_historical}, pe_industry={pe_industry}, pb_industry={pb_industry}") - return {"historical_valuation": historical_classification, "industry_valuation": industry_classification} + return { + "pe_historical": pe_historical, + "pb_historical": pb_historical, + "pe_industry": pe_industry, + "pb_industry": pb_industry + } except Exception as e: logger.error(f"提取估值分类失败: {str(e)}") - return {"historical_valuation": 0, "industry_valuation": 0} + return { + "pe_historical": 0, + "pb_historical": 0, + "pe_industry": 0, + "pb_industry": 0 + } - def _extract_historical_valuation(self, valuation_text: str) -> int: - """从估值水平分析中提取历史估值分类 + def _extract_pe_historical(self, valuation_text: str) -> int: + """从估值水平分析中提取PE历史分位分类 Args: valuation_text: 完整的估值水平分析文本 Returns: - int: 历史估值分类值 (高于历史:-1, 接近历史:0, 低于历史:1) + int: PE历史分位分类值 (-1:高于历史, 0:接近历史, 1:低于历史) """ try: - # 使用在线模型提取历史估值分类 - prompt = f"""请仔细分析以下估值水平文本,判断当前PE和PB在历史分位的位置,并返回对应的数值: - - 如果当前估值明显高于历史平均水平(高估),返回数值"-1" - - 如果当前估值接近历史平均水平,返回数值"0" - - 如果当前估值明显低于历史平均水平(低估),返回数值"1" + prompt = f"""请仔细分析以下估值水平文本,判断当前PE在历史分位的位置,并返回对应的数值: + - 如果当前PE为负数,返回数值"-1" + - 如果当前PE明显高于历史平均水平,返回数值"-1" + - 如果当前PE接近历史平均水平,返回数值"0" + - 如果当前PE明显低于历史平均水平,返回数值"1" - 如果文本中没有相关信息,返回数值"0" 估值水平文本: {valuation_text} 只需要输出一个数值,不要输出任何说明或解释。只输出:-1、0或1。""" - - # 使用千问离线模型提取数值 + + self.offline_bot_tl_qw.clear_history() response = self.offline_bot_tl_qw.chat(prompt) - # 清理模型输出 - hist_val_str = self._clean_model_output(response) - - # 尝试将响应转换为整数 + pe_hist_str = self._clean_model_output(response) + try: - hist_val = int(hist_val_str) - # 确保值在有效范围内 - if hist_val < -1 or hist_val > 1: - logger.warning(f"提取的历史估值分类值超出范围: {hist_val},设置为默认值0") + pe_hist = int(pe_hist_str) + if pe_hist < -1 or pe_hist > 1: + logger.warning(f"提取的PE历史分位分类值超出范围: {pe_hist},设置为默认值0") return 0 - return hist_val + return pe_hist except ValueError: - logger.warning(f"无法将提取的历史估值分类值转换为整数: {hist_val_str},设置为默认值0") + logger.warning(f"无法将提取的PE历史分位分类值转换为整数: {pe_hist_str},设置为默认值0") return 0 except Exception as e: - logger.error(f"提取历史估值分类失败: {str(e)}") + logger.error(f"提取PE历史分位分类失败: {str(e)}") return 0 - def _extract_industry_valuation(self, valuation_text: str) -> int: - """从估值水平分析中提取行业估值对比分类 + def _extract_pb_historical(self, valuation_text: str) -> int: + """从估值水平分析中提取PB历史分位分类 Args: valuation_text: 完整的估值水平分析文本 Returns: - int: 行业估值对比分类值 (高于行业:-1, 接近行业:0, 低于行业:1) + int: PB历史分位分类值 (-1:高于历史, 0:接近历史, 1:低于历史) """ try: - # 使用在线模型提取行业估值对比分类 - prompt = f"""请仔细分析以下估值水平文本,判断当前企业的PE和PB与行业平均水平的对比情况,并返回对应的数值: - - 如果当前企业估值明显高于行业平均水平,返回数值"-1" - - 如果当前企业估值接近行业平均水平,返回数值"0" - - 如果当前企业估值明显低于行业平均水平,返回数值"1" + prompt = f"""请仔细分析以下估值水平文本,判断当前PB在历史分位的位置,并返回对应的数值: + - 如果当前PB为负数,返回数值"-1" + - 如果当前PB明显高于历史平均水平,返回数值"-1" + - 如果当前PB接近历史平均水平,返回数值"0" + - 如果当前PB明显低于历史平均水平,返回数值"1" - 如果文本中没有相关信息,返回数值"0" 估值水平文本: {valuation_text} 只需要输出一个数值,不要输出任何说明或解释。只输出:-1、0或1。""" - - # 使用千问离线模型提取数值 - response = self.offline_bot_tl_qw.chat(prompt) - # 清理模型输出 - ind_val_str = self._clean_model_output(response) - # 尝试将响应转换为整数 + self.offline_bot_tl_qw.clear_history() + response = self.offline_bot_tl_qw.chat(prompt) + pb_hist_str = self._clean_model_output(response) + try: - ind_val = int(ind_val_str) - # 确保值在有效范围内 - if ind_val < -1 or ind_val > 1: - logger.warning(f"提取的行业估值对比分类值超出范围: {ind_val},设置为默认值0") + pb_hist = int(pb_hist_str) + if pb_hist < -1 or pb_hist > 1: + logger.warning(f"提取的PB历史分位分类值超出范围: {pb_hist},设置为默认值0") return 0 - return ind_val + return pb_hist except ValueError: - logger.warning(f"无法将提取的行业估值对比分类值转换为整数: {ind_val_str},设置为默认值0") + logger.warning(f"无法将提取的PB历史分位分类值转换为整数: {pb_hist_str},设置为默认值0") return 0 except Exception as e: - logger.error(f"提取行业估值对比分类失败: {str(e)}") + logger.error(f"提取PB历史分位分类失败: {str(e)}") + return 0 + + def _extract_pe_industry(self, valuation_text: str) -> int: + """从估值水平分析中提取PE行业对比分类 + + Args: + valuation_text: 完整的估值水平分析文本 + + Returns: + int: PE行业对比分类值 (-1:高于行业, 0:接近行业, 1:低于行业) + """ + try: + prompt = f"""请仔细分析以下估值水平文本,判断当前PE与行业平均水平的对比情况,并返回对应的数值: + - 如果当前PE为负数,返回数值"-1" + - 如果当前PE明显高于行业平均水平,返回数值"-1" + - 如果当前PE接近行业平均水平,返回数值"0" + - 如果当前PE明显低于行业平均水平,返回数值"1" + - 如果文本中没有相关信息,返回数值"0" + + 估值水平文本: + {valuation_text} + + 只需要输出一个数值,不要输出任何说明或解释。只输出:-1、0或1。""" + + self.offline_bot_tl_qw.clear_history() + response = self.offline_bot_tl_qw.chat(prompt) + pe_ind_str = self._clean_model_output(response) + + try: + pe_ind = int(pe_ind_str) + if pe_ind < -1 or pe_ind > 1: + logger.warning(f"提取的PE行业对比分类值超出范围: {pe_ind},设置为默认值0") + return 0 + return pe_ind + except ValueError: + logger.warning(f"无法将提取的PE行业对比分类值转换为整数: {pe_ind_str},设置为默认值0") + return 0 + + except Exception as e: + logger.error(f"提取PE行业对比分类失败: {str(e)}") + return 0 + + def _extract_pb_industry(self, valuation_text: str) -> int: + """从估值水平分析中提取PB行业对比分类 + + Args: + valuation_text: 完整的估值水平分析文本 + + Returns: + int: PB行业对比分类值 (-1:高于行业, 0:接近行业, 1:低于行业) + """ + try: + prompt = f"""请仔细分析以下估值水平文本,判断当前PB与行业平均水平的对比情况,并返回对应的数值: + - 如果当前PB为负数,返回数值"-1" + - 如果当前PB明显高于行业平均水平,返回数值"-1" + - 如果当前PB接近行业平均水平,返回数值"0" + - 如果当前PB明显低于行业平均水平,返回数值"1" + - 如果文本中没有相关信息,返回数值"0" + + 估值水平文本: + {valuation_text} + + 只需要输出一个数值,不要输出任何说明或解释。只输出:-1、0或1。""" + + self.offline_bot_tl_qw.clear_history() + response = self.offline_bot_tl_qw.chat(prompt) + pb_ind_str = self._clean_model_output(response) + + try: + pb_ind = int(pb_ind_str) + if pb_ind < -1 or pb_ind > 1: + logger.warning(f"提取的PB行业对比分类值超出范围: {pb_ind},设置为默认值0") + return 0 + return pb_ind + except ValueError: + logger.warning(f"无法将提取的PB行业对比分类值转换为整数: {pb_ind_str},设置为默认值0") + return 0 + + except Exception as e: + logger.error(f"提取PB行业对比分类失败: {str(e)}") return 0 def generate_investment_advice(self, stock_code: str, stock_name: str) -> bool: