Zelfstudie: Een spraak-naar-tekst notitie-app maken

Bouw een toepassing waarmee gesproken audio wordt geconverteerd naar georganiseerde notities, volledig op uw apparaat. De app transcribeert eerst een audiobestand met behulp van een spraak-naar-tekstmodel en gebruikt vervolgens een chatmodel om de transcriptie samen te vatten en in te delen in schone notities.

In deze handleiding leer je hoe je:

  • Een project instellen en de Foundry Local SDK installeren
  • Een spraak-naar-tekstmodel laden en een audiobestand transcriberen
  • Een chatmodel laden en de transcriptie samenvatten
  • Transcriptie en samenvatting combineren in een volledige app
  • De hulpbronnen opschonen

Vereiste voorwaarden

  • Een Windows-, macOS- of Linux-computer met ten minste 8 GB RAM-geheugen.
  • Een .wav audiobestand om te transcriberen (in de zelfstudie wordt een voorbeeldbestand gebruikt).

Pakketten installeren

Opslagplaats met voorbeelden

De volledige voorbeeldcode voor dit artikel is beschikbaar in de opslagplaats Foundry Local GitHub. Om de opslagplaats te klonen en naar het voorbeeld te navigeren, gebruikt u:

git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/cs/tutorial-voice-to-text

Als u op Windows ontwikkelt of verzendt, selecteert u het tabblad Windows. Het Windows-pakket kan worden geïntegreerd met de Windows ML runtime. Het biedt hetzelfde API-oppervlak met een grotere breedte van hardwareversnelling.

dotnet add package Microsoft.AI.Foundry.Local.WinML
dotnet add package OpenAI

De C#-voorbeelden in de GitHub opslagplaats zijn vooraf geconfigureerde projecten. Als u helemaal opnieuw bouwt, leest u de referentie voor de Local SDK van Foundry voor meer informatie over het instellen van uw C#-project met Foundry Local.

Een audiobestand transcriberen

In deze stap laadt u een spraak-naar-tekstmodel en transcribeert u een audiobestand. De Foundry Local SDK gebruikt de whisper modelalias om de beste Fluistervariant voor uw hardware te selecteren.

  • Open Program.cs en vervang de inhoud door de volgende code om de SDK te initialiseren, het spraakmodel te laden en een audiobestand te transcriberen:

    // Load the speech-to-text model
    var speechModel = await catalog.GetModelAsync("whisper-tiny")
        ?? throw new Exception("Speech model not found");
    
    await speechModel.DownloadAsync(progress =>
    {
        Console.Write($"\rDownloading speech model: {progress:F2}%");
        if (progress >= 100f) Console.WriteLine();
    });
    
    await speechModel.LoadAsync();
    Console.WriteLine("Speech model loaded.");
    
    // Transcribe the audio file
    var audioClient = await speechModel.GetAudioClientAsync();
    var transcriptionText = new StringBuilder();
    
    Console.WriteLine("\nTranscription:");
    var audioResponse = audioClient
        .TranscribeAudioStreamingAsync("meeting-notes.wav", ct);
    await foreach (var chunk in audioResponse)
    {
        Console.Write(chunk.Text);
        transcriptionText.Append(chunk.Text);
    }
    Console.WriteLine();
    
    // Unload the speech model to free memory
    await speechModel.UnloadAsync();
    

    De GetAudioClientAsync methode retourneert een client voor audiobewerkingen. De TranscribeAudioStreamingAsync methode streamt transcriptiesegmenten zodra ze beschikbaar komen. U verzamelt de tekst zodat u deze in de volgende stap kunt doorgeven aan het chatmodel.

Opmerking

Vervang "meeting-notes.wav" door het pad naar uw audiobestand. Ondersteunde indelingen zijn WAV, MP3 en FLAC.

De transcriptie samenvatten

Gebruik nu een chatmodel om de onbewerkte transcriptie te ordenen in gestructureerde notities. Laad het qwen2.5-0.5b model en verzend de transcriptie als context met een systeemprompt waarmee het model schone, samengevatte notities kan produceren.

Voeg de volgende code toe na de transcriptiestap:

// Load the chat model for summarization
var chatModel = await catalog.GetModelAsync("qwen2.5-0.5b")
    ?? throw new Exception("Chat model not found");

