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

Commit a52c71e

Browse files
committed
Sun Apr 21 14:17:44 PDT 2024
1 parent 911ad6b commit a52c71e

10 files changed

Lines changed: 94 additions & 18 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
name: Ship Home Assistant Add-on
2+
name: Ship Docker Image
33

44
on:
55
push:

README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Ava
2+
Self-hosted personal assistant in minutes with built-in Home Assistant integration and great extensibility and customizability.
3+
4+
Documentation is available on project website: https://ava.0x77.dev
5+
6+
![GitHub License](https://img.shields.io/github/license/0x77dev/ava)
7+
![Maintenance](https://img.shields.io/maintenance/yes/2024)
8+
![GitHub last commit](https://img.shields.io/github/last-commit/0x77dev/ava)
9+
[![Ship Docker Image](https://github.com/0x77dev/ava/actions/workflows/docker-image.yaml/badge.svg)](https://github.com/0x77dev/ava/actions/workflows/docker-image.yaml)
10+
11+
12+
## Features
13+
14+
- **Supports almost all major LLMs**: Support for OpenAI, Anthropic, and Ollama out of the box.
15+
- **Home Assistant Integration**: Ava can control your Home Assistant devices and answer questions about your entities.
16+
- **Extensible _(work in progress)_**: Ava is built with extensibility in mind. You can easily add new skills using custom HTTP endpoints.
17+
- **Customizable**: Great level of customizability with almost everything being configurable using environment variables.
18+
- **Fully private**: Ava is self-hosted, so you have full control over your data.
19+
- **OpenAI compatible endpoints**: Chat with your Ava using OpenAI compatible chat completion endpoint.
20+
- **Home Assistant addons**: Install Ava and Ollama as a Home Assistant addons with a couple of clicks.
21+
- **Dockerized**: Ava is available as a Docker image for both amd64 and aarch64, so you can manually spin it up in minutes.
22+
23+
## Home Assistant Installation
24+
25+
### Addons Repository
26+
27+
[![Open your Home Assistant instance and show the add add-on repository dialog with a specific repository URL pre-filled.](https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https://github.com/0x77dev/ava)
28+
29+
- [**Ollama**](./ollama): The easiest way to get up and running with large language models locally
30+
- [**Ava Server**](./server)
31+
32+
Learn more about configuring the addons on the [project website](https://ava.0x77.dev).
33+
34+
### Custom component
35+
36+
#### HACS
37+
38+
[![Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.](https://my.home-assistant.io/badges/hacs_repository.svg)](https://my.home-assistant.io/redirect/hacs_repository/?owner=0x77dev&repository=ava&category=integration)
39+
40+
#### Manual
41+
42+
Copy the [`custom_components/ava`](./custom_components/ava) folder to your `/config/custom_components` Home Assistant folder.
43+
44+
You can download the custom component zip directly using [GitZip](https://kinolien.github.io/gitzip/?download=https://github.com/0x77dev/ava/tree/main/custom_components/ava).
45+
46+
Learn more about configuring the custom component on the [project website](https://ava.0x77.dev).
47+
48+

bun.lockb

-480 KB
Binary file not shown.

packages/lang/agent/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import { LLM } from "../llm/config"
44
import { kindToPrompt, namespaceToKind } from "./mappings"
55
import type { ToolInterface } from "@langchain/core/tools"
66

7-
export const createAgent = (tools: ToolInterface[]) => {
7+
export const createAgent = async (tools: ToolInterface[]) => {
88
const kind = namespaceToKind[LLM.namespace]
99
const prompt = kindToPrompt[kind]
10-
const llm = createLLM()
10+
const llm = await createLLM()
1111

1212
switch (kind) {
1313
case "xml":

packages/lang/embeddings/providers/ollama.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { OllamaEmbeddings } from "langchain/embeddings/ollama";
22
import type { Embeddings } from "../schema";
3+
import { pullModel } from "../../services/ollama";
4+
5+
export const ollama = async (model: Embeddings) => {
6+
await pullModel(model.name, model.baseURL)
37

4-
export const ollama = (model: Embeddings) => {
58
return new OllamaEmbeddings({
69
model: model.name,
710
baseUrl: model.baseURL,

packages/lang/llm/providers/ollama.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { ChatOllama } from "langchain/chat_models/ollama";
22
import type { LLM } from "../schema";
3+
import { pullModel } from "../../services/ollama";
34

4-
export const ollama = (model: LLM) => {
5+
export const ollama = async (model: LLM) => {
6+
await pullModel(model.name, model.baseURL)
57
return new ChatOllama({
68
model: model.name,
79
baseUrl: model.baseURL,

packages/lang/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"easydl": "^1.1.1",
1818
"hnswlib-node": "^3",
1919
"langchain": "^0.1.34",
20+
"ollama": "^0.5.0",
2021
"xml-js": "^1.6.11",
2122
"znv": "^0.4.0",
2223
"zod": "^3.22.5"

packages/lang/services/ollama.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Ollama } from "ollama"
2+
3+
export const createOllama = (baseURL?: string) => {
4+
return new Ollama({
5+
host: baseURL,
6+
})
7+
}
8+
9+
export const pullModel = async (model: string, baseURL?: string) => {
10+
const ollama = createOllama(baseURL)
11+
const events = await ollama.pull({
12+
model,
13+
stream: true
14+
})
15+
16+
for await (const event of events) {
17+
console.log('[ollama] pulling', model, event)
18+
}
19+
}

skills/homeassistant/tools/entities.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ const entitiesToSearchable = async (entities: HassEntities, embeddings: Awaited<
3232

3333
const createStore = async () => {
3434
const embeddings = await createEmbeddings()
35-
let entityToSearchable: Record<string, Searchable> = {}
3635
const coll = entitiesColl(hass)
37-
let resolve: (...any: any) => void = () => {}
38-
const promise = new Promise(r => resolve = r)
3936
let store = new HNSWLib(embeddings, {
4037
space: 'cosine'
4138
})
39+
40+
let entityToSearchable: Record<string, Searchable> = {}
41+
4242
coll.subscribe(async (entities) => {
4343
const updatedSince = Object.fromEntries(
4444
Object.entries(entities)
@@ -73,11 +73,13 @@ const createStore = async () => {
7373
await store.addVectors(vectors, docs)
7474

7575
console.log('updated entities store with', Object.keys(updatedSince).length, 'updates, index size now is:', Object.keys(entityToSearchable).length)
76-
resolve()
7776
})
7877

79-
console.log('[ha] waiting for entities to load')
80-
await promise
78+
try {
79+
await coll.refresh()
80+
} catch (error) {
81+
console.warn(error)
82+
}
8183

8284
return async (query: string) => {
8385
console.log('[ha] searching for', query)

skills/homeassistant/tools/services.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ const servicesToSearchable = async (services: HassServices, embeddings: Awaited<
2424

2525
const createStore = async () => {
2626
const embeddings = await createEmbeddings()
27-
let serviceToSearchable: Record<string, Searchable> = {}
2827
const coll = servicesColl(hass)
29-
let resolve: (...any: any) => void = () => {}
30-
const promise = new Promise(r => resolve = r)
3128
let store = new HNSWLib(embeddings, {
3229
space: 'cosine'
3330
})
31+
32+
let serviceToSearchable: Record<string, Searchable> = {}
33+
3434
coll.subscribe(async (services) => {
3535
serviceToSearchable = { ...serviceToSearchable, ...await servicesToSearchable(services, embeddings) }
3636
store = new HNSWLib(embeddings, {
@@ -50,12 +50,13 @@ const createStore = async () => {
5050
await store.addVectors(vectors, docs)
5151

5252
console.log('updated services store with', Object.keys(servicesToSearchable).length)
53-
resolve()
5453
})
55-
await coll.refresh()
5654

57-
console.log('waiting for services to load')
58-
await promise
55+
try {
56+
await coll.refresh()
57+
} catch (error) {
58+
console.warn(error)
59+
}
5960

6061
return async (query: string) => {
6162
console.log('searching for', query)

0 commit comments

Comments
 (0)