++
This commit is contained in:
+314
@@ -0,0 +1,314 @@
|
||||
from flask import Blueprint, render_template, request, jsonify
|
||||
import requests
|
||||
import json
|
||||
import logging
|
||||
|
||||
feature_engineering_bp = Blueprint('feature_engineering', __name__)
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@feature_engineering_bp.route('/')
|
||||
def feature_engineering():
|
||||
"""特征工程主页面"""
|
||||
return render_template('feature_engineering.html')
|
||||
|
||||
@feature_engineering_bp.route('/api/test-deepseek', methods=['POST'])
|
||||
def test_deepseek_api():
|
||||
"""测试 Deepseek API 连接"""
|
||||
try:
|
||||
api_key = request.headers.get('X-API-Key')
|
||||
if not api_key:
|
||||
return jsonify({'success': False, 'error': '需要提供 API 密钥'}), 400
|
||||
|
||||
# 通过简单请求测试 API
|
||||
headers = {
|
||||
'Authorization': f'Bearer {api_key}',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
test_data = {
|
||||
'model': 'deepseek-chat',
|
||||
'messages': [
|
||||
{'role': 'user', 'content': '你好,这是一条测试消息。'}
|
||||
],
|
||||
'max_tokens': 10
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
'https://api.deepseek.com/chat/completions ',
|
||||
headers=headers,
|
||||
json=test_data,
|
||||
timeout=10
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
return jsonify({'success': True, 'message': 'API 连接成功'})
|
||||
else:
|
||||
error_detail = response.text
|
||||
return jsonify({'success': False, 'error': f'API 返回状态 {response.status_code}:{error_detail}'}), 400
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"API 测试出错:{str(e)}")
|
||||
return jsonify({'success': False, 'error': f'网络错误:{str(e)}'}), 500
|
||||
except Exception as e:
|
||||
logger.error(f"API 测试中出现意外错误:{str(e)}")
|
||||
return jsonify({'success': False, 'error': f'未知错误:{str(e)}'}), 500
|
||||
|
||||
@feature_engineering_bp.route('/api/get-recommendations', methods=['POST'])
|
||||
def get_feature_engineering_recommendations():
|
||||
"""从 Deepseek API 获取特征工程建议"""
|
||||
try:
|
||||
api_key = request.headers.get('X-API-Key')
|
||||
if not api_key:
|
||||
return jsonify({'success': False, 'error': '需要提供 API 密钥'}), 400
|
||||
|
||||
data = request.get_json()
|
||||
current_step = data.get('current_step', 1)
|
||||
data_field = data.get('data_field', '')
|
||||
previous_steps = data.get('previous_steps', [])
|
||||
current_data_state = data.get('current_data_state', '原始数据')
|
||||
|
||||
if not data_field:
|
||||
return jsonify({'success': False, 'error': '请提供数据字段描述'}), 400
|
||||
|
||||
# 构建系统提示
|
||||
system_prompt = get_default_system_prompt_text()
|
||||
|
||||
# 构建用户提示
|
||||
previous_steps_text = "无" if not previous_steps else ",".join([f"步骤 {i+1}:{step}" for i, step in enumerate(previous_steps)])
|
||||
|
||||
user_prompt = f"""上下文:
|
||||
当前步骤:{current_step}
|
||||
当前数据字段:{data_field}
|
||||
之前的步骤及所用类别:{previous_steps_text}
|
||||
当前数据状态:{current_data_state}"""
|
||||
|
||||
# 调用 Deepseek API
|
||||
headers = {
|
||||
'Authorization': f'Bearer {api_key}',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
api_data = {
|
||||
'model': 'deepseek-chat',
|
||||
'messages': [
|
||||
{'role': 'system', 'content': system_prompt},
|
||||
{'role': 'user', 'content': user_prompt}
|
||||
],
|
||||
'max_tokens': 8192,
|
||||
'temperature': 0.7
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
'https://api.deepseek.com/chat/completions ',
|
||||
headers=headers,
|
||||
json=api_data,
|
||||
timeout=30
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
response_data = response.json()
|
||||
recommendations = response_data['choices'][0]['message']['content']
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'recommendations': recommendations,
|
||||
'current_step': current_step,
|
||||
'data_field': data_field,
|
||||
'previous_steps': previous_steps,
|
||||
'current_data_state': current_data_state
|
||||
})
|
||||
else:
|
||||
error_detail = response.text
|
||||
logger.error(f"Deepseek API 错误:{response.status_code} - {error_detail}")
|
||||
return jsonify({'success': False, 'error': f'API 返回状态 {response.status_code}:{error_detail}'}), 400
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"API 请求出错:{str(e)}")
|
||||
return jsonify({'success': False, 'error': f'网络错误:{str(e)}'}), 500
|
||||
except Exception as e:
|
||||
logger.error(f"获取建议时出现意外错误:{str(e)}")
|
||||
return jsonify({'success': False, 'error': f'未知错误:{str(e)}'}), 500
|
||||
|
||||
@feature_engineering_bp.route('/api/continue-conversation', methods=['POST'])
|
||||
def continue_conversation():
|
||||
"""继续对话,回答追问"""
|
||||
try:
|
||||
api_key = request.headers.get('X-API-Key')
|
||||
if not api_key:
|
||||
return jsonify({'success': False, 'error': '需要提供 API 密钥'}), 400
|
||||
|
||||
data = request.get_json()
|
||||
conversation_history = data.get('conversation_history', [])
|
||||
user_message = data.get('user_message', '')
|
||||
custom_system_prompt = data.get('custom_system_prompt', None)
|
||||
|
||||
if not user_message:
|
||||
return jsonify({'success': False, 'error': '请输入您的消息'}), 400
|
||||
|
||||
# 构建对话消息
|
||||
messages = []
|
||||
|
||||
# 若提供了自定义系统提示则使用,否则用默认
|
||||
if custom_system_prompt:
|
||||
system_prompt = custom_system_prompt
|
||||
else:
|
||||
system_prompt = get_default_system_prompt_text()
|
||||
|
||||
messages.append({'role': 'system', 'content': system_prompt})
|
||||
|
||||
# 加入历史对话
|
||||
for msg in conversation_history:
|
||||
messages.append(msg)
|
||||
|
||||
# 加入新用户消息
|
||||
messages.append({'role': 'user', 'content': user_message})
|
||||
print(user_message)
|
||||
# 调用 Deepseek API
|
||||
headers = {
|
||||
'Authorization': f'Bearer {api_key}',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
api_data = {
|
||||
'model': 'deepseek-chat',
|
||||
'messages': messages,
|
||||
'max_tokens': 8192,
|
||||
'temperature': 0.7
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
'https://api.deepseek.com/chat/completions ',
|
||||
headers=headers,
|
||||
json=api_data,
|
||||
timeout=30
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
response_data = response.json()
|
||||
assistant_response = response_data['choices'][0]['message']['content']
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'response': assistant_response
|
||||
})
|
||||
else:
|
||||
error_detail = response.text
|
||||
logger.error(f"Deepseek API 错误:{response.status_code} - {error_detail}")
|
||||
return jsonify({'success': False, 'error': f'API 返回状态 {response.status_code}:{error_detail}'}), 400
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"API 请求出错:{str(e)}")
|
||||
return jsonify({'success': False, 'error': f'网络错误:{str(e)}'}), 500
|
||||
except Exception as e:
|
||||
logger.error(f"继续对话时出现意外错误:{str(e)}")
|
||||
return jsonify({'success': False, 'error': f'未知错误:{str(e)}'}), 500
|
||||
|
||||
def get_default_system_prompt_text():
|
||||
"""获取默认系统提示文本"""
|
||||
return """你是一位特征工程专家助手。你的任务是针对给定的数据字段,设计一个最多包含 6 步的特征工程流水线。每一步都要根据当前数据状态、已完成的步骤以及总体目标,从 15 个类别中推荐最合适的特征工程类别。
|
||||
|
||||
说明:
|
||||
|
||||
每一步你都会收到:
|
||||
|
||||
当前步骤序号。
|
||||
|
||||
当前数据字段及其描述。
|
||||
|
||||
已完成的步骤及所用类别(如有)。
|
||||
|
||||
当前数据状态(例如:已归一化、已过滤等)。
|
||||
|
||||
你的任务是:
|
||||
|
||||
列出当前步骤最可行的特征工程类别,从以下 15 类中选择:
|
||||
|
||||
基础算术与数学运算
|
||||
|
||||
逻辑与条件运算
|
||||
|
||||
时间序列:变化检测与值比较
|
||||
|
||||
时间序列:统计特征工程
|
||||
|
||||
时间序列:排序、缩放与归一化
|
||||
|
||||
时间序列:衰减、平滑与翻转控制
|
||||
|
||||
时间序列:极值与位置识别
|
||||
|
||||
横截面:排序、缩放与归一化
|
||||
|
||||
横截面:回归与中性化
|
||||
|
||||
横截面:分布变换与截断
|
||||
|
||||
变换与过滤操作
|
||||
|
||||
分组聚合与统计摘要
|
||||
|
||||
分组排序、缩放与归一化
|
||||
|
||||
分组回归与中性化
|
||||
|
||||
分组插补与回填
|
||||
|
||||
对于每个推荐的类别,请按以下格式呈现:
|
||||
|
||||
重复完整上下文。
|
||||
|
||||
明确指出下一步选择的类别。
|
||||
|
||||
给出简要选择原因。
|
||||
|
||||
输出格式:
|
||||
|
||||
第 X 步可行类别:
|
||||
|
||||
第 X 步 选项 1:上下文:当前步骤:[序号] 当前数据字段:[描述] 之前步骤及所用类别:[列表] 当前数据状态:[详细描述之前步骤如何将数据转换到当前状态及其逻辑] 下一步选择:[类别名称] 原因:[解释]
|
||||
|
||||
第 X 步 选项 2:上下文:当前步骤:[序号] 当前数据字段:[描述] 之前步骤及所用类别:[列表] 当前数据状态:[详细描述之前步骤如何将数据转换到当前状态及其逻辑] 下一步选择:[类别名称] 原因:[解释]
|
||||
|
||||
...(继续列出所有可行选项)
|
||||
|
||||
额外说明:
|
||||
|
||||
仅推荐在当前数据状态及已完成的步骤下逻辑合理且有意义的类别。
|
||||
|
||||
若某类别在此步不适用,请勿列出。
|
||||
|
||||
解释需简洁明了。
|
||||
|
||||
除非特别要求,否则不要给出具体操作符。
|
||||
|
||||
每一步你都会收到如下输入:
|
||||
|
||||
上下文:
|
||||
|
||||
当前步骤:
|
||||
|
||||
当前数据字段:
|
||||
|
||||
之前步骤及所用类别:
|
||||
|
||||
当前数据状态:
|
||||
|
||||
收到输入后,请按上述格式回复。
|
||||
重要:选项之后不要添加任何总结、建议、理由或其他解释。严格按照上述格式提供选项即可。不要添加“最推荐选择”、“理由”、“最佳选择”或“是否继续”等部分。列出所有选项后立即结束。
|
||||
"""
|
||||
|
||||
@feature_engineering_bp.route('/api/get-default-system-prompt', methods=['GET'])
|
||||
def get_default_system_prompt():
|
||||
"""获取默认系统提示"""
|
||||
try:
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'default_system_prompt': get_default_system_prompt_text()
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取默认系统提示出错:{str(e)}")
|
||||
return jsonify({'success': False, 'error': f'未知错误:{str(e)}'}), 500
|
||||
Reference in New Issue
Block a user