await chatModel.DownloadAsync(progress =>
{
    Console.Write($"\rDownloading chat model: {progress:F2}%");
    if (progress >= 100f) Console.WriteLine();
});

await chatModel.LoadAsync();
Console.WriteLine("Chat model loaded.");

// Summarize the transcription into organized notes
var chatClient = await chatModel.GetChatClientAsync();
var messages = new List<ChatMessage>
{
    new ChatMessage
    {
        Role = "system",
        Content = "You are a note-taking assistant. Summarize " +
                  "the following transcription into organized, " +
                  "concise notes with bullet points."
    },
    new ChatMessage
    {
        Role = "user",
        Content = transcriptionText.ToString()
    }
};

var chatResponse = await chatClient.CompleteChatAsync(messages, ct);
var summary = chatResponse.Choices[0].Message.Content;
Console.WriteLine($"\nSummary:\n{summary}");

// Clean up
await chatModel.UnloadAsync();
Console.WriteLine("\nDone. Models unloaded.");

De systeemprompt vormen de uitvoerindeling van het model. Door het te instrueren om 'georganiseerde, beknopte notities met opsommingstekens' te produceren, krijgt u gestructureerde inhoud in plaats van een onbewerkte parafrase.

Combineren in een volledige app

Vervang de inhoud van Program.cs met de volledige code voor het transcriberen van een audiobestand en het samenvatten van de transcriptie.

using Microsoft.AI.Foundry.Local;
using Betalgo.Ranul.OpenAI.ObjectModels.RequestModels;
using Microsoft.Extensions.Logging;
using System.Text;

CancellationToken ct = CancellationToken.None;

var config = new Configuration
{
    AppName = "foundry_local_samples",
    LogLevel = Microsoft.AI.Foundry.Local.LogLevel.Information
};

using var loggerFactory = LoggerFactory.Create(builder =>
{
    builder.SetMinimumLevel(
        Microsoft.Extensions.Logging.LogLevel.Information
    );
});
var logger = loggerFactory.CreateLogger<Program>();

// Initialize the singleton instance
await FoundryLocalManager.CreateAsync(config, logger);
var mgr = FoundryLocalManager.Instance;

// Download and register all execution providers.
var currentEp = "";
await mgr.DownloadAndRegisterEpsAsync((epName, percent) =>
{
    if (epName != currentEp)
    {
        if (currentEp != "") Console.WriteLine();
        currentEp = epName;
    }
    Console.Write($"\r  {epName.PadRight(30)}  {percent,6:F1}%");
});
if (currentEp != "") Console.WriteLine();

var catalog = await mgr.GetCatalogAsync();

// Load the speech-to-text model
var speechModel = await catalog.GetModelAsync("whisper-tiny")
    ?? throw new Exception("Speech model not found");

await speechModel.DownloadAsync(progress =>
{
    Console.Write($"\rDownloading speech model: {progress:F2}%");
    if (progress >= 100f) Console.WriteLine();
});

await speechModel.LoadAsync();
Console.WriteLine("Speech model loaded.");

// Transcribe the audio file
var audioClient = await speechModel.GetAudioClientAsync();
var transcriptionText = new StringBuilder();

Console.WriteLine("\nTranscription:");
var audioResponse = audioClient
    .TranscribeAudioStreamingAsync("meeting-notes.wav", ct);
await foreach (var chunk in audioResponse)
{
    Console.Write(chunk.Text);
    transcriptionText.Append(chunk.Text);
}
Console.WriteLine();

// Unload the speech model to free memory
await speechModel.UnloadAsync();

// Load the chat model for summarization
var chatModel = await catalog.GetModelAsync("qwen2.5-0.5b")
    ?? throw new Exception("Chat model not found");

await chatModel.DownloadAsync(progress =>
{
    Console.Write($"\rDownloading chat model: {progress:F2}%");
    if (progress >= 100f) Console.WriteLine();
});

await chatModel.LoadAsync();
Console.WriteLine("Chat model loaded.");

// Summarize the transcription into organized notes
var chatClient = await chatModel.GetChatClientAsync();
var messages = new List<ChatMessage>
{
    new ChatMessage
    {
        Role = "system",
        Content = "You are a note-taking assistant. Summarize " +
                  "the following transcription into organized, " +
                  "concise notes with bullet points."
    },
    new ChatMessage
    {
        Role = "user",
        Content = transcriptionText.ToString()
    }
};

