Gemini, 로컬 및 무료, Chrome 및 Angular와 함께
Source: Dev.to
위 링크에 있는 전체 텍스트를 제공해 주시면, 해당 내용을 한국어로 번역해 드리겠습니다. 코드 블록, URL 및 마크다운 형식은 그대로 유지하고, 본문만 번역해 드립니다.
Available APIs
- Language API – 주어진 텍스트의 언어를 감지합니다.
- Translation API – 텍스트를 한 언어에서 다른 언어로 번역합니다.
- Prompt API – 구조화된 출력을 위한 자유 형식 프롬프트를 받습니다.
- Summarization API – 긴 텍스트를 간결한 요약으로 압축합니다.
이 포스트에서는 토큰 비용을 지불하지 않고도 실제로 유용한 기능을 추가할 수 있는 방법을 보여드리겠습니다.
제가 특히 흥미롭게 생각하는 점은 구글 검색이 이제 종종 AI‑생성 요약이나 직접적인 답변을 제공한다는 것입니다. 때로는 전체 기사를 읽는 대신 핵심 요점만 원하죠. 바로 그 아이디어를 여기서 구현해 보겠습니다.
Google Search Summary feature
Goal: 블로그 포스트에 대해 TL;DR(읽기 너무 긴) 섹션을 불릿 포인트 형태로 자동 생성하는 작은 로직을 구축하여, 독자들이 즉시 내용을 파악할 수 있도록 합니다.
시작하기
-
Chrome 업데이트 – 최신 버전을 실행하고 있는지 확인하세요. 이전 버전에는 최신 온‑디바이스 모델이 포함되지 않을 수 있습니다.
-
필요한 플래그를 활성화하고 Chrome을 재시작하세요:
chrome://flags/#optimization-guide-on-device-model chrome://flags/#prompt-api-for-gemini-nano-multimodal-input -
모델을 설치하려면 콘솔(또는 Chrome API에 접근 가능한 스크립트)에서 아래 코드를 실행하세요:
const session = await LanguageModel.create({ monitor(m) { m.addEventListener('downloadprogress', (e) => { console.log(`Downloaded ${e.loaded * 100}%`); }); }, }); const summarizer = await Summarizer.create({ monitor(m) { m.addEventListener('downloadprogress', (e) => { console.log(`Downloaded ${e.loaded * 100}%`); }); }, });다운로드가 **100 %**에 도달하면 API를 사용할 준비가 된 것입니다.
Source: …
Implementation
우리는 Angular를 사용하여 구현합니다. 아직 설정하지 않았다면:
# Install the Angular CLI
npm install -g @angular/cli
# Create a new project (replace <name> with your desired name)
ng new <name>
UI Prompt (for Antigravity IDE)
Below is the prompt we fed to Google’s new IDE, Antigravity, to generate the UI component:
You are an expert Frontend Developer. Your task is to build a premium, visually stunning blog post page for an Angular application. The project is already initialized.
### Goal
Create a standalone component named `BlogPost` that serves as a static blog post page. The design should be modern, "dark mode" by default, and evoke a high‑tech, futuristic feel suitable for the topic of "Agentic AI".
### Structure & Content Constraints
The page must contain the following specific elements, stacked vertically:
1. **Header Section**
- **Tags**: A row of small pill‑shaped tags: "Artificial Intelligence", "Future", "Tech".
- **Title**: Large, impactful typography: "The Rise of Agentic AI: A New Era of Coding".
- **Subtitle**: A lighter sub‑heading: "How autonomous agents are transforming the software development landscape".
2. **TL;DR Section**
- Placed prominently below the header but before the main content.
- Must clearly stand out (e.g., border, different background tint, or accent color).
- **Heading**: "TL;DR".
- **Content**: A bulleted list summarizing the article (e.g., AI moving from autocomplete to autonomy, changing developer roles to architects).
3. **Main Content**
- Several paragraphs discussing "Agentic AI".
- Explain how it differs from traditional coding assistants.
- Discuss the shift from "writing code" to "guiding agents".
- Use highly readable typography with good line height and contrast.
### Design & Aesthetics (Crucial)
- **Theme**: Dark mode. Background very dark (nearly black), text light grey/white.
- **Typography**: Clean sans‑serif font like *Inter*.
- **Color Palette**: Neon/electric accents.
- *Primary Accent*: Electric teal or cyan (for tags/highlights).
- *Secondary Accent*: Electric purple (for the TL;DR section or links).
- **Visual Style**:
- Blog post container looks like a "card" floating in the center with subtle shadow and rounded corners.
- Subtle gradients for the title if possible.
- Fully responsive (mobile‑friendly).
### Technical Requirements
- Use Angular **Standalone Components**.
- Hardcode all text directly in the template or component class.
- **Do NOT** implement any actual AI calls or backend services; this is purely a UI implementation task.
Resulting UI Mockup
이 시점에서는 UI에만 집중합니다. 아직 AI 호출은 없습니다.
Source: …
API 구현
새로운 Angular 서비스를 생성하여 온‑디바이스 API를 래핑합니다. 아래는 깔끔한 시작 템플릿입니다:
import { Injectable } from '@angular/core';
// Types for the Chrome on‑device APIs (replace with actual typings if available)
declare const LanguageModel: any;
declare const Summarizer: any;
@Injectable({
providedIn: 'root',
})
export class OnDeviceAiService {
private languageModel: any;
private summarizer: any;
constructor() {
this.initModels();
}
/** Load the on‑device models */
private async initModels(): Promise {
this.languageModel = await LanguageModel.create({
monitor: (m: any) => {
m.addEventListener('downloadprogress', (e: any) => {
console.log(`Language model download: ${e.loaded * 100}%`);
});
},
});
this.summarizer = await Summarizer.create({
monitor: (m: any) => {
m.addEventListener('downloadprogress', (e: any) => {
console.log(`Summarizer download: ${e.loaded * 100}%`);
});
},
});
}
/** Detect language of a string */
async detectLanguage(text: string): Promise {
if (!this.languageModel) {
await this.initModels();
}
return this.languageModel.detectLanguage(text);
}
/** Summarize a block of text */
async summarize(text: string): Promise {
if (!this.summarizer) {
await this.initModels();
}
return this.summarizer.summarize(text);
}
}
이제 OnDeviceAiService를 원하는 컴포넌트(예: BlogPost 컴포넌트)에서 주입하고 summarize()를 호출하면 TL;DR 불릿 리스트를 생성할 수 있습니다.
다음 단계
- 서비스를
BlogPost컴포넌트에 연결하고 TL;DR 섹션에 생성된 불릿을 표시합니다. - 모델 로드에 실패했을 때를 대비해 오류 처리를 추가합니다.
- 보다 구조화된 출력(예: JSON 형식 요약)을 위해 Prompt API를 실험합니다.
이것으로 끝입니다! 이제 토큰 예산을 소모하지 않고 웹 앱에 풍부함을 더할 수 있는 무상(on‑device) AI 파이프라인이 준비되었습니다. 즐거운 코딩 되세요!
Chrome의 Summarizer 및 Prompt API를 활용한 AI 기반 TL;DR 생성
아래는 기사에서 핵심 포인트를 추출하고 Angular 컴포넌트에 TL;DR 리스트로 표시하는 서비스를 만드는 전체 정리된 가이드입니다. 코드는 Chrome의 Summarizer API(stable)와 Prompt API(experimental)를 사용합니다—두 API 모두 로컬에서 실행되므로 토큰 비용이 발생하지 않습니다.
1. Summarizer 세션 만들기
Summarizer는 텍스트에서 가장 중요한 포인트를 추출합니다.
private async createSummarizerSession() {
return await Summarizer.create({
type: 'key-points', // 요약 스타일을 결정
length: 'short', // 짧은 요약
expectedInputLanguages: ['en'], // 입력 언어
outputLanguage: 'en', // 출력 언어
expectedContextLanguages: ['en'],
sharedContext: 'About AI and Agentic AI'
});
}
Note:
type필드는 요약이 생성되는 방식을 좌우합니다.

