|
@@ -1,4 +1,4 @@
|
|
|
-import { ForbiddenException, Injectable, Logger } from '@nestjs/common'
|
|
|
|
|
|
|
+import { ForbiddenException, Injectable, InternalServerErrorException, Logger } from '@nestjs/common'
|
|
|
import { Observable } from 'rxjs'
|
|
import { Observable } from 'rxjs'
|
|
|
import { ChatGPTAPI, ChatMessage } from '../chatapi'
|
|
import { ChatGPTAPI, ChatMessage } from '../chatapi'
|
|
|
import type { RequestProps } from './types'
|
|
import type { RequestProps } from './types'
|
|
@@ -10,15 +10,20 @@ import { TokenUsage } from './entities/token-usage.entity'
|
|
|
import { format } from 'date-fns'
|
|
import { format } from 'date-fns'
|
|
|
import { MembershipService } from '../membership/membership.service'
|
|
import { MembershipService } from '../membership/membership.service'
|
|
|
import { MemberType } from '../membership/entities/membership.entity'
|
|
import { MemberType } from '../membership/entities/membership.entity'
|
|
|
|
|
+import { get_encoding } from '@dqbd/tiktoken'
|
|
|
|
|
+import { fetchSSE } from 'src/chatapi/fetch-sse'
|
|
|
|
|
+import { HttpService } from '@nestjs/axios'
|
|
|
|
|
|
|
|
@Injectable()
|
|
@Injectable()
|
|
|
export class ChatService {
|
|
export class ChatService {
|
|
|
|
|
+ tokenizer = get_encoding('cl100k_base')
|
|
|
constructor(
|
|
constructor(
|
|
|
@InjectRepository(ChatHistory)
|
|
@InjectRepository(ChatHistory)
|
|
|
private readonly chatHistoryRepository: Repository<ChatHistory>,
|
|
private readonly chatHistoryRepository: Repository<ChatHistory>,
|
|
|
@InjectRepository(TokenUsage)
|
|
@InjectRepository(TokenUsage)
|
|
|
private readonly tokenUsageRepository: Repository<TokenUsage>,
|
|
private readonly tokenUsageRepository: Repository<TokenUsage>,
|
|
|
- private readonly membershipService: MembershipService
|
|
|
|
|
|
|
+ private readonly membershipService: MembershipService,
|
|
|
|
|
+ private readonly httpService: HttpService
|
|
|
) {}
|
|
) {}
|
|
|
|
|
|
|
|
public chat(req, res): Observable<any> {
|
|
public chat(req, res): Observable<any> {
|
|
@@ -119,6 +124,53 @@ export class ChatService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ public async chatProxy(req) {
|
|
|
|
|
+ const url = `${process.env.AZURE_OPENAI_ENDPOINT}/openai/deployments/${process.env.AZURE_OPENAI_DEPLOYMENT}/chat/completions?api-version=${process.env.AZURE_OPENAI_VERSION}`
|
|
|
|
|
+ req.body.stream = false
|
|
|
|
|
+ try {
|
|
|
|
|
+ const { data } = await this.httpService.axiosRef.post(url, req.body, {
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
|
|
+ 'api-key': `${process.env.AZURE_OPENAI_KEY}`
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ return data
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ throw new InternalServerErrorException(e.response.data)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public streamChatProxy(req) {
|
|
|
|
|
+ Logger.log(req.body, 'CHAT PROXY')
|
|
|
|
|
+ const url = `${process.env.AZURE_OPENAI_ENDPOINT}/openai/deployments/${process.env.AZURE_OPENAI_DEPLOYMENT}/chat/completions?api-version=${process.env.AZURE_OPENAI_VERSION}`
|
|
|
|
|
+ req.body.stream = true
|
|
|
|
|
+ return new Observable((subscriber) => {
|
|
|
|
|
+ fetchSSE(url, {
|
|
|
|
|
+ body: JSON.stringify(req.body),
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
|
|
+ 'api-key': `${process.env.AZURE_OPENAI_KEY}`
|
|
|
|
|
+ },
|
|
|
|
|
+ method: 'POST',
|
|
|
|
|
+ onMessage: (msg) => {
|
|
|
|
|
+ Logger.log(msg, 'CHAT PROXY')
|
|
|
|
|
+ subscriber.next(msg)
|
|
|
|
|
+ if ('[DONE]' === msg) {
|
|
|
|
|
+ subscriber.complete()
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ onError: (err) => {
|
|
|
|
|
+ Logger.error(err, 'CHAT PROXY')
|
|
|
|
|
+ subscriber.error(err)
|
|
|
|
|
+ subscriber.complete()
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch((e) => {
|
|
|
|
|
+ Logger.error(e, 'CHAT PROXY')
|
|
|
|
|
+ subscriber.error(e)
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
public async saveUsage(userId: number, usage: number) {
|
|
public async saveUsage(userId: number, usage: number) {
|
|
|
const date = format(new Date(), 'yyyy-MM-dd')
|
|
const date = format(new Date(), 'yyyy-MM-dd')
|
|
|
const tokenUsage = await this.tokenUsageRepository.findOneBy({
|
|
const tokenUsage = await this.tokenUsageRepository.findOneBy({
|