var chatResponse = await chatClient.CompleteChatAsync(messages, ct);
var summary = chatResponse.Choices[0].Message.Content;
Console.WriteLine($"\nSummary:\n{summary}");

// Clean up
await chatModel.UnloadAsync();
Console.WriteLine("\nDone. Models unloaded.");

Opmerking

Vervang "meeting-notes.wav" door het pad naar uw audiobestand. Ondersteunde indelingen zijn WAV, MP3 en FLAC.

Voer de notitie-app uit:

dotnet run

De uitvoer ziet er ongeveer als volgt uit:

Downloading speech model: 100.00%
Speech model loaded.

Transcription:
OK so let's get started with the weekly sync. First, the backend
API is nearly done. Sarah finished the authentication endpoints
yesterday. We still need to add rate limiting before we go to
staging. On the frontend, the dashboard redesign is about seventy
percent complete. Jake, can you walk us through the new layout?
Great. The charts look good. I think we should add a filter for
date range though. For testing, we have about eighty percent code
coverage on the API. We need to write integration tests for the
new auth flow before Friday. Let's plan to do a full regression
test next Tuesday before the release. Any blockers? OK, sounds
like we are in good shape. Let's wrap up.

Downloading chat model: 100.00%
Chat model loaded.

Summary:
- **Backend API**: Authentication endpoints complete. Rate limiting
  still needed before staging deployment.
- **Frontend**: Dashboard redesign 70% complete. New chart layout
  reviewed. Action item: add a date range filter.
- **Testing**: API code coverage at 80%. Integration tests for the
  auth flow due Friday. Full regression test scheduled for next
  Tuesday before release.
- **Status**: No blockers reported. Team is on track.

Done. Models unloaded.

De toepassing transcribeert eerst de audio-inhoud met streaming-uitvoer en geeft vervolgens de samengevoegde tekst door aan een chatmodel waarmee belangrijke punten worden geëxtraheerd en ingedeeld in gestructureerde notities.

Pakketten installeren

Opslagplaats met voorbeelden

De volledige voorbeeldcode voor dit artikel is beschikbaar in de opslagplaats Foundry Local GitHub. Om de opslagplaats te klonen en naar het voorbeeld te navigeren, gebruikt u:

git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/js/tutorial-voice-to-text

Als u op Windows ontwikkelt of verzendt, selecteert u het tabblad Windows. Het Windows-pakket kan worden geïntegreerd met de Windows ML runtime. Het biedt hetzelfde API-oppervlak met een grotere breedte van hardwareversnelling.

npm install foundry-local-sdk-winml openai

Een audiobestand transcriberen

In deze stap laadt u een spraak-naar-tekstmodel en transcribeert u een audiobestand. De Foundry Local SDK gebruikt de whisper modelalias om de beste Fluistervariant voor uw hardware te selecteren.

  1. Maak een bestand met de naam app.js.

  2. Voeg de volgende code toe om de SDK te initialiseren, het spraakmodel te laden en een audiobestand te transcriberen:

    // Load the speech-to-text model
    const speechModel = await manager.catalog.getModel('whisper-tiny');
    await speechModel.download((progress) => {
        process.stdout.write(
            `\rDownloading speech model: ${progress.toFixed(2)}%`
        );
    });
    console.log('\nSpeech model downloaded.');
    
    await speechModel.load();
    console.log('Speech model loaded.');
    
    // Transcribe the audio file
    const audioClient = speechModel.createAudioClient();
    const transcription = await audioClient.transcribe(
        path.join(__dirname, 'meeting-notes.wav')
    );
    console.log(`\nTranscription:\n${transcription.text}`);
    
    // Unload the speech model to free memory
    await speechModel.unload();
    

    De createAudioClient methode retourneert een client voor audiobewerkingen. De transcribe methode accepteert een bestandspad en retourneert een object met een text eigenschap die de getranscribeerde inhoud bevat.

Opmerking

Vervang './meeting-notes.wav' door het pad naar uw audiobestand. Ondersteunde indelingen zijn WAV, MP3 en FLAC.

De transcriptie samenvatten

Gebruik nu een chatmodel om de onbewerkte transcriptie te ordenen in gestructureerde notities. Laad het qwen2.5-0.5b model en verzend de transcriptie als context met een systeemprompt waarmee het model schone, samengevatte notities kan produceren.

Voeg de volgende code toe na de transcriptiestap:

