[TIL/React] 2025/01/26
Google AI Studio ์ ์ฉํ๊ธฐ ๐ํ๋ก๊ทธ๋๋ฐ ๊ด๋ จ Q&A ์ฌ์ดํธ๋ฅผ ์ด์ฉํ๋ฉฐ ์๊ฒจ๋ ์ถ๊ฐ์ ์ธ ์ง๋ฌธ์, ์๋น์ค ๋ด์์ AI์๊ฒ ์ง๋ฌธํ ์ ์๋๋ก, ๊ด๋ จ ํ์ด์ง๋ฅผ ๊ฐ๋ฐํ๊ณ ์ถ์๋ค.Google AI Studio๋ฅผ ํ์ฉํ๋ค.Get API Key ๋ฒํผ์ ํด๋ฆญํ ๋ค, AP
Google AI Studio ์ ์ฉํ๊ธฐ ๐
ํ๋ก๊ทธ๋๋ฐ ๊ด๋ จ Q&A ์ฌ์ดํธ๋ฅผ ์ด์ฉํ๋ฉฐ ์๊ฒจ๋ ์ถ๊ฐ์ ์ธ ์ง๋ฌธ์, ์๋น์ค ๋ด์์ AI์๊ฒ ์ง๋ฌธํ ์ ์๋๋ก, ๊ด๋ จ ํ์ด์ง๋ฅผ ๊ฐ๋ฐํ๊ณ ์ถ์๋ค.
Google AI Studio๋ฅผ ํ์ฉํ๋ค.
1. ์ด๊ธฐ ์ค์ โ๏ธ
1-1. Get API Key ๐ฟ
Get API Key ๋ฒํผ์ ํด๋ฆญํ ๋ค, API ํค ๋ง๋ค๊ธฐ ๋ฒํผ์ ํด๋ฆญํ์ฌ API Key๋ฅผ ๋ฐ๊ธ๋ฐ๋๋ค.


๊ฒฐ์ ์ค์ ์ ๋ฐ๋ก ํ์ง ์์๊ธฐ์, ๊ธฐ๋ณธ์๊ธ์ ๋ '๋ฌด๋ฃ'๋ก ์ ์ฉ๋๋ค.

1-2. Gemini SDK Initialization ๐ฟ
SDK ํจํค์ง๋ฅผ ์ค์นํ๋ค. ํฅํ ํด๋น SDK ํจํค์ง๋ฅผ ํตํด genAI ๋ชจ๋ธ์ ์์ฑํ ์ ์๋ค.

2. ๊ตฌํ ํ๋ฆ โ๏ธ
2-1. Overall Flow ๐ฟ

