Migrated to vercel

This commit is contained in:
2025-04-21 10:08:28 +03:00
parent 54bb69bb32
commit 18d266e415
20 changed files with 212 additions and 2320 deletions

1
.gitignore vendored
View File

@@ -23,3 +23,4 @@ logs
.env
.env.*
!.env.example
.vercel

View File

@@ -1,7 +1,11 @@
import { defineConfig } from "drizzle-kit";
import { get } from "radash";
export default defineConfig({
dialect: "sqlite",
dialect: "postgresql",
schema: "./server/database/schema.ts",
out: "./server/database/migrations",
dbCredentials: {
url: get(process, "env.NUXT_DATABASE_URL"),
},
});

View File

@@ -1,7 +1,6 @@
export default defineNuxtConfig({
css: ["~/assets/css/main.css"],
modules: [
"@nuxthub/core",
"@nuxt/ui",
"@nuxt/icon",
"nuxt-auth-utils",
@@ -13,14 +12,10 @@ export default defineNuxtConfig({
webhooksUrl: "",
stravaVerifyToken: "",
openaiApiKey: "",
databaseUrl: "",
},
future: { compatibilityVersion: 4 },
compatibilityDate: "2025-03-01",
hub: {
ai: true,
database: true,
},
app: {
head: {
link: [

1501
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,22 +6,20 @@
"build": "nuxt build",
"dev": "nuxt dev --host=0.0.0.0",
"generate": "nuxt generate",
"preview": "npx nuxthub preview",
"deploy": "npx nuxthub deploy",
"postinstall": "nuxt prepare"
},
"dependencies": {
"@formkit/tempo": "^0.1.2",
"@neondatabase/serverless": "^1.0.0",
"@nuxt/icon": "1.11.0",
"@nuxt/image": "^1.10.0",
"@nuxt/ui": "3.0.2",
"@nuxthub/core": "^0.8.23",
"@vee-validate/nuxt": "^4.15.0",
"@vueuse/nuxt": "^13.0.0",
"drizzle-orm": "^0.41.0",
"nuxt": "^3.16.2",
"nuxt-auth-utils": "0.5.18",
"openai": "^4.91.1",
"openai": "^4.95.1",
"radash": "^12.1.0",
"url": "^0.11.4",
"vue": "^3.5.13",
@@ -30,8 +28,7 @@
"devDependencies": {
"drizzle-kit": "^0.30.6",
"typescript": "^5.8.2",
"vue-tsc": "^2.2.8",
"wrangler": "^4.6.0"
"vue-tsc": "^2.2.8"
},
"trustedDependencies": [
"@parcel/watcher",

View File

@@ -1,19 +0,0 @@
CREATE TABLE `tokens` (
`user_id` integer PRIMARY KEY NOT NULL,
`refresh_token` text,
`access_token` text,
`expires_at` integer NOT NULL,
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `tokens_user_id_unique` ON `tokens` (`user_id`);--> statement-breakpoint
CREATE TABLE `users` (
`id` integer PRIMARY KEY NOT NULL,
`name` text NOT NULL,
`avatar` text NOT NULL,
`city` text,
`country` text,
`sex` text,
`weight` integer,
`created_at` integer
);

View File

@@ -1,14 +0,0 @@
PRAGMA foreign_keys=OFF;--> statement-breakpoint
CREATE TABLE `__new_tokens` (
`id` integer PRIMARY KEY NOT NULL,
`user_id` integer,
`refresh_token` text,
`access_token` text,
`expires_at` integer NOT NULL,
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
INSERT INTO `__new_tokens`("id", "user_id", "refresh_token", "access_token", "expires_at") SELECT "id", "user_id", "refresh_token", "access_token", "expires_at" FROM `tokens`;--> statement-breakpoint
DROP TABLE `tokens`;--> statement-breakpoint
ALTER TABLE `__new_tokens` RENAME TO `tokens`;--> statement-breakpoint
PRAGMA foreign_keys=ON;

View File

@@ -1 +0,0 @@
CREATE UNIQUE INDEX `tokens_user_id_unique` ON `tokens` (`user_id`);

View File

@@ -1,15 +0,0 @@
PRAGMA foreign_keys=OFF;--> statement-breakpoint
CREATE TABLE `__new_tokens` (
`id` integer PRIMARY KEY NOT NULL,
`user_id` integer,
`refresh_token` text,
`access_token` text,
`expires_at` integer NOT NULL,
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
INSERT INTO `__new_tokens`("id", "user_id", "refresh_token", "access_token", "expires_at") SELECT "id", "user_id", "refresh_token", "access_token", "expires_at" FROM `tokens`;--> statement-breakpoint
DROP TABLE `tokens`;--> statement-breakpoint
ALTER TABLE `__new_tokens` RENAME TO `tokens`;--> statement-breakpoint
PRAGMA foreign_keys=ON;--> statement-breakpoint
CREATE UNIQUE INDEX `tokens_user_id_unique` ON `tokens` (`user_id`);

View File

@@ -1,8 +0,0 @@
CREATE TABLE `preferences` (
`id` integer PRIMARY KEY NOT NULL,
`user_id` integer,
`data` jsonb,
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE UNIQUE INDEX `preferences_user_id_unique` ON `preferences` (`user_id`);

View File

@@ -1,144 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "7cffca6e-97cc-4159-bf48-2f8bbd7aded4",
"prevId": "00000000-0000-0000-0000-000000000000",
"tables": {
"tokens": {
"name": "tokens",
"columns": {
"user_id": {
"name": "user_id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"refresh_token": {
"name": "refresh_token",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"access_token": {
"name": "access_token",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"expires_at": {
"name": "expires_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"tokens_user_id_unique": {
"name": "tokens_user_id_unique",
"columns": [
"user_id"
],
"isUnique": true
}
},
"foreignKeys": {
"tokens_user_id_users_id_fk": {
"name": "tokens_user_id_users_id_fk",
"tableFrom": "tokens",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"users": {
"name": "users",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"avatar": {
"name": "avatar",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"city": {
"name": "city",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"country": {
"name": "country",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"sex": {
"name": "sex",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"weight": {
"name": "weight",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@@ -1,143 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "9b994045-7d5b-470e-bd5a-bf4bf93bb270",
"prevId": "7cffca6e-97cc-4159-bf48-2f8bbd7aded4",
"tables": {
"tokens": {
"name": "tokens",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"refresh_token": {
"name": "refresh_token",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"access_token": {
"name": "access_token",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"expires_at": {
"name": "expires_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"tokens_user_id_users_id_fk": {
"name": "tokens_user_id_users_id_fk",
"tableFrom": "tokens",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"users": {
"name": "users",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"avatar": {
"name": "avatar",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"city": {
"name": "city",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"country": {
"name": "country",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"sex": {
"name": "sex",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"weight": {
"name": "weight",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@@ -1,151 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "2aec8d0e-ddc1-49ff-983c-ac0f5be3d10e",
"prevId": "9b994045-7d5b-470e-bd5a-bf4bf93bb270",
"tables": {
"tokens": {
"name": "tokens",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"refresh_token": {
"name": "refresh_token",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"access_token": {
"name": "access_token",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"expires_at": {
"name": "expires_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"tokens_user_id_unique": {
"name": "tokens_user_id_unique",
"columns": [
"user_id"
],
"isUnique": true
}
},
"foreignKeys": {
"tokens_user_id_users_id_fk": {
"name": "tokens_user_id_users_id_fk",
"tableFrom": "tokens",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"users": {
"name": "users",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"avatar": {
"name": "avatar",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"city": {
"name": "city",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"country": {
"name": "country",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"sex": {
"name": "sex",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"weight": {
"name": "weight",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@@ -1,151 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "828a623e-bbd1-4a3e-adcf-1ac58e81c9b3",
"prevId": "2aec8d0e-ddc1-49ff-983c-ac0f5be3d10e",
"tables": {
"tokens": {
"name": "tokens",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"refresh_token": {
"name": "refresh_token",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"access_token": {
"name": "access_token",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"expires_at": {
"name": "expires_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"tokens_user_id_unique": {
"name": "tokens_user_id_unique",
"columns": [
"user_id"
],
"isUnique": true
}
},
"foreignKeys": {
"tokens_user_id_users_id_fk": {
"name": "tokens_user_id_users_id_fk",
"tableFrom": "tokens",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"users": {
"name": "users",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"avatar": {
"name": "avatar",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"city": {
"name": "city",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"country": {
"name": "country",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"sex": {
"name": "sex",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"weight": {
"name": "weight",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@@ -1,204 +0,0 @@
{
"version": "6",
"dialect": "sqlite",
"id": "b1388198-f0bd-4d77-ba71-d5740f1a09a7",
"prevId": "828a623e-bbd1-4a3e-adcf-1ac58e81c9b3",
"tables": {
"preferences": {
"name": "preferences",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"data": {
"name": "data",
"type": "jsonb",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"preferences_user_id_unique": {
"name": "preferences_user_id_unique",
"columns": [
"user_id"
],
"isUnique": true
}
},
"foreignKeys": {
"preferences_user_id_users_id_fk": {
"name": "preferences_user_id_users_id_fk",
"tableFrom": "preferences",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"tokens": {
"name": "tokens",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"refresh_token": {
"name": "refresh_token",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"access_token": {
"name": "access_token",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"expires_at": {
"name": "expires_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"tokens_user_id_unique": {
"name": "tokens_user_id_unique",
"columns": [
"user_id"
],
"isUnique": true
}
},
"foreignKeys": {
"tokens_user_id_users_id_fk": {
"name": "tokens_user_id_users_id_fk",
"tableFrom": "tokens",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"users": {
"name": "users",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"avatar": {
"name": "avatar",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"city": {
"name": "city",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"country": {
"name": "country",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"sex": {
"name": "sex",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"weight": {
"name": "weight",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@@ -1,41 +0,0 @@
{
"version": "7",
"dialect": "sqlite",
"entries": [
{
"idx": 0,
"version": "6",
"when": 1743665160397,
"tag": "0000_tearful_the_initiative",
"breakpoints": true
},
{
"idx": 1,
"version": "6",
"when": 1743691140050,
"tag": "0001_spooky_gravity",
"breakpoints": true
},
{
"idx": 2,
"version": "6",
"when": 1743691375389,
"tag": "0002_plain_shooting_star",
"breakpoints": true
},
{
"idx": 3,
"version": "6",
"when": 1743691967975,
"tag": "0003_perpetual_bill_hollister",
"breakpoints": true
},
{
"idx": 4,
"version": "6",
"when": 1743776869050,
"tag": "0004_cultured_doctor_strange",
"breakpoints": true
}
]
}

View File

@@ -1,25 +1,14 @@
import { relations } from "drizzle-orm";
import {
sqliteTable,
pgTable,
text,
integer,
customType,
} from "drizzle-orm/sqlite-core";
timestamp,
jsonb,
} from "drizzle-orm/pg-core";
const customJsonb = <TData>(name: string) =>
customType<{ data: TData; driverData: string }>({
dataType() {
return "jsonb";
},
toDriver(value: TData): string {
return JSON.stringify(value);
},
fromDriver(value: string): TData {
return JSON.parse(value);
},
})(name);
export const users = sqliteTable("users", {
export const users = pgTable("users", {
id: integer("id").primaryKey(),
name: text("name").notNull(),
avatar: text("avatar").notNull(),
@@ -27,19 +16,17 @@ export const users = sqliteTable("users", {
country: text("country"),
sex: text("sex"),
weight: integer("weight"),
createdAt: integer("created_at", { mode: "timestamp" }).$defaultFn(
() => new Date(),
),
createdAt: timestamp("created_at").notNull().defaultNow(),
});
export const preferences = sqliteTable("preferences", {
id: integer("id").primaryKey(),
export const preferences = pgTable("preferences", {
id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
userId: integer("user_id")
.references(() => users.id, {
onDelete: "cascade",
})
.unique(),
data: customJsonb("data")
data: jsonb("data")
.$type<{
enabled: boolean;
language: string;
@@ -52,8 +39,8 @@ export const preferences = sqliteTable("preferences", {
})),
});
export const tokens = sqliteTable("tokens", {
id: integer("id").primaryKey(),
export const tokens = pgTable("tokens", {
id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
userId: integer("user_id")
.references(() => users.id, {
onDelete: "cascade",
@@ -61,7 +48,7 @@ export const tokens = sqliteTable("tokens", {
.unique(),
refreshToken: text("refresh_token"),
accessToken: text("access_token"),
expiresAt: integer("expires_at", { mode: "timestamp" }).notNull(),
expiresAt: timestamp("expires_at").notNull().defaultNow(),
});
// Define relationships

View File

@@ -1,14 +1,9 @@
import { get, omit } from "radash";
import { OpenAI } from "openai";
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const db = useDrizzle();
const config = useRuntimeConfig();
const openai = new OpenAI({
apiKey: config.openaiApiKey,
});
const openai = useOpenAI();
const user = await db.query.users.findFirst({
where: (f, o) => o.eq(f.id, body.owner_id),
@@ -25,9 +20,10 @@ export default defineEventHandler(async (event) => {
const [, activity] = await strava!<any>(`/activities/${body.object_id}`);
const aiResponse = await openai.chat.completions.create({
const [aiError, aiResponse] = await openai("/responses", {
body: {
model: "gpt-4o-mini",
messages: [
input: [
{
role: "user",
content: `
@@ -63,40 +59,41 @@ export default defineEventHandler(async (event) => {
`,
},
],
tools: [
{
type: "function",
function: {
name: "generate_strava_meta",
description: "Generates Strava metadata.",
parameters: {
text: {
format: {
type: "json_schema",
name: "activity",
schema: {
type: "object",
properties: {
title: {
type: "string",
description: "The title of the activity",
},
description: {
type: "string",
description: "A short description of the activity",
},
},
required: ["title", "description"],
additionalProperties: false,
},
},
},
],
tool_choice: {
type: "function",
function: {
name: "generate_strava_meta",
},
},
});
if (aiError) {
throw createError({
statusCode: 500,
message: `OPENAI API: ${aiError.message}`,
});
}
const responseObject = JSON.parse(
get(aiResponse, "choices.0.message.tool_calls.0.function.arguments"),
) as { title: string; description: string };
get(aiResponse, "output.0.content.0.text"),
) as {
title: string;
description: string;
};
const [stravaError] = await strava!(`activities/${body.object_id}`, {
method: "PUT",

View File

@@ -1,4 +1,4 @@
import { drizzle } from "drizzle-orm/d1";
import { drizzle } from "drizzle-orm/neon-http";
export { sql, eq, and, or } from "drizzle-orm";
import * as schema from "../database/schema";
@@ -6,7 +6,9 @@ import * as schema from "../database/schema";
export const tables = schema;
export function useDrizzle() {
return drizzle(hubDatabase(), { schema });
const config = useRuntimeConfig();
return drizzle(config.databaseUrl, { schema });
}
export type User = typeof schema.users.$inferSelect;

View File

@@ -0,0 +1,15 @@
import { tryit } from "radash";
export const useOpenAI = () => {
const config = useRuntimeConfig();
const client = $fetch.create({
baseURL: "https://api.openai.com/v1",
headers: {
Authorization: `Bearer ${config.openaiApiKey}`,
},
method: "post",
});
return tryit(client);
};