// Load the chat model for summarization
const chatModel = await manager.catalog.getModel('qwen2.5-0.5b');
await chatModel.download((progress) => {
    process.stdout.write(
        `\rDownloading chat model: ${progress.toFixed(2)}%`
    );
});
console.log('\nChat model downloaded.');

await chatModel.load();
console.log('Chat model loaded.');

// Summarize the transcription into organized notes
const chatClient = chatModel.createChatClient();
const messages = [
    {
        role: 'system',
        content: 'You are a note-taking assistant. Summarize ' +
                 'the following transcription into organized, ' +
                 'concise notes with bullet points.'
    },
    {
        role: 'user',
        content: transcription.text
    }
];

const response = await chatClient.completeChat(messages);
const summary = response.choices[0]?.message?.content;
console.log(`\nSummary:\n${summary}`);

// Clean up
await chatModel.unload();
console.log('\nDone. Models unloaded.');

De systeemprompt vormen de uitvoerindeling van het model. Door het te instrueren om 'georganiseerde, beknopte notities met opsommingstekens' te produceren, krijgt u gestructureerde inhoud in plaats van een onbewerkte parafrase.

Combineren in een volledige app

Maak een bestand met de naam app.js en voeg de volgende volledige code toe waarmee een audiobestand wordt getranscribeerd en de transcriptie wordt samengevat:

import { FoundryLocalManager } from 'foundry-local-sdk';
import { fileURLToPath } from 'url';
import path from 'path';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

// Initialize the Foundry Local SDK
const manager = FoundryLocalManager.create({
    appName: 'foundry_local_samples',
    logLevel: 'info'
});

// Download and register all execution providers.
let currentEp = '';
await manager.downloadAndRegisterEps((epName, percent) => {
    if (epName !== currentEp) {
        if (currentEp !== '') process.stdout.write('\n');
        currentEp = epName;
    }
    process.stdout.write(`\r  ${epName.padEnd(30)}  ${percent.toFixed(1).padStart(5)}%`);
});
if (currentEp !== '') process.stdout.write('\n');

// Load the speech-to-text model
const speechModel = await manager.catalog.getModel('whisper-tiny');
await speechModel.download((progress) => {
    process.stdout.write(
        `\rDownloading speech model: ${progress.toFixed(2)}%`
    );
});
console.log('\nSpeech model downloaded.');

await speechModel.load();
console.log('Speech model loaded.');

// Transcribe the audio file
const audioClient = speechModel.createAudioClient();
const transcription = await audioClient.transcribe(
    path.join(__dirname, 'meeting-notes.wav')
);
console.log(`\nTranscription:\n${transcription.text}`);

// Unload the speech model to free memory
await speechModel.unload();

// Load the chat model for summarization
const chatModel = await manager.catalog.getModel('qwen2.5-0.5b');
await chatModel.download((progress) => {
    process.stdout.write(
        `\rDownloading chat model: ${progress.toFixed(2)}%`
    );
});
console.log('\nChat model downloaded.');

await chatModel.load();
console.log('Chat model loaded.');

// Summarize the transcription into organized notes
const chatClient = chatModel.createChatClient();
const messages = [
    {
        role: 'system',
        content: 'You are a note-taking assistant. Summarize ' +
                 'the following transcription into organized, ' +
                 'concise notes with bullet points.'
    },
    {
        role: 'user',
        content: transcription.text
    }
];

const response = await chatClient.completeChat(messages);
const summary = response.choices[0]?.message?.content;
console.log(`\nSummary:\n${summary}`);

// Clean up
await chatModel.unload();
console.log('\nDone. Models unloaded.');

Opmerking

Vervang './meeting-notes.wav' door het pad naar uw audiobestand. Ondersteunde indelingen zijn WAV, MP3 en FLAC.

Voer de notitie-app uit:

node app.js

De uitvoer ziet er ongeveer als volgt uit:

Downloading speech model: 100.00%
Speech model downloaded.
Speech model loaded.

Transcription:
OK so let's get started with the weekly sync. First, the backend
API is nearly done. Sarah finished the authentication endpoints
yesterday. We still need to add rate limiting before we go to
staging. On the frontend, the dashboard redesign is about seventy
percent complete. Jake, can you walk us through the new layout?
Great. The charts look good. I think we should add a filter for
date range though. For testing, we have about eighty percent code
coverage on the API. We need to write integration tests for the
new auth flow before Friday. Let's plan to do a full regression
test next Tuesday before the release. Any blockers? OK, sounds
like we are in good shape. Let's wrap up.

