-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
요약 실패, Input Token 적은 경우에 대한 대응 #103
Changes from 3 commits
b7483ab
80aa760
bd53537
39bde52
bd2353b
f7ae3dd
3325fcd
6b94e29
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export const IS_LOCAL = process.env.NODE_ENV === 'local'; | ||
export const DEFAULT_FOLDER_NAME = '나중에 읽을 링크'; | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Do not import 'tiktoken' | ||
|
||
import { gptVersion } from '@src/infrastructure/ai/ai.constant'; | ||
import { summarizeURLContentFunctionFactory } from '@src/infrastructure/ai/functions'; | ||
import { encodingForModel } from 'js-tiktoken'; | ||
|
||
const encoder = encodingForModel(gptVersion); | ||
|
||
// Reference: https://platform.openai.com/docs/advanced-usage/managing-tokens | ||
// 주의: 실제 Open AI랑 약간의 오차 존재 | ||
export function promptTokenCalculator(content: string, folderList: string[]) { | ||
let tokenCount = 0; | ||
|
||
// Prompt Calculation | ||
const messages = [ | ||
{ | ||
role: 'system', | ||
content: '한글로 답변 부탁해', | ||
}, | ||
{ | ||
role: 'user', | ||
content: `주어진 글에 대해 요약하고 키워드 추출, 분류 부탁해 | ||
|
||
${content} | ||
`, | ||
}, | ||
]; | ||
for (const message of messages) { | ||
// Message struct Overhead | ||
tokenCount += 4; | ||
tokenCount += encoder.encode(message.role).length; | ||
tokenCount += encoder.encode(message.content).length; | ||
} | ||
tokenCount += 2; | ||
Comment on lines
+29
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @J-Hoplin 그리구 프롬프트에 넣는 role length는 넣은 이유가있어? 만약에 필요하다면 reduce를 사용해서 tokenCount 리턴하는것도 좋을듯~ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 나도 궁금쓰~ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OpenAI에서 프롬프팅 할때 Function, Role 담은 JSON을 Stringify해서 보내기때문에 그거랑 동일하게 연산하기 위해서 계산하는거로 공유 완료! |
||
|
||
// Function Calculation | ||
tokenCount += encoder.encode( | ||
JSON.stringify(summarizeURLContentFunctionFactory(folderList)), | ||
).length; | ||
return tokenCount; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
import { Injectable } from '@nestjs/common'; | ||
import { ConfigService } from '@nestjs/config'; | ||
import { promptTokenCalculator } from '@src/common/utils/tokenizer'; | ||
import OpenAI, { OpenAIError, RateLimitError } from 'openai'; | ||
import { DiscordAIWebhookProvider } from '../discord/discord-ai-webhook.provider'; | ||
import { gptVersion } from './ai.constant'; | ||
|
@@ -14,6 +15,7 @@ import { SummarizeURLContent } from './types/types'; | |
@Injectable() | ||
export class AiService { | ||
private openai: OpenAI; | ||
private leastTokenThreshold = 300; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 클래스 내의 한 메소드에서만 쓰는데 클래스의 private 멤버 변수로 선언한 이유가 궁금합니당 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 그러겡ㅎㅎ 인스턴스 프로퍼티로 들고있을 필요는 없을꺼같아서 변경했어! |
||
|
||
constructor( | ||
private readonly config: ConfigService, | ||
|
@@ -26,13 +28,23 @@ export class AiService { | |
|
||
async summarizeLinkContent( | ||
content: string, | ||
baseThumbnailContent: string, | ||
userFolderList: string[], | ||
url: string, | ||
temperature = 0.5, | ||
): Promise<SummarizeURLContentDto> { | ||
try { | ||
// 사용자 폴더 + 서버에서 임의로 붙여주는 폴더 리스트 | ||
const folderLists = [...userFolderList]; | ||
// Calculate post content | ||
const tokenCount = promptTokenCalculator(content, folderLists); | ||
if (tokenCount <= this.leastTokenThreshold) { | ||
return new SummarizeURLContentDto({ | ||
success: false, | ||
message: 'Too low input token count', | ||
thumbnailContent: baseThumbnailContent, | ||
}); | ||
} | ||
// AI Summary 호출 | ||
const promptResult = await this.invokeAISummary( | ||
content, | ||
|
@@ -63,7 +75,18 @@ export class AiService { | |
: err instanceof OpenAIError | ||
? err.message | ||
: '요약에 실패하였습니다.', | ||
thumbnailContent: baseThumbnailContent, | ||
}); | ||
|
||
// return new SummarizeURLContentDto({ | ||
// success: false, | ||
// message: | ||
// err instanceof RateLimitError | ||
// ? '크레딧을 모두 소진하였습니다.' | ||
// : err instanceof OpenAIError | ||
// ? err.message | ||
// : '요약에 실패하였습니다.', | ||
// }); | ||
} | ||
} | ||
|
||
|
@@ -104,7 +127,6 @@ ${content} | |
const functionResult: AiClassificationFunctionResult = JSON.parse( | ||
promptResult.choices[0].message.tool_calls[0].function.arguments, | ||
); | ||
|
||
return functionResult; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
"emitDecoratorMetadata": true, | ||
"experimentalDecorators": true, | ||
"allowSyntheticDefaultImports": true, | ||
"resolveJsonModule": true, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. json읽어올 일이 있었던건가? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아 원래 js-tiktoken 말고 tiktoken 사용하려했는데 거기서 JSON을 직접 import 해야되는게 있었어! 지금은 다른 패키지니 지워도 될듯 합니다 ㅎ |
||
"target": "ES2021", | ||
"sourceMap": true, | ||
"outDir": "./dist", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
굿~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
구웃~~