Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add databases use cases #35

Merged
merged 4 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions devdays-2025-ai/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,3 @@ dist

# Finder (MacOS) folder config
.DS_Store

# Database
local.db
5 changes: 5 additions & 0 deletions devdays-2025-ai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,8 @@ bun run src/index.ts "country code"
- Llama Index
- Vercel AI SDK
- [ ] Add more examples in db

## Database

You can connect to the database locally using an new SQLite Connection.
Choosing the path of your local.db file for "Database path"
Binary file modified devdays-2025-ai/bun.lockb
Binary file not shown.
Binary file added devdays-2025-ai/local.db
Binary file not shown.
1 change: 1 addition & 0 deletions devdays-2025-ai/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
},
"dependencies": {
"@libsql/client": "^0.14.0",
"@slack/web-api": "^7.8.0",
"openai": "^4.73.1"
}
}
87 changes: 0 additions & 87 deletions devdays-2025-ai/src/database.ts

This file was deleted.

1,407 changes: 1,407 additions & 0 deletions devdays-2025-ai/src/database/data.json

Large diffs are not rendered by default.

77 changes: 77 additions & 0 deletions devdays-2025-ai/src/database/database.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { createClient, type Client } from "@libsql/client";
import { embed } from "../openai";
import data from "./data.json";

export const database = createClient({
url: "file:local.db",
});

// In this sample codebase we rely on an libsql (sqlite with other stuff) database to store the errors and comments data and vectors that result from embeddings
// If you want to explore vector datases, you can have a look at:
// - Chroma: https://www.trychroma.com/
// - Pinecone: https://www.pinecone.io/

const sanitzedSQL = (message: string): string => {
return message.replaceAll("'", "");
};

export const reset = async (database: Client) => {
const dataWithEmbedding = await Promise.all(
data.map(async (item) => {
const threadsWithEmbeddings = await Promise.all(
item.threads.map(async (thread) => ({
...thread,
embedding: await embed(thread.message),
}))
);

return {
...item,
embedding: await embed(item.message),
threads: threadsWithEmbeddings,
};
})
);

await database.batch(
[
"DROP TABLE IF EXISTS comments",
"DROP TABLE IF EXISTS errors",
`CREATE TABLE IF NOT EXISTS errors (id INTEGER PRIMARY KEY AUTOINCREMENT, created_at DATETIME NOT NULL, title TEXT NOT NULL, message TEXT NOT NULL, embedding F32_BLOB(${process.env.EMBEDDING_DIMENSION}) NOT NULL)`,
`CREATE TABLE IF NOT EXISTS comments (id INTEGER PRIMARY KEY AUTOINCREMENT, created_at DATETIME NOT NULL, message TEXT NOT NULL, sender TEXT NOT NULL, embedding F32_BLOB(${process.env.EMBEDDING_DIMENSION}) NOT NULL, errors_id INTEGER NOT NULL REFERENCES errors(id))`,
"CREATE INDEX errors_idx ON errors (libsql_vector_idx(embedding))",
"CREATE INDEX comments_idx ON comments (libsql_vector_idx(embedding))",
],
"write"
);

await database.execute("BEGIN TRANSACTION");

try {
for (const item of dataWithEmbedding) {
const result = await database.execute(
`INSERT INTO errors (created_at, title, message, embedding) VALUES ('${
item.created_at
}', '${sanitzedSQL(item.title)}', '${sanitzedSQL(
item.message
)}', vector32('[${item.embedding}]'))`
);
const errorId = result.lastInsertRowid;

for (const thread of item.threads) {
await database.execute(
`INSERT INTO comments (errors_id, created_at, message, sender, embedding) VALUES ('${errorId}', '${
thread.created_at
}', '${sanitzedSQL(thread.message)}', '${
thread.sender
}', vector32('[${thread.embedding}]'))`
);
}
}

await database.execute("COMMIT");
} catch (error) {
await database.execute("ROLLBACK");
throw error;
}
};
File renamed without changes.
63 changes: 63 additions & 0 deletions devdays-2025-ai/src/database/slack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { LogLevel, WebClient } from "@slack/web-api";

type ErrorMessage = {
created_at: Date;
title: string;
message: string;
sender: string;
threads: Omit<ErrorMessage, "title" | "threads">[];
};

const ERROR_COLOR = "a30200";
const client = new WebClient(process.env.SLACK_TOKEN, {
logLevel: LogLevel.ERROR,
});

//mtg-jobs
const channelId = "C02FW8DGG2F";

try {
const result = await client.conversations.history({
channel: channelId,
limit: 200,
});

const messages = result.messages?.filter((message) =>
message.attachments?.some((attachment) => attachment.color === ERROR_COLOR)
);

const data: ErrorMessage[] = [];
for (const message of messages ?? []) {
if (!message.ts) {
continue;
}
const replies = await client.conversations.replies({
channel: channelId,
ts: message.ts,
});

const userReplies =
replies.messages?.filter(
(reply: any) => reply.subtype !== "bot_message"
) ?? [];

data.push({
created_at: new Date(parseFloat(message.ts) * 1000),
title:
(message.app_id === "A03DJ82GYP8" //LaliloBot
? message.text
: message.attachments?.[0].title) ?? "",
message: message.attachments?.[0].text ?? "",
sender: message.username ?? message.user ?? "",
threads:
userReplies.map((reply) => ({
created_at: new Date(parseFloat(reply.ts ?? "0") * 1000),
message: reply.text ?? "",
sender: reply.user ?? "",
})) || [],
});
}
console.log(JSON.stringify(data));
} catch (error) {
console.error(error);
}
8 changes: 4 additions & 4 deletions devdays-2025-ai/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { database } from "./database";
import { database } from "./database/database";
import { embed, generateMessage } from "./openai";

const args = process.argv.slice(2);
Expand All @@ -11,7 +11,7 @@ const searchQuery = args.join(" ");
const queryEmbed = await embed(searchQuery);
// https://docs.turso.tech/features/ai-and-embeddings
const distanceComputation = `vector_distance_cos(errors.embedding, vector32('[${queryEmbed.join(
", ",
", "
)}]'))`;
const result =
await database.execute(`SELECT errors.id as id, errors.message as errorMessage, errors.created_at as createdAt, comments.message as comment, comments.created_at as commentCreatedAt, comments.sender as commentSender, ${distanceComputation} as distance
Expand Down Expand Up @@ -39,6 +39,6 @@ const data = Object.values(orderedGroups).map((group) => ({
console.log(
await generateMessage(
"You are a specialized AI that reads Lalilo error reports and the comments written about them by the team. From a given JSON containing an error message and its comments, create a clear, brief summary sentence that captures the essence of the issue and its resolution. Focus on what happened and how it was resolved if that information is present. Also highlight any team member that could have context about it and the dates it happened.",
JSON.stringify(data, null, 2),
),
JSON.stringify(data, null, 2)
)
);