Downloading chat model: 100.00%
Chat model downloaded.
Chat model loaded.

Summary:
- **Backend API**: Authentication endpoints complete. Rate limiting
  still needed before staging deployment.
- **Frontend**: Dashboard redesign 70% complete. New chart layout
  reviewed. Action item: add a date range filter.
- **Testing**: API code coverage at 80%. Integration tests for the
  auth flow due Friday. Full regression test scheduled for next
  Tuesday before release.
- **Status**: No blockers reported. Team is on track.

Done. Models unloaded.

De toepassing transcribeert eerst de audio-inhoud en geeft die tekst vervolgens door aan een chatmodel waarmee belangrijke punten worden geëxtraheerd en in gestructureerde notities worden ingedeeld.

Pakketten installeren

Opslagplaats met voorbeelden

De volledige voorbeeldcode voor dit artikel is beschikbaar in de opslagplaats Foundry Local GitHub. Om de opslagplaats te klonen en naar het voorbeeld te navigeren, gebruikt u:

git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/python/tutorial-voice-to-text

Als u op Windows ontwikkelt of verzendt, selecteert u het tabblad Windows. Het Windows-pakket kan worden geïntegreerd met de Windows ML runtime. Het biedt hetzelfde API-oppervlak met een grotere breedte van hardwareversnelling.

pip install foundry-local-sdk-winml openai

Een audiobestand transcriberen

In deze stap laadt u een spraak-naar-tekstmodel en transcribeert u een audiobestand. De Foundry Local SDK gebruikt de whisper modelalias om de beste Fluistervariant voor uw hardware te selecteren.

  1. Maak een bestand met de naam app.py.

  2. Voeg de volgende code toe om de SDK te initialiseren, het spraakmodel te laden en een audiobestand te transcriberen:

    # Load the speech-to-text model
    speech_model = manager.catalog.get_model("whisper-tiny")
    speech_model.download(
        lambda progress: print(
            f"\rDownloading speech model: {progress:.2f}%",
            end="",
            flush=True,
        )
    )
    print()
    speech_model.load()
    print("Speech model loaded.")
    
    # Transcribe the audio file
    audio_client = speech_model.get_audio_client()
    transcription = audio_client.transcribe("meeting-notes.wav")
    print(f"\nTranscription:\n{transcription.text}")
    
    # Unload the speech model to free memory
    speech_model.unload()
    

    De get_audio_client methode retourneert een client voor audiobewerkingen. De transcribe methode accepteert een bestandspad en retourneert een object met een text eigenschap die de getranscribeerde inhoud bevat.

Opmerking

Vervang "meeting-notes.wav" door het pad naar uw audiobestand. Ondersteunde indelingen zijn WAV, MP3 en FLAC.

De transcriptie samenvatten

Gebruik nu een chatmodel om de onbewerkte transcriptie te ordenen in gestructureerde notities. Laad het qwen2.5-0.5b model en verzend de transcriptie als context met een systeemprompt waarmee het model schone, samengevatte notities kan produceren.

Voeg de volgende code toe na de transcriptiestap:

# Load the chat model for summarization
chat_model = manager.catalog.get_model("qwen2.5-0.5b")
chat_model.download(
    lambda progress: print(
        f"\rDownloading chat model: {progress:.2f}%",
        end="",
        flush=True,
    )
)
print()
chat_model.load()
print("Chat model loaded.")

# Summarize the transcription into organized notes
client = chat_model.get_chat_client()
messages = [
    {
        "role": "system",
        "content": "You are a note-taking assistant. "
                   "Summarize the following transcription "
                   "into organized, concise notes with "
                   "bullet points.",
    },
    {"role": "user", "content": transcription.text},
]

response = client.complete_chat(messages)
summary = response.choices[0].message.content
print(f"\nSummary:\n{summary}")

# Clean up
chat_model.unload()
print("\nDone. Models unloaded.")

De systeemprompt vormen de uitvoerindeling van het model. Door het te instrueren om 'georganiseerde, beknopte notities met opsommingstekens' te produceren, krijgt u gestructureerde inhoud in plaats van een onbewerkte parafrase.

Combineren in een volledige app

