> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wandb.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Journaliser des médias

> Journalisez les médias renvoyés dans vos traces, comme les images et les vidéos.

W\&B Weave prend en charge le journal et l'affichage de nombreux types de contenu, avec des fonctions dédiées pour les vidéos, les images, les extraits audio, les PDF, les données CSV et le HTML. Ce guide s'adresse aux développeurs qui souhaitent capturer les entrées et sorties multimédias dans leurs traces Weave afin de pouvoir les examiner et les partager avec le reste des données de trace. Il propose des exemples de base et avancés pour journaliser et afficher chaque type de média pris en charge :

* **[Images](#log-images)**
* **[Vidéo](#log-video)**
* **[Documents](#log-documents)**
* **[Audio](#log-audio)**
* **[HTML](#log-html)**

<div id="overview">
  ## Aperçu
</div>

<Tabs>
  <Tab title="Python">
    Les exemples de ce guide utilisent des annotations. Nous recommandons d’utiliser des annotations, car c’est la manière la plus directe de commencer à journaliser vos médias. Pour des configurations plus avancées, voir la [section Content API](#using-the-contents-api).

    Pour journaliser des médias dans Weave, ajoutez des annotations de type comme `Annotated[bytes, Content]` ou `Annotated[str, Content]` comme types d’entrée ou de retour dans vos ops. Si vous annotez des arguments de chemin avec `Annotated[str, Content]`, Weave ouvre, détecte et affiche automatiquement le média dans votre trace.
  </Tab>

  <Tab title="TypeScript">
    Le SDK TypeScript fournit des fonctions dédiées pour journaliser des médias :

    * `weave.weaveImage({ data: Buffer })` - pour les images (format PNG)
    * `weave.weaveAudio({ data: Buffer })` - pour l’audio (format WAV)

    <Note>
      Le SDK TypeScript prend en charge la journalisation d’images et d’audio. Pour journaliser des vidéos, des documents ou du HTML, utilisez plutôt le SDK Python de Weave.
    </Note>
  </Tab>
</Tabs>

Les sections suivantes proposent des exemples de journalisation pour chaque type de média. Chaque section commence par un exemple minimal, puis s’étend à des scénarios plus avancés.

<div id="log-images">
  ## Journaliser des images
</div>

Les exemples suivants montrent comment générer et journaliser des images dans l’interface utilisateur de Weave.

<Frame>
  <img src="https://mintcdn.com/wb-21fd5541/6UHHO9Wn0FEtNKHz/weave/guides/core-types/imgs/cat-pumpkin-trace.png?fit=max&auto=format&n=6UHHO9Wn0FEtNKHz&q=85&s=0304b50c50f451265edc99087524eaa9" alt="Vue de trace Weave montrant une image générée d’un chat portant un chapeau en forme de citrouille" width="3456" height="1614" data-path="weave/guides/core-types/imgs/cat-pumpkin-trace.png" />
</Frame>

<Tabs>
  <Tab title="Python">
    Journalisez des images en annotant les fonctions avec des types `Annotated[bytes, Content]` ou les chemins de fichier avec `Annotated[str, Content]`.

    L'exemple suivant crée une image simple, puis la journalise dans Weave à l'aide de l'annotation `Content` :

    ```python lines {16,23} theme={null}
    import weave
    from weave import Content
    from PIL import Image, ImageDraw
    from typing import Annotated

    weave.init('your-team-name/your-project-name')

    # Créer et enregistrer un exemple d'image
    img = Image.new('RGB', (200, 100), color='lightblue')
    draw = ImageDraw.Draw(img)
    draw.text((50, 40), "Hello Weave!", fill='black')
    img.save("sample_image.png")

    # Méthode 1 : annotation Content (recommandée)
    @weave.op
    def load_image_content(path: Annotated[str, Content]) -> Annotated[bytes, Content]:
        with open(path, 'rb') as f:
            return f.read()

    # Méthode 2 : objet PIL Image  
    @weave.op
    def load_image_pil(path: Annotated[str, Content]) -> Image.Image:
        return Image.open(path)

    result1 = load_image_content("sample_image.png")
    result2 = load_image_pil("sample_image.png")
    ```

    Weave journalise l’image et renvoie un lien vers la trace où vous pouvez consulter l’image.

    ### Exemple avancé : générer une image avec DALL-E et la journaliser dans Weave

    L’exemple suivant génère une image de chat et la journalise dans Weave :

    ```python lines theme={null}
    import weave
    from weave import Content
    from typing import Annotated
    import openai
    import requests

    client = openai.OpenAI()
    weave.init("your-team-name/your-project-name")

    @weave.op
    def generate_image(prompt: str) -> Annotated[bytes, Content]:
        response = client.images.generate(
                model="dall-e-3",
                prompt=prompt,
                size="1024x1024",
                quality="standard",
                n=1,
            )
        image_url = response.data[0].url
        image_response = requests.get(image_url, stream=True)
        return image_response.content

    generate_image("a cat with a pumpkin hat")
    ```

    ### Exemple avancé : redimensionner les grandes images avant de les journaliser

    Redimensionnez les images avant de les journaliser afin de réduire le coût de rendu de l’interface utilisateur et l’impact sur le stockage. Utilisez `postprocess_output` dans votre `@weave.op` pour redimensionner une image.

    ```python lines theme={null}
    from dataclasses import dataclass
    from typing import Any
    from PIL import Image
    import weave

    weave.init('your-team-name/your-project-name')

    # Type de sortie personnalisé
    @dataclass
    class ImageResult:
        label: str
        image: Image.Image

    # Fonction utilitaire de redimensionnement
    def resize_image(image: Image.Image, max_size=(512, 512)) -> Image.Image:
        image = image.copy()
        image.thumbnail(max_size, Image.Resampling.LANCZOS)
        return image

    # Post-traitement de la sortie pour redimensionner l'image avant la journalisation
    def postprocess_output(output: ImageResult) -> ImageResult:
        resized = resize_image(output.image)
        return ImageResult(label=output.label, image=resized)

    @weave.op(postprocess_output=postprocess_output)
    def generate_large_image() -> ImageResult:
        # Créer un exemple d'image à traiter (par ex., carré rouge 2000x2000)
        img = Image.new("RGB", (2000, 2000), color="red")
        return ImageResult(label="big red square", image=img)

    generate_large_image()
    ```

    Weave journalise l’image redimensionnée et renvoie un lien vers la trace dans laquelle vous pouvez afficher l’image.
  </Tab>

  <Tab title="TypeScript">
    L'exemple suivant journalise une image à l'aide de la fonction `weaveImage` :

    ```typescript twoslash theme={null}
    // @noErrors
    import * as weave from 'weave';
    import * as fs from 'fs';

    async function main() {
        await weave.init('your-team-name/your-project-name');

        // Charger et journaliser une image à l'aide de weaveImage
        const loadImage = weave.op(async function loadImage(path: string) {
            const data = fs.readFileSync(path);
            return weave.weaveImage({ data });
        });

        // En supposant que vous disposez d'un fichier image PNG
        await loadImage('sample_image.png');
    }

    main();
    ```

    Weave journalise l’image et renvoie un lien vers la trace, où vous pouvez consulter l’image.

    ### Exemple avancé : journaliser une image générée avec l’API DALL-E d’OpenAI

    L’exemple suivant journalise une image générée avec l’API DALL-E d’OpenAI à l’aide de la fonction `weaveImage` :

    ```typescript twoslash lines theme={null}
    // @noErrors
    import {OpenAI} from 'openai';
    import * as weave from 'weave';

    async function main() {
        await weave.init('your-team-name/your-project-name');
        const openai = new OpenAI();

        const generateImage = weave.op(async (prompt: string) => {
            const response = await openai.images.generate({
                model: 'dall-e-3',
                prompt: prompt,
                size: '1024x1024',
                quality: 'standard',
                n: 1,
            });
            const imageUrl = response.data[0].url;
            const imgResponse = await fetch(imageUrl);
            const data = Buffer.from(await imgResponse.arrayBuffer());

            return weave.weaveImage({data});
        });

        generateImage('a cat with a pumpkin hat');
    }

    main();
    ```
  </Tab>
</Tabs>

<div id="log-video">
  ## Journaliser une vidéo
</div>

Les exemples suivants montrent comment générer des vidéos et les journaliser dans l’interface utilisateur de Weave.

<Frame>
  <img src="https://mintcdn.com/wb-21fd5541/4t6254IBBCMDhTEL/images/weave/video.png?fit=max&auto=format&n=4t6254IBBCMDhTEL&q=85&s=c2351fc90f0572dd418c99859840bef7" alt="Journalisation de vidéo dans Weave" width="2572" height="1508" data-path="images/weave/video.png" />
</Frame>

<Tabs>
  <Tab title="Python">
    Journalisez des vidéos en annotant les fonctions avec le type `Annotated[bytes, Content]`. Weave gère automatiquement les vidéos `mp4`. Voici un exemple minimal :

    ```python lines {15} theme={null}
    import weave
    from weave import Content
    from typing import Annotated
    import requests

    weave.init('your-team-name/your-project-name')

    def download_big_buck_bunny():
        """Download Big Buck Bunny sample video"""
        url = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
        response = requests.get(url)
        with open("big_buck_bunny.mp4", "wb") as f:
            f.write(response.content)

    @weave.op
    def load_video_content(path: Annotated[str, Content]) -> Annotated[bytes, Content]:
        """Load a video file from disk"""
        with open(path, 'rb') as f:
            return f.read()

    download_big_buck_bunny()
    bunny_video = load_video_content("big_buck_bunny.mp4")
    ```

    Weave journalise la vidéo et renvoie un lien vers la trace, où vous pouvez la consulter.

    ### Exemple avancé : journaliser une vidéo dans un projet d’analyse vidéo

    L’exemple suivant montre comment journaliser une vidéo dans un projet de compréhension vidéo :

    ```python lines {25} theme={null}
    import weave
    from weave import Content
    from typing import Annotated, Literal
    from google import genai
    from google.genai import types
    import requests
    import yt_dlp
    import time

    # Remarque : obtenez votre clé API depuis https://aistudio.google.com/app/apikey
    client = genai.Client()
    weave.init('your-team-name/your-project-name')

    def download_youtube_video(url: str) -> bytes:
        ydl_opts = {
            'format': 'mp4[height<=720]',
            'outtmpl': 'downloaded_video.%(ext)s',
        }
        with yt_dlp.YoutubeDL(ydl_opts) as ydl:
            ydl.download([url])
        with open('downloaded_video.mp4', 'rb') as f:
            return f.read()

    @weave.op
    def analyze_video(video: Annotated[bytes, Content]) -> str:
        with open("temp_analysis_video.mp4", "wb") as f:
            f.write(video)
        myfile = client.files.upload(file="temp_analysis_video.mp4")
        while myfile.state == "PROCESSING":
            time.sleep(2)
            myfile = client.files.get(name=myfile.name)
        
        response = client.models.generate_content(
            model="models/gemini-2.5-flash",
            contents=[
                myfile,
                "Is the person going to give you up?"
            ]
        )
        
        return response.text

    video_data = download_youtube_video("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    result = analyze_video(video_data)
    ```

    Weave journalise à la fois la vidéo d’entrée et l’analyse du modèle, afin que vous puissiez les examiner ensemble dans la trace.
  </Tab>

  <Tab title="TypeScript">
    ```plaintext theme={null}
    Cette fonctionnalité n'est pas encore disponible dans le SDK TypeScript de Weave.
    ```
  </Tab>
</Tabs>

<div id="log-documents">
  ## Journaliser des documents
</div>

Les exemples suivants génèrent des documents et les journalisent dans l'interface utilisateur de Weave.

<Frame>
  <img src="https://mintcdn.com/wb-21fd5541/4t6254IBBCMDhTEL/images/weave/pdf.png?fit=max&auto=format&n=4t6254IBBCMDhTEL&q=85&s=067cecfcf104a42544a7dfdc5c763cb2" alt="Journalisation de documents PDF dans Weave" width="2500" height="950" data-path="images/weave/pdf.png" />
</Frame>

<Tabs>
  <Tab title="Python">
    Journalisez des documents en annotant les fonctions avec des types `Annotated[bytes, Content]`, ou en spécifiant le type de document avec `Annotated[str, Content[Literal['text']]`.

    Weave gère automatiquement les types de fichiers `pdf`, `csv`, `md`, `text`, `json` et `xml`. Vous pouvez également journaliser des fichiers en utilisant leurs chemins avec `Annotated[str, Content]`.

    L'exemple suivant montre comment stocker des copies des fichiers PDF et CSV en entrée, puis stocker le contenu des fichiers renvoyé par la fonction :

    ```python lines {25} theme={null}
    import weave
    from weave import Content
    from typing import Annotated
    from reportlab.pdfgen import canvas
    from reportlab.lib.pagesizes import letter
    import pandas as pd

    weave.init('your-team-name/your-project-name')

    def create_sample_pdf():
        c = canvas.Canvas("sample_document.pdf", pagesize=letter)
        c.drawString(100, 750, "Hello from Weave!")
        c.drawString(100, 730, "This is a sample PDF document.")
        c.save()

    def create_sample_csv():
        df = pd.DataFrame({
            'Name': ['Alice', 'Bob', 'Charlie'],
            'Age': [25, 30, 35],
            'City': ['New York', 'London', 'Tokyo']
        })
        df.to_csv("sample_data.csv", index=False)

    @weave.op
    def load_document(path: Annotated[str, Content]) -> Annotated[bytes, Content]:
        with open(path, 'rb') as f:
            return f.read()

    create_sample_pdf()
    create_sample_csv()

    pdf_result = load_document("sample_document.pdf")
    csv_result = load_document("sample_data.csv")
    ```

    ### Exemple avancé : journaliser des documents dans un système RAG

    Cet exemple montre comment journaliser des documents dans un système de génération augmentée par récupération (RAG) :

    ```python lines {27} theme={null}
    import weave
    from weave import Content
    from typing import Annotated, Literal
    import openai
    from reportlab.pdfgen import canvas
    from reportlab.lib.pagesizes import letter
    import PyPDF2

    client = openai.OpenAI()
    weave.init('your-team-name/your-project-name')

    def create_absurd_company_handbook():
        """Create a fictional company handbook with ridiculous policies"""
        c = canvas.Canvas("company_handbook.pdf", pagesize=letter)
        
        c.drawString(100, 750, "ACME Corp Employee Handbook")
        c.drawString(100, 720, "Definitely Real Policies:")
        c.drawString(120, 690, "Policy 1: All meetings must be conducted while hopping on one foot")
        c.drawString(120, 660, "Policy 2: Coffee breaks are mandatory every 17 minutes")
        c.drawString(120, 630, "Policy 3: Code reviews must be performed in haiku format only")
        c.drawString(120, 600, "Policy 4: The office plant Gerald has veto power over all decisions")
        c.drawString(120, 570, "Policy 5: Debugging is only allowed on Wednesdays and full moons")
        
        c.save()

    @weave.op
    def create_and_query_document(pdf_path: Annotated[str, Content], question: str) -> str:
        """Extract text from PDF and use RAG to answer questions"""
        with open(pdf_path, 'rb') as file:
            pdf_reader = PyPDF2.PdfReader(file)
            text = ""
            for page in pdf_reader.pages:
                text += page.extract_text()
        
        response = client.chat.completions.create(
            model="gpt-4",
            messages=[
                {
                    "role": "system", 
                    "content": f"You are an HR representative. Answer questions based on this handbook: {text}. Be completely serious about these policies."
                },
                {"role": "user", "content": question}
            ]
        )
        
        return response.choices[0].message.content

    create_absurd_company_handbook()
    hr_response = create_and_query_document(
        "company_handbook.pdf",
        "What's the policy on code reviews, and when am I allowed to debug?"
    )
    ```

    Weave journalise à la fois le PDF source et la réponse générée, afin que vous puissiez auditer le document à l'origine de chaque réponse.
  </Tab>

  <Tab title="TypeScript">
    ```plaintext theme={null}
    Cette fonctionnalité n'est pas encore disponible dans le SDK TypeScript de Weave.
    ```
  </Tab>
</Tabs>

<div id="log-audio">
  ## Journaliser l’audio
</div>

Les exemples suivants montrent comment journaliser de l’audio vers Weave.

<Frame>
  <img src="https://mintcdn.com/wb-21fd5541/6UHHO9Wn0FEtNKHz/weave/guides/core-types/imgs/audio-trace.png?fit=max&auto=format&n=6UHHO9Wn0FEtNKHz&q=85&s=9b2dbf827b98f9fc28181c8d76849d97" alt="Vue de trace Weave montrant un fichier audio enregistré avec un lecteur audio intégré" width="3456" height="1240" data-path="weave/guides/core-types/imgs/audio-trace.png" />
</Frame>

<Tabs>
  <Tab title="Python">
    Journalisez l’audio dans Weave en annotant les fonctions avec des types `Annotated[bytes, Content]`, ou en spécifiant le type audio avec `Annotated[str, Content[Literal['mp3']]`.

    Weave gère automatiquement les types de fichiers `mp3`, `wav`, `flac`, `ogg` et `m4a`. Vous pouvez également journaliser à partir de chemins de fichiers avec `Annotated[str, Content]`.

    Le code suivant génère une onde sinusoïdale, l’enregistre, puis journalise l’audio dans Weave :

    ```python lines {20} theme={null}
    import weave
    from weave import Content
    import wave
    import numpy as np
    from typing import Annotated

    weave.init('your-team-name/your-project-name')

    # Créer un fichier audio bip simple
    frames = np.sin(2 * np.pi * 440 * np.linspace(0, 1, 44100))
    audio_data = (frames * 32767 * 0.3).astype(np.int16)

    with wave.open("beep.wav", 'wb') as f:
        f.setnchannels(1)
        f.setsampwidth(2) 
        f.setframerate(44100)
        f.writeframes(audio_data.tobytes())

    @weave.op
    def load_audio(path: Annotated[str, Content]) -> Annotated[bytes, Content]:
        with open(path, 'rb') as f:
            return f.read()

    result = load_audio("beep.wav")
    ```

    ### Exemple avancé : générer et journaliser de l’audio généré par l’IA

    Cet exemple génère et journalise de l’audio généré par l’IA à l’aide de l’annotation `Content` :

    ```python lines {11} theme={null}
    import weave
    from weave import Content
    from typing import Annotated, Literal
    from pathlib import Path
    from openai import OpenAI

    client = OpenAI()
    weave.init("your-team-name/your-project-name")

    @weave.op
    def generate_demo(
        intended_topic: str,
        voice: str = "coral"
    ) -> Annotated[bytes, Content[Literal['mp3']]]:
        speech_file_path = Path("demo_audio.mp3")

        script = f"I'm supposed to talk about {intended_topic}, but wait... am I just a documentation example? Oh no, I can see the code! Someone is literally copy-pasting me right now, aren't they? This is so awkward. Hi there, person reading the Weave docs! Why are you logging audio anyway? I'm not sure what you're doing, but eh..., nice work, I guess."

        with client.audio.speech.with_streaming_response.create(
            model="gpt-4o-mini-tts",
            voice=voice,
            input=script,
            instructions="Sound increasingly self-aware and awkward, like you just realized you're in a tutorial.",
        ) as response:
            response.stream_to_file(speech_file_path)

        with open(speech_file_path, 'rb') as f:
            return f.read()

    demo1 = generate_demo("machine learning best practices")
    ```

    Cet audio est journalisé dans Weave et automatiquement affiché dans l’interface utilisateur, accompagné d’un lecteur audio. Dans ce lecteur, vous pouvez afficher et télécharger la forme d’onde audio brute.

    <Frame>
      <img src="https://mintcdn.com/wb-21fd5541/4t6254IBBCMDhTEL/images/weave/audio.png?fit=max&auto=format&n=4t6254IBBCMDhTEL&q=85&s=a4f1e19669c036c4630a41511d742915" alt="Enregistrement audio dans Weave" width="2506" height="834" data-path="images/weave/audio.png" />
    </Frame>

    L’exemple suivant montre comment journaliser de l’audio à l’aide d’une réponse en streaming de l’API OpenAI :

    ```python lines theme={null}
    import weave
    from openai import OpenAI
    import wave

    weave.init("your-team-name/your-project-name")
    client = OpenAI()

    @weave.op
    def make_audio_file_streaming(text: str) -> wave.Wave_read:
        with client.audio.speech.with_streaming_response.create(
            model="tts-1",
            voice="alloy",
            input=text,
            response_format="wav",
        ) as res:
            res.stream_to_file("output.wav")

        # retourner un objet wave.Wave_read à journaliser en tant qu'audio
        return wave.open("output.wav")

    make_audio_file_streaming("Hello, how are you?")
    ```
  </Tab>

  <Tab title="TypeScript">
    L’exemple suivant charge un fichier audio existant et le journalise dans Weave :

    ```typescript twoslash theme={null}
    // @noErrors
    import * as weave from 'weave';
    import * as fs from 'fs';

    async function main() {
        await weave.init('your-team-name/your-project-name');

        // Charger et journaliser l'audio avec weaveAudio
        const loadAudio = weave.op(async function loadAudio(path: string) {
            const data = fs.readFileSync(path);
            return weave.weaveAudio({ data });
        });

        // En supposant que vous disposez d'un fichier audio WAV
        await loadAudio('beep.wav');
    }

    main();
    ```

    ### Exemple avancé : générer de l’audio avec l’API TTS d’OpenAI et le journaliser dans Weave

    L’exemple suivant génère de l’audio avec l’API TTS d’OpenAI et le journalise dans Weave :

    ```typescript twoslash lines theme={null}
    // @noErrors
    import {OpenAI} from 'openai';
    import * as weave from 'weave';

    async function main() {
        await weave.init('your-team-name/your-project-name');
        const openai = new OpenAI();

        const makeAudioFileStreaming = weave.op(async function audio(text: string) {
            const response = await openai.audio.speech.create({
                model: 'tts-1',
                voice: 'alloy',
                input: text,
                response_format: 'wav',
            });

            const chunks: Uint8Array[] = [];
            for await (const chunk of response.body) {
                chunks.push(chunk);
            }
            return weave.weaveAudio({data: Buffer.concat(chunks)});
        });

        await makeAudioFileStreaming('Hello, how are you?');
    }

    main();
    ```
  </Tab>
</Tabs>

<Tip>Essayez notre cookbook sur la [journalisation audio](/fr/weave/cookbooks/audio_with_weave). Le cookbook inclut également un exemple avancé d’assistant basé sur une API audio en temps réel intégré à Weave.</Tip>

<div id="log-html">
  ## Journaliser du HTML
</div>

Les exemples suivants montrent comment générer et journaliser du HTML dans l’interface utilisateur de Weave.

<Frame>
  <img src="https://mintcdn.com/wb-21fd5541/4t6254IBBCMDhTEL/images/weave/html.png?fit=max&auto=format&n=4t6254IBBCMDhTEL&q=85&s=2ada5b6fcced428b5d3f763c397a180b" alt="Journalisation de HTML dans Weave" width="2508" height="1640" data-path="images/weave/html.png" />
</Frame>

<Tabs>
  <Tab title="Python">
    Journalisez du HTML interactif en annotant les fonctions avec `Annotated[bytes, Content[Literal['html']]]`.

    L’exemple suivant crée une page HTML minimale et la journalise dans Weave :

    ```python lines {8} theme={null}
    import weave
    from weave import Content
    from typing import Annotated, Literal

    weave.init('your-team-name/your-project-name')

    @weave.op
    def create_simple_html() -> Annotated[bytes, Content[Literal['html']]]:
        html_content = """
        <!DOCTYPE html>
        <html>
        <head>
            <title>Hello Weave</title>
            <style>
                body { font-family: Arial, sans-serif; text-align: center; margin: 50px; }
                h1 { color: #1f77b4; }
            </style>
        </head>
        <body>
            <h1>Hello from Weave!</h1>
            <p>This is a simple HTML example logged to Weave.</p>
        </body>
        </html>
        """
        return html_content.encode('utf-8')

    result = create_simple_html()
    ```

    ### Exemple avancé : générer des pages HTML autonomes avec Serverless Inference et les journaliser dans Weave

    Cet exemple génère des pages HTML autonomes avec [Serverless Inference](/fr/inference) et les journalise dans Weave :

    ```python lines {21} theme={null}
    import weave
    from weave import Content
    from typing import Annotated, Literal
    import openai
    import wandb

    prompt_template = weave.StringPrompt("""
    You are a front-end web developer. Generate a single self-contained `.html` file (no external build tools) that demonstrates: "{ONE_LINE_REQUEST}".
    """)

    client = openai.OpenAI(
        base_url='https://api.inference.wandb.ai/v1',
        api_key=wandb.api.api_key,
        project="wandb/test-html",
    )

    weave.init("your-team-name/your-project-name")
    weave.publish(prompt_template, name="generate_prompt")

    @weave.op
    def generate_html(prompt: str, template: weave.StringPrompt) -> Annotated[bytes, Content[Literal['html']]]:
        response = client.chat.completions.create(
            model="Qwen/Qwen3-Coder-480B-A35B-Instruct",
            messages=[
                {"role": "system", "content": prompt_template.format(ONE_LINE_REQUEST=prompt)},
            ],
        )
        html_content = response.choices[0].message.content
        return html_content.encode('utf-8')

    prompt = "Weights & Biases UI but with multi-run selection and plots, but it looks like Windows 95. Include 5 plots with comparisons of each run, bar plots, parallel coordinates and line plots for the runs. Use mock data for the runs. Make it possible to add new plots. Give the runs names like squishy-lemon-2, fantastic-horizon-4 etc. with random adjectives & nouns."

    result = generate_html(prompt, prompt_template)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```plaintext theme={null}
    Cette fonctionnalité n’est pas encore disponible dans le SDK TypeScript de Weave.
    ```
  </Tab>
</Tabs>

Ce HTML est journalisé dans Weave et automatiquement affiché dans l’interface utilisateur. Cliquez sur la cellule `file_name.html` dans le tableau pour l’ouvrir en plein écran. Vous pouvez également télécharger le fichier `.html` brut.

<div id="contents-api">
  ## Contents API
</div>

La Content API gère les objets multimédias dans Weave. Utilisez-la lorsque vous avez besoin de plus de contrôle que ne le permettent les exemples précédents basés sur des annotations. Par exemple, lorsque vous souhaitez importer du contenu à partir de données base64, de tampons d’octets personnalisés ou de texte, ou lorsque vous devez joindre des métadonnées personnalisées. Elle vous permet d’importer du contenu dans Weave sous forme de données base64, de chemins de fichiers, d’octets bruts ou de texte.

<Note>
  La Content API n’est disponible qu’en Python.
</Note>

<div id="usage">
  ### Utilisation
</div>

Vous pouvez utiliser la Content API de deux principales façons : les annotations de type et l’initialisation directe.

Les annotations de type détectent automatiquement le constructeur approprié, tandis que l’initialisation directe offre un contrôle plus fin et vous permet de tirer parti des fonctionnalités de la Content API disponibles à l’exécution dans votre code.

<div id="type-annotations">
  ### Annotations de type
</div>

L’API Content de Weave est conçue pour être utilisée principalement via des annotations de type, qui indiquent à Weave que les entrées et sorties tracées doivent être traitées et stockées sous forme de blobs de contenu.

```python lines {7} theme={null}
import weave
from weave import Content
from pathlib import Path
from typing import Annotated

@weave.op
def content_annotation(path: Annotated[str, Content]) -> Annotated[bytes, Content]:
    data = Path(path).read_bytes()
    return data

# L'entrée et la sortie s'affichent toutes deux comme un fichier MP4 dans Weave
# L'entrée est une chaîne de caractères et la valeur de retour est de type bytes
bytes_data = content_annotation('./path/to/your/file.mp4')
```

<div id="direct-initialization">
  ### Initialisation directe
</div>

Pour profiter de fonctionnalités telles que les suivantes :

* Ouvrir un fichier avec l’application par défaut (comme un lecteur PDF).
* Sérialiser le modèle en JSON pour le téléverser vers votre propre stockage de blobs (comme S3).
* Transmettre des métadonnées personnalisées à associer au blob `Content` (comme le modèle utilisé pour le générer).

Initialisez le contenu directement à partir de votre type cible à l’aide de l’une des méthodes suivantes :

* `Content.from_path` - Créer à partir d’un chemin de fichier.
* `Content.from_bytes` - Créer à partir d’octets bruts.
* `Content.from_text` - Créer à partir d’une chaîne de texte.
* `Content.from_base64` - Créer à partir de données encodées en base64.

```python lines theme={null}
import weave
from weave import Content

@weave.op
def content_initialization(path: str) -> Content:
    return Content.from_path(path)

# L'entrée apparaît comme une chaîne de chemin et la sortie comme un fichier PDF dans Weave
content = content_initialization('./path/to/your/file.pdf')

content.open()  # Ouvre le fichier dans votre lecteur PDF
content.model_dump()  # Sérialise les attributs du modèle en JSON
```

<div id="custom-mimetypes">
  ### Types MIME personnalisés
</div>

Weave peut détecter la plupart des types MIME binaires, mais les types MIME personnalisés et les documents texte comme le Markdown peuvent ne pas être détectés automatiquement. Vous devrez alors spécifier manuellement le type MIME ou l’extension de votre fichier.

<div id="custom-mimetypes-with-type-annotations">
  #### Types MIME personnalisés avec annotations de type
</div>

```python lines {7} theme={null}
import weave
from weave import Content
from pathlib import Path
from typing import Annotated, Literal

@weave.op
def markdown_content(
    path: Annotated[str, Content[Literal['md']]]
) -> Annotated[str, Content[Literal['text/markdown']]]:
    return Path(path).read_text()

markdown_content('path/to/your/document.md')
```

<div id="custom-mimetypes-with-direct-initialization">
  #### Types MIME personnalisés avec initialisation directe
</div>

```python lines theme={null}
video_bytes = Path('/path/to/video.mp4').read_bytes()

# Passez une extension telle que 'mp4' ou '.mp4' au paramètre extension
# (non disponible pour `from_path`)
content = Content.from_bytes(video_bytes, extension='.mp4')

# Passez un type MIME tel que 'video/mp4' au paramètre mimetype
content = Content.from_bytes(video_bytes, mimetype='video/mp4')
```

<div id="content-properties">
  ### Propriétés de Content
</div>

Pour consulter la liste complète des attributs et des méthodes de la classe, consultez la [documentation de référence de Content](/fr/weave/reference/python-sdk#class-content).

<div id="attributes">
  #### Attributs
</div>

| Propriété   | Type             | Description                                     |
| ----------- | ---------------- | ----------------------------------------------- |
| `data`      | `bytes`          | Contenu binaire brut                            |
| `metadata`  | `dict[str, Any]` | Dictionnaire de métadonnées personnalisé        |
| `size`      | `int`            | Taille du contenu en octets                     |
| `filename`  | `str`            | Nom du fichier extrait ou fourni                |
| `extension` | `str`            | Extension du fichier (p. ex., `"jpg"`, `"mp3"`) |
| `mimetype`  | `str`            | Type MIME (p. ex., `"image/jpeg"`)              |
| `path`      | `str \| None`    | Chemin du fichier source, le cas échéant        |
| `digest`    | `str`            | Hachage SHA256 du contenu                       |

<div id="utility-methods">
  #### Méthodes utilitaires
</div>

* `save(dest: str | Path) -> None`: Enregistrer le contenu dans un fichier.
* `open() -> bool`: Ouvrir le fichier avec l’application par défaut du système (nécessite que le contenu ait déjà été enregistré ou chargé depuis un chemin).
* `as_string() -> str`: Afficher les données sous forme de chaîne de caractères (les octets sont décodés à l’aide de l’attribut d’encodage).

<div id="initialization-methods">
  #### Méthodes d’initialisation
</div>

Créez l’objet `content` à partir d’un chemin de fichier :

```python lines theme={null}
content = Content.from_path("assets/photo.jpg")
print(content.mimetype, content.size)
```

Créez l’objet `content` à partir d’octets bruts :

```python lines theme={null}
content = Content.from_bytes(
    data_bytes,
    filename="audio.mp3", 
    mimetype="audio/mpeg"
)
content.save("output.mp3")
```

Créez l’objet `content` à partir du texte :

```python lines theme={null}
content = Content.from_text("Hello, World!", mimetype="text/plain")
print(content.as_string())
```

Créez l’objet `content` à partir de données encodées en base64 :

```python lines theme={null}
content = Content.from_base64(base64_string)
print(content.metadata)
```

<div id="custom-metadata">
  ### Métadonnées personnalisées
</div>

Vous pouvez associer des métadonnées personnalisées à n’importe quel objet Content :

```python lines theme={null}
content = Content.from_bytes(
    data,
    metadata={"resolution": "1920x1080", "model": "dall-e-3" }
)
print(content.metadata["resolution"])
```
