我将为您创建一个"AI面试助手"程序,帮助应届生备战职场面试。这个程序将结合自然语言处理和模板生成技术。
项目结构
ai_interview_assistant/
├── main.py
├── interview_assistant.py
├── question_generator.py
├── template_manager.py
├── response_evaluator.py
├── utils.py
├── config.py
├── data/
│ ├── questions.json
│ ├── templates.json
│ └── examples.json
└── README.md
1. 配置文件 (config.py)
# -*- coding: utf-8 -*-
"""
面试助手配置文件
包含程序运行的各种配置参数
"""
import os
# 基础配置
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(BASE_DIR, 'data')
# 文件路径配置
QUESTIONS_FILE = os.path.join(DATA_DIR, 'questions.json')
TEMPLATES_FILE = os.path.join(DATA_DIR, 'templates.json')
EXAMPLES_FILE = os.path.join(DATA_DIR, 'examples.json')
# AI模型配置(简化版,实际项目中可接入真实AI API)
AI_CONFIG = {
'model_type': 'template_based', # 基于模板的生成方式
'max_response_length': 500,
'temperature': 0.7,
'top_k': 50,
'language': 'zh-CN'
}
# 面试类别配置
INTERVIEW_CATEGORIES = {
'technical': '技术面试',
'hr': '人力资源面试',
'behavioral': '行为面试',
'case': '案例面试',
'general': '综合面试'
}
# 模板配置
TEMPLATE_STYLES = {
'STAR': '情境(Situation)、任务(Task)、行动(Action)、结果(Result)',
'PREP': '观点(Point)、理由(Reason)、例子(Example)、观点重申(Point)',
'CAR': '情况(Context)、行动(Action)、结果(Result)',
'SOFT': '软技能回答模板'
}
# 评分标准
EVALUATION_CRITERIA = {
'content_quality': 0.3, # 内容质量
'structure': 0.25, # 结构完整性
'relevance': 0.25, # 相关性
'professionalism': 0.2 # 专业度
}
2. 工具函数 (utils.py)
# -*- coding: utf-8 -*-
"""
工具函数模块
提供各种辅助功能
"""
import json
import re
import random
from datetime import datetime
from typing import List, Dict, Any, Optional
def load_json_file(file_path: str) -> Dict[str, Any]:
"""
加载JSON文件
Args:
file_path: JSON文件路径
Returns:
解析后的字典数据
"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
return json.load(f)
except FileNotFoundError:
print(f"警告: 文件 {file_path} 未找到")
return {}
except json.JSONDecodeError:
print(f"错误: 文件 {file_path} 格式不正确")
return {}
def save_json_file(data: Dict[str, Any], file_path: str) -> bool:
"""
保存数据到JSON文件
Args:
data: 要保存的数据
file_path: 保存路径
Returns:
保存是否成功
"""
try:
# 确保目录存在
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
return True
except Exception as e:
print(f"保存文件失败: {e}")
return False
def clean_text(text: str) -> str:
"""
清理文本,去除多余空格和特殊字符
Args:
text: 原始文本
Returns:
清理后的文本
"""
if not text:
return ""
# 去除多余空格
text = re.sub(r'\s+', ' ', text.strip())
# 去除特殊字符(保留中文、英文、数字和基本标点)
text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9\s.,!?;:,。!?;:]', '', text)
return text
def extract_keywords(text: str, top_k: int = 5) -> List[str]:
"""
提取关键词(简化版实现)
Args:
text: 输入文本
top_k: 返回关键词数量
Returns:
关键词列表
"""
# 简单的词频统计
words = re.findall(r'[\u4e00-\u9fa5a-zA-Z]{2,}', text.lower())
# 过滤停用词(简化版)
stop_words = {'的', '了', '在', '是', '我', '有', '和', '就', '不', '人', '都', '一', '一个', '上', '也', '很', '到', '说', '要', '去', '你', '会', '着', '没有', '看', '好', '自己', '这'}
word_freq = {}
for word in words:
if word not in stop_words and len(word) > 1:
word_freq[word] = word_freq.get(word, 0) + 1
# 按频率排序并返回前k个
sorted_words = sorted(word_freq.items(), key=lambda x: x[1], reverse=True)
return [word for word, freq in sorted_words[:top_k]]
def generate_timestamp() -> str:
"""生成时间戳字符串"""
return datetime.now().strftime("%Y%m%d_%H%M%S")
def validate_email(email: str) -> bool:
"""验证邮箱格式"""
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return re.match(pattern, email) is not None
def validate_phone(phone: str) -> bool:
"""验证手机号格式(中国)"""
pattern = r'^1[3-9]\d{9}$'
return re.match(pattern, phone) is not None
3. 问题生成器 (question_generator.py)
# -*- coding: utf-8 -*-
"""
面试问题生成器
负责生成和管理各类面试问题
"""
import random
import json
from typing import List, Dict, Any
from .utils import load_json_file, clean_text, extract_keywords
class QuestionGenerator:
def __init__(self, questions_file: str = "data/questions.json"):
"""
初始化问题生成器
Args:
questions_file: 问题数据文件路径
"""
self.questions_data = load_json_file(questions_file)
self.current_category = "general"
def get_questions_by_category(self, category: str, limit: int = 10) -> List[Dict[str, Any]]:
"""
根据类别获取面试问题
Args:
category: 问题类别
limit: 返回问题数量
Returns:
问题列表
"""
if category not in self.questions_data:
category = "general"
questions = self.questions_data.get(category, [])
if limit > 0 and len(questions) > limit:
return random.sample(questions, limit)
return questions
def search_questions(self, keyword: str, category: str = "all") -> List[Dict[str, Any]]:
"""
根据关键词搜索问题
Args:
keyword: 搜索关键词
category: 问题类别,'all'表示所有类别
Returns:
匹配的问题列表
"""
results = []
search_term = keyword.lower()
categories_to_search = [category] if category != "all" else self.questions_data.keys()
for cat in categories_to_search:
if cat not in self.questions_data:
continue
for question in self.questions_data[cat]:
question_text = question.get('question', '').lower()
if search_term in question_text or search_term in question.get('keywords', []):
results.append({
**question,
'category': cat
})
return results
def generate_custom_question(self, job_position: str, company_type: str = "tech") -> Dict[str, Any]:
"""
根据职位和公司类型生成定制问题
Args:
job_position: 职位名称
company_type: 公司类型
Returns:
生成的问题
"""
templates = [
f"请谈谈你对{job_position}这个职位的理解,以及为什么认为自己适合这个岗位?",
f"在{company_type}公司工作,你认为最重要的能力是什么?",
f"描述一次你在学习或实践中解决{job_position}相关问题的经历。",
f"如果让你设计一个{job_position}的工作流程,你会如何规划?",
f"你认为{job_position}在未来3-5年内会有什么发展趋势?"
]
question_text = random.choice(templates)
keywords = extract_keywords(question_text)
return {
'question': question_text,
'category': 'custom',
'difficulty': 'medium',
'keywords': keywords,
'type': 'open_ended',
'generated_at': self._get_current_time()
}
def get_interview_scenario(self, scenario_type: str = "full_interview") -> List[Dict[str, Any]]:
"""
获取完整面试场景的问题组合
Args:
scenario_type: 面试场景类型
Returns:
面试问题序列
"""
scenarios = {
'full_interview': [
{'category': 'hr', 'count': 3},
{'category': 'technical', 'count': 4},
{'category': 'behavioral', 'count': 3}
],
'technical_focus': [
{'category': 'technical', 'count': 6},
{'category': 'behavioral', 'count': 2}
],
'entry_level': [
{'category': 'hr', 'count': 4},
{'category': 'behavioral', 'count': 4},
{'category': 'general', 'count': 2}
]
}
if scenario_type not in scenarios:
scenario_type = 'full_interview'
selected_scenario = scenarios[scenario_type]
interview_questions = []
for item in selected_scenario:
category = item['category']
count = item['count']
questions = self.get_questions_by_category(category, count)
for q in questions:
q['scenario'] = scenario_type
interview_questions.append(q)
return interview_questions
def analyze_question_difficulty(self, question: str) -> str:
"""
分析问题难度(简化版)
Args:
question: 问题文本
Returns:
难度等级
"""
# 基于关键词和问题长度简单判断
length = len(question)
complex_keywords = ['设计', '架构', '策略', '分析', '评估', '优化', '创新', '领导']
keyword_count = sum(1 for kw in complex_keywords if kw in question)
if length > 100 or keyword_count >= 2:
return 'hard'
elif length > 50 or keyword_count >= 1:
return 'medium'
else:
return 'easy'
def _get_current_time(self) -> str:
"""获取当前时间字符串"""
from datetime import datetime
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
4. 模板管理器 (template_manager.py)
# -*- coding: utf-8 -*-
"""
回答模板管理器
提供各种面试回答模板和结构指导
"""
import json
from typing import Dict, List, Any
from .utils import load_json_file, clean_text
class TemplateManager:
def __init__(self, templates_file: str = "data/templates.json"):
"""
初始化模板管理器
Args:
templates_file: 模板数据文件路径
"""
self.templates_data = load_json_file(templates_file)
self.current_template_style = "STAR"
def get_template(self, template_name: str) -> Dict[str, Any]:
"""
获取指定模板
Args:
template_name: 模板名称
Returns:
模板信息
"""
return self.templates_data.get(template_name, {})
def get_all_templates(self) -> Dict[str, Dict[str, Any]]:
"""
获取所有可用模板
Returns:
所有模板字典
"""
return self.templates_data
def generate_star_response(self, situation: str, task: str, action: str, result: str) -> str:
"""
生成STAR格式回答
Args:
situation: 情境描述
task: 任务描述
action: 行动描述
result: 结果描述
Returns:
格式化回答
"""
template = """
【情境】{situation}
【任务】{task}
【行动】{action}
【结果】{result}
""".strip()
return template.format(
situation=clean_text(situation),
task=clean_text(task),
action=clean_text(action),
result=clean_text(result)
)
def generate_prep_response(self, point: str, reason: str, example: str, point_restate: str) -> str:
"""
生成PREP格式回答
Args:
point: 观点
reason: 理由
example: 例子
point_restate: 重申观点
Returns:
格式化回答
"""
template = """
【观点】{point}
【理由】{reason}
【例子】{example}
【重申观点】{point_restate}
""".strip()
return template.format(
point=clean_text(point),
reason=clean_text(reason),
example=clean_text(example),
point_restate=clean_text(point_restate)
)
def generate_car_response(self, context: str, action: str, result: str) -> str:
"""
生成CAR格式回答
Args:
context: 情况描述
action: 行动描述
result: 结果描述
Returns:
格式化回答
"""
template = """
【情况】{context}
【行动】{action}
【结果】{result}
""".strip()
return template.format(
context=clean_text(context),
action=clean_text(action),
result=clean_text(result)
)
def generate_soft_skill_response(self, skill: str, experience: str, learning: str, application: str) -> str:
"""
生成软技能回答模板
Args:
skill: 技能名称
experience: 相关经验
learning: 学到的东西
application: 未来应用
Returns:
格式化回答
"""
template = """
关于{skill}这个软技能:
【相关经验】{experience}
【心得体会】{learning}
【未来应用】{application}
我认为这个技能在未来的工作中会持续发挥重要作用。
""".strip()
return template.format(
skill=skill,
experience=clean_text(experience),
learning=clean_text(learning),
application=clean_text(application)
)
def suggest_template_for_question(self, question: str) -> str:
"""
根据问题推荐合适的模板
Args:
question: 面试问题
Returns:
推荐的模板名称
"""
question_lower = question.lower()
# 基于关键词推荐模板
if any(word in question_lower for word in ['经历', '经验', '项目', '例子', '举例']):
return 'STAR'
elif any(word in question_lower for word in ['看法', '认为', '觉得', '观点']):
return 'PREP'
elif any(word in question_lower for word in ['情况', '遇到', '面对', '处理']):
return 'CAR'
elif any(word in question_lower for word in ['团队合作', '沟通', '领导力', '解决问题']):
return 'SOFT_SKILL'
else:
return 'STAR' # 默认推荐STAR模板
def customize_template(self, template_content: str, personal_info: Dict[str, str]) -> str:
"""
根据个人信息定制模板
Args:
template_content: 模板内容
personal_info: 个人信息
Returns:
定制化后的模板
"""
customized = template_content
# 替换个人信息占位符
replacements = {
'{name}': personal_info.get('name', '我'),
'{major}': personal_info.get('major', '我的专业'),
'{university}': personal_info.get('university', '我的大学'),
'{experience}': personal_info.get('experience', '相关经验'),
'{strength}': personal_info.get('strength', '我的优势'),
'{career_goal}': personal_info.get('career_goal', '我的职业目标')
}
for placeholder, value in replacements.items():
customized = customized.replace(placeholder, value)
return customized
5. 回答评估器 (response_evaluator.py)
# -*- coding: utf-8 -*-
"""
回答评估器
评估面试回答的质量和相关性
"""
import re
from typing import Dict, List, Any, Tuple
from .utils import extract_keywords, clean_text
class ResponseEvaluator:
def __init__(self):
"""初始化回答评估器"""
self.evaluation_criteria = {
'content_quality': 0.3, # 内容质量
'structure': 0.25, # 结构完整性
'relevance': 0.25, # 相关性
'professionalism': 0.2 # 专业度
}
# 正面词汇库
self.positive_words = [
'成功', '提升', '改善', '优化', '创新', '领导', '协调', '解决',
'负责', '参与', '学习', '成长', '进步', '效率', '质量', '成果',
'优秀', '出色', '满意', '认可', '肯定', '信任', '支持', '合作'
]
# 负面词汇库
self.negative_words = [
'失败', '错误', '问题', '困难', '挫折', '不足', '缺点', '遗憾',
'抱歉', '不知道', '不太了解', '可能', '也许', '大概', '差不多'
]
def evaluate_response(self, question: str, response: str, keywords: List[str] = None) -> Dict[str, Any]:
"""
评估面试回答
Args:
question: 面试问题
response: 回答内容
keywords: 关键词列表(可选)
Returns:
评估结果
"""
if not response or len(response.strip()) < 10:
return {
'overall_score': 0,
'scores': {k: 0 for k in self.evaluation_criteria.keys()},
'feedback': '回答内容过短,请提供更详细的回答。',
'suggestions': ['增加回答的具体内容', '提供更多细节和例子']
}
# 各项评分
content_score = self._evaluate_content_quality(response)
structure_score = self._evaluate_structure(response)
relevance_score = self._evaluate_relevance(question, response, keywords)
professionalism_score = self._evaluate_professionalism(response)
# 计算加权总分
overall_score = (
content_score * self.evaluation_criteria['content_quality'] +
structure_score * self.evaluation_criteria['structure'] +
relevance_score * self.evaluation_criteria['relevance'] +
professionalism_score * self.evaluation_criteria['professionalism']
)
# 生成反馈和建议
feedback, suggestions = self._generate_feedback(
content_score, structure_score, relevance_score, professionalism_score, response
)
return {
'overall_score': round(overall_score, 2),
'scores': {
'content_quality': round(content_score, 2),
'structure': round(structure_score, 2),
'relevance': round(relevance_score, 2),
'professionalism': round(professionalism_score, 2)
},
'feedback': feedback,
'suggestions': suggestions,
'word_count': len(response),
'has_example': self._has_concrete_example(response)
}
def _evaluate_content_quality(self, response: str) -> float:
"""
评估内容质量
Args:
response: 回答内容
Returns:
内容质量分数 (0-100)
"""
score = 60 # 基础分
# 长度评估
word_count = len(response)
if word_count > 200:
score += 20
elif word_count > 100:
score += 10
# 具体内容评估
if self._has_concrete_example(response):
score += 15
# 数字和具体数据
numbers = re.findall(r'\d+', response)
if len(numbers) >= 3:
score += 10
# 积极词汇
positive_count = sum(1 for word in self.positive_words if word in response)
score += min(positive_count * 2, 15)
# 避免负面词汇
negative_count = sum(1 for word in self.negative_words if word in response)
score -= negative_count * 5
return max(0, min(100, score))
def _evaluate_structure(self, response: str) -> float:
"""
评估回答结构
Args:
response: 回答内容
Returns:
结构分数 (0-100)
"""
score = 50 # 基础分
# 段落结构
paragraphs = response.split('\n\n')
if len(paragraphs) >= 3:
score += 20
# 逻辑连接词
connectives = ['首先', '其次', '然后', '接着', '最后', '因此', '所以', '然而', '但是', '而且']
connective_count = sum(1 for word in connectives if word in response)
score += min(connective_count * 5, 20)
# 开头和结尾
has_opening = any(word in response[:50] for word in ['我认为', '我觉得', '在我看来', '对于这个问题'])
has_closing = any(word in response[-50:] for word in ['总结', '总之', '综上所述', '希望', '期待'])
if has_opening:
score += 5
if has_closing:
score += 5
return max(0, min(100, score))
def _evaluate_relevance(self, question: str, response: str, keywords: List[str] = None) -> float:
"""
评估回答相关性
Args:
question: 面试问题
response: 回答内容
keywords: 关键词列表
Returns:
相关性分数 (0-100)
"""
score = 70 # 基础分
# 提取问题关键词
if not keywords:
keywords = extract_keywords(question, top_k=5)
# 检查关键词覆盖
response_lower = response.lower()
covered_keywords = [kw for kw in keywords if kw.lower() in response_lower]
coverage_rate = len(covered_keywords) / len(keywords) if
关注我,有更多实用程序等着你!