전적으로 디바이스에서 텍스트 파일을 읽고 간결한 요약을 생성하는 애플리케이션을 빌드합니다. 이 기능은 문서를 완전히 읽지 않고 문서의 내용을 빠르게 이해해야 하는 경우와 컴퓨터에 나가지 않아야 하는 중요한 정보가 문서에 포함되어 있는 경우에 유용합니다.
이 튜토리얼에서는 다음을 배우게 됩니다:
- 프로젝트 설정 및 Foundry 로컬 SDK 설치
- 파일 시스템에서 텍스트 문서 읽기
- 모델 로드 및 요약 생성
- 시스템 프롬프트를 사용하여 요약 출력 제어
- 일괄 처리로 여러 문서 처리
- 자원을 정리하세요
사전 요구 사항
- RAM이 8GB 이상인 Windows, macOS 또는 Linux 컴퓨터
패키지 설치
샘플 리포지토리
이 문서의 전체 샘플 코드는 Foundry 로컬 GitHub 리포지토리 사용할 수 있습니다. 리포지토리를 복제하고 샘플로 이동하려면 다음을 사용합니다.
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/cs/tutorial-document-summarizer
Windows 개발하거나 배송하는 경우 Windows 탭을 선택합니다. Windows 패키지는 Windows ML 런타임과 통합되어 광범위한 하드웨어 가속으로 동일한 API 노출 영역을 제공합니다.
GitHub 리포지토리의 C# 샘플은 미리 구성된 프로젝트입니다. 처음부터 빌드하는 경우 Foundry Local을 사용하여 C# 프로젝트를 설정하는 방법에 대한 자세한 내용은 Foundry 로컬 SDK 참조 를 참조하세요.
텍스트 문서 읽기
요약하기 전에 작업할 샘플 문서가 필요합니다. 프로젝트 디렉터리에 호출 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 됩니다.
요약 생성
Foundry 로컬 SDK를 초기화하고, 모델을 로드하고, 요약하도록 모델에 지시하는 시스템 프롬프트와 함께 문서 콘텐츠를 보냅니다.
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!
패키지 설치
샘플 리포지토리
이 문서의 전체 샘플 코드는 Foundry 로컬 GitHub 리포지토리 사용할 수 있습니다. 리포지토리를 복제하고 샘플로 이동하려면 다음을 사용합니다.
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/js/tutorial-document-summarizer
Windows 개발하거나 배송하는 경우 Windows 탭을 선택합니다. Windows 패키지는 Windows ML 런타임과 통합되어 광범위한 하드웨어 가속으로 동일한 API 노출 영역을 제공합니다.
텍스트 문서 읽기
요약하기 전에 작업할 샘플 문서가 필요합니다. 프로젝트 디렉터리에 호출 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 됩니다.
요약 생성
Foundry 로컬 SDK를 초기화하고, 모델을 로드하고, 요약하도록 모델에 지시하는 시스템 프롬프트와 함께 문서 콘텐츠를 보냅니다.
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!
패키지 설치
샘플 리포지토리
이 문서의 전체 샘플 코드는 Foundry 로컬 GitHub 리포지토리 사용할 수 있습니다. 리포지토리를 복제하고 샘플로 이동하려면 다음을 사용합니다.
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/python/tutorial-document-summarizer
Windows 개발하거나 배송하는 경우 Windows 탭을 선택합니다. Windows 패키지는 Windows ML 런타임과 통합되어 광범위한 하드웨어 가속으로 동일한 API 노출 영역을 제공합니다.
텍스트 문서 읽기
요약하기 전에 작업할 샘플 문서가 필요합니다. 프로젝트 디렉터리에 호출 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 전체 파일을 문자열로 읽습니다.
요약 생성
Foundry 로컬 SDK를 초기화하고, 모델을 로드하고, 요약하도록 모델에 지시하는 시스템 프롬프트와 함께 문서 콘텐츠를 보냅니다.
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!
패키지 설치
샘플 리포지토리
이 문서의 전체 샘플 코드는 Foundry 로컬 GitHub 리포지토리 사용할 수 있습니다. 리포지토리를 복제하고 샘플로 이동하려면 다음을 사용합니다.
git clone https://github.com/microsoft/Foundry-Local.git
cd Foundry-Local/samples/rust/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 됩니다.
요약 생성
Foundry 로컬 SDK를 초기화하고, 모델을 로드하고, 요약하도록 모델에 지시하는 시스템 프롬프트와 함께 문서 콘텐츠를 보냅니다.
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("doc-summarizer"),
)?;
// 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!
자원을 정리하세요
모델 가중치는 모델을 언로드한 후 로컬 캐시에 유지됩니다. 즉, 다음에 애플리케이션을 실행할 때 다운로드 단계를 건너뛰고 모델이 더 빠르게 로드됩니다. 디스크 공간을 회수하려는 경우가 아니면 추가 정리가 필요하지 않습니다.