Skip to content
This repository has been archived by the owner on Jul 1, 2024. It is now read-only.

Commit

Permalink
update server and hass integration
Browse files Browse the repository at this point in the history
  • Loading branch information
0x77dev committed Apr 19, 2024
1 parent ab47a0b commit 61b81d5
Show file tree
Hide file tree
Showing 27 changed files with 222 additions and 81 deletions.
Binary file modified bun.lockb
Binary file not shown.
10 changes: 4 additions & 6 deletions custom_components/ava/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,20 +167,20 @@ async def async_process(
response=intent_response, conversation_id=conversation_id
)

messages.append(query_response.message.model_dump(exclude_none=True))
messages.append(query_response.message)
self.history[conversation_id] = messages

self.hass.bus.async_fire(
EVENT_CONVERSATION_FINISHED,
{
"response": query_response.response.model_dump(),
"response": query_response.message,
"user_input": user_input,
"messages": messages,
},
)

intent_response = intent.IntentResponse(language=user_input.language)
intent_response.async_set_speech(query_response.message.content)
intent_response.async_set_speech(query_response.message)
return conversation.ConversationResult(
response=intent_response, conversation_id=conversation_id
)
Expand All @@ -190,7 +190,7 @@ def _generate_system_message(
):
raw_prompt = self.entry.options.get(CONF_PROMPT, DEFAULT_PROMPT)
prompt = self._async_generate_prompt(raw_prompt, exposed_entities, user_input)
return {"role": "system", "content": prompt}
return {"role": "user", "content": prompt}

def _async_generate_prompt(
self,
Expand Down Expand Up @@ -248,8 +248,6 @@ async def query(
user=user_input.conversation_id,
)

_LOGGER.info("Response %s", response.model_dump(exclude_none=True))

choice: Choice = response.choices[0]
message = choice.message

Expand Down
2 changes: 1 addition & 1 deletion docs/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
// https://nuxt.com/docs/guide/concepts/typescript
"extends": "./.nuxt/tsconfig.json"
"extends": ["./.nuxt/tsconfig.json", "../tsconfig.json"]
}
1 change: 0 additions & 1 deletion oai/README.md

This file was deleted.

5 changes: 0 additions & 5 deletions oai/src/config.ts

This file was deleted.

60 changes: 0 additions & 60 deletions oai/src/index.ts

This file was deleted.

3 changes: 0 additions & 3 deletions oai/tsconfig.json

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"packages/*",
"skills/*",
"docs",
"oai"
"server"
],
"resolutions": {
"typescript": "^5.0.0",
Expand Down
1 change: 1 addition & 0 deletions packages/oai-openapi/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
generated/
3 changes: 3 additions & 0 deletions packages/oai-openapi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @ava/oai-openapi

[OAI OpenAPI](https://github.com/openai/openai-openapi) type definitions.
4 changes: 4 additions & 0 deletions packages/oai-openapi/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* Please run generate script to use this module, it should run on postinstall automatically
*/
export * from './generated'
16 changes: 16 additions & 0 deletions packages/oai-openapi/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "@ava/oai-openapi",
"module": "index.ts",
"type": "module",
"scripts": {
"generate": "bun run scripts/generate.ts",
"postinstall": "bun --bun run generate"
},
"devDependencies": {
"@types/bun": "latest",
"openapi-typescript-codegen": "^0.29.0"
},
"peerDependencies": {
"typescript": "^5.0.0"
}
}
15 changes: 15 additions & 0 deletions packages/oai-openapi/scripts/generate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { $, write } from 'bun'
import { mkdir } from 'fs/promises'
import { join } from 'path'
import { tmpdir } from 'os'

const tmpDir = join(tmpdir(), '@ava/oai-openapi')
await mkdir(tmpDir, { recursive: true })
const cwd = join(__dirname, '../generated')
await mkdir(cwd, { recursive: true })
const res = await fetch('https://raw.githubusercontent.com/openai/openai-openapi/2.0.0/openapi.yaml')
const def = await res.text()
const dest = join(tmpDir, 'openapi.yaml')
await write(dest, def)
console.log(cwd, dest)
await $`openapi --input ${dest} --output ${cwd}`
3 changes: 3 additions & 0 deletions packages/oai-openapi/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "../../tsconfig.json",
}
File renamed without changes.
15 changes: 15 additions & 0 deletions server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Elysia with Bun runtime

## Getting Started
To get started with this template, simply paste this command into your terminal:
```bash
bun create elysia ./elysia-example
```

## Development
To start the development server run:
```bash
bun run dev
```

