Created
April 10, 2025 03:58
-
-
Save pierrejoye/943a12c135e405bb4919e676b0ce9c43 to your computer and use it in GitHub Desktop.
OpenAi tool_calls example in typescript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { OpenAI } from "openai"; | |
import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions'; | |
// Define the types for our functions | |
interface CandidateProfile { | |
name: string; | |
currentRole?: string; | |
yearsExperience: number; | |
desiredRole: string; | |
education: string; | |
skills: string[]; | |
industryPreference?: string; | |
workPreference?: "remote" | "hybrid" | "onsite"; | |
salaryExpectation?: number; | |
} | |
interface JobMarketInfo { | |
role: string; | |
industry?: string; | |
region?: string; | |
currentYear?: number; | |
} | |
interface SkillsGapInfo { | |
currentSkills: string[]; | |
desiredRole: string; | |
} | |
// Initialize OpenAI client | |
const openai = new OpenAI({ | |
apiKey: process.env.OPENAI_API_KEY, | |
}); | |
// First, update your tools to match function names | |
const tools: OpenAI.ChatCompletionTool[] = [ | |
{ | |
type: "function", | |
function: { | |
name: 'gather_candidate_profile', | |
description: 'Collect profile information about the candidate', | |
parameters: { | |
type: 'object', | |
properties: { | |
name: { type: 'string' }, | |
currentRole: { type: 'string' }, | |
yearsExperience: { type: 'number' }, | |
desiredRole: { type: 'string' }, | |
education: { type: 'string' }, | |
skills: { | |
type: 'array', | |
items: { type: 'string' } | |
}, | |
industryPreference: { type: 'string' }, | |
workPreference: { | |
type: 'string', | |
enum: ['remote', 'hybrid', 'onsite'] | |
}, | |
salaryExpectation: { type: 'number' } | |
}, | |
required: ['name', 'yearsExperience', 'desiredRole', 'education', 'skills'] | |
} | |
} | |
}, | |
{ | |
type: 'function', | |
function: { | |
name: 'check_job_market', | |
description: 'Get current job market information for a specific role', | |
parameters: { | |
type: 'object', | |
properties: { | |
role: { type: 'string' }, | |
industry: { type: 'string' }, | |
region: { type: 'string' }, | |
currentYear: { type: 'number' } | |
}, | |
required: ['role'] | |
} | |
} | |
}, | |
{ | |
type: 'function', | |
function: { | |
name: 'analyze_skills_gap', | |
description: 'Analyze the gap between current skills and those needed for a desired role', | |
parameters: { | |
type: 'object', | |
properties: { | |
currentSkills: { | |
type: 'array', | |
items: { type: 'string' } | |
}, | |
desiredRole: { type: 'string' } | |
}, | |
required: ['currentSkills', 'desiredRole'] | |
} | |
} | |
} | |
]; | |
const tool_choice: OpenAI.Chat.ChatCompletionToolChoiceOption = "auto"; | |
// Mock function implementations that would normally connect to databases or APIs | |
async function gatherCandidateProfile(args: CandidateProfile): Promise<string> { | |
// In a real application, you might store this information in a database | |
console.log("Profile collected:", args); | |
return JSON.stringify({ | |
status: "success", | |
message: "Candidate profile collected successfully", | |
profile: args | |
}); | |
} | |
async function checkJobMarket(args: JobMarketInfo): Promise<string> { | |
// In a real application, this would fetch data from job market APIs or databases | |
const marketData = { | |
role: args.role, | |
industry: args.industry || "General", | |
demandLevel: args.role.includes("developer") ? "Very High" : "Moderate", | |
averageSalary: args.role.includes("developer") ? 120000 : 85000, | |
growthRate: args.role.includes("developer") ? "15% annually" : "8% annually", | |
topSkillsRequired: args.role.includes("developer") | |
? ["JavaScript", "TypeScript", "React", "Node.js"] | |
: ["Project Management", "Communication", "Leadership"], | |
remoteOpportunities: args.role.includes("developer") ? "Abundant" : "Limited" | |
}; | |
return JSON.stringify(marketData); | |
} | |
async function analyzeSkillsGap(args: SkillsGapInfo): Promise<string> { | |
// In a real application, this would analyze skills against job requirements data | |
const skillsNeeded = getRequiredSkillsForRole(args.desiredRole); | |
const missingSkills = skillsNeeded.filter(skill => !args.currentSkills.includes(skill)); | |
return JSON.stringify({ | |
requiredSkills: skillsNeeded, | |
missingSkills: missingSkills, | |
recommendedCourses: missingSkills.map(skill => `${skill} Masterclass`), | |
estimatedTimeToAcquire: `${missingSkills.length * 2} months` | |
}); | |
} | |
// Helper function to determine skills required for different roles | |
function getRequiredSkillsForRole(role: string): string[] { | |
const roleSkillsMap: Record<string, string[]> = { | |
"frontend developer": ["JavaScript", "HTML", "CSS", "React", "TypeScript", "UI/UX"], | |
"backend developer": ["Node.js", "Python", "Java", "SQL", "NoSQL", "API Design"], | |
"data scientist": ["Python", "R", "SQL", "Machine Learning", "Statistics", "Data Visualization"], | |
"product manager": ["Product Strategy", "User Research", "Roadmapping", "Agile", "Communication", "Analytics"], | |
"ux designer": ["User Research", "Wireframing", "Prototyping", "Figma", "UI Design", "User Testing"] | |
}; | |
// Default to a generic set of skills if role isn't in our map | |
return roleSkillsMap[role.toLowerCase()] || | |
["Communication", "Problem Solving", "Critical Thinking", "Collaboration", "Technical Aptitude"]; | |
} | |
// Function to call the appropriate function based on name | |
async function callFunction(name: string, args: any): Promise<string> { | |
switch (name) { | |
case "gather_candidate_profile": | |
return await gatherCandidateProfile(args as CandidateProfile); | |
case "check_job_market": | |
return await checkJobMarket(args as JobMarketInfo); | |
case "analyze_skills_gap": | |
return await analyzeSkillsGap(args as SkillsGapInfo); | |
default: | |
return JSON.stringify({ error: "Function not found" }); | |
} | |
} | |
// Main function to handle the career consultation process | |
async function careerConsultation(userInput: string) { | |
let finalResponse = null; | |
try { | |
const systemMessage: ChatCompletionMessageParam = { | |
role: "system", | |
content: `You are a career consultant. | |
Your job is to help users with their career-related questions and provide personalized advice. | |
Use the tools available to you to gather information and provide the best possible guidance. | |
If you need to ask the user for more information, do so in a friendly and professional manner.` | |
}; | |
const userMessage: ChatCompletionMessageParam = { | |
role: "user", | |
content: userInput | |
}; | |
const messages: ChatCompletionMessageParam[] = [ | |
systemMessage, | |
userMessage | |
]; | |
while (true) { | |
const completion = await openai.chat.completions.create({ | |
model: "gpt-4o", | |
messages: messages, | |
tools: tools, | |
tool_choice: tool_choice, | |
}); | |
const message = completion.choices[0]!.message; | |
console.log("Assistant response:", message.content); | |
messages.push(message); | |
if (!message.tool_calls || message.tool_calls.length === 0) { | |
console.log("No tool calls made by the assistant."); | |
// No tool calls, so we can return the assistant's message | |
finalResponse = message.content; | |
break; | |
} | |
console.log(`Model called ${message.tool_calls.length} tools`); | |
// Process each tool call | |
const toolCallPromises = message.tool_calls.map(async (toolCall) => { | |
if (toolCall.type === 'function') { | |
let functionArgs; | |
try { | |
functionArgs = JSON.parse(toolCall.function.arguments); | |
} catch (error) { | |
console.error("Error parsing arguments:", error); | |
return { | |
tool_call_id: toolCall.id, | |
role: "tool" as const, | |
content: JSON.stringify({ error: "Invalid arguments" }) | |
}; | |
} | |
const result = await callFunction(toolCall.function.name, functionArgs); | |
// Return the tool response in the expected format | |
return { | |
tool_call_id: toolCall.id, | |
role: "tool" as const, | |
content: result | |
}; | |
} | |
return { | |
tool_call_id: toolCall.id, | |
role: "tool" as const, | |
content: JSON.stringify({ error: "Unsupported tool type" }) | |
}; | |
}); | |
const toolResponses = await Promise.all(toolCallPromises); | |
messages.push(...toolResponses); | |
} | |
} catch (error) { | |
console.error("Error in career consultation:", error); | |
return "Sorry, there was an error processing your request."; | |
} | |
return finalResponse || "No response available."; | |
} | |
// Example usage | |
async function main() { | |
const userQuery = "I'm a marketing specialist with 4 years of experience, but I want to transition into UX design. I have a bachelor's in communications and I've done some design work on the side. What steps should I take?"; | |
console.log("User:", userQuery); | |
const response = await careerConsultation(userQuery); | |
console.log("\nCareer Consultant:", response); | |
} | |
main().catch(console.error); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment