shithub: oai

ref: 3b49941153a3ca965ba574d9e64f0325383316fd
dir: /oailib.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <json.h>
#include "oai.h"

static char *baseurl = nil;
static char *apikey = nil;

int
initoai(char *url, char *key)
{
	baseurl = url;
	apikey = key;
	
	if (!baseurl) {
		werrstr("invalid baseurl");
		return 0;
	}
	
	JSONfmtinstall();
	
	return 1;
}

static JSONEl*
mkstrjson(char *name, char *value)
{
	JSONEl *el;
	
	el = mallocz(sizeof(JSONEl), 1);
	assert(el);
	el->name = strdup(name);
	assert(el->name);
	el->val = mallocz(sizeof(JSON), 1);
	assert(el->val);
	el->val->t = JSONString;
	el->val->s = strdup(value);
	assert(el->val->s);
	return el;
}

static JSONEl*
prompt2json(OPrompt *p)
{
	JSONEl *el;
	
	el = mallocz(sizeof(JSONEl), 1);
	el->val = mallocz(sizeof(JSON), 1);
	el->val->t = JSONObject;
	el->val->first = mkstrjson("role", p->role);
	el->val->first->next = mkstrjson("content", p->content);
	return el;
}

static JSON*
req2json(ORequest *req)
{
	JSON *j;
	JSONEl *el;
	OPrompt *p;
	
	j = mallocz(sizeof(JSON), 1);
	assert(j);
	
	j->t = JSONObject;
	
	el = mallocz(sizeof(JSONEl), 1);
	assert(el);
	el->name = strdup("messages");
	assert(el->name);
	el->val = mallocz(sizeof(JSON), 1);
	assert(el->val);
	el->val->t = JSONArray;
	j->first = el;
	
	for (p = req->prompts; p; p = p->next) {
		if (!el->val->first) {
			el->val->first = prompt2json(p);
			el = el->val->first;
			continue;
		}
		el->next = prompt2json(p);
		el = el->next;
	}
	
	if (req->model) {
		j->first->next = mkstrjson("model", req->model);
	}
	
	return j;
}

static OResult
j2res(JSON *j)
{
	OResult r;
	JSON *choices;
	JSON *message;
	JSON *role;
	JSON *content;
	
	choices = jsonbyname(j, "choices");
	
	if (!choices)
		sysfatal("no choices");
	if (choices->t != JSONArray)
		sysfatal("invalid response: choices not an array");
	if (!(choices->first && choices->first->val))
		sysfatal("no response message");
	
	message = jsonbyname(choices->first->val, "message");
	if (!message)
		sysfatal("choice has no message");
	if (message->t != JSONObject)
		sysfatal("message is not an object");
	
	role = jsonbyname(message, "role");
	r.role = jsonstr(role);
	if (!r.role)
		sysfatal("choice has no role");
	
	content = jsonbyname(message, "content");
	r.message = jsonstr(content);
	if (!r.message)
		sysfatal("choice has no content");
	
	r.role = strdup(r.role);
	r.message = strdup(r.message);
	return r;
}

OResult
makerequest(ORequest req)
{
	char buf[128];
	int ctlfd, pbodyfd;
	Biobuf *body;
	char *s;
	int n;
	OResult ret;
	JSON *jreq;
	JSON *jres;
	
	jreq = req2json(&req);
	
	ctlfd = open("/mnt/web/clone", ORDWR);
	if (ctlfd < 0)
		sysfatal("webfs ctl open: %r");
	if ((n = read(ctlfd, buf, sizeof buf)) < 0)
		sysfatal("webfs ctl read: %r");
	buf[n] = 0;
	
	n = atoi(buf);
	
	fprint(ctlfd, "useragent 9front\n");
	fprint(ctlfd, "contenttype application/json\n");
	fprint(ctlfd, "headers Authorization: Bearer %s\n", apikey ? apikey : "no-key");
	fprint(ctlfd, "baseurl %s\n", baseurl);
	fprint(ctlfd, "url ./v1/chat/completions\n");
	
	snprint(buf, sizeof buf, "/mnt/web/%d/postbody", n);
	pbodyfd = open(buf, OWRITE);
	if (pbodyfd < 0)
		sysfatal("webfs pbody open: %r");
	fprint(pbodyfd, "%J", jreq);
	close(pbodyfd);
	
	snprint(buf, sizeof buf, "/mnt/web/%d/body", n);
	body = Bopen(buf, OREAD);
	if (!body)
		sysfatal("webfs body open: %r");
	
	s = Brdstr(body, 0, 0);
	Bterm(body);
	close(ctlfd);
	
	jres = jsonparse(s);
	ret = j2res(jres);
	
	free(s);
	jsonfree(jreq);
	jsonfree(jres);
	
	return ret;
}