Open http://localhost:3000/ with your browser to see the result.
10 changes: 7 additions & 3 deletions oai/package.json → server/package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
{
"name": "@ava/oai",
"name": "server",
"version": "1.0.50",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "bun run --watch src/index.ts"
},
"dependencies": {
"@ava/lang": "workspace:../packages/lang",
"@ava/skills-homeassistant": "workspace:../skills/homeassistant",
"@ava/oai-openapi": "workspace:../packages/oai-openapi",
"@ava/skills-homeassistant": "workspace:../packages/skills-homeassistant",
"@bogeychan/elysia-logger": "^0.0.21",
"@elysiajs/swagger": "^1.0.3",
"elysia": "latest",
"elysia-autoload": "^0.2.3",
"elysia-autoroutes": "^0.5.0",
"uuid": "^9.0.1",
"znv": "^0.4.0",
"zod": "^3.22.5"
},
Expand Down
19 changes: 19 additions & 0 deletions server/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Elysia } from 'elysia'
import { swagger } from './services/swagger'
import { autoload } from "elysia-autoload"
import { PORT } from './services/config'
import { elysiaLogger } from './services/logger'
import { getAssistant } from './services/assistant'

const assistant = await getAssistant()
console.log('Assistant initialized', assistant.getName())

const app = new Elysia()
.use(swagger)
.use(elysiaLogger)
.use(autoload())
.listen(PORT, (server) => {
console.log(`listening on http://${server.hostname}:${server.port}`)
})

export type ElysiaApp = typeof app
3 changes: 3 additions & 0 deletions server/src/routes/health/ready.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import type { ElysiaApp } from "~/index";

export default (app: ElysiaApp) => app.get('/', { ready: true })
12 changes: 12 additions & 0 deletions server/src/routes/v1/chat/completions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { CreateChatCompletionRequest, CreateChatCompletionResponse } from "@ava/oai-openapi";
import { t } from "elysia";
import type { ElysiaApp } from "~/index";
import { executeChatCompletion } from "~/services/oai/lang";

export default (app: ElysiaApp) => {
return app.post('/', async ({ body }): Promise<CreateChatCompletionResponse> => {
return executeChatCompletion(body as CreateChatCompletionRequest)
}, {
type: 'json'
})
}
19 changes: 19 additions & 0 deletions server/src/services/assistant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { createAssistant, type ToolInterface } from "@ava/lang";

let assistant: Awaited<ReturnType<typeof createAssistant>> | null = null

export const getAssistant = async () => {
if (assistant) {
return assistant
}

const tools: ToolInterface[] = []

if (process.env.HOMEASSISTANT) {
const { createHomeAssistantToolkit } = await import('@ava/skills-homeassistant')
tools.push(...await createHomeAssistantToolkit())
}

assistant = await createAssistant(tools)
return assistant
}
12 changes: 12 additions & 0 deletions server/src/services/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {parseEnv, port, z} from 'znv'

export const { PORT, LOG_LEVEL } = parseEnv(process.env, {
PORT: {
schema: port().default(2881),
description: 'Port for HTTP server to listen on'
},
LOG_LEVEL: {
schema: z.enum(["fatal", "error", "warn", "info", "debug", "trace"]).default('info'),
description: 'Log level for the server'
}
})
7 changes: 7 additions & 0 deletions server/src/services/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { logger } from "@bogeychan/elysia-logger";
import { LOG_LEVEL } from "./config";

export const elysiaLogger = logger({
name: '@ava/server',
level: LOG_LEVEL
})
61 changes: 61 additions & 0 deletions server/src/services/oai/lang.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import type { ChatCompletionRequestMessage, CreateChatCompletionRequest, CreateChatCompletionResponse } from "@ava/oai-openapi"
import { v4 } from "uuid"
import { getAssistant } from "../assistant"
import { AIMessage, HumanMessage, SystemMessage } from "@ava/lang"

const oaiToLangMessage = (messages: ChatCompletionRequestMessage[]) => {
return messages.map(({role, content}) => {
if(!content) return

switch (role) {
case 'user':
return new HumanMessage(content)
case 'assistant':
return new AIMessage(content)
case 'system':
return new SystemMessage(content)
default:
return
}
}).filter(Boolean)
}

export const executeChatCompletion = async (req: CreateChatCompletionRequest): Promise<CreateChatCompletionResponse> => {
const id = v4()
const assistant = await getAssistant()

if(req.stream) {
throw new Error('streaming is not supported yet')
}

const lastMessage = req.messages[req.messages.length - 1]
if (lastMessage.role !== 'user') {
throw new Error('last message must be from user role')
}
const input = lastMessage.content
const chat_history = oaiToLangMessage(req.messages.slice(0, -1))


const res = await assistant.invoke({
input,
chat_history,
}, {
configurable: {
sessionId: id
}
})

return {
id,
model: 'ava',
choices: [
{
index: 0,
finish_reason: 'stop',
message: res.output,
}
],
object: 'chat.completion',
created: Math.floor(Date.now() / 1000)
}
}
11 changes: 11 additions & 0 deletions server/src/services/swagger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Swagger from '@elysiajs/swagger'

export const swagger = Swagger({
documentation: {
info: {
title: 'Ava',
description: 'Ava API',
version: '0.0.0'
}
}
})
8 changes: 8 additions & 0 deletions server/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"paths": {
"~/*": ["./src/*"],
}
}
}
1 change: 0 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,

// Bundler mode
Expand Down

0 comments on commit 61b81d5

Please sign in to comment.