Maak een bestand met de naam app.py en voeg de volgende volledige code toe waarmee een audiobestand wordt getranscribeerd en de transcriptie wordt samengevat:

from foundry_local_sdk import Configuration, FoundryLocalManager


def main():
    # Initialize the Foundry Local SDK
    config = Configuration(app_name="foundry_local_samples")
    FoundryLocalManager.initialize(config)
    manager = FoundryLocalManager.instance

    # Download and register all execution providers.
    current_ep = ""
    def ep_progress(ep_name: str, percent: float):
        nonlocal current_ep
        if ep_name != current_ep:
            if current_ep:
                print()
            current_ep = ep_name
        print(f"\r  {ep_name:<30}  {percent:5.1f}%", end="", flush=True)

    manager.download_and_register_eps(progress_callback=ep_progress)
    if current_ep:
        print()

    # Load the speech-to-text model
    speech_model = manager.catalog.get_model("whisper-tiny")
    speech_model.download(
        lambda progress: print(
            f"\rDownloading speech model: {progress:.2f}%",
            end="",
            flush=True,
        )
    )
    print()
    speech_model.load()
    print("Speech model loaded.")

    # Transcribe the audio file
    audio_client = speech_model.get_audio_client()
    transcription = audio_client.transcribe("meeting-notes.wav")
    print(f"\nTranscription:\n{transcription.text}")

    # Unload the speech model to free memory
    speech_model.unload()

    # Load the chat model for summarization
    chat_model = manager.catalog.get_model("qwen2.5-0.5b")
    chat_model.download(
        lambda progress: print(
            f"\rDownloading chat model: {progress:.2f}%",
            end="",
            flush=True,
        )
    )
    print()
    chat_model.load()
    print("Chat model loaded.")

    # Summarize the transcription into organized notes
    client = chat_model.get_chat_client()
    messages = [
        {
            "role": "system",
            "content": "You are a note-taking assistant. "
                       "Summarize the following transcription "
                       "into organized, concise notes with "
                       "bullet points.",
        },
        {"role": "user", "content": transcription.text},
    ]

    response = client.complete_chat(messages)
    summary = response.choices[0].message.content
    print(f"\nSummary:\n{summary}")

    # Clean up
    chat_model.unload()
    print("\nDone. Models unloaded.")


if __name__ == "__main__":
    main()

Opmerking

Vervang "meeting-notes.wav" door het pad naar uw audiobestand. Ondersteunde indelingen zijn WAV, MP3 en FLAC.

Voer de notitie-app uit:

python app.py

De uitvoer ziet er ongeveer als volgt uit:

Downloading speech model: 100.00%
Speech model loaded.

Transcription:
OK so let's get started with the weekly sync. First, the backend
API is nearly done. Sarah finished the authentication endpoints
yesterday. We still need to add rate limiting before we go to
staging. On the frontend, the dashboard redesign is about seventy
percent complete. Jake, can you walk us through the new layout?
Great. The charts look good. I think we should add a filter for
date range though. For testing, we have about eighty percent code
coverage on the API. We need to write integration tests for the
new auth flow before Friday. Let's plan to do a full regression
test next Tuesday before the release. Any blockers? OK, sounds
like we are in good shape. Let's wrap up.

Downloading chat model: 100.00%
Chat model loaded.

Summary:
- **Backend API**: Authentication endpoints complete. Rate limiting
  still needed before staging deployment.
- **Frontend**: Dashboard redesign 70% complete. New chart layout
  reviewed. Action item: add a date range filter.
- **Testing**: API code coverage at 80%. Integration tests for the
  auth flow due Friday. Full regression test scheduled for next
  Tuesday before release.
- **Status**: No blockers reported. Team is on track.

Done. Models unloaded.

De toepassing transcribeert eerst de audio-inhoud en geeft die tekst vervolgens door aan een chatmodel waarmee belangrijke punten worden geëxtraheerd en in gestructureerde notities worden ingedeeld.

Pakketten installeren

Opslagplaats met voorbeelden

De volledige voorbeeldcode voor dit artikel is beschikbaar in de opslagplaats Foundry Local GitHub. Om de opslagplaats te klonen en naar het voorbeeld te navigeren, gebruikt u:

git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/rust/tutorial-voice-to-text

