refactor: switch to /v1/events endpoint (#42)

* refactor: Add EventType enum for validation

* refactor: use /v1/events in monaco components

* refactor: use /v1/events in vscode client

* refactor: remove unused api endpoint

* refactor: improve api endpoint type check
add-more-languages
Meng Zhang 2023-04-04 19:42:57 +08:00 committed by GitHub
parent 51e3b54016
commit 6da7c17f67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 51 additions and 41 deletions

View File

@ -110,9 +110,11 @@ export class TabbyClient extends EventEmitter {
this.ping();
}
try {
const response = await axios.post(
`${this.tabbyServerUrl}/v1/completions/${event.id}/choices/${event.index}/${event.type}`
);
const response = await axios.post(`${this.tabbyServerUrl}/v1/events`, {
type: event.type,
completion_id: event.id,
choice_index: event.index
});
assert(response.status == 200);
} catch (e) {
this.ping();

View File

@ -1,9 +1,9 @@
{
"files": {
"main.js": "./static/js/main.c14dfe27.js",
"main.js": "./static/js/main.ab7e9a50.js",
"index.html": "./index.html"
},
"entrypoints": [
"static/js/main.c14dfe27.js"
"static/js/main.ab7e9a50.js"
]
}

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><title>Streamlit Component</title><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Streamlit Component"/><link rel="stylesheet" href="bootstrap.min.css"/><script defer="defer" src="./static/js/main.c14dfe27.js"></script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><title>Streamlit Component</title><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Streamlit Component"/><link rel="stylesheet" href="bootstrap.min.css"/><script defer="defer" src="./static/js/main.ab7e9a50.js"></script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

View File

@ -1,7 +1,7 @@
import axios from "axios"
import { useRenderData } from "streamlit-component-lib-react-hooks"
import React, { useRef, useEffect} from "react"
import React, { useRef, useEffect } from "react"
import Editor, { useMonaco } from "@monaco-editor/react"
let TabbyServerURL = "http://localhost:5000"
@ -162,6 +162,10 @@ class CompletionProvider {
}
}
function logAction(id, index, event) {
axios.post(`${TabbyServerURL}/v1/completions/${id}/choices/${index}/${event}`)
function logAction(completion_id, choice_index, type) {
axios.post(`${TabbyServerURL}/v1/events`, {
type,
completion_id,
choice_index,
})
}

View File

@ -5,9 +5,15 @@ from fastapi import FastAPI, Response
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from . import events
from . import events as events_lib
from .backend import PythonModelService, TritonService
from .models import CompletionRequest, CompletionResponse
from .models import (
ChoiceEvent,
CompletionEvent,
CompletionRequest,
CompletionResponse,
EventTypeMapping,
)
app = FastAPI(
title="TabbyServer",
@ -37,23 +43,21 @@ else:
LOGS_DIR = os.environ.get("LOGS_DIR", None)
if LOGS_DIR is not None:
events.setup_logging(os.path.join(LOGS_DIR, "tabby-server"))
events_lib.setup_logging(os.path.join(LOGS_DIR, "tabby-server"))
@app.post("/v1/completions")
async def completions(request: CompletionRequest) -> CompletionResponse:
response = model_backend(request)
events.log_completions(request, response)
events_lib.log_completion(request, response)
return response
@app.post("/v1/completions/{id}/choices/{index}/view")
async def view(id: str, index: int) -> JSONResponse:
events.log_view(id, index)
return JSONResponse(content="ok")
@app.post("/v1/completions/{id}/choices/{index}/select")
async def select(id: str, index: int) -> JSONResponse:
events.log_select(id, index)
return JSONResponse(content="ok")
@app.post("/v1/events")
async def events(e: ChoiceEvent | CompletionEvent) -> JSONResponse:
if isinstance(e, EventTypeMapping[e.type]):
events_lib.log_event(e)
return JSONResponse(content="ok")
else:
print(type(e))
return JSONResponse(content="invalid event", status_code=422)

View File

@ -27,18 +27,12 @@ def setup_logging(logdir):
)
def log_completions(
def log_completion(
request: models.CompletionRequest, response: models.CompletionResponse
) -> None:
event = models.CompletionEvent.build(request, response)
logger.info(event.json())
def log_view(id: str, index: int) -> None:
event = models.ChoiceEvent.build_view(id, index)
logger.info(event.json())
def log_select(id: str, index: int) -> None:
event = models.ChoiceEvent.build_select(id, index)
def log_event(event: models.Event):
logger.info(event.json())

View File

@ -1,3 +1,4 @@
from enum import Enum
from typing import List
from pydantic import BaseModel, Field
@ -21,8 +22,14 @@ class CompletionResponse(BaseModel):
choices: List[Choice]
class EventType(str, Enum):
COMPLETION = "completion"
VIEW = "view"
SELECT = "select"
class Event(BaseModel):
type: str
type: EventType
class CompletionEvent(Event):
@ -34,7 +41,7 @@ class CompletionEvent(Event):
@classmethod
def build(cls, request: CompletionRequest, response: CompletionResponse):
return cls(
type="completion",
type=EventType.COMPLETION,
id=response.id,
prompt=request.prompt,
created=response.created,
@ -46,10 +53,9 @@ class ChoiceEvent(Event):
completion_id: str
choice_index: int
@classmethod
def build_view(cls, id, index):
return cls(type="view", completion_id=id, choice_index=index)
@classmethod
def build_select(cls, id, index):
return cls(type="select", completion_id=id, choice_index=index)
EventTypeMapping = {
EventType.COMPLETION: CompletionEvent,
EventType.VIEW: ChoiceEvent,
EventType.SELECT: ChoiceEvent,
}