전체 옵션 목록은 공식 문서를 참고하세요.
2. Prompt(언어 모델) 세션 만들기
Prompt API를 사용해 원시 bullet 포인트를 깔끔한 HTML로 변환합니다.
private async createLanguageModelSession() {
return await LanguageModel.create({
initialPrompts: [
{
role: 'system',
content: 'Convert these bullets into HTML. Return only the HTML.'
}
],
});
}
3. 두 세션 결합하기
아래 함수가 전체 흐름을 연결합니다.
async generateTlDr(content: string): Promise {
// 1️⃣ 기사 요약
const summarizer = await this.createSummarizerSession();
const summary = await summarizer.summarize(content, {
context: 'This article is intended for a tech‑savvy audience.',
});
summarizer.destroy();
// 2️⃣ 요약을 구조화된 출력으로 변환
const lm = await this.createLanguageModelSession();
const result = await lm.prompt(summary, { responseConstraint: schema });
lm.destroy();
// 3️⃣ JSON 응답 파싱
const parsed = JSON.parse(result);
return parsed?.items ?? [];
}
schema(아래에 표시)는 Prompt API가 "bullet_list" 타입과 문자열 배열 items를 포함한 JSON 객체를 반환하도록 강제합니다.
4. 전체 서비스 코드
import { Injectable } from '@angular/core';
declare const Summarizer: any;
declare const LanguageModel: any;
const schema = {
type: 'object',
required: ['type', 'items'],
properties: {
type: {
type: 'string',
enum: ['bullet_list'],
description: 'Identifies the content as a bullet list'
},
items: {
type: 'array',
minItems: 1,
items: {
type: 'string',
minLength: 1
},
description: 'Each entry is one bullet item, without bullet symbols'
}
},
additionalProperties: false
};
@Injectable({
providedIn: 'root'
})
export class AiService {
async generateTlDr(content: string): Promise {
const summarizer = await this.createSummarizerSession();
const summary = await summarizer.summarize(content, {
context: 'This article is intended for a tech‑savvy audience.',
});
summarizer.destroy();
const lm = await this.createLanguageModelSession();
const result = await lm.prompt(summary, { responseConstraint: schema });
lm.destroy();
const parsed = JSON.parse(result);
return parsed?.items ?? [];
}
private async createSummarizerSession() {
return await Summarizer.create({
type: 'key-points',
length: 'short',
expectedInputLanguages: ['en'],
outputLanguage: 'en',
expectedContextLanguages: ['en'],
sharedContext: 'About AI and Agentic AI'
});
}
private async createLanguageModelSession() {
return await LanguageModel.create({
initialPrompts:
5. 서비스를 컴포넌트에 연결하기
컴포넌트 TypeScript
import { Component, inject, OnInit, signal } from '@angular/core';
import { AiService } from './ai.service';
@Component({
selector: 'app-post',
templateUrl: './post.component.html',
styleUrls: ['./post.component.scss']
})
export class PostComponent implements OnInit {
private aiService = inject(AiService);
public readonly postContent = content; // ([]);
async ngOnInit() {
const tldr = await this.aiService.generateTlDr(this.postContent);
this.tltrContent.set(tldr);
}
}
컴포넌트 템플릿 (post.component.html)
<h3>TL;DR</h3>
@if (tltrContent().length > 0) {
<ul>
@for (item of tltrContent(); track $index) {
<li>{{ item }}</li>
}
</ul>
} @else {
Loading...
}
로컬 AI가 처리를 마치면 TL;DR 목록이 렌더링됩니다.
6. 결과 미리보기
아래는 완전히 온‑디바이스에서 생성된 실제 예시입니다 (외부 토큰 없이, 비용도 없습니다).

7. 지원 및 안정성
| API | 안정성 | 이 예시에서의 역할 |
|---|---|---|
| Summarizer API | 안정적 | 핵심 요약 생성 |
| Prompt API | 실험적 | 불릿을 HTML(또는 JSON)으로 포맷 |