๊ธฐ๋ณธ์ ์ผ๋ก AskAIPage์์ ์ง๋ฌธํ๊ธฐ ๋ฒํผ์ ํด๋ฆญํ๋ฉด, ์๋ฒ ์ฃผ์๋ก ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ prompt์ ๋ํ POST ์์ฒญ์ด ์งํ๋๋ค.
์์ฒญ์ ๋ฐ๋ ์๋ฒ์ ๊ฒฝ๋ก๋ controller ์์ ๋ช ์๋์ด ์๊ณ , controller์์ ์ํํ๋ ์ธ๋ถ ๋ก์ง์ธ generateContent ํจ์ ์ฝ๋๋ service์ ์์ฑ๋์ด ์๋ค.
์ต์ข ์ ์ผ๋ก controller์์ ์ฒ๋ฆฌ๋ response ๊ฐ์ state์ ์ ์ฅํ์ฌ front-end์์ ๋ ๋๋ง ํ๋ค.
2-2. gemini.module.ts ๐ฟ
import { Module } from '@nestjs/common';
import { GoogleGenerativeAIService } from './gemini.service';
import { GoogleGenerativeAIController } from './gemini.controller';
@Module({
controllers: [GoogleGenerativeAIController],
providers: [GoogleGenerativeAIService],
})
export class GeminiModule {}
์ปจํธ๋กค๋ฌ์ ์๋น์ค๋ฅผ ๋ชจ๋ ๋จ์๋ก ๊ด๋ฆฌํ๊ธฐ ์ํด gemini.module.ts ํ์ผ์ ์์ฑํ๋ค. ์ด ํ์ผ์ ์ต์๋จ app.module.ts์ ๋ฑ๋ก๋์ด์ผ ํ๋ค.
2-3. gemini.controller.ts ๐ฟ
import { Controller, Post, Body } from '@nestjs/common';
import { GoogleGenerativeAIService } from './gemini.service';
@Controller('api/ask-ai')
export class GoogleGenerativeAIController {
constructor(
private readonly googleGenerativeAIService: GoogleGenerativeAIService,
) {}
@Post()
async askAI(@Body('prompt') prompt: string): Promise<{ result: string }> {
try {
const result =
await this.googleGenerativeAIService.generateContent(prompt);
return { result };
} catch (error) {
console.error('Error in GoogleGenerativeAIController:', error);
return { result: 'Failed to generate content from Google Generative AI' };
}
}
}์์ฒญ์ body์์ prompt๋ฅผ ๋ฐ์์์, ์๋น์ค ํ์ผ์ ์์ฑ๋์ด ์๋ generateContent ํจ์๋ก ์ ๋ฌํ๋ค. ํด๋น ํจ์์ return ๊ฐ์ result์ ์ ์ฅํ ๋ค ์ต์ข ์ ์ผ๋ก ๋ฐํํ๊ฒ ๋๋ค.
2-4. gemini.service.ts ๐ฟ
import { Injectable } from '@nestjs/common';
import { GoogleGenerativeAI } from '@google/generative-ai';
@Injectable()
export class GoogleGenerativeAIService {
private genAI: GoogleGenerativeAI;
constructor() {
const apiKey = process.env.GEMINI_API_KEY;
if (!apiKey) {
throw new Error('API Key is required');
}
this.genAI = new GoogleGenerativeAI(apiKey);
}
async generateContent(prompt: string): Promise<string> {
try {
const model = this.genAI.getGenerativeModel({ model: 'gemini-pro' });
const result = await model.generateContent(prompt);
const response = await result.response;
const text = await response.text();
return text;
} catch (error) {
console.error('Google Generative AI Error:', error);
throw new Error('Failed to generate content from Google Generative AI');
}
}
}env ํ์ผ์ ๋ฏธ๋ฆฌ ์์ฑํด๋์ apiKey๋ฅผ GoogleGenerativeAI ํจ์์ ์ ๋ฌํด์ genAI๋ผ๋ ํด๋์ค๋ฅผ ์์ฑํ๋ค.
์ดํ ํด๋น ํด๋์ค์ getGenerativeModel์ ํตํด gemini-pro ๋ชจ๋ธ์ ์ฌ์ฉํ ๊ฒ์ ๋ช ์ํ๋ค.
model.generateContent(prompt)๋ฅผ ํตํด prompt์ ๋ํ ์ฝํ ์ธ ๋ฅผ ์์ฑํ๋ค. prompt๋ ํด๋ผ์ด์ธํธ์์ ์ ๋ฌ๋ ํ ์คํธ๋ก, Google Generative AI ๋ชจ๋ธ์ด ํด๋น ํ ์คํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฝํ ์ธ ๋ฅผ ์์ฑํ๊ฒ ๋๋ค.
์ต์ข ์ ์ผ๋ก response.text()๋ฅผ ํตํด ์๋ต์ผ๋ก๋ถํฐ ํ ์คํธ๋ฅผ ์ถ์ถํ๋ค.
3. ๊ตฌํ ํ๋ฉด โ๏ธ
3-1. Light Mode ๐ฟ

3-2. Dark Mode ๐ฟ

