Exemples de Code

Intégration API ATS IA

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.

🚀 Prêt à Coder ?

Découvrez nos exemples de code et commencez à intégrer l'IA dans vos applications

Langage:
Niveau:

Analyse de CV avec JavaScript

Intégration simple pour analyser un CV et extraire les informations clés

Langage: javascriptNiveau: Débutant
CVAnalyseJavaScriptSDK

Code Source

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

Résultat Attendu

{
  "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"]
  }
}

Matching Candidat/Offre avec Python

Algorithme de matching intelligent avec pondération des critères

Langage: pythonNiveau: Intermédiaire
MatchingPythonAsyncAlgorithme

Code Source

python
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())

Résultat Attendu

Candidat 1: 92/100
Candidat 2: 67/100

Recherche Sémantique avec PHP

Moteur de recherche intelligent avec filtres avancés et pagination

Langage: phpNiveau: Intermédiaire
RecherchePHPFiltresPagination

Code Source

php
<?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']}
";
}

Résultat Attendu

Candidat: Marie Dubois - Score: 95
Candidat: Thomas Martin - Score: 88
Candidat: Sophie Bernard - Score: 82
Total: 47 candidats trouvés

Génération d'Offres avec React

Interface React pour générer des offres d'emploi personnalisées

Langage: javascriptNiveau: Avancé
ReactGénérationInterfaceFormulaires

Code Source

javascript
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;

Analytics Avancées avec Go

Collecte et analyse de données de recrutement avec Go et goroutines

Langage: goNiveau: Avancé
GoAnalyticsGoroutinesPerformance

Code Source

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