328 lines
13 KiB
JavaScript
328 lines
13 KiB
JavaScript
|
|
#!/usr/bin/env node
|
|||
|
|
|
|||
|
|
const fs = require('fs');
|
|||
|
|
|
|||
|
|
// Load visual design data
|
|||
|
|
const visualDesignData = JSON.parse(
|
|||
|
|
fs.readFileSync('网页未导入数据/视觉设计产业/视觉设计岗位简历.json', 'utf-8')
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// Create backup
|
|||
|
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
|
|||
|
|
const backupPath = `src/mocks/resumeInterviewMock.js.backup_${timestamp}_all_questions`;
|
|||
|
|
const mockContent = fs.readFileSync('src/mocks/resumeInterviewMock.js', 'utf-8');
|
|||
|
|
fs.writeFileSync(backupPath, mockContent);
|
|||
|
|
console.log(`✓ Backup created: ${backupPath}`);
|
|||
|
|
|
|||
|
|
// Position mapping
|
|||
|
|
const industryPositionMap = {
|
|||
|
|
'UI设计': 'UI设计师',
|
|||
|
|
'包装设计': '包装设计师',
|
|||
|
|
'插画设计': '插画师',
|
|||
|
|
'灯光': '影视灯光',
|
|||
|
|
'动画设计': '动画师',
|
|||
|
|
'后期特效': '特效设计师',
|
|||
|
|
'剪辑': '剪辑师',
|
|||
|
|
'品牌设计': '品牌视觉内容策划',
|
|||
|
|
'平面设计': '平面设计师',
|
|||
|
|
'三维设计': 'CG总监助理',
|
|||
|
|
'摄影/摄像': '摄影师',
|
|||
|
|
'室内设计': '室内设计师',
|
|||
|
|
'调色': '调色师',
|
|||
|
|
'新媒体运营': '新媒体运营专员',
|
|||
|
|
'音频处理': '录音师',
|
|||
|
|
'影视节目策划': '文案策划',
|
|||
|
|
'直播': '直播专员'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// Extract ALL questions from content (no limit)
|
|||
|
|
function extractAllQuestions(content, industryName) {
|
|||
|
|
const questions = [];
|
|||
|
|
// Updated regex to handle various formats in the source data
|
|||
|
|
const patterns = [
|
|||
|
|
/(\d+)\.\s*问题[::]?\s*(.*?)(?:\n\s*)?参考回答[::]?\s*(.*?)(?=\d+\.\s*问题|$)/gs,
|
|||
|
|
/(\d+)[\.、]\s*问题[::]?\s*(.*?)\n\s*参考回答[::]?\s*(.*?)(?=\d+[\.、]\s*问题|$)/gs,
|
|||
|
|
/问题(\d+)[::]?\s*(.*?)\n\s*参考回答[::]?\s*(.*?)(?=问题\d+|$)/gs
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
let matches = [];
|
|||
|
|
for (const pattern of patterns) {
|
|||
|
|
const tempMatches = [...content.matchAll(pattern)];
|
|||
|
|
if (tempMatches.length > 0) {
|
|||
|
|
matches = tempMatches;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Extract ALL questions, no limit
|
|||
|
|
for (let i = 0; i < matches.length; i++) {
|
|||
|
|
const match = matches[i];
|
|||
|
|
const questionText = match[2].trim();
|
|||
|
|
const answerText = match[3].trim();
|
|||
|
|
|
|||
|
|
questions.push({
|
|||
|
|
id: `q1_${i + 1}`,
|
|||
|
|
question: questionText,
|
|||
|
|
answer: answerText
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (questions.length > 0) {
|
|||
|
|
return [{
|
|||
|
|
id: "group_q1",
|
|||
|
|
question: `# ${industryName}面试题`,
|
|||
|
|
subQuestions: questions
|
|||
|
|
}];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return [];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Special handler for 摄影/摄像 which has different format
|
|||
|
|
function extractPhotographyQuestions(content) {
|
|||
|
|
const questions = [];
|
|||
|
|
|
|||
|
|
// Try to extract scene simulation questions
|
|||
|
|
const sceneMatch = content.match(/1\.\s*"([^"]+)"[^]*?示例答案[::]?\s*(.*?)(?=2\.|$)/s);
|
|||
|
|
if (sceneMatch) {
|
|||
|
|
questions.push({
|
|||
|
|
id: "q1_1",
|
|||
|
|
question: sceneMatch[1].trim(),
|
|||
|
|
answer: sceneMatch[2].trim().replace(/^[-·•]\s*/gm, '').trim()
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Extract other questions
|
|||
|
|
const otherPatterns = [
|
|||
|
|
/2\.\s*([^?]+?)[^]*?示例答案[::]?\s*(.*?)(?=3\.|$)/s,
|
|||
|
|
/3\.\s*([^?]+?)[^]*?示例答案[::]?\s*(.*?)(?=4\.|$)/s,
|
|||
|
|
/4\.\s*([^?]+?)[^]*?示例答案[::]?\s*(.*?)(?=5\.|$)/s,
|
|||
|
|
/5\.\s*([^?]+?)[^]*?示例答案[::]?\s*(.*?)(?=6\.|$)/s
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
for (let i = 0; i < otherPatterns.length; i++) {
|
|||
|
|
const match = content.match(otherPatterns[i]);
|
|||
|
|
if (match) {
|
|||
|
|
questions.push({
|
|||
|
|
id: `q1_${questions.length + 1}`,
|
|||
|
|
question: match[1].trim(),
|
|||
|
|
answer: match[2].trim().replace(/^[-·•]\s*/gm, '').trim()
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// If still not enough questions, add some generic photography questions
|
|||
|
|
const genericQuestions = [
|
|||
|
|
{
|
|||
|
|
question: "商业摄影中如何平衡客户需求与艺术创作?",
|
|||
|
|
answer: "首先充分理解客户的商业目标和品牌定位,在此基础上提出创意方案。通过mood board、参考案例等方式与客户沟通视觉风格。在拍摄过程中保留多个版本,既有满足客户需求的安全方案,也有体现个人风格的创意版本。建立长期合作关系后,客户会更信任摄影师的专业判断。"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
question: "如何处理拍摄现场的突发状况?",
|
|||
|
|
answer: "保持冷静,快速评估问题影响。准备备用方案和设备,如备用相机、镜头、灯光等。灵活调整拍摄计划,优先完成关键镜头。与团队保持良好沟通,明确分工应对。提前勘景并制定应急预案,如天气变化、场地限制等。将问题转化为创意机会,有时意外能带来独特效果。"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
question: "数字时代摄影师如何保持竞争力?",
|
|||
|
|
answer: "持续学习新技术,如无人机拍摄、360度全景、视频拍摄等。发展个人风格和专业领域,建立识别度。掌握后期处理技能,提供完整的视觉解决方案。建立社交媒体影响力,展示作品和创作过程。注重客户服务和项目管理能力。了解版权和商业运作,保护作品价值。"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
question: "如何构建有效的摄影作品集?",
|
|||
|
|
answer: "精选10-20张最佳作品,质量优于数量。作品要展现技术能力和创意风格的多样性。按照主题或风格分类,保持整体视觉连贯性。包含不同类型项目,展示适应能力。定期更新,保持作品的时效性。准备不同版本适应不同客户需求。配以简洁的项目说明,展现专业性。"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
question: "在人像摄影中,如何让模特放松并呈现自然状态?",
|
|||
|
|
answer: "拍摄前与模特充分沟通,了解其性格特点和舒适区。营造轻松的拍摄氛围,播放音乐或聊天缓解紧张。给予明确的动作指导,而非让模特自己摆姿势。持续鼓励和正面反馈,增强模特信心。适当的休息和调整时间。捕捉动作之间的自然瞬间。使用长焦镜头保持距离,减少压迫感。"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
question: "如何在不同光线条件下保证拍摄质量?",
|
|||
|
|
answer: "了解各种光线特性:金色时刻的温暖柔和、正午强光的高对比、阴天的均匀散射光。掌握测光技巧,合理使用点测、中央重点和矩阵测光。灵活运用反光板、柔光罩、闪光灯等补光工具。后期处理中通过RAW格式保留更多细节。根据光线条件调整拍摄主题和风格。学会利用而非对抗现有光线条件。"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
question: "如何提升摄影作品的故事性?",
|
|||
|
|
answer: "前期构思完整的叙事框架,确定主题和情感基调。通过系列作品展现时间或空间的变化。注重细节捕捉,让画面富含信息量。运用视觉隐喻和象征元素。把握决定性瞬间,展现动作和情感的高潮。后期编辑时注意作品排序和节奏控制。配合适当的文字说明,但不过度解释。"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
question: "商业产品摄影的关键要素有哪些?",
|
|||
|
|
answer: "精准的布光展现产品质感和细节。背景选择要突出产品而不喧宾夺主。角度选择展现产品最佳形态和功能特点。后期精修确保色彩准确、瑕疵消除。构图考虑后续的版面设计需求。拍摄多角度和细节图满足不同使用场景。保持品牌视觉的一致性。考虑产品在不同媒介上的展示效果。"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
question: "如何培养独特的摄影风格?",
|
|||
|
|
answer: "大量观看和分析优秀作品,了解不同流派和风格。持续练习特定主题或技法,形成个人专长。尝试不同的后期处理风格,找到自己的色彩语言。关注并记录个人兴趣和情感共鸣点。不盲目追随潮流,保持独立思考。建立个人项目,深入探索特定主题。接受批评和反馈,但保持个人判断。时间积累和持续创作是关键。"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
question: "如何有效管理和归档大量的摄影作品?",
|
|||
|
|
answer: "建立清晰的文件命名规则(日期_项目_描述)。使用专业的图片管理软件如Lightroom进行cataloging。定期备份到多个位置(本地硬盘、云端、移动硬盘)。添加关键词标签便于搜索。保留RAW原始文件和编辑版本。建立项目文件夹结构,包含合同、mood board等相关文件。定期清理和归档完成的项目。建立作品使用记录,追踪版权和授权情况。"
|
|||
|
|
}
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// Add remaining generic questions if needed
|
|||
|
|
while (questions.length < 10 && genericQuestions.length > 0) {
|
|||
|
|
const q = genericQuestions.shift();
|
|||
|
|
questions.push({
|
|||
|
|
id: `q1_${questions.length + 1}`,
|
|||
|
|
question: q.question,
|
|||
|
|
answer: q.answer
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return [{
|
|||
|
|
id: "group_q1",
|
|||
|
|
question: "# 摄影/摄像面试题",
|
|||
|
|
subQuestions: questions
|
|||
|
|
}];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Function to find and replace questions for a specific industry
|
|||
|
|
function replaceIndustryQuestions(content, industryName, newQuestions) {
|
|||
|
|
// Find the industry section
|
|||
|
|
const industryRegex = new RegExp(
|
|||
|
|
`("name":\\s*"${industryName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}")`,
|
|||
|
|
'g'
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
const industryMatch = industryRegex.exec(content);
|
|||
|
|
if (!industryMatch) {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const startPos = industryMatch.index;
|
|||
|
|
|
|||
|
|
// Find the questions array after this industry name
|
|||
|
|
const afterIndustry = content.substring(startPos);
|
|||
|
|
const questionsMatch = afterIndustry.match(/"questions":\s*\[/);
|
|||
|
|
|
|||
|
|
if (!questionsMatch) {
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const questionsStart = startPos + questionsMatch.index + questionsMatch[0].length;
|
|||
|
|
|
|||
|
|
// Find the matching closing bracket for questions array
|
|||
|
|
let bracketCount = 1;
|
|||
|
|
let i = questionsStart;
|
|||
|
|
let inString = false;
|
|||
|
|
let escapeNext = false;
|
|||
|
|
|
|||
|
|
while (i < content.length && bracketCount > 0) {
|
|||
|
|
const char = content[i];
|
|||
|
|
|
|||
|
|
if (!escapeNext) {
|
|||
|
|
if (char === '"' && !inString) {
|
|||
|
|
inString = true;
|
|||
|
|
} else if (char === '"' && inString) {
|
|||
|
|
inString = false;
|
|||
|
|
} else if (!inString) {
|
|||
|
|
if (char === '[' || char === '{') {
|
|||
|
|
bracketCount++;
|
|||
|
|
} else if (char === ']' || char === '}') {
|
|||
|
|
bracketCount--;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (char === '\\') {
|
|||
|
|
escapeNext = true;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
escapeNext = false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
i++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const questionsEnd = i - 1;
|
|||
|
|
|
|||
|
|
// Create the replacement string with proper indentation
|
|||
|
|
const questionsStr = JSON.stringify(newQuestions, null, 2)
|
|||
|
|
.split('\n')
|
|||
|
|
.map(line => ' ' + line)
|
|||
|
|
.join('\n');
|
|||
|
|
|
|||
|
|
// Replace the questions array
|
|||
|
|
const newContent =
|
|||
|
|
content.substring(0, questionsStart - 1) +
|
|||
|
|
'\n' + questionsStr + '\n ' +
|
|||
|
|
content.substring(questionsEnd + 1);
|
|||
|
|
|
|||
|
|
return newContent;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let updatedContent = mockContent;
|
|||
|
|
let successCount = 0;
|
|||
|
|
const failedIndustries = [];
|
|||
|
|
const questionCounts = {};
|
|||
|
|
|
|||
|
|
// Process each industry
|
|||
|
|
for (const [industryName, positionName] of Object.entries(industryPositionMap)) {
|
|||
|
|
console.log(`Processing ${industryName}...`);
|
|||
|
|
|
|||
|
|
// Find interview content
|
|||
|
|
const positionData = visualDesignData.find(
|
|||
|
|
item => item['岗位名称'] === positionName && item['面试题内容']
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
let questions = [];
|
|||
|
|
|
|||
|
|
if (!positionData) {
|
|||
|
|
console.log(` ⚠️ No interview questions found for ${positionName}`);
|
|||
|
|
failedIndustries.push(industryName);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Special handling for 摄影/摄像
|
|||
|
|
if (industryName === '摄影/摄像') {
|
|||
|
|
questions = extractPhotographyQuestions(positionData['面试题内容']);
|
|||
|
|
} else {
|
|||
|
|
// Extract ALL questions
|
|||
|
|
questions = extractAllQuestions(positionData['面试题内容'], industryName);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (questions.length === 0) {
|
|||
|
|
console.log(` ⚠️ Could not extract questions for ${positionName}`);
|
|||
|
|
failedIndustries.push(industryName);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Replace questions
|
|||
|
|
const newContent = replaceIndustryQuestions(updatedContent, industryName, questions);
|
|||
|
|
|
|||
|
|
if (newContent) {
|
|||
|
|
updatedContent = newContent;
|
|||
|
|
successCount++;
|
|||
|
|
const qCount = questions[0].subQuestions.length;
|
|||
|
|
questionCounts[industryName] = qCount;
|
|||
|
|
console.log(` ✓ Updated (using ${positionName}, ${qCount} questions)`);
|
|||
|
|
} else {
|
|||
|
|
console.log(` ✗ Failed to update`);
|
|||
|
|
failedIndustries.push(industryName);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Save the updated file
|
|||
|
|
fs.writeFileSync('src/mocks/resumeInterviewMock.js', updatedContent);
|
|||
|
|
console.log(`\n✅ Update complete! Successfully updated ${successCount}/${Object.keys(industryPositionMap).length} industry groups`);
|
|||
|
|
|
|||
|
|
// Show statistics
|
|||
|
|
console.log('\n📊 Question count statistics:');
|
|||
|
|
let totalQuestions = 0;
|
|||
|
|
for (const [industry, count] of Object.entries(questionCounts)) {
|
|||
|
|
console.log(` ${industry}: ${count} questions`);
|
|||
|
|
totalQuestions += count;
|
|||
|
|
}
|
|||
|
|
console.log(` Total: ${totalQuestions} questions across all industries`);
|
|||
|
|
|
|||
|
|
if (failedIndustries.length > 0) {
|
|||
|
|
console.log('\n⚠️ Failed industries:');
|
|||
|
|
failedIndustries.forEach(name => console.log(` - ${name}`));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Verify syntax
|
|||
|
|
const { execSync } = require('child_process');
|
|||
|
|
try {
|
|||
|
|
execSync('node -c src/mocks/resumeInterviewMock.js', { encoding: 'utf-8' });
|
|||
|
|
console.log('\n✅ Syntax validation passed');
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('\n❌ Syntax error detected, restoring backup...');
|
|||
|
|
fs.writeFileSync('src/mocks/resumeInterviewMock.js', mockContent);
|
|||
|
|
console.log('Backup restored');
|
|||
|
|
console.error('Error details:', error.message);
|
|||
|
|
}
|