lakshmisravya123
Upgrade: STAR method coaching, ideal answers, follow-up questions, detailed scoring
f88c6fa
const GROQ_API_KEY = process.env.GROQ_API_KEY;
const OLLAMA_URL = process.env.OLLAMA_URL || 'http://localhost:11434';
const GROQ_MODEL = process.env.GROQ_MODEL || 'llama-3.3-70b-versatile';
const OLLAMA_MODEL = process.env.OLLAMA_MODEL || 'llama3.2:3b';
async function callAI(prompt) {
if (GROQ_API_KEY) {
const res = await fetch('https://api.groq.com/openai/v1/chat/completions', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${GROQ_API_KEY}` },
body: JSON.stringify({ model: GROQ_MODEL, messages: [{ role: 'user', content: prompt }], temperature: 0.7, max_tokens: 4096 }),
});
if (res.ok) { const data = await res.json(); return data.choices[0].message.content; }
console.warn('Groq failed, falling back to Ollama...');
}
const res = await fetch(`${OLLAMA_URL}/api/generate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ model: OLLAMA_MODEL, prompt, stream: false }),
});
if (!res.ok) throw new Error('Both Groq and Ollama failed. Set GROQ_API_KEY or start Ollama.');
return (await res.json()).response;
}
function parseJSON(text) {
try { return JSON.parse(text.trim()); }
catch {
const m = text.match(/\{[\s\S]*\}/);
if (m) {
try { return JSON.parse(m[0]); }
catch { /* fall through */ }
}
throw new Error('Failed to parse AI response');
}
}
const DIFFICULTY_MAP = {
easy: 'Ask straightforward, common interview questions. Be encouraging.',
medium: 'Ask standard industry interview questions with some follow-ups. Be professional.',
hard: 'Ask challenging, senior-level questions with tricky follow-ups. Probe deeply into answers.'
};
const INTERVIEW_TYPES = {
behavioral: 'Focus on behavioral questions (STAR method).',
technical: 'Focus on technical knowledge, system design, problem-solving.',
mixed: 'Mix behavioral and technical questions naturally.'
};
async function generateQuestions(role, difficulty, interviewType, count = 5) {
const text = await callAI(`You are an expert interviewer for ${role} positions.
DIFFICULTY: ${difficulty} - ${DIFFICULTY_MAP[difficulty] || DIFFICULTY_MAP.medium}
TYPE: ${interviewType} - ${INTERVIEW_TYPES[interviewType] || INTERVIEW_TYPES.mixed}
Generate exactly ${count} interview questions. Return ONLY valid JSON:
{"questions":[{"id":1,"question":"<question>","category":"<behavioral|technical|situational>","hint":"<hint>"}]}
Return ONLY JSON, no markdown.`);
return parseJSON(text);
}
async function evaluateAnswer(role, question, answer, difficulty) {
const text = await callAI(`You are an elite interview coach who has served on Google's hiring committee and trained thousands of candidates. You evaluate with precision and depth.
ROLE: ${role}
DIFFICULTY: ${difficulty}
QUESTION: ${question}
CANDIDATE'S ANSWER: ${answer}
Perform a comprehensive evaluation across multiple dimensions:
1. STAR METHOD: Did the candidate use Situation-Task-Action-Result? Identify which elements are present/missing.
2. CONTENT QUALITY: Evaluate specificity (concrete examples vs vague claims), relevance, and technical depth.
3. COMMUNICATION: Detect filler words or vague language ("stuff", "things", "basically", "kind of", "sort of", "I think", "maybe"). Evaluate clarity.
4. CONFIDENCE: Does the answer show ownership ("I led", "I decided") or deflection ("we just", "they told me to")?
5. SCORING: Use a Google hiring committee rubric - score each dimension independently.
6. FOLLOW-UP QUESTIONS: What would a skilled interviewer ask next?
7. IDEAL ANSWER: Write the answer a top candidate would give.
8. DELIVERY TIPS: Body language, pacing, presentation improvements.
9. REWRITTEN ANSWER: Rewrite their answer to be significantly stronger while keeping their core content.
Return ONLY valid JSON (no markdown, no code fences):
{
"score": <1-10 overall>,
"feedback": "<2-3 sentence overall assessment>",
"strengths": ["<strength 1>", "<strength 2>"],
"improvements": ["<specific improvement 1>", "<specific improvement 2>"],
"starAnalysis": {
"situation": {"present": true, "feedback": "<what they said or what is missing>"},
"task": {"present": false, "feedback": "<what they said or what is missing>"},
"action": {"present": true, "feedback": "<what they said or what is missing>"},
"result": {"present": false, "feedback": "<what they said or what is missing>"}
},
"detailedScores": {
"relevance": <1-10>,
"specificity": <1-10>,
"structure": <1-10>,
"communication": <1-10>,
"confidence": <1-10>,
"technicalDepth": <1-10>
},
"fillerWords": ["<detected filler word or phrase>"],
"vagueStatements": ["<vague statement from their answer>"],
"followUpQuestions": ["<follow-up Q1>", "<follow-up Q2>", "<follow-up Q3>"],
"idealAnswer": "<the ideal answer a top candidate would give>",
"rewrittenAnswer": "<their answer rewritten to be much stronger>",
"deliveryTips": ["<tip 1>", "<tip 2>", "<tip 3>"],
"sampleAnswer": "<brief strong example answer>"
}
Use true/false booleans for present fields. Be thorough and actionable. Return ONLY JSON.`);
return parseJSON(text);
}
async function generateFinalReport(role, questionsAndAnswers) {
const qaPairs = questionsAndAnswers.map((qa, i) =>
`Q${i+1}: ${qa.question}\nAnswer: ${qa.answer}\nScore: ${qa.score}/10`
).join('\n\n');
const text = await callAI(`You are an elite interview coach writing a comprehensive final assessment for a ${role} candidate. You have evaluated candidates for top tech companies.
INTERVIEW TRANSCRIPT:
${qaPairs}
Provide a thorough final report. Analyze patterns across all answers.
Return ONLY valid JSON (no markdown, no code fences):
{
"overallScore": <1-100>,
"verdict": "<STRONG_HIRE|HIRE|MAYBE|NO_HIRE>",
"summary": "<4-5 sentence comprehensive summary>",
"topStrengths": ["<strength 1>", "<strength 2>", "<strength 3>"],
"areasToImprove": ["<area 1>", "<area 2>", "<area 3>"],
"recommendation": "<3-4 sentences of specific next steps>",
"readinessLevel": "<Not Ready|Getting There|Almost Ready|Interview Ready>",
"communicationProfile": {
"clarity": <1-10>,
"conciseness": <1-10>,
"confidence": <1-10>,
"storytelling": <1-10>,
"technicalArticulation": <1-10>
},
"interviewPatterns": {
"consistentStrengths": ["<pattern 1>", "<pattern 2>"],
"consistentWeaknesses": ["<pattern 1>", "<pattern 2>"],
"trajectory": "<improving|stable|declining>"
},
"actionPlan": [
{"priority": "high", "action": "<specific action item>", "timeframe": "<e.g., 1 week>"},
{"priority": "medium", "action": "<specific action item>", "timeframe": "<e.g., 2 weeks>"},
{"priority": "low", "action": "<specific action item>", "timeframe": "<e.g., 1 month>"}
],
"mockInterviewTips": ["<tip 1>", "<tip 2>", "<tip 3>"]
}
Return ONLY JSON.`);
return parseJSON(text);
}
module.exports = { generateQuestions, evaluateAnswer, generateFinalReport };