Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Создайте приложение, которое считывает текстовые файлы и создает краткие сводки — полностью на устройстве. Это полезно, если необходимо быстро понять содержимое документов, не читая их полностью, и когда документы содержат конфиденциальную информацию, которая не должна оставить компьютер.
В этом руководстве вы узнаете, как:
- Настройка проекта и установка локального SDK Foundry
- Чтение текстового документа из файловой системы
- Загрузка модели и создание сводки
- Управление сводными выходными данными с помощью системных запросов
- Обработка нескольких документов в пакете
- Очистите ресурсы
Необходимые условия
- Компьютер Windows, macOS или Linux с не менее 8 ГБ ОЗУ.
- должен быть установлен пакет SDK .NET 8.0 или более поздней версии.
Репозиторий примеров
Полный код примера для этой статьи доступен в репозитории GitHub foundry-samples. Чтобы клонировать репозиторий и перейти к примеру, используйте:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/csharp/foundry-local/tutorial-document-summarizer
Установка пакетов
Если вы разрабатываете или поставляете на Windows, выберите вкладку Windows. Пакет Windows интегрируется со средой выполнения Windows ML — обеспечивает тот же интерфейс API с более широким спектром аппаратного ускорения.
dotnet add package Microsoft.AI.Foundry.Local.WinML
dotnet add package OpenAI
Примеры C# в репозитории GitHub предварительно настроены. Если вы создаете с нуля, ознакомьтесь со справочником по локальному пакету SDK Foundry для получения дополнительных сведений о настройке проекта C# с помощью Foundry Local.
Чтение текстового документа
Прежде чем суммировать все, вам потребуется пример документа для работы. Создайте файл, названный document.txt, в каталоге вашего проекта и добавьте следующее содержимое:
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.
Теперь откройте Program.cs и добавьте следующий код для чтения документа:
var target = args.Length > 0 ? args[0] : "document.txt";
Код принимает необязательный путь к файлу в качестве аргумента командной строки и по умолчанию использует document.txt, если путь не указан.
Создание сводки
Инициализировать локальный пакет SDK Для Foundry, загрузить модель и отправить содержимое документа вместе с системным запросом, который указывает модели суммировать.
Замените все содержимое Program.cs следующим кодом:
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);
}
Метод GetModelAsync принимает псевдоним модели, который является коротким понятным именем, которое сопоставляется с определенной моделью в каталоге. Метод DownloadAsync извлекает вес модели в локальный кэш (и пропускает скачивание, если они уже находятся в кэше) и LoadAsync подготавливает модель для выполнения выводов. Системная подсказка сообщает модели создавать сводки в виде маркированных списков, ориентированные на ключевые идеи.
Управление выходными данными сводки
Различные ситуации вызывают различные стили сводки. Вы можете изменить системный запрос, чтобы управлять структурой выходных данных модели. Ниже приведены три полезных варианта:
Точки маркера (по умолчанию из предыдущего шага):
var systemPrompt =
"Summarize the following document into concise bullet points. " +
"Focus on the key points and main ideas.";
Сводка по одному абзацу:
var systemPrompt =
"Summarize the following document in a single, concise paragraph. " +
"Capture the main argument and supporting points.";
Ключевые моменты:
var systemPrompt =
"Extract the three most important takeaways from the following document. " +
"Number each takeaway and keep each to one or two sentences.";
Чтобы попробовать другой стиль, замените значение Content в системном сообщении на один из запросов. Модель следует инструкциям в системном запросе для формирования формата и глубины сводки.
Обработка нескольких документов
Расширьте приложение, чтобы суммировать каждый .txt файл в каталоге. Это полезно, если у вас есть папка документов, для которых требуются сводки.
Следующий метод выполняет итерацию по всем .txt файлам в указанном каталоге и суммирует каждый из них:
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();
}
}
Каждый файл считывается, связывается с одинаковым системным запросом и отправляется в модель независимо. Модель не содержит контекст между файлами, поэтому каждая сводка является автономной.
Полный код
Замените содержимое Program.cs следующим полным кодом:
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();
}
}
Сводка одного файла:
dotnet run -- document.txt
Или обобщайте каждый .txt файл в каталоге:
dotnet run -- ./docs
Выходные данные похожи на следующие:
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 или более поздней версии установлен.
Репозиторий примеров
Полный код примеров для этой статьи доступен в репозитории GitHub foundry-samples. Чтобы клонировать репозиторий и перейти к примеру, используйте:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/javascript/foundry-local/tutorial-document-summarizer
Установка пакетов
Если вы разрабатываете или поставляете на Windows, выберите вкладку Windows. Пакет Windows интегрируется со средой выполнения Windows ML — обеспечивает тот же интерфейс API с более широким спектром аппаратного ускорения.
npm install foundry-local-sdk-winml openai
Чтение текстового документа
Прежде чем суммировать все, вам потребуется пример документа для работы. Создайте файл, названный document.txt, в каталоге вашего проекта и добавьте следующее содержимое:
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.
Теперь создайте файл с именем index.js и добавьте следующий код для чтения документа:
const target = process.argv[2] || 'document.txt';
Скрипт принимает необязательный путь к файлу в качестве аргумента командной строки и, если путь не указан, использует по умолчанию document.txt.
Создание сводки
Инициализировать локальный пакет SDK Для Foundry, загрузить модель и отправить содержимое документа вместе с системным запросом, который указывает модели суммировать.
Замените все содержимое index.js следующим кодом:
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);
}
Метод getModel принимает псевдоним модели, который является коротким понятным именем, которое сопоставляется с определенной моделью в каталоге. Метод download извлекает вес модели в локальный кэш (и пропускает скачивание, если они уже находятся в кэше) и load подготавливает модель для выполнения выводов. Системная подсказка сообщает модели создавать сводки в виде маркированных списков, ориентированные на ключевые идеи.
Управление выходными данными сводки
Различные ситуации вызывают различные стили сводки. Вы можете изменить системный запрос, чтобы управлять структурой выходных данных модели. Ниже приведены три полезных варианта:
Точки маркера (по умолчанию из предыдущего шага):
const systemPrompt =
'Summarize the following document into concise bullet points. ' +
'Focus on the key points and main ideas.';
Сводка по одному абзацу:
const systemPrompt =
'Summarize the following document in a single, concise paragraph. ' +
'Capture the main argument and supporting points.';
Ключевые моменты:
const systemPrompt =
'Extract the three most important takeaways from the following document. ' +
'Number each takeaway and keep each to one or two sentences.';
Чтобы попробовать другой стиль, замените значение content в системном сообщении на один из запросов. Модель следует инструкциям в системном запросе для формирования формата и глубины сводки.
Обработка нескольких документов
Расширьте приложение, чтобы суммировать каждый .txt файл в каталоге. Это полезно, если у вас есть папка документов, для которых требуются сводки.
Следующая функция выполняет итерацию по всем .txt файлам в указанном каталоге и суммирует каждую из них:
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();
}
}
Каждый файл считывается, связывается с одинаковым системным запросом и отправляется в модель независимо. Модель не содержит контекст между файлами, поэтому каждая сводка является автономной.
Полный код
Создайте файл с именем index.js и добавьте следующий полный код:
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!');
Сводка одного файла:
node index.js document.txt
Или обобщайте каждый .txt файл в каталоге:
node index.js ./docs
Выходные данные похожи на следующие:
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 или более поздней версии, установленные.
Репозиторий примеров
Полный исходный код примера для этой статьи доступен в репозитории GitHub foundry-samples. Чтобы клонировать репозиторий и перейти к примеру, используйте:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/python/foundry-local/tutorial-document-summarizer
Установка пакетов
Если вы разрабатываете или поставляете на Windows, выберите вкладку Windows. Пакет Windows интегрируется со средой выполнения Windows ML — обеспечивает тот же интерфейс API с более широким спектром аппаратного ускорения.
pip install foundry-local-sdk-winml openai
Чтение текстового документа
Прежде чем суммировать все, вам потребуется пример документа для работы. Создайте файл, названный document.txt, в каталоге вашего проекта и добавьте следующее содержимое:
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.
Теперь создайте файл с именем main.py и добавьте следующий код для чтения документа:
target = sys.argv[1] if len(sys.argv) > 1 else "document.txt"
target_path = Path(target)
Скрипт принимает необязательный путь к файлу в качестве аргумента командной строки и, если путь не указан, использует по умолчанию document.txt. Метод Path.read_text считывает весь файл в строку.
Создание сводки
Инициализировать локальный пакет SDK Для Foundry, загрузить модель и отправить содержимое документа вместе с системным запросом, который указывает модели суммировать.
Замените все содержимое main.py следующим кодом:
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)
Метод get_model принимает псевдоним модели, который является коротким понятным именем, которое сопоставляется с определенной моделью в каталоге. Метод download извлекает вес модели в локальный кэш (и пропускает скачивание, если они уже находятся в кэше) и load подготавливает модель для выполнения выводов. Системная подсказка сообщает модели создавать сводки в виде маркированных списков, ориентированные на ключевые идеи.
Управление выходными данными сводки
Различные ситуации вызывают различные стили сводки. Вы можете изменить системный запрос, чтобы управлять структурой выходных данных модели. Ниже приведены три полезных варианта:
Точки маркера (по умолчанию из предыдущего шага):
system_prompt = (
"Summarize the following document into concise bullet points. "
"Focus on the key points and main ideas."
)
Сводка по одному абзацу:
system_prompt = (
"Summarize the following document in a single, concise paragraph. "
"Capture the main argument and supporting points."
)
Ключевые моменты:
system_prompt = (
"Extract the three most important takeaways from the following document. "
"Number each takeaway and keep each to one or two sentences."
)
Чтобы попробовать другой стиль, замените значение "content" в системном сообщении на один из запросов. Модель следует инструкциям в системном запросе для формирования формата и глубины сводки.
Обработка нескольких документов
Расширьте приложение, чтобы суммировать каждый .txt файл в каталоге. Это полезно, если у вас есть папка документов, для которых требуются сводки.
Следующая функция выполняет итерацию по всем .txt файлам в указанном каталоге и суммирует каждую из них:
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()
Каждый файл считывается, связывается с одинаковым системным запросом и отправляется в модель независимо. Модель не содержит контекст между файлами, поэтому каждая сводка является автономной.
Полный код
Создайте файл с именем main.py и добавьте следующий полный код:
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()
Сводка одного файла:
python main.py document.txt
Или обобщайте каждый .txt файл в каталоге:
python main.py ./docs
Выходные данные похожи на следующие:
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 и Cargo установлены (Rust 1.70.0 или более поздней версии).
Репозиторий примеров
Полный пример кода для этой статьи доступен в репозитории GitHub foundry-samples. Чтобы клонировать репозиторий и перейти к примеру, используйте:
git clone https://github.com/microsoft-foundry/foundry-samples.git
cd foundry-samples/samples/rust/foundry-local/tutorial-document-summarizer
Установка пакетов
Если вы разрабатываете или поставляете на Windows, выберите вкладку Windows. Пакет Windows интегрируется со средой выполнения Windows ML — обеспечивает тот же интерфейс API с более широким спектром аппаратного ускорения.
cargo add foundry-local-sdk --features winml
cargo add tokio --features full
cargo add tokio-stream anyhow
Чтение текстового документа
Прежде чем суммировать все, вам потребуется пример документа для работы. Создайте файл, названный document.txt, в каталоге вашего проекта и добавьте следующее содержимое:
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.
Теперь откройте src/main.rs и добавьте следующий код для чтения документа:
let target = env::args()
.nth(1)
.unwrap_or_else(|| "document.txt".to_string());
let target_path = Path::new(&target);
Код принимает необязательный путь к файлу в качестве аргумента командной строки и по умолчанию использует document.txt, если путь не указан.
Создание сводки
Инициализировать локальный пакет SDK Для Foundry, загрузить модель и отправить содержимое документа вместе с системным запросом, который указывает модели суммировать.
Замените все содержимое src/main.rs следующим кодом:
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?;
}
Метод get_model принимает псевдоним модели, который является коротким понятным именем, которое сопоставляется с определенной моделью в каталоге. Метод download извлекает вес модели в локальный кэш (и пропускает скачивание, если они уже находятся в кэше) и load подготавливает модель для выполнения выводов. Системная подсказка сообщает модели создавать сводки в виде маркированных списков, ориентированные на ключевые идеи.
Управление выходными данными сводки
Различные ситуации вызывают различные стили сводки. Вы можете изменить системный запрос, чтобы управлять структурой выходных данных модели. Ниже приведены три полезных варианта:
Точки маркера (по умолчанию из предыдущего шага):
let system_prompt =
"Summarize the following document into concise bullet points. \
Focus on the key points and main ideas.";
Сводка по одному абзацу:
let system_prompt =
"Summarize the following document in a single, concise paragraph. \
Capture the main argument and supporting points.";
Ключевые моменты:
let system_prompt =
"Extract the three most important takeaways from the following document. \
Number each takeaway and keep each to one or two sentences.";
Чтобы попробовать другой стиль, замените содержимое системного сообщения одним из запросов. Модель следует инструкциям в системном запросе для формирования формата и глубины сводки.
Обработка нескольких документов
Расширьте приложение, чтобы суммировать каждый .txt файл в каталоге. Это полезно, если у вас есть папка документов, для которых требуются сводки.
Следующая функция выполняет итерацию по всем .txt файлам в указанном каталоге и суммирует каждую из них:
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(())
}
Каждый файл считывается, связывается с одинаковым системным запросом и отправляется в модель независимо. Модель не содержит контекст между файлами, поэтому каждая сводка является автономной.
Полный код
Замените содержимое src/main.rs следующим полным кодом:
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(())
}
Сводка одного файла:
cargo run -- document.txt
Или обобщайте каждый .txt файл в каталоге:
cargo run -- ./docs
Выходные данные похожи на следующие:
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!
Очистите ресурсы
Вес модели остается в локальном кэше после выгрузки модели. Это означает, что при следующем запуске приложения шаг загрузки пропускается, а модель загружается быстрее. Дополнительная очистка не требуется, если вы не хотите освободить место на диске.