Als u op Windows ontwikkelt of verzendt, selecteert u het tabblad Windows. Het Windows-pakket kan worden geïntegreerd met de Windows ML runtime. Het biedt hetzelfde API-oppervlak met een grotere breedte van hardwareversnelling.

cargo add foundry-local-sdk --features winml
cargo add tokio --features full
cargo add tokio-stream anyhow

Een audiobestand transcriberen

In deze stap laadt u een spraak-naar-tekstmodel en transcribeert u een audiobestand. De Foundry Local SDK gebruikt de whisper modelalias om de beste Fluistervariant voor uw hardware te selecteren.

  • Open src/main.rs en vervang de inhoud door de volgende code om de SDK te initialiseren, het spraakmodel te laden en een audiobestand te transcriberen:

    // Load the speech-to-text model
    let speech_model = manager
        .catalog()
        .get_model("whisper-tiny")
        .await?;
    
    if !speech_model.is_cached().await? {
        println!("Downloading speech model...");
        speech_model
            .download(Some(|progress: f64| {
                print!("\r  {progress:.1}%");
                io::stdout().flush().ok();
            }))
            .await?;
        println!();
    }
    
    speech_model.load().await?;
    println!("Speech model loaded.");
    
    // Transcribe the audio file
    let audio_client = speech_model.create_audio_client();
    let transcription = audio_client
        .transcribe("meeting-notes.wav")
        .await?;
    println!("\nTranscription:\n{}", transcription.text);
    
    // Unload the speech model to free memory
    speech_model.unload().await?;
    

    De create_audio_client methode retourneert een client voor audiobewerkingen. De transcribe methode accepteert een bestandspad en retourneert een object met een text veld met de getranscribeerde inhoud.

Opmerking

Vervang "meeting-notes.wav" door het pad naar uw audiobestand. Ondersteunde indelingen zijn WAV, MP3 en FLAC.

De transcriptie samenvatten

Gebruik nu een chatmodel om de onbewerkte transcriptie te ordenen in gestructureerde notities. Laad het qwen2.5-0.5b model en verzend de transcriptie als context met een systeemprompt waarmee het model schone, samengevatte notities kan produceren.

Voeg de volgende code toe na de transcriptiestap, binnen de main functie:

// Load the chat model for summarization
let chat_model = manager
    .catalog()
    .get_model("qwen2.5-0.5b")
    .await?;

if !chat_model.is_cached().await? {
    println!("Downloading chat model...");
    chat_model
        .download(Some(|progress: f64| {
            print!("\r  {progress:.1}%");
            io::stdout().flush().ok();
        }))
        .await?;
    println!();
}

chat_model.load().await?;
println!("Chat model loaded.");

// Summarize the transcription into organized notes
let client = chat_model
    .create_chat_client()
    .temperature(0.7)
    .max_tokens(512);

let messages: Vec<ChatCompletionRequestMessage> = vec![
    ChatCompletionRequestSystemMessage::from(
        "You are a note-taking assistant. Summarize \
         the following transcription into organized, \
         concise notes with bullet points.",
    )
    .into(),
    ChatCompletionRequestUserMessage::from(
        transcription.text.as_str(),
    )
    .into(),
];

let response = client
    .complete_chat(&messages, None)
    .await?;
let summary = response.choices[0]
    .message
    .content
    .as_deref()
    .unwrap_or("");
println!("\nSummary:\n{}", summary);

// Clean up
chat_model.unload().await?;
println!("\nDone. Models unloaded.");

De systeemprompt vormen de uitvoerindeling van het model. Door het te instrueren om 'georganiseerde, beknopte notities met opsommingstekens' te produceren, krijgt u gestructureerde inhoud in plaats van een onbewerkte parafrase.

Combineren in een volledige app

Vervang de inhoud van src/main.rs met de volledige code voor het transcriberen van een audiobestand en het samenvatten van de transcriptie.

