@@ -13,7 +13,6 @@ export class GoogleProxyService {
1313
1414 async generateContent ( body : any , headers : any , query : any , model : string ) {
1515 const url = `https://generativelanguage.googleapis.com/v1beta/models/${ model } :generateContent` ;
16-
1716 return this . makeRequest ( url , headers , body , query , false ) ;
1817 }
1918
@@ -24,55 +23,188 @@ export class GoogleProxyService {
2423 model : string ,
2524 ) {
2625 const url = `https://generativelanguage.googleapis.com/v1beta/models/${ model } :streamGenerateContent` ;
27-
2826 return this . makeRequest ( url , headers , body , query , true ) ;
2927 }
3028
29+ async uploadFileInit ( body : any , headers : any ) : Promise < { status : number ; headers : any ; data : any } > {
30+ const url = 'https://generativelanguage.googleapis.com/upload/v1beta/files' ;
31+ const result = await this . makeRequest ( url , headers , body , { } , false , {
32+ customHeaders : {
33+ 'X-Goog-Upload-Protocol' : headers [ 'x-goog-upload-protocol' ] ,
34+ 'X-Goog-Upload-Command' : headers [ 'x-goog-upload-command' ] ,
35+ 'X-Goog-Upload-Header-Content-Length' : headers [ 'x-goog-upload-header-content-length' ] ,
36+ 'X-Goog-Upload-Header-Content-Type' : headers [ 'x-goog-upload-header-content-type' ] ,
37+ } ,
38+ validateStatus : ( status ) => status === 200 || status === 308 ,
39+ timeout : 2 * MINUTE ,
40+ returnFullResponse : true ,
41+ } ) ;
42+ return result ;
43+ }
44+
45+ async uploadFileData ( uploadUrl : string , body : Buffer , headers : any ) {
46+ const contentLength = headers [ 'content-length' ] || body . length ;
47+ const uploadOffset = headers [ 'x-goog-upload-offset' ] || '0' ;
48+ const uploadCommand = headers [ 'x-goog-upload-command' ] || 'upload, finalize' ;
49+ const result = await this . makeRequest ( uploadUrl , headers , body , { } , false , {
50+ customHeaders : {
51+ 'Content-Length' : contentLength . toString ( ) ,
52+ 'X-Goog-Upload-Offset' : uploadOffset ,
53+ 'X-Goog-Upload-Command' : uploadCommand ,
54+ } ,
55+ timeout : 5 * MINUTE ,
56+ maxContentLength : Infinity ,
57+ maxBodyLength : Infinity ,
58+ validateStatus : ( status ) => status === 200 || status === 308 ,
59+ isBinaryData : true ,
60+ } ) ;
61+ return result . data ;
62+ }
63+
64+ async uploadFileChunk (
65+ uploadUrl : string ,
66+ chunkData : Buffer ,
67+ headers : any ,
68+ chunkIndex : number ,
69+ totalChunks : number
70+ ) {
71+ const contentLength = chunkData . length ;
72+ const uploadOffset = headers [ 'x-goog-upload-offset' ] || '0' ;
73+ const isLastChunk = chunkIndex === totalChunks - 1 ;
74+ const uploadCommand = isLastChunk ? 'upload, finalize' : 'upload' ;
75+
76+ const result = await this . makeRequest ( uploadUrl , headers , chunkData , { } , false , {
77+ customHeaders : {
78+ 'Content-Length' : contentLength . toString ( ) ,
79+ 'X-Goog-Upload-Offset' : uploadOffset ,
80+ 'X-Goog-Upload-Command' : uploadCommand ,
81+ } ,
82+ timeout : 5 * MINUTE ,
83+ maxContentLength : Infinity ,
84+ maxBodyLength : Infinity ,
85+ validateStatus : ( status ) => status === 200 || status === 308 ,
86+ isBinaryData : true ,
87+ } ) ;
88+ return result . data ;
89+ }
90+
91+ async getFileInfo ( url : string , headers : any ) {
92+ return this . makeRequest ( url , headers , null , { } , false , {
93+ method : 'GET' ,
94+ timeout : 30000 ,
95+ } ) ;
96+ }
97+
3198 private async makeRequest (
3299 url : string ,
33100 headers : any ,
34101 body : any ,
35102 query : any ,
36103 stream ?: boolean ,
104+ options ?: {
105+ method ?: string ;
106+ customHeaders ?: Record < string , string > ;
107+ validateStatus ?: ( status : number ) => boolean ;
108+ timeout ?: number ;
109+ returnFullResponse ?: boolean ;
110+ maxContentLength ?: number ;
111+ maxBodyLength ?: number ;
112+ isBinaryData ?: boolean ;
113+ } ,
37114 ) {
38115 const { httpAgent, httpsAgent } = this . getAgents ( ) ;
116+ const {
117+ method = 'POST' ,
118+ customHeaders = { } ,
119+ validateStatus = ( status ) => status === 200 ,
120+ timeout = 10 * MINUTE ,
121+ returnFullResponse = false ,
122+ maxContentLength,
123+ maxBodyLength,
124+ isBinaryData = false ,
125+ } = options || { } ;
126+
127+ const requestHeaders : Record < string , string > = {
128+ ...customHeaders ,
129+ } ;
130+ if ( ! isBinaryData ) {
131+ requestHeaders [ 'Content-Type' ] = 'application/json' ;
132+ }
133+ if ( headers [ 'anthropic-version' ] ) {
134+ requestHeaders [ 'anthropic-version' ] = headers [ 'anthropic-version' ] ;
135+ }
136+ if ( headers [ 'x-api-key' ] ) {
137+ requestHeaders [ 'x-api-key' ] = headers [ 'x-api-key' ] ;
138+ }
139+ if ( headers [ 'x-goog-api-key' ] ) {
140+ requestHeaders [ 'x-goog-api-key' ] = headers [ 'x-goog-api-key' ] ;
141+ }
142+ const axiosConfig : any = {
143+ httpAgent,
144+ httpsAgent,
145+ method,
146+ headers : requestHeaders ,
147+ params : query ,
148+ responseType : stream ? 'stream' : 'json' ,
149+ data : body ,
150+ timeout,
151+ validateStatus,
152+ } ;
153+ if ( maxContentLength !== undefined ) {
154+ axiosConfig . maxContentLength = maxContentLength ;
155+ }
156+ if ( maxBodyLength !== undefined ) {
157+ axiosConfig . maxBodyLength = maxBodyLength ;
158+ }
39159 let response : any ;
40160 try {
41- response = await axios ( url , {
42- httpAgent,
43- httpsAgent,
44- method : 'POST' ,
45- headers : {
46- 'Content-Type' : 'application/json' ,
47- 'anthropic-version' : headers [ 'anthropic-version' ] ,
48- 'x-api-key' : headers [ 'x-api-key' ] ,
49- } ,
50- params : query ,
51- responseType : stream ? 'stream' : 'json' ,
52- data : body ,
53- timeout : 10 * MINUTE ,
54- } ) ;
161+ response = await axios ( url , axiosConfig ) ;
55162 } catch ( e ) {
56163 if ( e . response ) {
57164 if ( stream ) {
58165 return e . response . data ;
59166 }
60- throw new HttpException ( e . response . data , e . response . status ) ;
167+ throw new HttpException ( {
168+ message : e . response . data ?. message || e . message ,
169+ data : e . response . data ,
170+ status : e . response . status ,
171+ statusText : e . response . statusText ,
172+ headers : e . response . headers ,
173+ } , e . response . status ) ;
61174 } else if ( e . request ) {
62- console . log ( e . message ) ;
63- throw new Error (
64- `Failed to send message. error message: ${ e . message } , request: ${ e . request } ` ,
65- ) ;
175+ throw new HttpException ( {
176+ message : `Network request failed: ${ e . message } ` ,
177+ code : e . code ,
178+ errno : e . errno ,
179+ syscall : e . syscall ,
180+ hostname : e . hostname ,
181+ port : e . port ,
182+ path : e . path ,
183+ } , 500 ) ;
66184 } else {
67- throw e ;
185+ throw new HttpException ( {
186+ message : e . message ,
187+ stack : e . stack ,
188+ name : e . name ,
189+ } , 500 ) ;
68190 }
69191 }
70-
71- if ( response . status !== 200 ) {
72- const error = new HttpException ( response . data , response . status ) ;
73- throw error ;
192+ if ( ! validateStatus ( response . status ) ) {
193+ throw new HttpException ( {
194+ message : response . data ?. message || `HTTP ${ response . status } Error` ,
195+ data : response . data ,
196+ status : response . status ,
197+ statusText : response . statusText ,
198+ headers : response . headers ,
199+ } , response . status ) ;
74200 }
75- return response . data ;
201+ return returnFullResponse
202+ ? {
203+ status : response . status ,
204+ headers : response . headers ,
205+ data : response . data ,
206+ }
207+ : response . data ;
76208 }
77209
78210 private getAgents ( ) {
0 commit comments