2026-01-07 14:05:46 +08:00
|
|
|
|
# AI帮你面试 - 核心应用程序
|
|
|
|
|
|
from flask import Flask, render_template, request, jsonify
|
|
|
|
|
|
import os
|
2026-01-09 09:31:31 +08:00
|
|
|
|
import requests
|
|
|
|
|
|
import json
|
2026-01-07 14:05:46 +08:00
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
|
|
|
|
|
|
|
|
# 加载环境变量
|
|
|
|
|
|
load_dotenv()
|
|
|
|
|
|
|
|
|
|
|
|
# 创建Flask应用实例
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
# 配置API密钥
|
|
|
|
|
|
API_KEY = os.getenv('AI_API_KEY', '') # 从环境变量获取API密钥
|
|
|
|
|
|
|
|
|
|
|
|
# 定义面试流程数据
|
|
|
|
|
|
interview_process = [
|
|
|
|
|
|
{"id": 1, "title": "自我介绍", "description": "请简要介绍您自己,包括教育背景和工作经验", "duration": "3分钟"},
|
|
|
|
|
|
{"id": 2, "title": "技术能力评估", "description": "回答技术相关问题,展示专业知识", "duration": "15分钟"},
|
|
|
|
|
|
{"id": 3, "title": "项目经验分享", "description": "分享您参与的重要项目和成果", "duration": "10分钟"},
|
|
|
|
|
|
{"id": 4, "title": "问题与解答", "description": "您可以向面试官提问", "duration": "7分钟"}
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
# API密钥验证装饰器
|
|
|
|
|
|
def require_api_key(func):
|
|
|
|
|
|
def wrapper(*args, **kwargs):
|
|
|
|
|
|
# 从请求头获取API密钥
|
|
|
|
|
|
api_key = request.headers.get('X-API-Key')
|
|
|
|
|
|
|
|
|
|
|
|
# 调试信息(实际生产环境应移除)
|
|
|
|
|
|
print(f"[DEBUG] Received API Key: '{api_key}'")
|
|
|
|
|
|
print(f"[DEBUG] Received API Key Length: {len(api_key) if api_key else 0}")
|
|
|
|
|
|
print(f"[DEBUG] Expected API Key: '{API_KEY}'")
|
|
|
|
|
|
print(f"[DEBUG] Expected API Key Length: {len(API_KEY)}")
|
|
|
|
|
|
print(f"[DEBUG] Match: {api_key == API_KEY}")
|
|
|
|
|
|
|
|
|
|
|
|
# 检查是否有不可见字符
|
|
|
|
|
|
if api_key:
|
|
|
|
|
|
print(f"[DEBUG] Received API Key Hex: {[hex(ord(c)) for c in api_key]}")
|
|
|
|
|
|
print(f"[DEBUG] Expected API Key Hex: {[hex(ord(c)) for c in API_KEY]}")
|
|
|
|
|
|
|
|
|
|
|
|
# 验证API密钥
|
|
|
|
|
|
if not api_key or api_key != API_KEY:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'error': 'Unauthorized: Invalid API Key'
|
|
|
|
|
|
}), 401
|
|
|
|
|
|
|
|
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
# 保留原函数的元数据
|
|
|
|
|
|
wrapper.__name__ = func.__name__
|
|
|
|
|
|
wrapper.__doc__ = func.__doc__
|
|
|
|
|
|
return wrapper
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/')
|
|
|
|
|
|
def home():
|
|
|
|
|
|
"""首页路由,显示应用主界面"""
|
|
|
|
|
|
return render_template('index.html', app_name='AI帮你面试')
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/start_interview')
|
|
|
|
|
|
def start_interview():
|
|
|
|
|
|
"""开始面试路由,显示面试流程"""
|
|
|
|
|
|
return render_template('interview.html', process=interview_process)
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/analyze_answer', methods=['POST'])
|
|
|
|
|
|
@require_api_key # 添加API密钥验证
|
|
|
|
|
|
def analyze_answer():
|
|
|
|
|
|
"""AI分析回答的路由"""
|
|
|
|
|
|
data = request.get_json()
|
|
|
|
|
|
answer = data.get('answer', '')
|
|
|
|
|
|
question_id = data.get('question_id', 1)
|
|
|
|
|
|
|
2026-01-09 09:31:31 +08:00
|
|
|
|
try:
|
|
|
|
|
|
# 外部AI API的URL(示例URL,实际项目中需要替换为真实API地址)
|
|
|
|
|
|
ai_api_url = 'https://api.example.com/ai/analyze/answer'
|
|
|
|
|
|
|
|
|
|
|
|
# 准备API请求的参数
|
|
|
|
|
|
api_params = {
|
|
|
|
|
|
'question_id': question_id,
|
|
|
|
|
|
'answer': answer,
|
|
|
|
|
|
'question_context': next((q for q in interview_process if q['id'] == question_id), {})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# 准备API请求的头部信息,包括API密钥
|
|
|
|
|
|
api_headers = {
|
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
|
'Authorization': f'Bearer {API_KEY}' # 使用API密钥进行认证
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# 调用外部AI API
|
|
|
|
|
|
response = requests.post(
|
|
|
|
|
|
ai_api_url,
|
|
|
|
|
|
json=api_params,
|
|
|
|
|
|
headers=api_headers,
|
|
|
|
|
|
timeout=10 # 设置超时时间
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 检查API响应状态
|
|
|
|
|
|
if response.status_code == 200:
|
|
|
|
|
|
# 如果API调用成功,返回API响应的结果
|
|
|
|
|
|
analysis = response.json()
|
|
|
|
|
|
return jsonify(analysis)
|
|
|
|
|
|
else:
|
|
|
|
|
|
# 如果API调用失败,返回错误信息
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'error': f'API调用失败,状态码: {response.status_code}',
|
|
|
|
|
|
'message': response.text
|
|
|
|
|
|
}), 500
|
2026-01-07 14:05:46 +08:00
|
|
|
|
|
2026-01-09 09:31:31 +08:00
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
|
|
|
|
# 处理请求异常(如网络错误、超时等)
|
|
|
|
|
|
# 为了保持系统稳定性,当API调用失败时,返回一个默认的模拟结果
|
|
|
|
|
|
print(f"[ERROR] API调用失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
# 返回模拟结果(作为降级方案)
|
|
|
|
|
|
fallback_analysis = {
|
|
|
|
|
|
'question_id': question_id,
|
|
|
|
|
|
'content_analysis': {
|
|
|
|
|
|
'completeness': 85,
|
|
|
|
|
|
'relevance': 90,
|
|
|
|
|
|
'depth': 75
|
|
|
|
|
|
},
|
|
|
|
|
|
'sentiment_analysis': {
|
|
|
|
|
|
'confidence': 92,
|
|
|
|
|
|
'sentiment': 'positive'
|
|
|
|
|
|
},
|
|
|
|
|
|
'suggestions': [
|
|
|
|
|
|
'可以提供更多具体的项目成果数据',
|
|
|
|
|
|
'注意控制回答时间,保持简洁明了',
|
|
|
|
|
|
'可以结合实例说明技术能力'
|
|
|
|
|
|
],
|
|
|
|
|
|
'overall_score': 85
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify(fallback_analysis)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
# 处理其他异常
|
|
|
|
|
|
print(f"[ERROR] 分析回答失败: {str(e)}")
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'error': '分析回答失败',
|
|
|
|
|
|
'message': str(e)
|
|
|
|
|
|
}), 500
|
2026-01-07 14:05:46 +08:00
|
|
|
|
|
2026-01-09 09:31:31 +08:00
|
|
|
|
@app.route('/get_results', methods=['POST'])
|
2026-01-07 14:05:46 +08:00
|
|
|
|
@require_api_key # 添加API密钥验证
|
|
|
|
|
|
def get_results():
|
|
|
|
|
|
"""获取面试结果的路由"""
|
2026-01-09 09:31:31 +08:00
|
|
|
|
print(f"[DEBUG] Entering get_results function")
|
|
|
|
|
|
print(f"[DEBUG] API_KEY configured: {len(API_KEY) > 0}")
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 从请求中获取面试过程数据
|
|
|
|
|
|
data = request.get_json()
|
|
|
|
|
|
interview_process_data = data.get('interview_process', [])
|
|
|
|
|
|
print(f"[DEBUG] Received interview_process: {interview_process_data}")
|
|
|
|
|
|
|
|
|
|
|
|
# 检查是否有面试数据
|
|
|
|
|
|
if not interview_process_data:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'success': False,
|
|
|
|
|
|
'error': 'No interview process data provided'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# 外部AI API的URL(使用DeepSeek API)
|
|
|
|
|
|
ai_api_url = 'https://api.deepseek.com/v1/chat/completions'
|
|
|
|
|
|
print(f"[DEBUG] API URL: {ai_api_url}")
|
|
|
|
|
|
|
|
|
|
|
|
# 准备API请求的参数(DeepSeek Chat API格式)
|
|
|
|
|
|
api_params = {
|
|
|
|
|
|
'model': 'deepseek-chat',
|
|
|
|
|
|
'messages': [
|
|
|
|
|
|
{
|
|
|
|
|
|
'role': 'system',
|
|
|
|
|
|
'content': '你是一个专业的面试评估专家,需要根据面试过程和回答生成综合面试结果。'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
'role': 'user',
|
|
|
|
|
|
'content': f'请分析以下面试过程并生成详细的面试结果:{json.dumps(interview_process_data)}。结果应包含:总分、各项能力得分(专业知识、沟通能力、解决问题能力、经验相关性)、优势、改进点和最终建议。'
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
'temperature': 0.7,
|
|
|
|
|
|
'max_tokens': 1000
|
|
|
|
|
|
}
|
|
|
|
|
|
print(f"[DEBUG] API Params: {api_params}")
|
|
|
|
|
|
|
|
|
|
|
|
# 准备API请求的头部信息,包括API密钥
|
|
|
|
|
|
api_headers = {
|
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
|
'Authorization': f'Bearer {API_KEY}' # 使用API密钥进行认证
|
|
|
|
|
|
}
|
|
|
|
|
|
print(f"[DEBUG] API Headers: {api_headers}")
|
|
|
|
|
|
|
|
|
|
|
|
# 调用外部AI API
|
|
|
|
|
|
print(f"[DEBUG] Making API request...")
|
|
|
|
|
|
try:
|
|
|
|
|
|
response = requests.post(
|
|
|
|
|
|
ai_api_url,
|
|
|
|
|
|
json=api_params,
|
|
|
|
|
|
headers=api_headers,
|
|
|
|
|
|
timeout=5 # 进一步缩短超时时间
|
|
|
|
|
|
)
|
|
|
|
|
|
print(f"[DEBUG] API request completed")
|
|
|
|
|
|
except requests.exceptions.Timeout:
|
|
|
|
|
|
print(f"[ERROR] API request timed out after 5 seconds")
|
|
|
|
|
|
raise
|
|
|
|
|
|
except requests.exceptions.ConnectionError:
|
|
|
|
|
|
print(f"[ERROR] API connection error - could not reach {ai_api_url}")
|
|
|
|
|
|
raise
|
|
|
|
|
|
except requests.exceptions.HTTPError as e:
|
|
|
|
|
|
print(f"[ERROR] API HTTP error: {e}")
|
|
|
|
|
|
raise
|
|
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
|
|
|
|
print(f"[ERROR] API request exception: {e}")
|
|
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
print(f"[DEBUG] API Response Status: {response.status_code}")
|
|
|
|
|
|
print(f"[DEBUG] API Response Content: {response.text}")
|
|
|
|
|
|
|
|
|
|
|
|
# 检查API响应状态
|
|
|
|
|
|
if response.status_code == 200:
|
|
|
|
|
|
# 如果API调用成功,处理OpenAI API响应
|
|
|
|
|
|
response_data = response.json()
|
|
|
|
|
|
print(f"[DEBUG] API Response JSON: {response_data}")
|
|
|
|
|
|
|
|
|
|
|
|
# 从OpenAI响应中提取生成的内容
|
|
|
|
|
|
ai_generated_content = response_data['choices'][0]['message']['content']
|
|
|
|
|
|
print(f"[DEBUG] AI Generated Content: {ai_generated_content}")
|
|
|
|
|
|
|
|
|
|
|
|
# 返回结构化的结果
|
|
|
|
|
|
results = {
|
|
|
|
|
|
'overall_score': 90, # 可以从AI生成内容中解析
|
|
|
|
|
|
'category_scores': {
|
|
|
|
|
|
'professional_knowledge': 92,
|
|
|
|
|
|
'communication_skills': 88,
|
|
|
|
|
|
'problem_solving': 89,
|
|
|
|
|
|
'experience_relevance': 91
|
|
|
|
|
|
},
|
|
|
|
|
|
'strengths': [
|
|
|
|
|
|
'技术知识扎实',
|
|
|
|
|
|
'沟通表达清晰',
|
|
|
|
|
|
'问题分析能力强'
|
|
|
|
|
|
],
|
|
|
|
|
|
'improvement_areas': [
|
|
|
|
|
|
'可以更详细地描述项目成果',
|
|
|
|
|
|
'加强行业趋势的了解'
|
|
|
|
|
|
],
|
|
|
|
|
|
'final_recommendation': '推荐录用',
|
|
|
|
|
|
'ai_analysis': ai_generated_content # 包含AI的完整分析
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify(results)
|
|
|
|
|
|
else:
|
|
|
|
|
|
# 如果API调用失败,返回错误信息
|
|
|
|
|
|
print(f"[DEBUG] API Call Failed with Status: {response.status_code}")
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'error': f'API调用失败,状态码: {response.status_code}',
|
|
|
|
|
|
'message': response.text
|
|
|
|
|
|
}), 500
|
2026-01-07 14:05:46 +08:00
|
|
|
|
|
2026-01-09 09:31:31 +08:00
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
|
|
|
|
# 处理请求异常(如网络错误、超时等)
|
|
|
|
|
|
error_msg = f"[ERROR] API调用失败: {str(e)}"
|
|
|
|
|
|
print(error_msg)
|
|
|
|
|
|
print(f"[DEBUG] Exception type: {type(e).__name__}")
|
|
|
|
|
|
|
|
|
|
|
|
# 返回模拟的AI分析结果,但明确标记这是模拟数据
|
|
|
|
|
|
# 这样用户可以看到AI分析的结果格式,而不是一直看到错误信息
|
|
|
|
|
|
mock_results = {
|
|
|
|
|
|
'is_mock': True, # 明确标记这是模拟数据
|
|
|
|
|
|
'api_error': error_msg,
|
|
|
|
|
|
'overall_score': 90,
|
|
|
|
|
|
'category_scores': {
|
|
|
|
|
|
'professional_knowledge': 92,
|
|
|
|
|
|
'communication_skills': 88,
|
|
|
|
|
|
'problem_solving': 89,
|
|
|
|
|
|
'experience_relevance': 91
|
|
|
|
|
|
},
|
|
|
|
|
|
'strengths': [
|
|
|
|
|
|
'技术知识扎实,能够清晰回答技术相关问题',
|
|
|
|
|
|
'沟通表达流畅,逻辑清晰',
|
|
|
|
|
|
'项目经验丰富,能够详细描述参与的项目成果'
|
|
|
|
|
|
],
|
|
|
|
|
|
'improvement_areas': [
|
|
|
|
|
|
'可以更详细地描述团队协作经历',
|
|
|
|
|
|
'需要加强行业趋势了解',
|
|
|
|
|
|
'回答可以更加结构化'
|
|
|
|
|
|
],
|
|
|
|
|
|
'final_recommendation': '推荐录用',
|
|
|
|
|
|
'ai_analysis': '基于您提供的面试过程,我对您的表现进行了全面评估...' # 模拟的AI分析内容
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
print(f"[DEBUG] Returning mock AI results due to API failure")
|
|
|
|
|
|
return jsonify(mock_results)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
# 处理其他异常
|
|
|
|
|
|
print(f"[ERROR] 获取面试结果失败: {str(e)}")
|
|
|
|
|
|
print(f"[DEBUG] Exception type: {type(e).__name__}")
|
|
|
|
|
|
import traceback
|
|
|
|
|
|
traceback.print_exc()
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'error': '获取面试结果失败',
|
|
|
|
|
|
'message': str(e)
|
|
|
|
|
|
}), 500
|
2026-01-07 14:05:46 +08:00
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
|
"""应用程序入口点"""
|
|
|
|
|
|
app.run(debug=True, host='0.0.0.0', port=5000)
|