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))
}