4. ๋ณด์์ โ๏ธ
1. ๊ตฌํ์ ์ง์คํด์ Gemini ๋ฌธ์๋ฅผ ์์ง ์ ๋ ํ์ง๋ ์์ 2. ๋ชจ๋ธ ์ด๋ฆ์ด ํ๋์ฝ๋ฉ๋์ด ์๋๋ฐ, ์ ์ฐ์ฑ์ ์์ ์ ์๊ฒ ๋ค๋ ์๊ฐ์ด ๋ฆ 3. ๋ํ ์ผํ ํ๋ก ํธ์๋ ์ฒ๋ฆฌ๊ฐ ์์ง ๋ถ์กฑํจ
More to read
Amazon VPC Architecture ์ดํดํ๊ธฐ
์๋ก์ด ํ๋ก์ ํธ๋ฅผ ๊ธฐํํ๋ฉฐ, ๊ฐ๋ฐ์์ ๋ฌด์์ ๊ฐ์ฅ ๋จผ์ ๊ณ ๋ฏผํด์ผ ํ๋์ง ๋ค์ ๋์๋ณด๊ฒ ๋์์ต๋๋ค.ํ๋๋ ํ๋ก ํธ์๋๊ฐ ๋ชจ๋ ์ค๊ณ์ ์ถ๋ฐ์ ์ด๋ผ๊ณ ๋ฏฟ์์ต๋๋ค. ์ ์ ๊ฐ ๋ฌด์์ ๋ณด๊ณ , ์ด๋ค ํ๋ฆ์์ ๋จธ๋ฌด๋ฅด๊ณ ์ดํํ๋์ง์ ๋ํ ์ดํด ์์ด ์๋น์ค๋ฅผ ๋ง๋ ๋ค๋ ๊ฑด ๋ถ๊ฐ๋ฅํ๋ค๊ณ ์๊ฐํ๊ธฐ
'์์ฌ์ดํธ'ํ๋ก ํธ์๋ ๊ด์ ์ผ๋ก ์๊ณ ๋ฆฌ์ฆ ์ดํดํ๊ธฐ
์ค๋๋ง์ ๋ฐฉ๋ฒ๋ก ์ ๊ดํ ๊ธ์ ์ฐ๊ฒ ๋์์ต๋๋ค. ์ต๊ทผ ์ํฉ์ ์ด๋ ์ต๋๋ค. SSAFY์์๋ ํ๋ฃจ์ ์์ฒญ๋ ์์ ์๊ณ ๋ฆฌ์ฆ ๋ฌธ์ ๋ค์ ๊ณผ์ ๋ก ์ํํ๊ฒ ๋ฉ๋๋ค. ๊ทธ ๊ณผ์ ์์, '๊ตฌํ๋ ฅ'์ด ๋งค์ฐ ๋จ์ด์ง๋ค๋ ์๊ฐ์ด ๋ค์์ต๋๋ค. ์์ ํ ์ด๋ ค์ด ๋ฌธ์ ๋ผ๋ฉด '์์ฌ์'์ด๋ผ๋ ๊ฐ์ ์กฐ์ฐจ ๋๋ผ์ง
SubnetVPC ์ค๊ณ์ ์์: IP์ Subnet
๋ฐ๋ณต๋๋ ๋ฃจํด ์์์ ์ป์ ์์ ๊ฐ์ ๋ฐํ ์ผ์, ์ด์ ๋ ๊ธฐ์ ์ ์คํํธ๋ผ์ ๋ํ๊ธฐ ์ํ ๊ฐ์ธ ํ๋ก์ ํธ์ ์ฐฉ์ํ๊ณ ์ ํฉ๋๋ค.์ด๋ฒ ํ๋ก์ ํธ์ ๋ชฉํ๋ ๋จ์ํ ํฌํธํด๋ฆฌ์ค ๊ตฌ์ถ์ ๋์ด, ์ค์ ์๋น์ค ์์ค์ ๋ธ๋ก๊ทธ ์์คํ ๊ตฌํ๊ณผ ๋ค๊ตญ์ด ์ฒ๋ฆฌ ์ ์ฉ ๋ฑ ์ค๋ฌด์ ๊ฐ๊น์ด ์ญ๋์ ํ ๋จ๊ณ