2023-08-28 03:46:12 -06:00
require ( "dotenv" ) . config ( ) ;
const express = require ( 'express' ) ;
const axios = require ( 'axios' ) ;
const app = express ( ) ;
app . use ( express . json ( ) ) ;
const API _TOKEN = process . env . API _TOKEN ;
app . post ( '/v1/complete' , async ( req , res ) => {
res . setHeader ( 'Content-Type' , 'text/event-stream; charset=utf-8' ) ;
res . setHeader ( 'Cache-Control' , 'no-cache' ) ;
res . setHeader ( 'Connection' , 'keep-alive' ) ;
res . setHeader ( 'Transfer-Encoding' , 'chunked' ) ;
res . flushHeaders ( ) ;
//console.log(req.body);
const model = req . body . model ;
const temp = req . body . temperature || 1.0 ;
const top _p = req . body . top _p || null ;
const top _k = req . body . top _k || null ;
const maxTokens = req . body . max _tokens _to _sample ;
const stopSequences = req . body . stop _sequences || null ;
2023-08-28 04:39:57 -06:00
const isStream = req . body . stream || false ;
2023-08-28 03:46:12 -06:00
const prompt = req . body . prompt ;
2023-08-28 04:39:57 -06:00
console . log ( ` Doing a request with stream = ${ isStream } . ` )
2023-08-28 03:46:12 -06:00
// Set up axios instance for SSE
const sourcegraph = axios . create ( {
baseURL : 'https://sourcegraph.com/.api/completions/stream' ,
headers : {
'Content-Type' : 'application/json' ,
'Authorization' : ` token ${ API _TOKEN } `
} ,
responseType : 'stream' ,
timeout : 180000 ,
} ) ;
2023-08-28 04:39:57 -06:00
let fullContent = "" ;
2023-08-28 03:46:12 -06:00
try {
let postData = {
model : model ,
prompt : prompt ,
maxTokensToSample : maxTokens
} ;
if ( temp ) postData . temperature = temp ;
if ( stopSequences ) postData . stop _sequences = stopSequences ;
if ( top _p ) postData . top _p = top _p ;
if ( top _k ) postData . top _k = top _k ;
const response = await sourcegraph . post ( '' , postData ) ;
let previousCompletion = "" ;
let buffer = "" ; // Buffer to hold incomplete lines
response . data . on ( 'data' , ( chunk ) => {
buffer += chunk . toString ( ) ;
let lines = buffer . split ( "\n" ) ;
buffer = lines . pop ( ) ; // Keep the last (potentially incomplete) line in the buffer
const data = lines . filter ( line => line . startsWith ( 'data: ' ) ) . map ( line => line . replace ( /^data: / , '' ) ) ;
data . forEach ( ( chunk ) => {
try {
const parsedData = JSON . parse ( chunk ) ;
if ( 'completion' in parsedData ) {
//console.log(resp);
2023-08-28 04:39:57 -06:00
if ( isStream ) {
// SourceGraph API always returns the full string, but we need the diff
const newPart = parsedData . completion . replace ( previousCompletion , '' ) ;
previousCompletion = parsedData . completion ;
let resp = { completion : newPart , stop _reason : null } ;
res . write ( ` event: completion \r \n data: ${ JSON . stringify ( resp ) } \r \n \r \n ` ) ;
}
else {
fullContent = parsedData . completion ;
}
2023-08-28 03:46:12 -06:00
}
} catch ( error ) {
// If an error is thrown, the JSON is not valid
console . error ( 'Invalid JSON:' , chunk ) ;
} } )
} ) ;
response . data . on ( 'end' , ( ) => {
2023-08-28 04:39:57 -06:00
if ( isStream ) {
let finalResp = { completion : "" , stop _reason : "stop_sequence" } ;
res . write ( ` event: completion \r \n data: ${ JSON . stringify ( finalResp ) } \r \n \r \n ` ) ;
}
else {
res . write ( JSON . stringify ( { completion : fullContent , stop _reason : "stop_sequence" } ) ) ;
}
2023-08-28 04:42:41 -06:00
res . end ( ) ;
console . log ( ` Request done. ` )
2023-08-28 03:46:12 -06:00
} ) ;
} catch ( error ) {
2023-08-28 04:39:57 -06:00
console . error ( "Got an error: " , error ) ;
2023-08-28 03:46:12 -06:00
res . status ( 500 ) . send ( 'An error occurred while making the request.' ) ;
}
} ) ;
app . use ( ( err , req , res , next ) => {
console . log ( err ) ;
res . status ( 500 ) . json ( { "error" : true } ) ;
} ) ;
process . on ( 'uncaughtException' , ( err ) => {
console . error ( 'Uncaught exception:' , err ) ;
} ) ;
process . on ( 'unhandledRejection' , ( reason , promise ) => {
console . error ( 'Unhandled Promise Rejection:' , reason ) ;
} ) ;
2023-08-28 05:04:54 -06:00
async function checkToken ( token ) {
const data = {
query : 'query { currentUser { username } }'
} ;
const config = {
method : 'post' ,
url : 'https://sourcegraph.com/.api/graphql' ,
headers : {
'Authorization' : ` token ${ token } `
} ,
data : data
} ;
try {
const response = await axios ( config ) ;
if ( response . data && response . data . data && response . data . data . currentUser ) {
console . log ( ` Token works, username: ${ response . data . data . currentUser . username } ` ) ;
return true ;
} else {
return false ;
}
} catch ( error ) {
return false ;
}
}
// Two basic checks
2023-08-28 04:50:56 -06:00
if ( ! API _TOKEN ) {
console . error ( "SourceGraph API token not found! Create a file named '.env' and put your token there as an API_TOKEN. See .env.example for an example." ) ;
2023-08-28 05:04:54 -06:00
process . exit ( 1 ) ;
2023-08-28 04:50:56 -06:00
}
else if ( API _TOKEN . indexOf ( "sgp_" ) == - 1 ) {
2023-08-28 05:04:54 -06:00
console . error ( "Invalid SourceGraph API token! Make sure you copied the whole token starting with sgp_, like 'sgp_blablabla'." ) ;
process . exit ( 1 ) ;
2023-08-28 04:50:56 -06:00
}
2023-08-28 05:04:54 -06:00
// Check token validity
checkToken ( API _TOKEN ) . then ( isValid => {
if ( ! isValid ) {
console . error ( "Invalid SourceGraph API token! The token is not valid. Make sure you copied the whole token." ) ;
process . exit ( 1 ) ;
}
const port = process . env . PORT || 3000 ;
app . listen ( port , ( ) => console . log ( ` Server listening on port ${ port } ` ) ) ;
} ) ;