Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Buat aplikasi yang membaca file teks dan menghasilkan ringkasan ringkasan — sepenuhnya di perangkat Anda. Ini berguna ketika Anda perlu dengan cepat memahami konten dokumen tanpa membacanya secara penuh, dan ketika dokumen berisi informasi sensitif yang seharusnya tidak meninggalkan komputer Anda.
Dalam tutorial ini, Anda akan belajar cara:
- Menyiapkan proyek dan menginstal SDK Lokal Foundry
- Membaca dokumen teks dari sistem file
- Memuat model dan menghasilkan ringkasan
- Mengontrol output ringkasan dengan perintah sistem
- Memproses beberapa dokumen dalam batch
- Membersihkan sumber daya
Prasyarat
- Komputer Windows, macOS, atau Linux dengan RAM minimal 8 GB.
- .NET 8.0 SDK atau yang lebih baru telah diinstal.
Repositori Penampung Sampel
Kode sampel lengkap untuk artikel ini tersedia di repositori GitHub foundry-samples. Untuk mengkloning repositori dan menavigasi ke penggunaan sampel:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/csharp/foundry-local/tutorial-document-summarizer
Memasang paket
Jika Anda mengembangkan atau mengirim di Windows, pilih tab Windows. Paket Windows terintegrasi dengan runtime Windows ML — ini menyediakan area permukaan API yang sama dengan luas akselerasi perangkat keras yang lebih luas.
dotnet add package Microsoft.AI.Foundry.Local.WinML
dotnet add package OpenAI
Sampel C# di repositori GitHub adalah proyek yang telah dikonfigurasi sebelumnya. Jika Anda membangun dari awal, Anda harus membaca referensi Foundry Local SDK untuk detail selengkapnya tentang cara menyiapkan proyek C# Anda dengan Foundry Local.
Membaca dokumen teks
Sebelum meringkas apa pun, Anda memerlukan contoh dokumen untuk dikerjakan. Buat file yang disebut document.txt di direktori proyek Anda dan tambahkan konten berikut:
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.
Sekarang buka Program.cs dan tambahkan kode berikut untuk membaca dokumen:
var target = args.Length > 0 ? args[0] : "document.txt";
Kode menerima jalur file opsional sebagai argumen baris perintah dan kembali jika document.txt tidak ada yang disediakan.
Membuat ringkasan
Inisialisasi Foundry Local SDK, muat model, dan kirim konten dokumen bersama dengan permintaan sistem yang menginstruksikan model untuk meringkas.
Ganti isi Program.cs dengan kode berikut:
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);
}
Metode ini GetModelAsync menerima alias model, yang merupakan nama pendek yang ramah yang memetakan ke model tertentu dalam katalog. Metode ini DownloadAsync mengambil bobot model ke cache lokal Anda (dan melewati unduhan jika sudah di-cache), dan LoadAsync membuat model siap untuk inferensi. Prompt sistem memberi tahu model untuk menghasilkan ringkasan poin-poin yang berfokus pada ide-ide utama.
Mengendalikan ringkasan output
Situasi yang berbeda memanggil gaya ringkasan yang berbeda. Anda dapat mengubah permintaan sistem untuk mengontrol bagaimana model menyusun outputnya. Berikut adalah tiga variasi yang berguna:
Tanda poin (default dari langkah sebelumnya):
var systemPrompt =
"Summarize the following document into concise bullet points. " +
"Focus on the key points and main ideas.";
Ringkasan satu paragraf:
var systemPrompt =
"Summarize the following document in a single, concise paragraph. " +
"Capture the main argument and supporting points.";
Poin-Poin Utama:
var systemPrompt =
"Extract the three most important takeaways from the following document. " +
"Number each takeaway and keep each to one or two sentences.";
Untuk mencoba gaya yang berbeda, ganti Content nilai dalam pesan sistem dengan salah satu perintah. Model mengikuti instruksi dalam prompt sistem untuk membentuk format dan kedalaman ringkasan.
Memproses beberapa dokumen
Perluas aplikasi untuk meringkas setiap .txt file dalam direktori. Ini berguna ketika Anda memiliki folder dokumen yang semua memerlukan ringkasan.
Metode berikut melakukan iterasi atas semua .txt file dalam direktori tertentu dan meringkas masing-masing file:
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();
}
}
Setiap file dibaca, dipasangkan dengan prompt sistem yang sama, dan dikirim ke model secara independen. Model tidak membawa konteks antar file, sehingga setiap ringkasan mandiri.
Kode lengkap
Ganti konten Program.cs dengan kode lengkap berikut:
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();
}
}
Meringkas satu file:
dotnet run -- document.txt
Atau ringkas setiap .txt file dalam direktori:
dotnet run -- ./docs
Anda melihat output yang mirip dengan:
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 atau yang lebih baru terinstal.
Repositori Penampung Sampel
Kode sampel lengkap untuk artikel ini tersedia di repositori GitHub foundry-samples. Untuk mengkloning repositori dan menavigasi ke penggunaan sampel:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/javascript/foundry-local/tutorial-document-summarizer
Memasang paket
Jika Anda mengembangkan atau mengirim di Windows, pilih tab Windows. Paket Windows terintegrasi dengan runtime Windows ML — ini menyediakan area permukaan API yang sama dengan luas akselerasi perangkat keras yang lebih luas.
npm install foundry-local-sdk-winml openai
Membaca dokumen teks
Sebelum meringkas apa pun, Anda memerlukan contoh dokumen untuk dikerjakan. Buat file yang disebut document.txt di direktori proyek Anda dan tambahkan konten berikut:
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.
Sekarang buat file index.js bernama dan tambahkan kode berikut untuk membaca dokumen:
const target = process.argv[2] || 'document.txt';
Skrip menerima jalur file opsional sebagai argumen baris perintah dan menggunakan document.txt jika tidak ada yang disediakan.
Membuat ringkasan
Inisialisasi Foundry Local SDK, muat model, dan kirim konten dokumen bersama dengan permintaan sistem yang menginstruksikan model untuk meringkas.
Ganti isi index.js dengan kode berikut:
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);
}
Metode ini getModel menerima alias model, yang merupakan nama pendek yang ramah yang memetakan ke model tertentu dalam katalog. Metode ini download mengambil bobot model ke cache lokal Anda (dan melewati unduhan jika sudah di-cache), dan load membuat model siap untuk inferensi. Prompt sistem memberi tahu model untuk menghasilkan ringkasan poin-poin yang berfokus pada ide-ide utama.
Mengendalikan ringkasan output
Situasi yang berbeda memanggil gaya ringkasan yang berbeda. Anda dapat mengubah permintaan sistem untuk mengontrol bagaimana model menyusun outputnya. Berikut adalah tiga variasi yang berguna:
Tanda poin (default dari langkah sebelumnya):
const systemPrompt =
'Summarize the following document into concise bullet points. ' +
'Focus on the key points and main ideas.';
Ringkasan satu paragraf:
const systemPrompt =
'Summarize the following document in a single, concise paragraph. ' +
'Capture the main argument and supporting points.';
Poin-Poin Utama:
const systemPrompt =
'Extract the three most important takeaways from the following document. ' +
'Number each takeaway and keep each to one or two sentences.';
Untuk mencoba gaya yang berbeda, ganti content nilai dalam pesan sistem dengan salah satu perintah. Model mengikuti instruksi dalam prompt sistem untuk membentuk format dan kedalaman ringkasan.
Memproses beberapa dokumen
Perluas aplikasi untuk meringkas setiap .txt file dalam direktori. Ini berguna ketika Anda memiliki folder dokumen yang semua memerlukan ringkasan.
Fungsi berikut melakukan iterasi atas semua .txt file dalam direktori tertentu dan meringkas masing-masing file:
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();
}
}
Setiap file dibaca, dipasangkan dengan prompt sistem yang sama, dan dikirim ke model secara independen. Model tidak membawa konteks antar file, sehingga setiap ringkasan mandiri.
Kode lengkap
Buat file bernama index.js dan tambahkan kode lengkap berikut:
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!');
Meringkas satu file:
node index.js document.txt
Atau ringkas setiap .txt file dalam direktori:
node index.js ./docs
Anda melihat output yang mirip dengan:
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 atau yang lebih baru terinstal.
Repositori Penampung Sampel
Kode sampel lengkap untuk artikel ini tersedia di repositori GitHub foundry-samples. Untuk mengkloning repositori dan menavigasi ke penggunaan sampel:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/python/foundry-local/tutorial-document-summarizer
Memasang paket
Jika Anda mengembangkan atau mengirim di Windows, pilih tab Windows. Paket Windows terintegrasi dengan runtime Windows ML — ini menyediakan area permukaan API yang sama dengan luas akselerasi perangkat keras yang lebih luas.
pip install foundry-local-sdk-winml openai
Membaca dokumen teks
Sebelum meringkas apa pun, Anda memerlukan contoh dokumen untuk dikerjakan. Buat file yang disebut document.txt di direktori proyek Anda dan tambahkan konten berikut:
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.
Sekarang buat file main.py bernama dan tambahkan kode berikut untuk membaca dokumen:
target = sys.argv[1] if len(sys.argv) > 1 else "document.txt"
target_path = Path(target)
Skrip menerima jalur file opsional sebagai argumen baris perintah dan menggunakan document.txt jika tidak ada yang disediakan. Metode Path.read_text membaca seluruh file ke dalam string.
Membuat ringkasan
Inisialisasi Foundry Local SDK, muat model, dan kirim konten dokumen bersama dengan permintaan sistem yang menginstruksikan model untuk meringkas.
Ganti isi main.py dengan kode berikut:
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)
Metode ini get_model menerima alias model, yang merupakan nama pendek yang ramah yang memetakan ke model tertentu dalam katalog. Metode ini download mengambil bobot model ke cache lokal Anda (dan melewati unduhan jika sudah di-cache), dan load membuat model siap untuk inferensi. Prompt sistem memberi tahu model untuk menghasilkan ringkasan poin-poin yang berfokus pada ide-ide utama.
Mengendalikan ringkasan output
Situasi yang berbeda memanggil gaya ringkasan yang berbeda. Anda dapat mengubah permintaan sistem untuk mengontrol bagaimana model menyusun outputnya. Berikut adalah tiga variasi yang berguna:
Tanda poin (default dari langkah sebelumnya):
system_prompt = (
"Summarize the following document into concise bullet points. "
"Focus on the key points and main ideas."
)
Ringkasan satu paragraf:
system_prompt = (
"Summarize the following document in a single, concise paragraph. "
"Capture the main argument and supporting points."
)
Poin-Poin Utama:
system_prompt = (
"Extract the three most important takeaways from the following document. "
"Number each takeaway and keep each to one or two sentences."
)
Untuk mencoba gaya yang berbeda, ganti "content" nilai dalam pesan sistem dengan salah satu perintah. Model mengikuti instruksi dalam prompt sistem untuk membentuk format dan kedalaman ringkasan.
Memproses beberapa dokumen
Perluas aplikasi untuk meringkas setiap .txt file dalam direktori. Ini berguna ketika Anda memiliki folder dokumen yang semua memerlukan ringkasan.
Fungsi berikut melakukan iterasi atas semua .txt file dalam direktori tertentu dan meringkas masing-masing file:
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()
Setiap file dibaca, dipasangkan dengan prompt sistem yang sama, dan dikirim ke model secara independen. Model tidak membawa konteks antar file, sehingga setiap ringkasan mandiri.
Kode lengkap
Buat file bernama main.py dan tambahkan kode lengkap berikut:
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()
Meringkas satu file:
python main.py document.txt
Atau ringkas setiap .txt file dalam direktori:
python main.py ./docs
Anda melihat output yang mirip dengan:
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!
- Rust dan Cargo terpasang (Rust 1.70.0 atau yang lebih baru).
Repositori Penampung Sampel
Kode sampel lengkap untuk artikel ini tersedia di repositori GitHub foundry-samples. Untuk mengkloning repositori dan menavigasi ke penggunaan sampel:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/rust/foundry-local/tutorial-document-summarizer
Memasang paket
Jika Anda mengembangkan atau mengirim di Windows, pilih tab Windows. Paket Windows terintegrasi dengan runtime Windows ML — ini menyediakan area permukaan API yang sama dengan luas akselerasi perangkat keras yang lebih luas.
cargo add foundry-local-sdk --features winml
cargo add tokio --features full
cargo add tokio-stream anyhow
Membaca dokumen teks
Sebelum meringkas apa pun, Anda memerlukan contoh dokumen untuk dikerjakan. Buat file yang disebut document.txt di direktori proyek Anda dan tambahkan konten berikut:
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.
Sekarang buka src/main.rs dan tambahkan kode berikut untuk membaca dokumen:
let target = env::args()
.nth(1)
.unwrap_or_else(|| "document.txt".to_string());
let target_path = Path::new(&target);
Kode menerima jalur file opsional sebagai argumen baris perintah dan kembali jika document.txt tidak ada yang disediakan.
Membuat ringkasan
Inisialisasi Foundry Local SDK, muat model, dan kirim konten dokumen bersama dengan permintaan sistem yang menginstruksikan model untuk meringkas.
Ganti isi src/main.rs dengan kode berikut:
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?;
}
Metode ini get_model menerima alias model, yang merupakan nama pendek yang ramah yang memetakan ke model tertentu dalam katalog. Metode ini download mengambil bobot model ke cache lokal Anda (dan melewati unduhan jika sudah di-cache), dan load membuat model siap untuk inferensi. Prompt sistem memberi tahu model untuk menghasilkan ringkasan poin-poin yang berfokus pada ide-ide utama.
Mengendalikan ringkasan output
Situasi yang berbeda memanggil gaya ringkasan yang berbeda. Anda dapat mengubah permintaan sistem untuk mengontrol bagaimana model menyusun outputnya. Berikut adalah tiga variasi yang berguna:
Tanda poin (default dari langkah sebelumnya):
let system_prompt =
"Summarize the following document into concise bullet points. \
Focus on the key points and main ideas.";
Ringkasan satu paragraf:
let system_prompt =
"Summarize the following document in a single, concise paragraph. \
Capture the main argument and supporting points.";
Poin-Poin Utama:
let system_prompt =
"Extract the three most important takeaways from the following document. \
Number each takeaway and keep each to one or two sentences.";
Untuk mencoba gaya yang berbeda, ganti konten pesan sistem dengan salah satu perintah. Model mengikuti instruksi dalam prompt sistem untuk membentuk format dan kedalaman ringkasan.
Memproses beberapa dokumen
Perluas aplikasi untuk meringkas setiap .txt file dalam direktori. Ini berguna ketika Anda memiliki folder dokumen yang semua memerlukan ringkasan.
Fungsi berikut melakukan iterasi atas semua .txt file dalam direktori tertentu dan meringkas masing-masing file:
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(())
}
Setiap file dibaca, dipasangkan dengan prompt sistem yang sama, dan dikirim ke model secara independen. Model tidak membawa konteks antar file, sehingga setiap ringkasan mandiri.
Kode lengkap
Ganti konten src/main.rs dengan kode lengkap berikut:
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(())
}
Meringkas satu file:
cargo run -- document.txt
Atau ringkas setiap .txt file dalam direktori:
cargo run -- ./docs
Anda melihat output yang mirip dengan:
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!
Membersihkan sumber daya
Bobot model akan tetap berada di cache lokal Anda setelah Anda menghapus model. Ini berarti lain kali Anda menjalankan aplikasi, langkah unduhan dilewati dan model dimuat lebih cepat. Tidak diperlukan pembersihan tambahan kecuali Anda ingin mengklaim kembali ruang disk.