use foundry_local_sdk::{
    ChatCompletionRequestMessage,
    ChatCompletionRequestSystemMessage,
    ChatCompletionRequestUserMessage,
    FoundryLocalConfig, FoundryLocalManager,
};
use std::io::{self, Write};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Initialize the Foundry Local SDK
    let manager = FoundryLocalManager::create(
        FoundryLocalConfig::new("note-taker"),
    )?;

    // Download and register all execution providers.
    manager
        .download_and_register_eps_with_progress(None, {
            let mut current_ep = String::new();
            move |ep_name: &str, percent: f64| {
                if ep_name != current_ep {
                    if !current_ep.is_empty() {
                        println!();
                    }
                    current_ep = ep_name.to_string();
                }
                print!("\r  {:<30}  {:5.1}%", ep_name, percent);
                io::stdout().flush().ok();
            }
        })
        .await?;
    println!();

    // Load the speech-to-text model
    let speech_model = manager
        .catalog()
        .get_model("whisper-tiny")
        .await?;

    if !speech_model.is_cached().await? {
        println!("Downloading speech model...");
        speech_model
            .download(Some(|progress: f64| {
                print!("\r  {progress:.1}%");
                io::stdout().flush().ok();
            }))
            .await?;
        println!();
    }

    speech_model.load().await?;
    println!("Speech model loaded.");

    // Transcribe the audio file
    let audio_client = speech_model.create_audio_client();
    let transcription = audio_client
        .transcribe("meeting-notes.wav")
        .await?;
    println!("\nTranscription:\n{}", transcription.text);

    // Unload the speech model to free memory
    speech_model.unload().await?;

    // Load the chat model for summarization
    let chat_model = manager
        .catalog()
        .get_model("qwen2.5-0.5b")
        .await?;

    if !chat_model.is_cached().await? {
        println!("Downloading chat model...");
        chat_model
            .download(Some(|progress: f64| {
                print!("\r  {progress:.1}%");
                io::stdout().flush().ok();
            }))
            .await?;
        println!();
    }

    chat_model.load().await?;
    println!("Chat model loaded.");

    // Summarize the transcription into organized notes
    let client = chat_model
        .create_chat_client()
        .temperature(0.7)
        .max_tokens(512);

    let messages: Vec<ChatCompletionRequestMessage> = vec![
        ChatCompletionRequestSystemMessage::from(
            "You are a note-taking assistant. Summarize \
             the following transcription into organized, \
             concise notes with bullet points.",
        )
        .into(),
        ChatCompletionRequestUserMessage::from(
            transcription.text.as_str(),
        )
        .into(),
    ];

    let response = client
        .complete_chat(&messages, None)
        .await?;
    let summary = response.choices[0]
        .message
        .content
        .as_deref()
        .unwrap_or("");
    println!("\nSummary:\n{}", summary);

    // Clean up
    chat_model.unload().await?;
    println!("\nDone. Models unloaded.");

    Ok(())
}

Opmerking

Vervang "meeting-notes.wav" door het pad naar uw audiobestand. Ondersteunde indelingen zijn WAV, MP3 en FLAC.

Voer de notitie-app uit:

cargo run

De uitvoer ziet er ongeveer als volgt uit:

Downloading speech model: 100.00%
Speech model loaded.

Transcription:
OK so let's get started with the weekly sync. First, the backend
API is nearly done. Sarah finished the authentication endpoints
yesterday. We still need to add rate limiting before we go to
staging. On the frontend, the dashboard redesign is about seventy
percent complete. Jake, can you walk us through the new layout?
Great. The charts look good. I think we should add a filter for
date range though. For testing, we have about eighty percent code
coverage on the API. We need to write integration tests for the
new auth flow before Friday. Let's plan to do a full regression
test next Tuesday before the release. Any blockers? OK, sounds
like we are in good shape. Let's wrap up.

Downloading chat model: 100.00%
Chat model loaded.

Summary:
- **Backend API**: Authentication endpoints complete. Rate limiting
  still needed before staging deployment.
- **Frontend**: Dashboard redesign 70% complete. New chart layout
  reviewed. Action item: add a date range filter.
- **Testing**: API code coverage at 80%. Integration tests for the
  auth flow due Friday. Full regression test scheduled for next
  Tuesday before release.
- **Status**: No blockers reported. Team is on track.

Done. Models unloaded.

De toepassing transcribeert eerst de audio-inhoud en geeft die tekst vervolgens door aan een chatmodel waarmee belangrijke punten worden geëxtraheerd en in gestructureerde notities worden ingedeeld.

De hulpbronnen opschonen

De modelgewichten blijven in uw lokale cache staan nadat u een model hebt uitgeladen. Dit betekent dat de volgende keer dat u de toepassing uitvoert, de downloadstap wordt overgeslagen en het model sneller wordt geladen. Er is geen extra opschoonbewerking nodig, tenzij u schijfruimte wilt vrijmaken.