Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Utwórz aplikację, która odczytuje pliki tekstowe i generuje zwięzłe podsumowania — w całości na urządzeniu. Jest to przydatne, gdy trzeba szybko zrozumieć zawartość dokumentów bez ich pełnego odczytania, a dokumenty zawierają poufne informacje, które nie powinny opuszczać komputera.
W tym poradniku nauczysz się, jak:
- Konfigurowanie projektu i instalowanie lokalnego zestawu SDK rozwiązania Foundry
- Odczytywanie dokumentu tekstowego z systemu plików
- Ładowanie modelu i generowanie podsumowania
- Kontrolowanie wyjściowych podsumowań za pomocą monitów systemowych
- Przetwarzanie wielu dokumentów zbiorczo
- Uprzątnij zasoby
Wymagania wstępne
- Komputer Windows, macOS lub Linux z co najmniej 8 GB pamięci RAM.
- .NET 8.0 SDK lub nowsza wersja zainstalowana.
Repozytorium przykładów
Kompletny przykładowy kod dla tego artykułu jest dostępny w repozytorium foundry-samples GitHub. Aby sklonować repozytorium i przejść do przykładowego użycia:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/csharp/foundry-local/tutorial-document-summarizer
Instalowanie pakietów
Jeśli programujesz lub wysyłasz na Windows, wybierz kartę Windows. Pakiet Windows integruje się z środowiskiem uruchomieniowym Windows ML — zapewnia ten sam obszar powierzchni interfejsu API z szerszym zakresem przyspieszania sprzętowego.
dotnet add package Microsoft.AI.Foundry.Local.WinML
dotnet add package OpenAI
Przykłady języka C# w repozytorium GitHub to wstępnie skonfigurowane projekty. Jeśli tworzysz od podstaw, zapoznaj się z dokumentacją zestawu SDK lokalnego rozwiązania Foundry , aby uzyskać więcej informacji na temat sposobu konfigurowania projektu w języku C# przy użyciu rozwiązania Foundry Local.
Odczytywanie dokumentu tekstowego
Zanim podsumujesz wszystko, musisz pracować z przykładowym dokumentem. Utwórz plik o nazwie document.txt w katalogu projektu i dodaj następującą zawartość:
Automated testing is a practice in software development where tests are written and executed
by specialized tools rather than performed manually. There are several categories of automated
tests, including unit tests, integration tests, and end-to-end tests. Unit tests verify that
individual functions or methods behave correctly in isolation. Integration tests check that
multiple components work together as expected. End-to-end tests simulate real user workflows
across the entire application.
Adopting automated testing brings measurable benefits to a development team. It catches
regressions early, before they reach production. It reduces the time spent on repetitive
manual verification after each code change. It serves as living documentation of expected
behavior, which helps new team members understand the codebase. Continuous integration
pipelines rely on automated tests to gate deployments and maintain release quality.
Effective test suites follow a few guiding principles. Tests should be deterministic, meaning
they produce the same result every time they run. Tests should be independent, so that one
failing test does not cascade into false failures elsewhere. Tests should run fast, because
slow tests discourage developers from running them frequently. Finally, tests should be
maintained alongside production code so they stay accurate as the application evolves.
Teraz otwórz Program.cs i dodaj następujący kod, aby odczytać dokument:
var target = args.Length > 0 ? args[0] : "document.txt";
Kod akceptuje opcjonalną ścieżkę pliku jako argument wiersza polecenia i domyślnie korzysta z document.txt, jeśli nie podano żadnej.
Generowanie podsumowania
Zainicjuj lokalny zestaw SDK usługi Foundry, załaduj model i wyślij zawartość dokumentu wraz z monitem systemowym, który nakazuje modelowi podsumowanie.
Zastąp zawartość Program.cs następującym kodem:
var systemPrompt =
"Summarize the following document into concise bullet points. " +
"Focus on the key points and main ideas.";
var target = args.Length > 0 ? args[0] : "document.txt";
if (Directory.Exists(target))
{
await SummarizeDirectoryAsync(chatClient, target, systemPrompt, ct);
}
else
{
Console.WriteLine($"--- {Path.GetFileName(target)} ---");
await SummarizeFileAsync(chatClient, target, systemPrompt, ct);
}
Metoda GetModelAsync akceptuje alias modelu, który jest krótką, przyjazną nazwą odnoszącą się do określonego modelu w wykazie. Metoda DownloadAsync pobiera wagi modelu do lokalnej pamięci podręcznej (i pomija pobieranie, jeśli są już buforowane) i LoadAsync sprawia, że model jest gotowy do wnioskowania. Monit systemowy informuje model o utworzeniu podsumowań punktów punktowych skoncentrowanych na kluczowych pomysłach.
Dane wyjściowe podsumowania kontroli
Różne sytuacje wymagają różnych stylów podsumowania. Możesz zmienić monit systemowy, aby kontrolować sposób tworzenia struktury danych wyjściowych modelu. Oto trzy przydatne odmiany:
Punkty punktorowe (wartość domyślna z poprzedniego kroku):
var systemPrompt =
"Summarize the following document into concise bullet points. " +
"Focus on the key points and main ideas.";
Podsumowanie jednego akapitu:
var systemPrompt =
"Summarize the following document in a single, concise paragraph. " +
"Capture the main argument and supporting points.";
Najważniejsze wnioski:
var systemPrompt =
"Extract the three most important takeaways from the following document. " +
"Number each takeaway and keep each to one or two sentences.";
Aby wypróbować inny styl, zastąp Content wartość w komunikacie systemowym jednym z monitów. Model realizuje instrukcje w systemie, aby ukształtować format i głębokość podsumowania.
Przetwarzanie wielu dokumentów
Rozszerz aplikację, aby podsumować każdy .txt plik w katalogu. Jest to przydatne, gdy masz folder dokumentów, które wymagają podsumowań.
Poniższa metoda iteruje wszystkie .txt pliki w danym katalogu i podsumowuje każdy z nich:
async Task SummarizeDirectoryAsync(
dynamic chatClient,
string directory,
string systemPrompt,
CancellationToken ct)
{
var txtFiles = Directory.GetFiles(directory, "*.txt")
.OrderBy(f => f)
.ToArray();
if (txtFiles.Length == 0)
{
Console.WriteLine($"No .txt files found in {directory}");
return;
}
foreach (var txtFile in txtFiles)
{
var fileContent = await File.ReadAllTextAsync(txtFile, ct);
var msgs = new List<ChatMessage>
{
new ChatMessage { Role = "system", Content = systemPrompt },
new ChatMessage { Role = "user", Content = fileContent }
};
Console.WriteLine($"--- {Path.GetFileName(txtFile)} ---");
var resp = await chatClient.CompleteChatAsync(msgs, ct);
Console.WriteLine(resp.Choices[0].Message.Content);
Console.WriteLine();
}
}
Każdy plik jest odczytywany, sparowany z tym samym monitem systemowym i wysyłany niezależnie do modelu. Model nie przenosi kontekstu między plikami, więc każde podsumowanie jest samodzielne.
Kompletny kod
Zastąp zawartość Program.cs następującym kompletnym kodem:
using Microsoft.AI.Foundry.Local;
using Betalgo.Ranul.OpenAI.ObjectModels.RequestModels;
using Microsoft.Extensions.Logging;
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();
// Select and load a model from the catalog
var catalog = await mgr.GetCatalogAsync();
var model = await catalog.GetModelAsync("qwen2.5-0.5b")
?? throw new Exception("Model not found");
await model.DownloadAsync(progress =>
{
Console.Write($"\rDownloading model: {progress:F2}%");
if (progress >= 100f) Console.WriteLine();
});
await model.LoadAsync();
Console.WriteLine("Model loaded and ready.\n");
// Get a chat client
var chatClient = await model.GetChatClientAsync();
var systemPrompt =
"Summarize the following document into concise bullet points. " +
"Focus on the key points and main ideas.";
var target = args.Length > 0 ? args[0] : "document.txt";
if (Directory.Exists(target))
{
await SummarizeDirectoryAsync(chatClient, target, systemPrompt, ct);
}
else
{
Console.WriteLine($"--- {Path.GetFileName(target)} ---");
await SummarizeFileAsync(chatClient, target, systemPrompt, ct);
}
// Clean up
await model.UnloadAsync();
Console.WriteLine("\nModel unloaded. Done!");
async Task SummarizeFileAsync(
dynamic client,
string filePath,
string prompt,
CancellationToken token)
{
var fileContent = await File.ReadAllTextAsync(filePath, token);
var messages = new List<ChatMessage>
{
new ChatMessage { Role = "system", Content = prompt },
new ChatMessage { Role = "user", Content = fileContent }
};
var response = await client.CompleteChatAsync(messages, token);
Console.WriteLine(response.Choices[0].Message.Content);
}
async Task SummarizeDirectoryAsync(
dynamic client,
string directory,
string prompt,
CancellationToken token)
{
var txtFiles = Directory.GetFiles(directory, "*.txt")
.OrderBy(f => f)
.ToArray();
if (txtFiles.Length == 0)
{
Console.WriteLine($"No .txt files found in {directory}");
return;
}
foreach (var txtFile in txtFiles)
{
Console.WriteLine($"--- {Path.GetFileName(txtFile)} ---");
await SummarizeFileAsync(client, txtFile, prompt, token);
Console.WriteLine();
}
}
Podsumowywanie pojedynczego pliku:
dotnet run -- document.txt
Lub podsumuj każdy .txt plik w katalogu:
dotnet run -- ./docs
Zobaczysz dane wyjściowe podobne do:
Downloading model: 100.00%
Model loaded and ready.
--- document.txt ---
- Automated testing uses specialized tools to execute tests instead of manual verification.
- Tests fall into three main categories: unit tests (individual functions), integration tests
(component interactions), and end-to-end tests (full user workflows).
- Key benefits include catching regressions early, reducing manual effort, serving as living
documentation, and gating deployments through continuous integration pipelines.
- Effective test suites should be deterministic, independent, fast, and maintained alongside
production code.
Model unloaded. Done!
- Node.js 20 lub nowszy zainstalowany.
Repozytorium przykładów
Kompletny przykładowy kod dla tego artykułu jest dostępny w repozytorium foundry-samples GitHub. Aby sklonować repozytorium i przejść do przykładowego użycia:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/javascript/foundry-local/tutorial-document-summarizer
Instalowanie pakietów
Jeśli programujesz lub wysyłasz na Windows, wybierz kartę Windows. Pakiet Windows integruje się z środowiskiem uruchomieniowym Windows ML — zapewnia ten sam obszar powierzchni interfejsu API z szerszym zakresem przyspieszania sprzętowego.
npm install foundry-local-sdk-winml openai
Odczytywanie dokumentu tekstowego
Zanim podsumujesz wszystko, musisz pracować z przykładowym dokumentem. Utwórz plik o nazwie document.txt w katalogu projektu i dodaj następującą zawartość:
Automated testing is a practice in software development where tests are written and executed
by specialized tools rather than performed manually. There are several categories of automated
tests, including unit tests, integration tests, and end-to-end tests. Unit tests verify that
individual functions or methods behave correctly in isolation. Integration tests check that
multiple components work together as expected. End-to-end tests simulate real user workflows
across the entire application.
Adopting automated testing brings measurable benefits to a development team. It catches
regressions early, before they reach production. It reduces the time spent on repetitive
manual verification after each code change. It serves as living documentation of expected
behavior, which helps new team members understand the codebase. Continuous integration
pipelines rely on automated tests to gate deployments and maintain release quality.
Effective test suites follow a few guiding principles. Tests should be deterministic, meaning
they produce the same result every time they run. Tests should be independent, so that one
failing test does not cascade into false failures elsewhere. Tests should run fast, because
slow tests discourage developers from running them frequently. Finally, tests should be
maintained alongside production code so they stay accurate as the application evolves.
Teraz utwórz plik o nazwie index.js i dodaj następujący kod, aby odczytać dokument:
const target = process.argv[2] || 'document.txt';
Skrypt akceptuje opcjonalną ścieżkę pliku jako argument wiersza polecenia i wraca do document.txt, jeśli żadna nie została podana.
Generowanie podsumowania
Zainicjuj lokalny zestaw SDK usługi Foundry, załaduj model i wyślij zawartość dokumentu wraz z monitem systemowym, który nakazuje modelowi podsumowanie.
Zastąp zawartość index.js następującym kodem:
const systemPrompt =
'Summarize the following document into concise bullet points. ' +
'Focus on the key points and main ideas.';
const target = process.argv[2] || 'document.txt';
try {
const stats = statSync(target);
if (stats.isDirectory()) {
await summarizeDirectory(chatClient, target, systemPrompt);
} else {
console.log(`--- ${basename(target)} ---`);
await summarizeFile(chatClient, target, systemPrompt);
}
} catch {
console.log(`--- ${basename(target)} ---`);
await summarizeFile(chatClient, target, systemPrompt);
}
Metoda getModel akceptuje alias modelu, który jest krótką, przyjazną nazwą odnoszącą się do określonego modelu w wykazie. Metoda download pobiera wagi modelu do lokalnej pamięci podręcznej (i pomija pobieranie, jeśli są już buforowane) i load sprawia, że model jest gotowy do wnioskowania. Monit systemowy informuje model o utworzeniu podsumowań punktów punktowych skoncentrowanych na kluczowych pomysłach.
Dane wyjściowe podsumowania kontroli
Różne sytuacje wymagają różnych stylów podsumowania. Możesz zmienić monit systemowy, aby kontrolować sposób tworzenia struktury danych wyjściowych modelu. Oto trzy przydatne odmiany:
Punkty punktorowe (wartość domyślna z poprzedniego kroku):
const systemPrompt =
'Summarize the following document into concise bullet points. ' +
'Focus on the key points and main ideas.';
Podsumowanie jednego akapitu:
const systemPrompt =
'Summarize the following document in a single, concise paragraph. ' +
'Capture the main argument and supporting points.';
Najważniejsze wnioski:
const systemPrompt =
'Extract the three most important takeaways from the following document. ' +
'Number each takeaway and keep each to one or two sentences.';
Aby wypróbować inny styl, zastąp content wartość w komunikacie systemowym jednym z monitów. Model realizuje instrukcje w systemie, aby ukształtować format i głębokość podsumowania.
Przetwarzanie wielu dokumentów
Rozszerz aplikację, aby podsumować każdy .txt plik w katalogu. Jest to przydatne, gdy masz folder dokumentów, które wymagają podsumowań.
Następująca funkcja iteruje wszystkie .txt pliki w danym katalogu i podsumowuje każdy z nich:
import { readdirSync } from 'fs';
import { join, basename } from 'path';
async function summarizeDirectory(chatClient, directory, systemPrompt) {
const txtFiles = readdirSync(directory)
.filter(f => f.endsWith('.txt'))
.sort();
if (txtFiles.length === 0) {
console.log(`No .txt files found in ${directory}`);
return;
}
for (const fileName of txtFiles) {
const fileContent = readFileSync(join(directory, fileName), 'utf-8');
const msgs = [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: fileContent }
];
console.log(`--- ${fileName} ---`);
const resp = await chatClient.completeChat(msgs);
console.log(resp.choices[0]?.message?.content);
console.log();
}
}
Każdy plik jest odczytywany, sparowany z tym samym monitem systemowym i wysyłany niezależnie do modelu. Model nie przenosi kontekstu między plikami, więc każde podsumowanie jest samodzielne.
Kompletny kod
Utwórz plik o nazwie index.js i dodaj następujący kompletny kod:
import { FoundryLocalManager } from 'foundry-local-sdk';
import { readFileSync, readdirSync, statSync } from 'fs';
import { join, basename } from 'path';
async function summarizeFile(chatClient, filePath, systemPrompt) {
const content = readFileSync(filePath, 'utf-8');
const messages = [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: content }
];
const response = await chatClient.completeChat(messages);
console.log(response.choices[0]?.message?.content);
}
async function summarizeDirectory(chatClient, directory, systemPrompt) {
const txtFiles = readdirSync(directory)
.filter(f => f.endsWith('.txt'))
.sort();
if (txtFiles.length === 0) {
console.log(`No .txt files found in ${directory}`);
return;
}
for (const fileName of txtFiles) {
console.log(`--- ${fileName} ---`);
await summarizeFile(chatClient, join(directory, fileName), systemPrompt);
console.log();
}
}
// 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');
// Select and load a model from the catalog
const model = await manager.catalog.getModel('qwen2.5-0.5b');
await model.download((progress) => {
process.stdout.write(`\rDownloading model: ${progress.toFixed(2)}%`);
});
console.log('\nModel downloaded.');
await model.load();
console.log('Model loaded and ready.\n');
// Create a chat client
const chatClient = model.createChatClient();
const systemPrompt =
'Summarize the following document into concise bullet points. ' +
'Focus on the key points and main ideas.';
const target = process.argv[2] || 'document.txt';
try {
const stats = statSync(target);
if (stats.isDirectory()) {
await summarizeDirectory(chatClient, target, systemPrompt);
} else {
console.log(`--- ${basename(target)} ---`);
await summarizeFile(chatClient, target, systemPrompt);
}
} catch {
console.log(`--- ${basename(target)} ---`);
await summarizeFile(chatClient, target, systemPrompt);
}
// Clean up
await model.unload();
console.log('\nModel unloaded. Done!');
Podsumowywanie pojedynczego pliku:
node index.js document.txt
Lub podsumuj każdy .txt plik w katalogu:
node index.js ./docs
Zobaczysz dane wyjściowe podobne do:
Downloading model: 100.00%
Model downloaded.
Model loaded and ready.
--- document.txt ---
- Automated testing uses specialized tools to execute tests instead of manual verification.
- Tests fall into three main categories: unit tests (individual functions), integration tests
(component interactions), and end-to-end tests (full user workflows).
- Key benefits include catching regressions early, reducing manual effort, serving as living
documentation, and gating deployments through continuous integration pipelines.
- Effective test suites should be deterministic, independent, fast, and maintained alongside
production code.
Model unloaded. Done!
- Python 3.11 lub nowszy.
Repozytorium przykładów
Kompletny przykładowy kod dla tego artykułu jest dostępny w repozytorium foundry-samples GitHub. Aby sklonować repozytorium i przejść do przykładowego użycia:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/python/foundry-local/tutorial-document-summarizer
Instalowanie pakietów
Jeśli programujesz lub wysyłasz na Windows, wybierz kartę Windows. Pakiet Windows integruje się z środowiskiem uruchomieniowym Windows ML — zapewnia ten sam obszar powierzchni interfejsu API z szerszym zakresem przyspieszania sprzętowego.
pip install foundry-local-sdk-winml openai
Odczytywanie dokumentu tekstowego
Zanim podsumujesz wszystko, musisz pracować z przykładowym dokumentem. Utwórz plik o nazwie document.txt w katalogu projektu i dodaj następującą zawartość:
Automated testing is a practice in software development where tests are written and executed
by specialized tools rather than performed manually. There are several categories of automated
tests, including unit tests, integration tests, and end-to-end tests. Unit tests verify that
individual functions or methods behave correctly in isolation. Integration tests check that
multiple components work together as expected. End-to-end tests simulate real user workflows
across the entire application.
Adopting automated testing brings measurable benefits to a development team. It catches
regressions early, before they reach production. It reduces the time spent on repetitive
manual verification after each code change. It serves as living documentation of expected
behavior, which helps new team members understand the codebase. Continuous integration
pipelines rely on automated tests to gate deployments and maintain release quality.
Effective test suites follow a few guiding principles. Tests should be deterministic, meaning
they produce the same result every time they run. Tests should be independent, so that one
failing test does not cascade into false failures elsewhere. Tests should run fast, because
slow tests discourage developers from running them frequently. Finally, tests should be
maintained alongside production code so they stay accurate as the application evolves.
Teraz utwórz plik o nazwie main.py i dodaj następujący kod, aby odczytać dokument:
target = sys.argv[1] if len(sys.argv) > 1 else "document.txt"
target_path = Path(target)
Skrypt akceptuje opcjonalną ścieżkę pliku jako argument wiersza polecenia i wraca do document.txt, jeśli żadna nie została podana. Metoda Path.read_text odczytuje cały plik do ciągu znaków.
Generowanie podsumowania
Zainicjuj lokalny zestaw SDK usługi Foundry, załaduj model i wyślij zawartość dokumentu wraz z monitem systemowym, który nakazuje modelowi podsumowanie.
Zastąp zawartość main.py następującym kodem:
system_prompt = (
"Summarize the following document into concise bullet points. "
"Focus on the key points and main ideas."
)
target = sys.argv[1] if len(sys.argv) > 1 else "document.txt"
target_path = Path(target)
if target_path.is_dir():
summarize_directory(client, target_path, system_prompt)
else:
print(f"--- {target_path.name} ---")
summarize_file(client, target_path, system_prompt)
Metoda get_model akceptuje alias modelu, który jest krótką, przyjazną nazwą odnoszącą się do określonego modelu w wykazie. Metoda download pobiera wagi modelu do lokalnej pamięci podręcznej (i pomija pobieranie, jeśli są już buforowane) i load sprawia, że model jest gotowy do wnioskowania. Monit systemowy informuje model o utworzeniu podsumowań punktów punktowych skoncentrowanych na kluczowych pomysłach.
Dane wyjściowe podsumowania kontroli
Różne sytuacje wymagają różnych stylów podsumowania. Możesz zmienić monit systemowy, aby kontrolować sposób tworzenia struktury danych wyjściowych modelu. Oto trzy przydatne odmiany:
Punkty punktorowe (wartość domyślna z poprzedniego kroku):
system_prompt = (
"Summarize the following document into concise bullet points. "
"Focus on the key points and main ideas."
)
Podsumowanie jednego akapitu:
system_prompt = (
"Summarize the following document in a single, concise paragraph. "
"Capture the main argument and supporting points."
)
Najważniejsze wnioski:
system_prompt = (
"Extract the three most important takeaways from the following document. "
"Number each takeaway and keep each to one or two sentences."
)
Aby wypróbować inny styl, zastąp "content" wartość w komunikacie systemowym jednym z monitów. Model realizuje instrukcje w systemie, aby ukształtować format i głębokość podsumowania.
Przetwarzanie wielu dokumentów
Rozszerz aplikację, aby podsumować każdy .txt plik w katalogu. Jest to przydatne, gdy masz folder dokumentów, które wymagają podsumowań.
Następująca funkcja iteruje wszystkie .txt pliki w danym katalogu i podsumowuje każdy z nich:
async def summarize_directory(client, directory):
txt_files = sorted(Path(directory).glob("*.txt"))
if not txt_files:
print(f"No .txt files found in {directory}")
return
for txt_file in txt_files:
content = txt_file.read_text(encoding="utf-8")
messages = [
{
"role": "system",
"content": "Summarize the following document into concise bullet points. "
"Focus on the key points and main ideas."
},
{"role": "user", "content": content}
]
print(f"--- {txt_file.name} ---")
response = client.complete_chat(messages)
print(response.choices[0].message.content)
print()
Każdy plik jest odczytywany, sparowany z tym samym monitem systemowym i wysyłany niezależnie do modelu. Model nie przenosi kontekstu między plikami, więc każde podsumowanie jest samodzielne.
Kompletny kod
Utwórz plik o nazwie main.py i dodaj następujący kompletny kod:
import sys
from pathlib import Path
from foundry_local_sdk import Configuration, FoundryLocalManager
def summarize_file(client, file_path, system_prompt):
"""Summarize a single file and print the result."""
content = Path(file_path).read_text(encoding="utf-8")
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": content},
]
response = client.complete_chat(messages)
print(response.choices[0].message.content)
def summarize_directory(client, directory, system_prompt):
"""Summarize all .txt files in a directory."""
txt_files = sorted(Path(directory).glob("*.txt"))
if not txt_files:
print(f"No .txt files found in {directory}")
return
for txt_file in txt_files:
print(f"--- {txt_file.name} ---")
summarize_file(client, txt_file, system_prompt)
print()
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()
# Select and load a model from the catalog
model = manager.catalog.get_model("qwen2.5-0.5b")
model.download(
lambda p: print(f"\rDownloading model: {p:.2f}%", end="", flush=True)
)
print()
model.load()
print("Model loaded and ready.\n")
# Get a chat client
client = model.get_chat_client()
system_prompt = (
"Summarize the following document into concise bullet points. "
"Focus on the key points and main ideas."
)
target = sys.argv[1] if len(sys.argv) > 1 else "document.txt"
target_path = Path(target)
if target_path.is_dir():
summarize_directory(client, target_path, system_prompt)
else:
print(f"--- {target_path.name} ---")
summarize_file(client, target_path, system_prompt)
# Clean up
model.unload()
print("\nModel unloaded. Done!")
if __name__ == "__main__":
main()
Podsumowywanie pojedynczego pliku:
python main.py document.txt
Lub podsumuj każdy .txt plik w katalogu:
python main.py ./docs
Zobaczysz dane wyjściowe podobne do:
Downloading model: 100.00%
Model loaded and ready.
--- document.txt ---
- Automated testing uses specialized tools to execute tests instead of manual verification.
- Tests fall into three main categories: unit tests (individual functions), integration tests
(component interactions), and end-to-end tests (full user workflows).
- Key benefits include catching regressions early, reducing manual effort, serving as living
documentation, and gating deployments through continuous integration pipelines.
- Effective test suites should be deterministic, independent, fast, and maintained alongside
production code.
Model unloaded. Done!
- Zainstalowano oprogramowanie Rust i Cargo (Rust 1.70.0 lub nowszy).
Repozytorium przykładów
Kompletny przykładowy kod dla tego artykułu jest dostępny w repozytorium foundry-samples GitHub. Aby sklonować repozytorium i przejść do przykładowego użycia:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/rust/foundry-local/tutorial-document-summarizer
Instalowanie pakietów
Jeśli programujesz lub wysyłasz na Windows, wybierz kartę Windows. Pakiet Windows integruje się z środowiskiem uruchomieniowym Windows ML — zapewnia ten sam obszar powierzchni interfejsu API z szerszym zakresem przyspieszania sprzętowego.
cargo add foundry-local-sdk --features winml
cargo add tokio --features full
cargo add tokio-stream anyhow
Odczytywanie dokumentu tekstowego
Zanim podsumujesz wszystko, musisz pracować z przykładowym dokumentem. Utwórz plik o nazwie document.txt w katalogu projektu i dodaj następującą zawartość:
Automated testing is a practice in software development where tests are written and executed
by specialized tools rather than performed manually. There are several categories of automated
tests, including unit tests, integration tests, and end-to-end tests. Unit tests verify that
individual functions or methods behave correctly in isolation. Integration tests check that
multiple components work together as expected. End-to-end tests simulate real user workflows
across the entire application.
Adopting automated testing brings measurable benefits to a development team. It catches
regressions early, before they reach production. It reduces the time spent on repetitive
manual verification after each code change. It serves as living documentation of expected
behavior, which helps new team members understand the codebase. Continuous integration
pipelines rely on automated tests to gate deployments and maintain release quality.
Effective test suites follow a few guiding principles. Tests should be deterministic, meaning
they produce the same result every time they run. Tests should be independent, so that one
failing test does not cascade into false failures elsewhere. Tests should run fast, because
slow tests discourage developers from running them frequently. Finally, tests should be
maintained alongside production code so they stay accurate as the application evolves.
Teraz otwórz src/main.rs i dodaj następujący kod, aby odczytać dokument:
let target = env::args()
.nth(1)
.unwrap_or_else(|| "document.txt".to_string());
let target_path = Path::new(&target);
Kod akceptuje opcjonalną ścieżkę pliku jako argument wiersza polecenia i domyślnie korzysta z document.txt, jeśli nie podano żadnej.
Generowanie podsumowania
Zainicjuj lokalny zestaw SDK usługi Foundry, załaduj model i wyślij zawartość dokumentu wraz z monitem systemowym, który nakazuje modelowi podsumowanie.
Zastąp zawartość src/main.rs następującym kodem:
let system_prompt = "Summarize the following document \
into concise bullet points. Focus on the key \
points and main ideas.";
let target = env::args()
.nth(1)
.unwrap_or_else(|| "document.txt".to_string());
let target_path = Path::new(&target);
if target_path.is_dir() {
summarize_directory(
&client,
target_path,
system_prompt,
)
.await?;
} else {
let file_name = target_path
.file_name()
.map(|n| n.to_string_lossy().to_string())
.unwrap_or_else(|| target.clone());
println!("--- {} ---", file_name);
summarize_file(
&client,
target_path,
system_prompt,
)
.await?;
}
Metoda get_model akceptuje alias modelu, który jest krótką, przyjazną nazwą odnoszącą się do określonego modelu w wykazie. Metoda download pobiera wagi modelu do lokalnej pamięci podręcznej (i pomija pobieranie, jeśli są już buforowane) i load sprawia, że model jest gotowy do wnioskowania. Monit systemowy informuje model o utworzeniu podsumowań punktów punktowych skoncentrowanych na kluczowych pomysłach.
Dane wyjściowe podsumowania kontroli
Różne sytuacje wymagają różnych stylów podsumowania. Możesz zmienić monit systemowy, aby kontrolować sposób tworzenia struktury danych wyjściowych modelu. Oto trzy przydatne odmiany:
Punkty punktorowe (wartość domyślna z poprzedniego kroku):
let system_prompt =
"Summarize the following document into concise bullet points. \
Focus on the key points and main ideas.";
Podsumowanie jednego akapitu:
let system_prompt =
"Summarize the following document in a single, concise paragraph. \
Capture the main argument and supporting points.";
Najważniejsze wnioski:
let system_prompt =
"Extract the three most important takeaways from the following document. \
Number each takeaway and keep each to one or two sentences.";
Aby wypróbować inny styl, zastąp zawartość komunikatów systemowych jednym z monitów. Model realizuje instrukcje w systemie, aby ukształtować format i głębokość podsumowania.
Przetwarzanie wielu dokumentów
Rozszerz aplikację, aby podsumować każdy .txt plik w katalogu. Jest to przydatne, gdy masz folder dokumentów, które wymagają podsumowań.
Następująca funkcja iteruje wszystkie .txt pliki w danym katalogu i podsumowuje każdy z nich:
use std::path::Path;
async fn summarize_directory(
client: &foundry_local_sdk::ChatClient,
directory: &Path,
system_prompt: &str,
) -> anyhow::Result<()> {
let mut txt_files: Vec<_> = fs::read_dir(directory)?
.filter_map(|entry| entry.ok())
.filter(|entry| {
entry.path().extension()
.map(|ext| ext == "txt")
.unwrap_or(false)
})
.collect();
txt_files.sort_by_key(|e| e.path());
if txt_files.is_empty() {
println!("No .txt files found in {}", directory.display());
return Ok(());
}
for entry in &txt_files {
let file_content = fs::read_to_string(entry.path())?;
let messages: Vec<ChatCompletionRequestMessage> = vec![
ChatCompletionRequestSystemMessage::new(system_prompt).into(),
ChatCompletionRequestUserMessage::new(&file_content).into(),
];
let file_name = entry.file_name();
println!("--- {} ---", file_name.to_string_lossy());
let resp = client.complete_chat(&messages, None).await?;
let text = resp.choices[0]
.message
.content
.as_deref()
.unwrap_or("");
println!("{}\n", text);
}
Ok(())
}
Każdy plik jest odczytywany, sparowany z tym samym monitem systemowym i wysyłany niezależnie do modelu. Model nie przenosi kontekstu między plikami, więc każde podsumowanie jest samodzielne.
Kompletny kod
Zastąp zawartość src/main.rs następującym kompletnym kodem:
use foundry_local_sdk::{
ChatCompletionRequestMessage,
ChatCompletionRequestSystemMessage,
ChatCompletionRequestUserMessage, FoundryLocalConfig,
FoundryLocalManager,
};
use std::io::{self, Write};
use std::path::Path;
use std::{env, fs};
async fn summarize_file(
client: &foundry_local_sdk::openai::ChatClient,
file_path: &Path,
system_prompt: &str,
) -> anyhow::Result<()> {
let content = fs::read_to_string(file_path)?;
let messages: Vec<ChatCompletionRequestMessage> = vec![
ChatCompletionRequestSystemMessage::from(system_prompt)
.into(),
ChatCompletionRequestUserMessage::from(content.as_str())
.into(),
];
let response =
client.complete_chat(&messages, None).await?;
let summary = response.choices[0]
.message
.content
.as_deref()
.unwrap_or("");
println!("{}", summary);
Ok(())
}
async fn summarize_directory(
client: &foundry_local_sdk::openai::ChatClient,
directory: &Path,
system_prompt: &str,
) -> anyhow::Result<()> {
let mut txt_files: Vec<_> = fs::read_dir(directory)?
.filter_map(|entry| entry.ok())
.filter(|entry| {
entry
.path()
.extension()
.map(|ext| ext == "txt")
.unwrap_or(false)
})
.collect();
txt_files.sort_by_key(|e| e.path());
if txt_files.is_empty() {
println!(
"No .txt files found in {}",
directory.display()
);
return Ok(());
}
for entry in &txt_files {
let file_name = entry.file_name();
println!(
"--- {} ---",
file_name.to_string_lossy()
);
summarize_file(
client,
&entry.path(),
system_prompt,
)
.await?;
println!();
}
Ok(())
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Initialize the Foundry Local SDK
let manager = FoundryLocalManager::create(
FoundryLocalConfig::new("foundry_local_samples"),
)?;
// 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!();
// Select and load a model from the catalog
let model = manager
.catalog()
.get_model("qwen2.5-0.5b")
.await?;
if !model.is_cached().await? {
println!("Downloading model...");
model
.download(Some(|progress: f64| {
print!("\r {progress:.1}%");
io::stdout().flush().ok();
}))
.await?;
println!();
}
model.load().await?;
println!("Model loaded and ready.\n");
// Create a chat client
let client = model
.create_chat_client()
.temperature(0.7)
.max_tokens(512);
let system_prompt = "Summarize the following document \
into concise bullet points. Focus on the key \
points and main ideas.";
let target = env::args()
.nth(1)
.unwrap_or_else(|| "document.txt".to_string());
let target_path = Path::new(&target);
if target_path.is_dir() {
summarize_directory(
&client,
target_path,
system_prompt,
)
.await?;
} else {
let file_name = target_path
.file_name()
.map(|n| n.to_string_lossy().to_string())
.unwrap_or_else(|| target.clone());
println!("--- {} ---", file_name);
summarize_file(
&client,
target_path,
system_prompt,
)
.await?;
}
// Clean up
model.unload().await?;
println!("\nModel unloaded. Done!");
Ok(())
}
Podsumowywanie pojedynczego pliku:
cargo run -- document.txt
Lub podsumuj każdy .txt plik w katalogu:
cargo run -- ./docs
Zobaczysz dane wyjściowe podobne do:
Downloading model: 100.00%
Model loaded and ready.
--- document.txt ---
- Automated testing uses specialized tools to execute tests instead of manual verification.
- Tests fall into three main categories: unit tests (individual functions), integration tests
(component interactions), and end-to-end tests (full user workflows).
- Key benefits include catching regressions early, reducing manual effort, serving as living
documentation, and gating deployments through continuous integration pipelines.
- Effective test suites should be deterministic, independent, fast, and maintained alongside
production code.
Model unloaded. Done!
Uprzątnij zasoby
Wagi modelu są przechowywane w Twojej lokalnej pamięci podręcznej po rozładowaniu modelu. Oznacza to, że przy następnym uruchomieniu aplikacji krok pobierania zostanie pominięty, a model ładuje się szybciej. Nie jest wymagane żadne dodatkowe czyszczenie, chyba że chcesz odzyskać miejsce na dysku.