# fenic

[fenic](https://github.com/typedef-ai/fenic) est un framework de DataFrame inspiré de PySpark, conçu pour créer des applications IA et agentiques de production. fenic prend en charge la lecture de jeux de données directement depuis le Hugging Face Hub.

## Premiers pas

Pour commencer, installez `fenic` avec pip :

```bash
pip install fenic
```

### Créer une session

Instanciez une session fenic avec la configuration par défaut (suffisante pour la lecture de jeux de données et d'autres opérations non sémantiques) :

```python
import fenic as fc

session = fc.Session.get_or_create(fc.SessionConfig())
```

## Aperçu

fenic est un framework de traitement de données à l'opinion forte qui combine :
- **API DataFrame** : opérations inspirées de PySpark pour une manipulation de données familière
- **Opérations sémantiques** : Opérations IA/LLM intégrées, incluant les fonctions sémantiques, les embeddings et le clustering
- **Intégration de modèles** : prise en charge native des fournisseurs d'IA (Anthropic, OpenAI, Cohere, Google)
- **Optimisation des requêtes** : optimisation automatique par transformations du plan logique

## Lire depuis Hugging Face Hub

fenic peut lire des jeux de données directement depuis le Hugging Face Hub à l'aide du protocole `hf://`. Cette fonctionnalité est intégrée à l'interface DataFrameReader de fenic.

### Formats pris en charge

fenic prend en charge la lecture des formats suivants depuis Hugging Face :
- **Fichiers Parquet** (`.parquet`)
- **Fichiers CSV** (`.csv`)

### Lecture des jeux de données

Pour lire un jeu de données depuis le Hugging Face Hub :

```python
import fenic as fc

session = fc.Session.get_or_create(fc.SessionConfig())

# Read a CSV file from a public dataset
df = session.read.csv("hf://datasets/datasets-examples/doc-formats-csv-1/data.csv")

# Read Parquet files using glob patterns
df = session.read.parquet("hf://datasets/cais/mmlu/astronomy/*.parquet")

# Read from a specific dataset revision
df = session.read.parquet("hf://datasets/datasets-examples/doc-formats-csv-1@~parquet/**/*.parquet")
```

### Lecture avec gestion de schéma

```python
# Read multiple CSV files with schema merging
df = session.read.csv("hf://datasets/username/dataset_name/*.csv", merge_schemas=True)

# Read multiple Parquet files with schema merging
df = session.read.parquet("hf://datasets/username/dataset_name/*.parquet", merge_schemas=True)
```

> **Remarque :** Dans fenic, un schéma est l'ensemble des noms de colonnes et de leurs types de données. Lorsque vous activez `merge_schemas`, fenic tente de réconcilier les différences entre les fichiers en remplissant les colonnes manquantes avec des valeurs nulles et en élargissant les types lorsque c'est possible. Certaines structures ne peuvent toujours pas être fusionnées — consultez la documentation de fenic pour les [limites de fusion des schémas CSV](https://docs.fenic.ai/latest/reference/fenic/?h=parquet#fenic.DataFrameReader.csv) et les [limites de fusion des schémas Parquet](https://docs.fenic.ai/latest/reference/fenic/?h=parquet#fenic.DataFrameReader.parquet).

### Authentification

Pour lire des jeux de données privés, vous devez définir votre jeton Hugging Face en tant que variable d’environnement :

```shell
export HF_TOKEN="your_hugging_face_token_here"
```

### Format du chemin

Le format de chemin Hugging Face dans fenic suit cette structure :
```
hf://{repo_type}/{repo_id}/{path_to_file}
```

Vous pouvez également spécifier des révisions ou des versions de jeu de données :
```
hf://{repo_type}/{repo_id}@{revision}/{path_to_file}
```

Fonctionnalités :
- Prend en charge les motifs glob (`*`, `**`)
- Révisions/versions de jeu de données utilisant la notation `@` :
  - Commit spécifique : `@d50d8923b5934dc8e74b66e6e4b0e2cd85e9142e`
  - Branche : `@refs/convert/parquet`
  - Alias de branche : `@~parquet`
- Nécessite la variable d'environnement `HF_TOKEN` pour les jeux de données privés

### Mélanger des sources de données

fenic vous permet de combiner plusieurs sources de données dans une seule opération de lecture, y compris en mélangeant différents protocoles :

```python
# Mix HF and local files in one read call
df = session.read.parquet([
    "hf://datasets/cais/mmlu/astronomy/*.parquet",
    "file:///local/data/*.parquet",
    "./relative/path/data.parquet"
])
```

Cette flexibilité vous permet de combiner sans effort les données du Hugging Face Hub et les fichiers locaux dans votre pipeline de traitement de données.

## Traitement des données depuis Hugging Face

Une fois chargé depuis Hugging Face, vous pouvez utiliser l’API complète de DataFrame de fenic :

### Opérations de base sur les DataFrames

```python
import fenic as fc

session = fc.Session.get_or_create(fc.SessionConfig())

# Load IMDB dataset from Hugging Face
df = session.read.parquet("hf://datasets/imdb/plain_text/train-*.parquet")

# Filter and select
positive_reviews = df.filter(fc.col("label") == 1).select("text", "label")

# Group by and aggregate
label_counts = df.group_by("label").agg(
    fc.count("*").alias("count")
)
```

### Opérations propulsées par l'IA

Pour utiliser les opérations sémantiques et d'embedding, configurez les modèles de langage et d'embedding dans votre SessionConfig. Une fois configuré :

```python
import fenic as fc

# Requires OPENAI_API_KEY to be set for language and embedding calls
session = fc.Session.get_or_create(
    fc.SessionConfig(
        semantic=fc.SemanticConfig(
            language_models={
                "gpt-4o-mini": fc.OpenAILanguageModel(
                    model_name="gpt-4o-mini",
                    rpm=60,
                    tpm=60000,
                )
            },
            embedding_models={
                "text-embedding-3-small": fc.OpenAIEmbeddingModel(
                    model_name="text-embedding-3-small",
                    rpm=60,
                    tpm=60000,
                )
            },
        )
    )
)

# Load a text dataset from Hugging Face
df = session.read.parquet("hf://datasets/imdb/plain_text/train-00000-of-00001.parquet")

# Add embeddings to text columns
df_with_embeddings = df.select(
    "*",
    fc.semantic.embed(fc.col("text")).alias("embedding")
)

# Apply semantic functions for sentiment analysis
df_analyzed = df_with_embeddings.select(
    "*",
    fc.semantic.analyze_sentiment(
        fc.col("text"),
        model_alias="gpt-4o-mini",  # Optional: specify model
    ).alias("sentiment")
)
```

## Exemple : Analyse du jeu de données MMLU

```python
import fenic as fc

# Requires OPENAI_API_KEY to be set for semantic calls
session = fc.Session.get_or_create(
    fc.SessionConfig(
        semantic=fc.SemanticConfig(
            language_models={
                "gpt-4o-mini": fc.OpenAILanguageModel(
                    model_name="gpt-4o-mini",
                    rpm=60,
                    tpm=60000,
                )
            },
        )
    )
)

# Load MMLU astronomy subset from Hugging Face
df = session.read.parquet("hf://datasets/cais/mmlu/astronomy/*.parquet")

# Process the data
processed_df = (df
    # Filter for specific criteria
    .filter(fc.col("subject") == "astronomy")
    # Select relevant columns
    .select("question", "choices", "answer")
    # Add difficulty analysis using semantic.map
    .select(
        "*",
        fc.semantic.map(
            "Rate the difficulty of this question from 1-5: {{question}}",
            question=fc.col("question"),
            model_alias="gpt-4o-mini"  # Optional: specify model
        ).alias("difficulty")
    )
)

# Show results
processed_df.show()
```

## Ressources

- [Dépôt GitHub fenic](https://github.com/typedef-ai/fenic)
- [Documentation fenic](https://docs.fenic.ai/latest/)

