Download src/g.cpp from HelloSun/dosmqtt: direct link, hf CLI and curl.
- Browser
- Download file 7.41 kB
-
https://huggingface.co/spaces/HelloSun/dosmqtt/resolve/main/src/g.cpp
- Command line
-
hf download hf://spaces/HelloSun/dosmqtt/src/g.cpp
-
curl -L -o g.cpp https://huggingface.co/spaces/HelloSun/dosmqtt/resolve/main/src/g.cpp
7.41 kB
| // G.EXE - ask a Gradio Space one question, over plain HTTP, from DOS. | |
| // | |
| // G <question words...> | |
| // environment: GRADIO_HOST (default tencent-hy3.hf.space) | |
| // | |
| // It speaks the documented Gradio HTTP API itself: | |
| // 1) POST /gradio_api/call/chat {"data":[...9 parameters...]} -> {"event_id":"..."} | |
| // 2) GET /gradio_api/call/chat/<event_id> -> server-sent events | |
| // ("generating" frames while the model streams, then one "complete" frame) | |
| // DOS has no TLS, so the page's bridge (gradio-bridge.js) forwards these requests over HTTPS. | |
| // The emulator's TCP sends 1460-byte segments back to back, ignores the receive window and never | |
| // retransmits, so a segment that does not fit in our buffer is lost for good and the connection hangs. | |
| // Keep the receive buffer several segments large and drain it quickly. | |
| static char line[LINE_MAX_LEN]; | |
| static int lineLen = 0; | |
| static char finalData[LINE_MAX_LEN]; | |
| static char evt[16]; | |
| static int haveFinal = 0, sawError = 0, frames = 0; | |
| static char statusLine[48]; | |
| static int statusDone = 0; | |
| static char resp[1024]; | |
| static int respLen = 0; | |
| static void handleLine( void ) { | |
| if ( !statusDone ) { // first line of an HTTP response | |
| strncpy( statusLine, line, sizeof( statusLine ) - 1 ); | |
| statusDone = 1; | |
| return; | |
| } | |
| if ( strncmp( line, "event: ", 7 ) == 0 ) { | |
| strncpy( evt, line + 7, sizeof( evt ) - 1 ); | |
| evt[sizeof( evt ) - 1] = 0; | |
| if ( strcmp( evt, "generating" ) == 0 ) { frames++; printf( "." ); fflush( stdout ); } | |
| if ( strcmp( evt, "error" ) == 0 ) sawError = 1; | |
| } | |
| else if ( strncmp( line, "data: ", 6 ) == 0 && strcmp( evt, "complete" ) == 0 ) { | |
| strcpy( finalData, line + 6 ); | |
| haveFinal = 1; | |
| } | |
| } | |
| static void feed( const uint8_t *p, int n, int sse ) { | |
| for ( int i = 0; i < n; i++ ) { | |
| if ( !sse ) { if ( respLen < (int)sizeof( resp ) - 1 ) resp[respLen++] = (char)p[i]; continue; } | |
| char c = (char)p[i]; | |
| if ( c == '\n' ) { line[lineLen] = 0; handleLine( ); lineLen = 0; } | |
| else if ( c != '\r' && lineLen < LINE_MAX_LEN - 1 ) line[lineLen++] = c; | |
| } | |
| } | |
| static uint16_t portCounter = 0; | |
| // One HTTP request/response on a fresh TCP connection. The response is read until the server closes. | |
| static int httpExchange( IpAddr_t addr, const char *req, int sse, uint32_t timeoutSec ) { | |
| TcpSocket *s = TcpSocketMgr::getSocket( ); | |
| if ( s->setRecvBuffer( RECV_BUF ) ) { printf( "TCP: no memory for the receive buffer\n" ); TcpSocketMgr::freeSocket( s ); return -1; } | |
| portCounter += 17; | |
| if ( s->connect( (uint16_t)( pseudoPort( ) + portCounter ), addr, 80, 10000 ) != 0 ) { | |
| TcpSocketMgr::freeSocket( s ); | |
| printf( "TCP: connect to port 80 failed\n" ); | |
| return -1; | |
| } | |
| lineLen = 0; respLen = 0; statusDone = 0; statusLine[0] = 0; evt[0] = 0; | |
| s->send( (uint8_t *)req, (uint16_t)strlen( req ) ); | |
| static uint8_t buf[1024]; | |
| clockTicks_t start = TIMER_GET_CURRENT( ); | |
| int closed = 0, rc = 0; | |
| while ( !CtrlBreakDetected ) { | |
| Utils::processPackets( ); | |
| int16_t r = s->recv( buf, sizeof( buf ) ); | |
| if ( r > 0 ) { feed( buf, r, sse ); continue; } | |
| if ( closed ) break; | |
| if ( s->isRemoteClosed( ) ) { closed = 1; continue; } // one more pass to drain the buffer | |
| if ( Timer_diff( start, TIMER_GET_CURRENT( ) ) > TIMER_SECS_TO_TICKS( timeoutSec ) ) { | |
| printf( "\nHTTP: timed out after %lu s\n", (unsigned long)timeoutSec ); rc = -2; break; | |
| } | |
| } | |
| s->close( ); | |
| TcpSocketMgr::freeSocket( s ); | |
| if ( sse && lineLen > 0 ) { line[lineLen] = 0; handleLine( ); } | |
| return rc; | |
| } | |
| // Decode the first JSON string that follows `[["` in the SSE data line and print it word wrapped. | |
| static void printAnswer( const char *data ) { | |
| const char *p = strstr( data, "[[\"" ); | |
| if ( !p ) { printf( "A> (no text in reply: %.60s)\n", data ); return; } | |
| p += 3; | |
| char out[1200]; int n = 0; | |
| while ( *p && n < (int)sizeof( out ) - 2 ) { | |
| if ( *p == '"' ) break; | |
| if ( *p == '\\' ) { | |
| p++; | |
| if ( *p == 'n' ) out[n++] = ' '; | |
| else if ( *p == 'u' ) { | |
| unsigned v = 0; int k; | |
| for ( k = 1; k <= 4 && p[k]; k++ ) { char h = p[k]; v = v * 16 + ( h <= '9' ? h - '0' : ( h | 32 ) - 'a' + 10 ); } | |
| out[n++] = ( v >= 32 && v < 127 ) ? (char)v : '?'; | |
| p += 4; | |
| } | |
| else out[n++] = *p; | |
| if ( *p ) p++; | |
| continue; | |
| } | |
| out[n++] = *p++; | |
| } | |
| out[n] = 0; | |
| printf( "A> " ); | |
| int col = 3; | |
| for ( char *w = strtok( out, " " ); w; w = strtok( NULL, " " ) ) { | |
| int l = (int)strlen( w ); | |
| if ( col + l + 1 > 78 ) { printf( "\n " ); col = 3; } | |
| printf( "%s ", w ); col += l + 1; | |
| } | |
| printf( "\n" ); | |
| } | |
| int main( int argc, char *argv[] ) { | |
| char question[160]; question[0] = 0; | |
| for ( int i = 1; i < argc; i++ ) { | |
| if ( strlen( question ) + strlen( argv[i] ) + 2 > sizeof( question ) ) break; | |
| if ( i > 1 ) strcat( question, " " ); | |
| strcat( question, argv[i] ); | |
| } | |
| for ( char *q = question; *q; q++ ) if ( *q < 32 || *q > 126 || *q == '"' || *q == '\\' ) *q = ' '; | |
| if ( !question[0] ) { printf( "Usage: G <question>\n env GRADIO_HOST (default %s)\n", DEFAULT_HOST ); return 1; } | |
| const char *host = getenv( "GRADIO_HOST" ); | |
| if ( !host || !*host ) host = DEFAULT_HOST; | |
| printf( "G.EXE - asking Gradio Space %s\nQ> %s\n", host, question ); | |
| if ( netInit( ) ) { printf( "TCP/IP init failed (is the packet driver loaded?)\n" ); return 2; } | |
| IpAddr_t addr; | |
| printf( "DNS: resolving %s ...\n", host ); | |
| if ( resolveHost( host, addr ) ) { printf( "DNS: failed\n" ); netShutdown( 3 ); } | |
| printf( "DNS: %d.%d.%d.%d\n", addr[0], addr[1], addr[2], addr[3] ); | |
| clockTicks_t t0 = TIMER_GET_CURRENT( ); | |
| char body[400], req[700], now[16]; | |
| sprintf( body, "{\"data\":[\"%s\",\"%s\",[],\"no_think\",null,0,0,null,\"\"]}", question, SYSTEM_PROMPT ); | |
| sprintf( req, "POST /gradio_api/call/chat HTTP/1.0\r\nHost: %s\r\nContent-Type: application/json\r\nContent-Length: %d\r\nConnection: close\r\n\r\n%s", | |
| host, (int)strlen( body ), body ); | |
| stamp( now ); | |
| printf( "[%s] POST /gradio_api/call/chat (%d bytes)\n", now, (int)strlen( body ) ); | |
| if ( httpExchange( addr, req, 0, 30 ) ) netShutdown( 4 ); | |
| resp[respLen] = 0; | |
| printf( "HTTP: %.40s\n", resp ); | |
| char *e = strstr( resp, "\"event_id\":\"" ); | |
| if ( !e ) { printf( "No event_id in reply:\n%.300s\n", resp ); netShutdown( 5 ); } | |
| e += 12; | |
| char id[64]; int k = 0; | |
| while ( *e && *e != '"' && k < 62 ) id[k++] = *e++; | |
| id[k] = 0; | |
| printf( "event_id: %s\n", id ); | |
| sprintf( req, "GET /gradio_api/call/chat/%s HTTP/1.0\r\nHost: %s\r\nAccept: text/event-stream\r\nConnection: close\r\n\r\n", id, host ); | |
| stamp( now ); | |
| printf( "[%s] GET /gradio_api/call/chat/<event_id> (waiting for the model) ", now ); | |
| fflush( stdout ); | |
| if ( httpExchange( addr, req, 1, 150 ) ) netShutdown( 6 ); | |
| printf( "\n" ); | |
| stamp( now ); | |
| if ( !haveFinal ) { printf( "[%s] No answer received (%s, events: %s)\n", now, statusLine, sawError ? "error" : "none" ); netShutdown( 7 ); } | |
| unsigned long secs = ( TIMER_GET_CURRENT( ) - t0 ) / 18; | |
| printf( "[%s] %d streaming frames, done in %lu s\n", now, frames, secs ); | |
| printAnswer( finalData ); | |
| netShutdown( 0 ); | |
| return 0; | |
| } | |