Découvrez comment intégrer nos services d'IA dans vos applications avec des exemples pratiques pour JavaScript, Python, PHP, Go et bien d'autres langages.
Intégration simple pour analyser un CV et extraire les informations clés
import { ATSIA } from '@ats-ia/sdk'; const ats = new ATSIA('YOUR_API_KEY'); // Analyser un CV const analyzeCV = async (file) => { try { const result = await ats.cv.analyze(file, { extractSkills: true, analyzeSentiment: true, extractExperience: true }); console.log('Score:', result.data.score); console.log('Compétences:', result.data.skills); console.log('Expérience:', result.data.experience); return result; } catch (error) { console.error('Erreur analyse CV:', error); throw error; } }; // Utilisation const fileInput = document.getElementById('cv-file'); fileInput.addEventListener('change', (e) => { const file = e.target.files[0]; analyzeCV(file); });
{ "success": true, "data": { "score": 87, "skills": ["React", "Node.js", "PostgreSQL", "TypeScript"], "experience": [ { "company": "TechCorp", "position": "Développeur Full Stack", "duration": "2 ans", "skills": ["React", "Node.js"] } ], "insights": ["Expertise technique solide", "Potentiel de leadership"] } }
Algorithme de matching intelligent avec pondération des critères
from ats_ia import ATSIA import asyncio from typing import Dict, List class CandidateMatcher: def __init__(self, api_key: str): self.ats = ATSIA(api_key=api_key) async def match_candidates(self, job_requirements: Dict, candidates: List[Dict]) -> List[Dict]: """Match des candidats avec une offre d'emploi""" matches = [] for candidate in candidates: try: result = await self.ats.matching.analyze( candidate=candidate, job=job_requirements, weights={ 'technical': 0.4, 'experience': 0.3, 'education': 0.2, 'soft_skills': 0.1 } ) matches.append({ 'candidate': candidate, 'score': result['data']['score'], 'breakdown': result['data']['breakdown'], 'recommendation': result['data']['recommendation'] }) except Exception as e: print(f"Erreur matching candidat {candidate['id']}: {e}") continue # Trier par score décroissant matches.sort(key=lambda x: x['score'], reverse=True) return matches # Utilisation async def main(): matcher = CandidateMatcher('YOUR_API_KEY') job = { 'title': 'Développeur Full Stack', 'requirements': { 'skills': ['React', 'Node.js', 'PostgreSQL'], 'experience': '3+ years', 'education': 'Bac+3' } } candidates = [ {'id': 1, 'skills': ['React', 'Node.js'], 'experience': '5 years'}, {'id': 2, 'skills': ['Vue.js', 'Python'], 'experience': '2 years'} ] results = await matcher.match_candidates(job, candidates) for match in results: print(f"Candidat {match['candidate']['id']}: {match['score']}/100") asyncio.run(main())
Candidat 1: 92/100 Candidat 2: 67/100
Moteur de recherche intelligent avec filtres avancés et pagination
<?php require_once 'vendor/autoload.php'; use ATSIAATSIA; use ATSIASearchSearchBuilder; class CandidateSearch { private ATSIA $ats; public function __construct(string $apiKey) { $this->ats = new ATSIA($apiKey); } public function searchCandidates(array $filters, int $page = 1, int $limit = 20): array { try { $searchBuilder = new SearchBuilder(); // Construire la requête de recherche $searchBuilder ->setQuery($filters['query'] ?? '') ->setPage($page) ->setLimit($limit); // Ajouter les filtres if (isset($filters['skills'])) { $searchBuilder->addSkillFilter($filters['skills']); } if (isset($filters['location'])) { $searchBuilder->addLocationFilter($filters['location']); } if (isset($filters['experience'])) { $searchBuilder->addExperienceFilter($filters['experience']); } if (isset($filters['availability'])) { $searchBuilder->addAvailabilityFilter($filters['availability']); } // Exécuter la recherche $results = $this->ats->search->semantic($searchBuilder->build()); return [ 'success' => true, 'data' => $results['data'], 'pagination' => [ 'page' => $page, 'limit' => $limit, 'total' => $results['data']['total'], 'pages' => ceil($results['data']['total'] / $limit) ] ]; } catch (Exception $e) { return [ 'success' => false, 'error' => $e->getMessage() ]; } } } // Utilisation $searcher = new CandidateSearch('YOUR_API_KEY'); $filters = [ 'query' => 'développeur React expérimenté avec Node.js', 'skills' => ['React', 'JavaScript'], 'location' => 'Paris', 'experience' => '3+ years', 'availability' => 'immediate' ]; $results = $searcher->searchCandidates($filters, 1, 10); if ($results['success']) { foreach ($results['data']['results'] as $candidate) { echo "Candidat: {$candidate['name']} - Score: {$candidate['score']} "; } echo "Total: {$results['data']['total']} candidats trouvés "; } else { echo "Erreur: {$results['error']} "; }
Candidat: Marie Dubois - Score: 95 Candidat: Thomas Martin - Score: 88 Candidat: Sophie Bernard - Score: 82 Total: 47 candidats trouvés
Interface React pour générer des offres d'emploi personnalisées
import React, { useState, useEffect } from 'react'; import { ATSIA } from '@ats-ia/sdk'; const JobGenerator = () => { const [formData, setFormData] = useState({ company: '', position: '', skills: [], experience: '', tone: 'corporate', keywords: [] }); const [generatedJob, setGeneratedJob] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const ats = new ATSIA(process.env.REACT_APP_ATS_API_KEY); const handleSubmit = async (e) => { e.preventDefault(); setLoading(true); setError(null); try { const result = await ats.jobs.generate({ requirements: { company: formData.company, position: formData.position, skills: formData.skills, experience: formData.experience }, tone: formData.tone, keywords: formData.keywords }); setGeneratedJob(result.data); } catch (err) { setError(err.message); } finally { setLoading(false); } }; const handleCopy = async () => { if (generatedJob) { const text = `${generatedJob.title}\n\n${generatedJob.summary}\n\n${generatedJob.missions.join('\n')}`; await navigator.clipboard.writeText(text); } }; const handleDownload = () => { if (generatedJob) { const content = `${generatedJob.title}\n\n${generatedJob.summary}\n\n${generatedJob.missions.join('\n')}`; const blob = new Blob([content], { type: 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${generatedJob.title}.txt`; a.click(); URL.revokeObjectURL(url); } }; return ( <div className="max-w-4xl mx-auto p-6"> <h1 className="text-3xl font-bold mb-8">Générateur d'Offres d'Emploi</h1> <form onSubmit={handleSubmit} className="space-y-6 mb-8"> <div className="grid grid-cols-1 md:grid-cols-2 gap-6"> <div> <label className="block text-sm font-medium mb-2">Entreprise</label> <input type="text" value={formData.company} onChange={(e) => setFormData({...formData, company: e.target.value})} className="w-full p-3 border rounded-lg" required /> </div> <div> <label className="block text-sm font-medium mb-2">Poste</label> <input type="text" value={formData.position} onChange={(e) => setFormData({...formData, position: e.target.value})} className="w-full p-3 border rounded-lg" required /> </div> </div> <div> <label className="block text-sm font-medium mb-2">Compétences (séparées par des virgules)</label> <input type="text" value={formData.skills.join(', ')} onChange={(e) => setFormData({...formData, skills: e.target.value.split(',').map(s => s.trim())})} className="w-full p-3 border rounded-lg" placeholder="React, Node.js, PostgreSQL" /> </div> <div> <label className="block text-sm font-medium mb-2">Expérience requise</label> <select value={formData.experience} onChange={(e) => setFormData({...formData, experience: e.target.value})} className="w-full p-3 border rounded-lg" > <option value="">Sélectionner</option> <option value="0-1 years">0-1 an</option> <option value="1-3 years">1-3 ans</option> <option value="3-5 years">3-5 ans</option> <option value="5+ years">5+ ans</option> </select> </div> <div className="grid grid-cols-1 md:grid-cols-2 gap-6"> <div> <label className="block text-sm font-medium mb-2">Tonalité</label> <select value={formData.tone} onChange={(e) => setFormData({...formData, tone: e.target.value})} className="w-full p-3 border rounded-lg" > <option value="corporate">Corporate</option> <option value="startup">Startup</option> <option value="creative">Créatif</option> <option value="casual">Décontracté</option> </select> </div> <div> <label className="block text-sm font-medium mb-2">Mots-clés SEO</label> <input type="text" value={formData.keywords.join(', ')} onChange={(e) => setFormData({...formData, keywords: e.target.value.split(',').map(s => s.trim())})} className="w-full p-3 border rounded-lg" placeholder="innovation, scalabilité, cloud" /> </div> </div> <button type="submit" disabled={loading} className="w-full bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white font-bold py-3 px-6 rounded-lg transition-colors" > {loading ? 'Génération en cours...' : 'Générer l'Offre'} </button> </form> {error && ( <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-6"> {error} </div> )} {generatedJob && ( <div className="bg-gray-50 rounded-lg p-6"> <div className="flex items-center justify-between mb-4"> <h2 className="text-2xl font-bold">{generatedJob.title}</h2> <div className="flex gap-2"> <button onClick={handleCopy} className="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded transition-colors" > Copier </button> <button onClick={handleDownload} className="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded transition-colors" > Télécharger </button> </div> </div> <div className="space-y-4"> <div> <h3 className="font-semibold mb-2">Résumé</h3> <p className="text-gray-700">{generatedJob.summary}</p> </div> <div> <h3 className="font-semibold mb-2">Missions</h3> <ul className="list-disc list-inside space-y-1"> {generatedJob.missions.map((mission, index) => ( <li key={index} className="text-gray-700">{mission}</li> ))} </ul> </div> <div className="grid grid-cols-1 md:grid-cols-3 gap-4 pt-4 border-t"> <div className="text-center"> <div className="text-2xl font-bold text-blue-600">{generatedJob.seoScore}</div> <div className="text-sm text-gray-600">Score SEO</div> </div> <div className="text-center"> <div className="text-2xl font-bold text-green-600">{generatedJob.wordCount}</div> <div className="text-sm text-gray-600">Mots</div> </div> <div className="text-center"> <div className="text-2xl font-bold text-purple-600">{generatedJob.tone}</div> <div className="text-sm text-gray-600">Tonalité</div> </div> </div> </div> </div> )} </div> ); }; export default JobGenerator;
Collecte et analyse de données de recrutement avec Go et goroutines
package main import ( "context" "encoding/json" "fmt" "log" "sync" "time" "github.com/ats-ia/go-sdk" ) type RecruitmentAnalytics struct { ats *ats.Client } type AnalyticsData struct { TotalCandidates int `json:"total_candidates"` AverageScore float64 `json:"average_score"` TopSkills []string `json:"top_skills"` ExperienceDistribution map[string]int `json:"experience_distribution"` LocationDistribution map[string]int `json:"location_distribution"` SalaryRange map[string]int `json:"salary_range"` MarketInsights []string `json:"market_insights"` Recommendations []string `json:"recommendations"` } func NewRecruitmentAnalytics(apiKey string) (*RecruitmentAnalytics, error) { client, err := ats.NewClient(apiKey) if err != nil { return nil, fmt.Errorf("erreur création client: %w", err) } return &RecruitmentAnalytics{ats: client}, nil } func (ra *RecruitmentAnalytics) CollectAnalytics(ctx context.Context, filters map[string]interface{}) (*AnalyticsData, error) { // Collecter les données en parallèle avec des goroutines var wg sync.WaitGroup var mu sync.Mutex data := &AnalyticsData{} // Canal pour les erreurs errChan := make(chan error, 5) // Collecter les statistiques de base wg.Add(1) go func() { defer wg.Done() if err := ra.collectBasicStats(ctx, data, filters); err != nil { errChan <- fmt.Errorf("erreur stats de base: %w", err) } }() // Collecter l'analyse des compétences wg.Add(1) go func() { defer wg.Done() if err := ra.collectSkillsAnalysis(ctx, data, filters); err != nil { errChan <- fmt.Errorf("erreur analyse compétences: %w", err) } }() // Collecter la distribution géographique wg.Add(1) go func() { defer wg.Done() if err := ra.collectLocationAnalysis(ctx, data, filters); err != nil { errChan <- fmt.Errorf("erreur analyse géographique: %w", err) } }() // Collecter l'analyse des salaires wg.Add(1) go func() { defer wg.Done() if err := ra.collectSalaryAnalysis(ctx, data, filters); err != nil { errChan <- fmt.Errorf("erreur analyse salaires: %w", err) } }() // Collecter les insights du marché wg.Add(1) go func() { defer wg.Done() if err := ra.collectMarketInsights(ctx, data, filters); err != nil { errChan <- fmt.Errorf("erreur insights marché: %w", err) } }() // Attendre que toutes les goroutines se terminent wg.Wait() close(errChan) // Vérifier s'il y a eu des erreurs for err := range errChan { if err != nil { log.Printf("Erreur collecte analytics: %v", err) } } // Générer les recommandations ra.generateRecommendations(data) return data, nil } func (ra *RecruitmentAnalytics) collectBasicStats(ctx context.Context, data *AnalyticsData, filters map[string]interface{}) error { // Rechercher tous les candidats avec les filtres searchResult, err := ra.ats.Search.Semantic(ctx, &ats.SearchRequest{ Query: "", Filters: filters, Limit: 1000, // Limite élevée pour les analytics }) if err != nil { return fmt.Errorf("erreur recherche candidats: %w", err) } mu.Lock() data.TotalCandidates = searchResult.Total mu.Unlock() // Calculer le score moyen var totalScore float64 for _, candidate := range searchResult.Results { totalScore += float64(candidate.Score) } if len(searchResult.Results) > 0 { mu.Lock() data.AverageScore = totalScore / float64(len(searchResult.Results)) mu.Unlock() } return nil } func (ra *RecruitmentAnalytics) collectSkillsAnalysis(ctx context.Context, data *AnalyticsData, filters map[string]interface{}) error { // Analyser les compétences les plus demandées skillsCount := make(map[string]int) // Rechercher les candidats avec analyse des compétences searchResult, err := ra.ats.Search.Semantic(ctx, &ats.SearchRequest{ Query: "", Filters: filters, Limit: 500, }) if err != nil { return fmt.Errorf("erreur recherche compétences: %w", err) } // Compter les compétences for _, candidate := range searchResult.Results { for _, skill := range candidate.Skills { skillsCount[skill]++ } } // Trouver les compétences les plus populaires topSkills := findTopSkills(skillsCount, 10) mu.Lock() data.TopSkills = topSkills mu.Unlock() return nil } func (ra *RecruitmentAnalytics) collectLocationAnalysis(ctx context.Context, data *AnalyticsData, filters map[string]interface{}) error { locationCount := make(map[string]int) searchResult, err := ra.ats.Search.Semantic(ctx, &ats.SearchRequest{ Query: "", Filters: filters, Limit: 1000, }) if err != nil { return fmt.Errorf("erreur recherche localisation: %w", err) } // Compter par localisation for _, candidate := range searchResult.Results { location := candidate.Location if location != "" { locationCount[location]++ } } mu.Lock() data.LocationDistribution = locationCount mu.Unlock() return nil } func (ra *RecruitmentAnalytics) collectSalaryAnalysis(ctx context.Context, data *AnalyticsData, filters map[string]interface{}) error { salaryRanges := map[string]int{ "<30k": 0, "30k-50k": 0, "50k-80k": 0, "80k-100k": 0, ">100k": 0, } searchResult, err := ra.ats.Search.Semantic(ctx, &ats.SearchRequest{ Query: "", Filters: filters, Limit: 1000, }) if err != nil { return fmt.Errorf("erreur recherche salaires: %w", err) } // Catégoriser par tranche de salaire for _, candidate := range searchResult.Results { salary := candidate.ExpectedSalary switch { case salary < 30000: salaryRanges["<30k"]++ case salary < 50000: salaryRanges["30k-50k"]++ case salary < 80000: salaryRanges["50k-80k"]++ case salary < 100000: salaryRanges["80k-100k"]++ default: salaryRanges[">100k"]++ } } mu.Lock() data.SalaryRange = salaryRanges mu.Unlock() return nil } func (ra *RecruitmentAnalytics) collectMarketInsights(ctx context.Context, data *AnalyticsData, filters map[string]interface{}) error { // Analyser les tendances du marché insights := []string{} // Vérifier la demande vs l'offre if data.TotalCandidates > 0 { demandRatio := float64(data.TotalCandidates) / 100.0 if demandRatio > 2.0 { insights = append(insights, "Marché très concurrentiel - nombreux candidats disponibles") } else if demandRatio < 0.5 { insights = append(insights, "Marché tendu - peu de candidats disponibles") } else { insights = append(insights, "Marché équilibré") } } // Analyser les compétences critiques if len(data.TopSkills) > 0 { insights = append(insights, fmt.Sprintf("Compétences les plus demandées: %s", data.TopSkills[0])) } mu.Lock() data.MarketInsights = insights mu.Unlock() return nil } func (ra *RecruitmentAnalytics) generateRecommendations(data *AnalyticsData) { recommendations := []string{} // Recommandations basées sur les données if data.AverageScore < 70 { recommendations = append(recommendations, "Améliorer la qualité des candidatures") } if len(data.TopSkills) > 0 { recommendations = append(recommendations, fmt.Sprintf("Se concentrer sur les compétences: %s", data.TopSkills[0])) } if data.TotalCandidates < 50 { recommendations = append(recommendations, "Élargir les canaux de recrutement") } data.Recommendations = recommendations } func findTopSkills(skillsCount map[string]int, limit int) []string { // Trier les compétences par popularité type skillCount struct { skill string count int } var skills []skillCount for skill, count := range skillsCount { skills = append(skills, skillCount{skill, count}) } // Trier par count décroissant sort.Slice(skills, func(i, j int) bool { return skills[i].count > skills[j].count }) // Extraire les top skills var result []string for i := 0; i < limit && i < len(skills); i++ { result = append(result, skills[i].skill) } return result } func main() { // Créer l'instance d'analytics analytics, err := NewRecruitmentAnalytics("YOUR_API_KEY") if err != nil { log.Fatalf("Erreur création analytics: %v", err) } // Définir les filtres filters := map[string]interface{}{ "experience": "3+ years", "skills": []string{"React", "Node.js"}, "location": "Paris", } // Collecter les analytics ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() data, err := analytics.CollectAnalytics(ctx, filters) if err != nil { log.Fatalf("Erreur collecte analytics: %v", err) } // Afficher les résultats jsonData, _ := json.MarshalIndent(data, "", " ") fmt.Printf("Analytics:\n%s\n", string(jsonData)) }