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