Added Email, Contacts and ChatGPT
This commit is contained in:
parent
0312f50d51
commit
5e3631c49d
20
.wundergraph/operations/getChatwootContacts.ts
Normal file
20
.wundergraph/operations/getChatwootContacts.ts
Normal file
@ -0,0 +1,20 @@
|
||||
// .wundergraph/operations/getChatwootContacts.ts
|
||||
import { createOperation, z } from '../generated/wundergraph.factory';
|
||||
import axios from 'axios';
|
||||
|
||||
export default createOperation.query({
|
||||
input: z.object({
|
||||
page: z.number().optional(),
|
||||
}),
|
||||
handler: async ({ page = 1 }) => {
|
||||
console.log('Making request to Chatwoot API');
|
||||
|
||||
const { data } = await axios.get(`https://chatwoot.andert.me/api/v1/accounts/1/contacts?page=${page}`, {
|
||||
headers: {
|
||||
api_access_token: process.env.CHATWOOT_API_ACCESS_TOKEN
|
||||
},
|
||||
});
|
||||
|
||||
return data;
|
||||
},
|
||||
});
|
19
.wundergraph/operations/getChatwootConversations.ts
Normal file
19
.wundergraph/operations/getChatwootConversations.ts
Normal file
@ -0,0 +1,19 @@
|
||||
// .wundergraph/operations/getChatwootConversations.ts
|
||||
import { createOperation, z } from '../generated/wundergraph.factory';
|
||||
import axios from 'axios';
|
||||
|
||||
export default createOperation.query({
|
||||
input: z.object({}),
|
||||
handler: async () => {
|
||||
console.log('Making request to Chatwoot API');
|
||||
|
||||
const { data } = await axios.get('https://chatwoot.andert.me/api/v1/accounts/1/conversations?status=open&sort_by=last_activity_at', {
|
||||
headers: {
|
||||
api_access_token: process.env.CHATWOOT_API_ACCESS_TOKEN
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
return data;
|
||||
},
|
||||
});
|
@ -6,34 +6,58 @@ export default createOperation.query({
|
||||
input: z.object({}),
|
||||
handler: async () => {
|
||||
console.log('Making request to Paperless API');
|
||||
|
||||
const { data } = await axios.get('https://paperless.andert.me/api/documents/', {
|
||||
headers: {
|
||||
Authorization: process.env.PAPERLESS_TOKEN,
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
console.log('Received response:', data.results);
|
||||
|
||||
// Add download link, thumbnail link, preview link, and PDF data to each document
|
||||
const documentsWithLinksAndData = await Promise.all(data.results.map(async doc => {
|
||||
// Add download link, thumbnail link, preview link, PDF data, and metadata to each document
|
||||
const documentsWithLinksDataAndMetadata = await Promise.all(data.results.map(async doc => {
|
||||
const response = await axios.get(`https://paperless.andert.me/api/documents/${doc.id}/preview/`, {
|
||||
responseType: 'arraybuffer',
|
||||
headers: {
|
||||
Authorization: process.env.PAPERLESS_TOKEN,
|
||||
},
|
||||
});
|
||||
|
||||
const pdfData = Buffer.from(response.data, 'binary').toString('base64');
|
||||
|
||||
const correspondentResponse = await axios.get(`https://paperless.andert.me/api/correspondents/${doc.correspondent}/`, {
|
||||
headers: {
|
||||
Authorization: process.env.PAPERLESS_TOKEN,
|
||||
},
|
||||
});
|
||||
const correspondent = correspondentResponse.data;
|
||||
|
||||
const tagsResponse = await Promise.all(doc.tags.map(tag => axios.get(`https://paperless.andert.me/api/tags/${tag}/`, {
|
||||
headers: {
|
||||
Authorization: process.env.PAPERLESS_TOKEN,
|
||||
},
|
||||
})));
|
||||
const tags = tagsResponse.map(response => response.data);
|
||||
|
||||
const documentTypeResponse = await axios.get(`https://paperless.andert.me/api/document_types/${doc.document_type}/`, {
|
||||
headers: {
|
||||
Authorization: process.env.PAPERLESS_TOKEN,
|
||||
},
|
||||
});
|
||||
const documentType = documentTypeResponse.data;
|
||||
|
||||
return {
|
||||
...doc,
|
||||
downloadLink: `https://paperless.andert.me/api/documents/${doc.id}/download/`,
|
||||
thumbnailLink: `https://paperless.andert.me/api/documents/${doc.id}/thumb/`,
|
||||
previewLink: `https://paperless.andert.me/api/documents/${doc.id}/preview/`,
|
||||
pdfData,
|
||||
correspondent,
|
||||
tags,
|
||||
document_type: documentType,
|
||||
};
|
||||
}));
|
||||
|
||||
return documentsWithLinksAndData;
|
||||
return documentsWithLinksDataAndMetadata;
|
||||
},
|
||||
});
|
@ -2,41 +2,40 @@ type Query {
|
||||
projects(filter: projects_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): [projects!]!
|
||||
projects_by_id(id: ID!): projects
|
||||
projects_aggregated(groupBy: [String], filter: projects_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [projects_aggregated!]!
|
||||
todos(filter: todos_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): [todos!]!
|
||||
todos_by_id(id: ID!): todos
|
||||
todos_aggregated(groupBy: [String], filter: todos_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [todos_aggregated!]!
|
||||
bookmarks(filter: bookmarks_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): [bookmarks!]!
|
||||
bookmarks_by_id(id: ID!): bookmarks
|
||||
bookmarks_aggregated(groupBy: [String], filter: bookmarks_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [bookmarks_aggregated!]!
|
||||
todos(filter: todos_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): [todos!]!
|
||||
todos_by_id(id: ID!): todos
|
||||
todos_aggregated(groupBy: [String], filter: todos_filter, limit: Int, offset: Int, page: Int, search: String, sort: [String]): [todos_aggregated!]!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
create_projects_items(filter: projects_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String, data: [create_projects_input!]): [projects!]!
|
||||
create_projects_item(data: create_projects_input!): projects
|
||||
create_todos_items(filter: todos_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String, data: [create_todos_input!]): [todos!]!
|
||||
create_todos_item(data: create_todos_input!): todos
|
||||
create_bookmarks_items(filter: bookmarks_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String, data: [create_bookmarks_input!]): [bookmarks!]!
|
||||
create_bookmarks_item(data: create_bookmarks_input!): bookmarks
|
||||
create_todos_items(filter: todos_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String, data: [create_todos_input!]): [todos!]!
|
||||
create_todos_item(data: create_todos_input!): todos
|
||||
update_projects_items(filter: projects_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String, ids: [ID]!, data: update_projects_input!): [projects!]!
|
||||
update_projects_batch(filter: projects_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String, data: [update_projects_input!]): [projects!]!
|
||||
update_projects_item(id: ID!, data: update_projects_input!): projects
|
||||
update_todos_items(filter: todos_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String, ids: [ID]!, data: update_todos_input!): [todos!]!
|
||||
update_todos_batch(filter: todos_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String, data: [update_todos_input!]): [todos!]!
|
||||
update_todos_item(id: ID!, data: update_todos_input!): todos
|
||||
update_bookmarks_items(filter: bookmarks_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String, ids: [ID]!, data: update_bookmarks_input!): [bookmarks!]!
|
||||
update_bookmarks_batch(filter: bookmarks_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String, data: [update_bookmarks_input!]): [bookmarks!]!
|
||||
update_bookmarks_item(id: ID!, data: update_bookmarks_input!): bookmarks
|
||||
update_todos_items(filter: todos_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String, ids: [ID]!, data: update_todos_input!): [todos!]!
|
||||
update_todos_batch(filter: todos_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String, data: [update_todos_input!]): [todos!]!
|
||||
update_todos_item(id: ID!, data: update_todos_input!): todos
|
||||
delete_projects_items(ids: [ID]!): delete_many
|
||||
delete_projects_item(id: ID!): delete_one
|
||||
delete_todos_items(ids: [ID]!): delete_many
|
||||
delete_todos_item(id: ID!): delete_one
|
||||
delete_bookmarks_items(ids: [ID]!): delete_many
|
||||
delete_bookmarks_item(id: ID!): delete_one
|
||||
delete_todos_items(ids: [ID]!): delete_many
|
||||
delete_todos_item(id: ID!): delete_one
|
||||
}
|
||||
|
||||
type Subscription {
|
||||
projects_mutated(event: EventEnum): projects_mutated
|
||||
todos_mutated(event: EventEnum): todos_mutated
|
||||
directus_dashboards_mutated(event: EventEnum): directus_dashboards_mutated
|
||||
directus_activity_mutated(event: EventEnum): directus_activity_mutated
|
||||
directus_notifications_mutated(event: EventEnum): directus_notifications_mutated
|
||||
@ -55,6 +54,7 @@ type Subscription {
|
||||
directus_shares_mutated(event: EventEnum): directus_shares_mutated
|
||||
directus_webhooks_mutated(event: EventEnum): directus_webhooks_mutated
|
||||
bookmarks_mutated(event: EventEnum): bookmarks_mutated
|
||||
todos_mutated(event: EventEnum): todos_mutated
|
||||
}
|
||||
|
||||
"""The `Boolean` scalar type represents `true` or `false`."""
|
||||
@ -620,15 +620,16 @@ type projects_mutated {
|
||||
|
||||
type todos {
|
||||
id: ID!
|
||||
status: String
|
||||
sort: Int
|
||||
user_created(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
date_created: Date
|
||||
date_created_func: datetime_functions
|
||||
user_updated(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
date_updated: Date
|
||||
date_updated_func: datetime_functions
|
||||
enddate: Date
|
||||
enddate_func: datetime_functions
|
||||
task: String
|
||||
type: String
|
||||
}
|
||||
|
||||
type todos_aggregated {
|
||||
@ -636,27 +637,17 @@ type todos_aggregated {
|
||||
countAll: Int
|
||||
count: todos_aggregated_count
|
||||
countDistinct: todos_aggregated_count
|
||||
avg: todos_aggregated_fields
|
||||
sum: todos_aggregated_fields
|
||||
avgDistinct: todos_aggregated_fields
|
||||
sumDistinct: todos_aggregated_fields
|
||||
min: todos_aggregated_fields
|
||||
max: todos_aggregated_fields
|
||||
}
|
||||
|
||||
type todos_aggregated_count {
|
||||
id: Int
|
||||
status: Int
|
||||
sort: Int
|
||||
user_created: Int
|
||||
date_created: Int
|
||||
user_updated: Int
|
||||
date_updated: Int
|
||||
enddate: Int
|
||||
task: Int
|
||||
}
|
||||
|
||||
type todos_aggregated_fields {
|
||||
sort: Float
|
||||
type: Int
|
||||
}
|
||||
|
||||
type todos_mutated {
|
||||
@ -786,13 +777,13 @@ input create_projects_input {
|
||||
|
||||
input create_todos_input {
|
||||
id: ID
|
||||
status: String
|
||||
sort: Int
|
||||
user_created: create_directus_users_input
|
||||
date_created: Date
|
||||
user_updated: create_directus_users_input
|
||||
date_updated: Date
|
||||
enddate: Date
|
||||
task: String
|
||||
type: String
|
||||
}
|
||||
|
||||
input date_filter_operators {
|
||||
@ -1073,15 +1064,16 @@ input string_filter_operators {
|
||||
|
||||
input todos_filter {
|
||||
id: string_filter_operators
|
||||
status: string_filter_operators
|
||||
sort: number_filter_operators
|
||||
user_created: directus_users_filter
|
||||
date_created: date_filter_operators
|
||||
date_created_func: datetime_function_filter_operators
|
||||
user_updated: directus_users_filter
|
||||
date_updated: date_filter_operators
|
||||
date_updated_func: datetime_function_filter_operators
|
||||
enddate: date_filter_operators
|
||||
enddate_func: datetime_function_filter_operators
|
||||
task: string_filter_operators
|
||||
type: string_filter_operators
|
||||
_and: [todos_filter]
|
||||
_or: [todos_filter]
|
||||
}
|
||||
@ -1178,11 +1170,11 @@ input update_projects_input {
|
||||
|
||||
input update_todos_input {
|
||||
id: ID
|
||||
status: String
|
||||
sort: Int
|
||||
user_created: update_directus_users_input
|
||||
date_created: Date
|
||||
user_updated: update_directus_users_input
|
||||
date_updated: Date
|
||||
enddate: Date
|
||||
task: String
|
||||
type: String
|
||||
}
|
@ -199,7 +199,6 @@ type Mutation {
|
||||
|
||||
type Subscription {
|
||||
projects_mutated(event: EventEnum): projects_mutated
|
||||
todos_mutated(event: EventEnum): todos_mutated
|
||||
directus_dashboards_mutated(event: EventEnum): directus_dashboards_mutated
|
||||
directus_activity_mutated(event: EventEnum): directus_activity_mutated
|
||||
directus_notifications_mutated(event: EventEnum): directus_notifications_mutated
|
||||
@ -218,6 +217,7 @@ type Subscription {
|
||||
directus_shares_mutated(event: EventEnum): directus_shares_mutated
|
||||
directus_webhooks_mutated(event: EventEnum): directus_webhooks_mutated
|
||||
bookmarks_mutated(event: EventEnum): bookmarks_mutated
|
||||
todos_mutated(event: EventEnum): todos_mutated
|
||||
}
|
||||
|
||||
"""The `Boolean` scalar type represents `true` or `false`."""
|
||||
@ -1392,15 +1392,16 @@ type server_info_websocket_rest {
|
||||
|
||||
type todos {
|
||||
id: ID!
|
||||
status: String
|
||||
sort: Int
|
||||
user_created(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
date_created: Date
|
||||
date_created_func: datetime_functions
|
||||
user_updated(filter: directus_users_filter, sort: [String], limit: Int, offset: Int, page: Int, search: String): directus_users
|
||||
date_updated: Date
|
||||
date_updated_func: datetime_functions
|
||||
enddate: Date
|
||||
enddate_func: datetime_functions
|
||||
task: String
|
||||
type: String
|
||||
}
|
||||
|
||||
type todos_mutated {
|
||||
|
@ -58,6 +58,7 @@
|
||||
"@wundergraph/sdk": "^0.174.5",
|
||||
"@wundergraph/svelte-query": "^0.3.10",
|
||||
"@xstate/svelte": "^2.1.0",
|
||||
"ai": "^2.2.13",
|
||||
"axios": "^1.4.0",
|
||||
"cookie": "^0.5.0",
|
||||
"dotenv": "^16.3.1",
|
||||
@ -67,6 +68,7 @@
|
||||
"jsonwebtoken": "^9.0.1",
|
||||
"jwks-rsa": "^3.0.1",
|
||||
"node-jose": "^2.2.0",
|
||||
"openai": "^4.8.0",
|
||||
"path": "^0.12.7",
|
||||
"sqlite3": "^5.1.6",
|
||||
"svelte-kit-cookie-session": "^4.0.0",
|
||||
|
302
pnpm-lock.yaml
generated
302
pnpm-lock.yaml
generated
@ -52,6 +52,9 @@ dependencies:
|
||||
'@xstate/svelte':
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0(svelte@3.54.0)(xstate@4.38.2)
|
||||
ai:
|
||||
specifier: ^2.2.13
|
||||
version: 2.2.13(react@18.2.0)(solid-js@1.7.12)(svelte@3.54.0)(vue@3.3.4)
|
||||
axios:
|
||||
specifier: ^1.4.0
|
||||
version: 1.4.0
|
||||
@ -79,6 +82,9 @@ dependencies:
|
||||
node-jose:
|
||||
specifier: ^2.2.0
|
||||
version: 2.2.0
|
||||
openai:
|
||||
specifier: ^4.8.0
|
||||
version: 4.8.0
|
||||
path:
|
||||
specifier: ^0.12.7
|
||||
version: 0.12.7
|
||||
@ -5410,6 +5416,13 @@ packages:
|
||||
resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==}
|
||||
dev: false
|
||||
|
||||
/@types/node-fetch@2.6.5:
|
||||
resolution: {integrity: sha512-OZsUlr2nxvkqUFLSaY2ZbA+P1q22q+KrlxWOn/38RX+u5kTkYL2mTujEpzUhGkS+K/QCYp9oagfXG39XOzyySg==}
|
||||
dependencies:
|
||||
'@types/node': 20.5.8
|
||||
form-data: 4.0.0
|
||||
dev: false
|
||||
|
||||
/@types/node@12.20.55:
|
||||
resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
|
||||
dev: false
|
||||
@ -5502,6 +5515,89 @@ packages:
|
||||
'@types/yargs-parser': 21.0.0
|
||||
dev: false
|
||||
|
||||
/@vue/compiler-core@3.3.4:
|
||||
resolution: {integrity: sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==}
|
||||
dependencies:
|
||||
'@babel/parser': 7.22.16
|
||||
'@vue/shared': 3.3.4
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.0.2
|
||||
dev: false
|
||||
|
||||
/@vue/compiler-dom@3.3.4:
|
||||
resolution: {integrity: sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==}
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.3.4
|
||||
'@vue/shared': 3.3.4
|
||||
dev: false
|
||||
|
||||
/@vue/compiler-sfc@3.3.4:
|
||||
resolution: {integrity: sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==}
|
||||
dependencies:
|
||||
'@babel/parser': 7.22.16
|
||||
'@vue/compiler-core': 3.3.4
|
||||
'@vue/compiler-dom': 3.3.4
|
||||
'@vue/compiler-ssr': 3.3.4
|
||||
'@vue/reactivity-transform': 3.3.4
|
||||
'@vue/shared': 3.3.4
|
||||
estree-walker: 2.0.2
|
||||
magic-string: 0.30.3
|
||||
postcss: 8.4.29
|
||||
source-map-js: 1.0.2
|
||||
dev: false
|
||||
|
||||
/@vue/compiler-ssr@3.3.4:
|
||||
resolution: {integrity: sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==}
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.3.4
|
||||
'@vue/shared': 3.3.4
|
||||
dev: false
|
||||
|
||||
/@vue/reactivity-transform@3.3.4:
|
||||
resolution: {integrity: sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==}
|
||||
dependencies:
|
||||
'@babel/parser': 7.22.16
|
||||
'@vue/compiler-core': 3.3.4
|
||||
'@vue/shared': 3.3.4
|
||||
estree-walker: 2.0.2
|
||||
magic-string: 0.30.3
|
||||
dev: false
|
||||
|
||||
/@vue/reactivity@3.3.4:
|
||||
resolution: {integrity: sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==}
|
||||
dependencies:
|
||||
'@vue/shared': 3.3.4
|
||||
dev: false
|
||||
|
||||
/@vue/runtime-core@3.3.4:
|
||||
resolution: {integrity: sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==}
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.3.4
|
||||
'@vue/shared': 3.3.4
|
||||
dev: false
|
||||
|
||||
/@vue/runtime-dom@3.3.4:
|
||||
resolution: {integrity: sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==}
|
||||
dependencies:
|
||||
'@vue/runtime-core': 3.3.4
|
||||
'@vue/shared': 3.3.4
|
||||
csstype: 3.1.2
|
||||
dev: false
|
||||
|
||||
/@vue/server-renderer@3.3.4(vue@3.3.4):
|
||||
resolution: {integrity: sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==}
|
||||
peerDependencies:
|
||||
vue: 3.3.4
|
||||
dependencies:
|
||||
'@vue/compiler-ssr': 3.3.4
|
||||
'@vue/shared': 3.3.4
|
||||
vue: 3.3.4
|
||||
dev: false
|
||||
|
||||
/@vue/shared@3.3.4:
|
||||
resolution: {integrity: sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==}
|
||||
dev: false
|
||||
|
||||
/@wagmi/chains@1.7.0(typescript@5.0.2):
|
||||
resolution: {integrity: sha512-TKVeHv0GqP5sV1yQ8BDGYToAFezPnCexbbBpeH14x7ywi5a1dDStPffpt9x+ytE6LJWkZ6pAMs/HNWXBQ5Nqmw==}
|
||||
peerDependencies:
|
||||
@ -6247,6 +6343,40 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/ai@2.2.13(react@18.2.0)(solid-js@1.7.12)(svelte@3.54.0)(vue@3.3.4):
|
||||
resolution: {integrity: sha512-tq0OpUUryPjSPn7WYhZ7viGUq1d2/L5T0FZawGun9ojYYOzu5eJIAQAnZ2HRTXsFIwuYTb9wAgZUx+sQUDjdnQ==}
|
||||
engines: {node: '>=14.6'}
|
||||
peerDependencies:
|
||||
react: ^18.2.0
|
||||
solid-js: ^1.7.7
|
||||
svelte: ^3.0.0 || ^4.0.0
|
||||
vue: ^3.3.4
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
solid-js:
|
||||
optional: true
|
||||
svelte:
|
||||
optional: true
|
||||
vue:
|
||||
optional: true
|
||||
dependencies:
|
||||
eventsource-parser: 1.0.0
|
||||
nanoid: 3.3.6
|
||||
openai: 4.2.0
|
||||
react: 18.2.0
|
||||
solid-js: 1.7.12
|
||||
solid-swr-store: 0.10.7(solid-js@1.7.12)(swr-store@0.10.6)
|
||||
sswr: 2.0.0(svelte@3.54.0)
|
||||
svelte: 3.54.0
|
||||
swr: 2.2.0(react@18.2.0)
|
||||
swr-store: 0.10.6
|
||||
swrv: 1.0.4(vue@3.3.4)
|
||||
vue: 3.3.4
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
dev: false
|
||||
|
||||
/ajv-formats@2.1.1(ajv@8.12.0):
|
||||
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
|
||||
peerDependencies:
|
||||
@ -6916,6 +7046,10 @@ packages:
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/charenc@0.0.2:
|
||||
resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
|
||||
dev: false
|
||||
|
||||
/charset@1.0.1:
|
||||
resolution: {integrity: sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==}
|
||||
engines: {node: '>=4.0.0'}
|
||||
@ -7207,12 +7341,20 @@ packages:
|
||||
which: 2.0.2
|
||||
dev: false
|
||||
|
||||
/crypt@0.0.2:
|
||||
resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
|
||||
dev: false
|
||||
|
||||
/cssesc@3.0.0:
|
||||
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/csstype@3.1.2:
|
||||
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
|
||||
dev: false
|
||||
|
||||
/d@1.0.1:
|
||||
resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==}
|
||||
dependencies:
|
||||
@ -7334,6 +7476,11 @@ packages:
|
||||
prop-types: 15.8.1
|
||||
dev: false
|
||||
|
||||
/dequal@2.0.3:
|
||||
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/destroy@1.2.0:
|
||||
resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
|
||||
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
|
||||
@ -7372,6 +7519,13 @@ packages:
|
||||
engines: {node: '>=0.3.1'}
|
||||
dev: false
|
||||
|
||||
/digest-fetch@1.3.0:
|
||||
resolution: {integrity: sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==}
|
||||
dependencies:
|
||||
base-64: 0.1.0
|
||||
md5: 2.3.0
|
||||
dev: false
|
||||
|
||||
/dijkstrajs@1.0.3:
|
||||
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
|
||||
dev: false
|
||||
@ -7635,6 +7789,10 @@ packages:
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/estree-walker@2.0.2:
|
||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||
dev: false
|
||||
|
||||
/esutils@2.0.3:
|
||||
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -7794,6 +7952,11 @@ packages:
|
||||
engines: {node: '>=0.8.x'}
|
||||
dev: false
|
||||
|
||||
/eventsource-parser@1.0.0:
|
||||
resolution: {integrity: sha512-9jgfSCa3dmEme2ES3mPByGXfgZ87VbP97tng1G2nWwWx6bV2nYxm2AWCrbQjXToSe+yYlqaZNtxffR9IeQr95g==}
|
||||
engines: {node: '>=14.18'}
|
||||
dev: false
|
||||
|
||||
/execa@5.1.1:
|
||||
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
|
||||
engines: {node: '>=10'}
|
||||
@ -8048,6 +8211,10 @@ packages:
|
||||
resolution: {integrity: sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==}
|
||||
dev: false
|
||||
|
||||
/form-data-encoder@1.7.2:
|
||||
resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
|
||||
dev: false
|
||||
|
||||
/form-data@4.0.0:
|
||||
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
|
||||
engines: {node: '>= 6'}
|
||||
@ -8056,6 +8223,14 @@ packages:
|
||||
combined-stream: 1.0.8
|
||||
mime-types: 2.1.35
|
||||
|
||||
/formdata-node@4.4.1:
|
||||
resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==}
|
||||
engines: {node: '>= 12.20'}
|
||||
dependencies:
|
||||
node-domexception: 1.0.0
|
||||
web-streams-polyfill: 4.0.0-beta.3
|
||||
dev: false
|
||||
|
||||
/forwarded@0.2.0:
|
||||
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
|
||||
engines: {node: '>= 0.6'}
|
||||
@ -8758,6 +8933,10 @@ packages:
|
||||
binary-extensions: 2.2.0
|
||||
dev: true
|
||||
|
||||
/is-buffer@1.1.6:
|
||||
resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
|
||||
dev: false
|
||||
|
||||
/is-callable@1.2.7:
|
||||
resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -9642,7 +9821,6 @@ packages:
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
dev: true
|
||||
|
||||
/make-dir@2.1.0:
|
||||
resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
|
||||
@ -9699,6 +9877,14 @@ packages:
|
||||
resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==}
|
||||
dev: false
|
||||
|
||||
/md5@2.3.0:
|
||||
resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
|
||||
dependencies:
|
||||
charenc: 0.0.2
|
||||
crypt: 0.0.2
|
||||
is-buffer: 1.1.6
|
||||
dev: false
|
||||
|
||||
/memoize-one@5.2.1:
|
||||
resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==}
|
||||
dev: false
|
||||
@ -10379,6 +10565,11 @@ packages:
|
||||
minimatch: 3.1.2
|
||||
dev: false
|
||||
|
||||
/node-domexception@1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
engines: {node: '>=10.5.0'}
|
||||
dev: false
|
||||
|
||||
/node-fetch-h2@2.3.0:
|
||||
resolution: {integrity: sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==}
|
||||
engines: {node: 4.x || >=6.0.0}
|
||||
@ -10647,6 +10838,38 @@ packages:
|
||||
- debug
|
||||
dev: false
|
||||
|
||||
/openai@4.2.0:
|
||||
resolution: {integrity: sha512-zfvpO2eITIxIjTG8T6Cek7NB2dMvP/LW0TRUJ4P9E8+qbBNKw00DrtfF64b+fAV2+wUYCVyynT6iSycJ//TtbA==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@types/node': 18.15.13
|
||||
'@types/node-fetch': 2.6.5
|
||||
abort-controller: 3.0.0
|
||||
agentkeepalive: 4.5.0
|
||||
digest-fetch: 1.3.0
|
||||
form-data-encoder: 1.7.2
|
||||
formdata-node: 4.4.1
|
||||
node-fetch: 2.7.0
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
dev: false
|
||||
|
||||
/openai@4.8.0:
|
||||
resolution: {integrity: sha512-CnLZvHi2x4pIoGAWCaj3jHi1a6NA4oFBL6mJDSXkIR5A/wv6lven7uL2gxMevjGBLA7OqYqis3Z2PMluiGauVw==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@types/node': 18.15.13
|
||||
'@types/node-fetch': 2.6.5
|
||||
abort-controller: 3.0.0
|
||||
agentkeepalive: 4.5.0
|
||||
digest-fetch: 1.3.0
|
||||
form-data-encoder: 1.7.2
|
||||
formdata-node: 4.4.1
|
||||
node-fetch: 2.7.0
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
dev: false
|
||||
|
||||
/openapi-types@12.1.0:
|
||||
resolution: {integrity: sha512-XpeCy01X6L5EpP+6Hc3jWN7rMZJ+/k1lwki/kTmWzbVhdPie3jd5O2ZtedEx8Yp58icJ0osVldLMrTB/zslQXA==}
|
||||
dev: false
|
||||
@ -11009,7 +11232,6 @@ packages:
|
||||
nanoid: 3.3.6
|
||||
picocolors: 1.0.0
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/postman-collection@4.2.0:
|
||||
resolution: {integrity: sha512-tvOLgN1h6Kab6dt43PmBoV5kYO/YUta3x0C2QqfmbzmHZe47VTpZ/+gIkGlbNhjKNPUUub5X6ehxYKoaTYdy1w==}
|
||||
@ -11784,6 +12006,11 @@ packages:
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/seroval@0.5.1:
|
||||
resolution: {integrity: sha512-ZfhQVB59hmIauJG5Ydynupy8KHyr5imGNtdDhbZG68Ufh1Ynkv9KOYOAABf71oVbQxJ8VkWnMHAjEHE7fWkH5g==}
|
||||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
/serve-static@1.15.0:
|
||||
resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
@ -12003,6 +12230,24 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/solid-js@1.7.12:
|
||||
resolution: {integrity: sha512-QoyoOUKu14iLoGxjxWFIU8+/1kLT4edQ7mZESFPonsEXZ//VJtPKD8Ud1aTKzotj+MNWmSs9YzK6TdY+fO9Eww==}
|
||||
dependencies:
|
||||
csstype: 3.1.2
|
||||
seroval: 0.5.1
|
||||
dev: false
|
||||
|
||||
/solid-swr-store@0.10.7(solid-js@1.7.12)(swr-store@0.10.6):
|
||||
resolution: {integrity: sha512-A6d68aJmRP471aWqKKPE2tpgOiR5fH4qXQNfKIec+Vap+MGQm3tvXlT8n0I8UgJSlNAsSAUuw2VTviH2h3Vv5g==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
solid-js: ^1.2
|
||||
swr-store: ^0.10
|
||||
dependencies:
|
||||
solid-js: 1.7.12
|
||||
swr-store: 0.10.6
|
||||
dev: false
|
||||
|
||||
/sonic-boom@2.8.0:
|
||||
resolution: {integrity: sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==}
|
||||
dependencies:
|
||||
@ -12028,7 +12273,6 @@ packages:
|
||||
/source-map-js@1.0.2:
|
||||
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/source-map-support@0.5.21:
|
||||
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
|
||||
@ -12106,6 +12350,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/sswr@2.0.0(svelte@3.54.0):
|
||||
resolution: {integrity: sha512-mV0kkeBHcjcb0M5NqKtKVg/uTIYNlIIniyDfSGrSfxpEdM9C365jK0z55pl9K0xAkNTJi2OAOVFQpgMPUk+V0w==}
|
||||
peerDependencies:
|
||||
svelte: ^4.0.0
|
||||
dependencies:
|
||||
svelte: 3.54.0
|
||||
swrev: 4.0.0
|
||||
dev: false
|
||||
|
||||
/stack-utils@2.0.6:
|
||||
resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
|
||||
engines: {node: '>=10'}
|
||||
@ -12399,6 +12652,34 @@ packages:
|
||||
- encoding
|
||||
dev: false
|
||||
|
||||
/swr-store@0.10.6:
|
||||
resolution: {integrity: sha512-xPjB1hARSiRaNNlUQvWSVrG5SirCjk2TmaUyzzvk69SZQan9hCJqw/5rG9iL7xElHU784GxRPISClq4488/XVw==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
dequal: 2.0.3
|
||||
dev: false
|
||||
|
||||
/swr@2.2.0(react@18.2.0):
|
||||
resolution: {integrity: sha512-AjqHOv2lAhkuUdIiBu9xbuettzAzWXmCEcLONNKJRba87WAefz8Ca9d6ds/SzrPc235n1IxWYdhJ2zF3MNUaoQ==}
|
||||
peerDependencies:
|
||||
react: ^16.11.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
use-sync-external-store: 1.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/swrev@4.0.0:
|
||||
resolution: {integrity: sha512-LqVcOHSB4cPGgitD1riJ1Hh4vdmITOp+BkmfmXRh4hSF/t7EnS4iD+SOTmq7w5pPm/SiPeto4ADbKS6dHUDWFA==}
|
||||
dev: false
|
||||
|
||||
/swrv@1.0.4(vue@3.3.4):
|
||||
resolution: {integrity: sha512-zjEkcP8Ywmj+xOJW3lIT65ciY/4AL4e/Or7Gj0MzU3zBJNMdJiT8geVZhINavnlHRMMCcJLHhraLTAiDOTmQ9g==}
|
||||
peerDependencies:
|
||||
vue: '>=3.2.26 < 4'
|
||||
dependencies:
|
||||
vue: 3.3.4
|
||||
dev: false
|
||||
|
||||
/symbol-observable@2.0.3:
|
||||
resolution: {integrity: sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA==}
|
||||
engines: {node: '>=0.10'}
|
||||
@ -13093,6 +13374,16 @@ packages:
|
||||
resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==}
|
||||
dev: false
|
||||
|
||||
/vue@3.3.4:
|
||||
resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==}
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.3.4
|
||||
'@vue/compiler-sfc': 3.3.4
|
||||
'@vue/runtime-dom': 3.3.4
|
||||
'@vue/server-renderer': 3.3.4(vue@3.3.4)
|
||||
'@vue/shared': 3.3.4
|
||||
dev: false
|
||||
|
||||
/wait-on@7.0.1:
|
||||
resolution: {integrity: sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
@ -13124,6 +13415,11 @@ packages:
|
||||
engines: {node: '>= 8'}
|
||||
dev: false
|
||||
|
||||
/web-streams-polyfill@4.0.0-beta.3:
|
||||
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
|
||||
engines: {node: '>= 14'}
|
||||
dev: false
|
||||
|
||||
/web-vitals@3.4.0:
|
||||
resolution: {integrity: sha512-n9fZ5/bG1oeDkyxLWyep0eahrNcPDF6bFqoyispt7xkW0xhDzpUBTgyDKqWDi1twT0MgH4HvvqzpUyh0ZxZV4A==}
|
||||
dev: false
|
||||
|
49
src/lib/Ai.svelte
Normal file
49
src/lib/Ai.svelte
Normal file
@ -0,0 +1,49 @@
|
||||
<script>
|
||||
import { useChat } from "ai/svelte";
|
||||
import Icon from "@iconify/svelte";
|
||||
|
||||
const { input, handleSubmit, messages } = useChat();
|
||||
</script>
|
||||
|
||||
<div class="chat-grid h-full p-4">
|
||||
<ul class="overflow-auto flex flex-col p-4 text-sm">
|
||||
{#each $messages as message}
|
||||
<li class="message {message.role === 'user' ? 'user' : 'assistant'} p-2">
|
||||
{message.content}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<div class="w-full">
|
||||
<form on:submit={handleSubmit} class="flex items-center">
|
||||
<input bind:value={$input} class="input flex-grow mr-4" type="text" />
|
||||
<button class="btn-icon variant-filled-success" type="submit">
|
||||
<div class="px-4">
|
||||
<Icon icon="carbon:send-alt-filled" class="" width="24" height="24" />
|
||||
</div>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.chat-grid {
|
||||
display: grid;
|
||||
grid-template-rows: 1fr auto;
|
||||
height: 100%;
|
||||
}
|
||||
.message {
|
||||
max-width: 80%;
|
||||
padding: px;
|
||||
margin: 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.user {
|
||||
align-self: flex-end;
|
||||
background-color: #0d6efd;
|
||||
color: white;
|
||||
}
|
||||
.assistant {
|
||||
align-self: flex-start;
|
||||
background-color: lightblue;
|
||||
}
|
||||
</style>
|
5
src/lib/JsonViewer.svelte
Normal file
5
src/lib/JsonViewer.svelte
Normal file
@ -0,0 +1,5 @@
|
||||
<script>
|
||||
export let json;
|
||||
</script>
|
||||
|
||||
<pre>{JSON.stringify(json, null, 2)}</pre>
|
14
src/lib/MailViewer.svelte
Normal file
14
src/lib/MailViewer.svelte
Normal file
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
function shadowroot(node, { html }) {
|
||||
node.attachShadow({ mode: "open" }).innerHTML = html;
|
||||
return {
|
||||
update({ html }) {
|
||||
node.shadowRoot.innerHTML = html;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export let html = "<h1>Some custom HTML</h1>";
|
||||
</script>
|
||||
|
||||
<div use:shadowroot={{ html }} />
|
@ -96,19 +96,6 @@
|
||||
</aside>
|
||||
<div class="col-span-5 w-full">
|
||||
<div class="flex justify-end space-x-4">
|
||||
<div class="w-full">
|
||||
<input bind:value={search} class="input" type="text" />
|
||||
</div>
|
||||
<button type="button" class="btn-icon variant-filled-success">
|
||||
<div class="px-4">
|
||||
<Icon
|
||||
icon="carbon:send-alt-filled"
|
||||
class=""
|
||||
width="24"
|
||||
height="24"
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
on:click={signRequestTrigger}
|
||||
type="button"
|
||||
|
@ -55,22 +55,31 @@
|
||||
<!-- (fallback contents) -->
|
||||
{/if}</Drawer
|
||||
>
|
||||
|
||||
<div class="grid h-screen grid-rows-layout bg-color">
|
||||
<QueryClientProvider client={data.queryClient}>
|
||||
<div class="grid h-screen grid-layout bg-color">
|
||||
<QueryClientProvider client={data.queryClient} class="main">
|
||||
<slot />
|
||||
</QueryClientProvider>
|
||||
|
||||
<div class="row-start-2 row-end-3">
|
||||
<footer>
|
||||
<Wallet />
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.bg-color {
|
||||
background-color: #e6e7e1;
|
||||
}
|
||||
.grid-rows-layout {
|
||||
.grid-layout {
|
||||
grid-template-areas:
|
||||
"main "
|
||||
"footer ";
|
||||
grid-template-rows: 1fr auto;
|
||||
}
|
||||
.main {
|
||||
grid-area: main;
|
||||
}
|
||||
|
||||
footer {
|
||||
grid-area: footer;
|
||||
}
|
||||
</style>
|
||||
|
34
src/routes/api/chat/+server.ts
Normal file
34
src/routes/api/chat/+server.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import OpenAI from 'openai';
|
||||
import { OpenAIStream, StreamingTextResponse } from 'ai';
|
||||
|
||||
import { env } from '$env/dynamic/private';
|
||||
// You may want to replace the above with a static private env variable
|
||||
// for dead-code elimination and build-time type-checking:
|
||||
// import { OPENAI_API_KEY } from '$env/static/private'
|
||||
|
||||
import type { RequestHandler } from './$types';
|
||||
|
||||
// Create an OpenAI API client
|
||||
const openai = new OpenAI({
|
||||
apiKey: env.OPENAI_API_KEY || '',
|
||||
});
|
||||
|
||||
export const POST = (async ({ request }) => {
|
||||
// Extract the `prompt` from the body of the request
|
||||
const { messages } = await request.json();
|
||||
|
||||
// Ask OpenAI for a streaming chat completion given the prompt
|
||||
const response = await openai.chat.completions.create({
|
||||
model: 'gpt-3.5-turbo',
|
||||
stream: true,
|
||||
messages: messages.map((message: any) => ({
|
||||
content: message.content,
|
||||
role: message.role,
|
||||
})),
|
||||
});
|
||||
|
||||
// Convert the response into a friendly text-stream
|
||||
const stream = OpenAIStream(response);
|
||||
// Respond with the stream
|
||||
return new StreamingTextResponse(stream);
|
||||
}) satisfies RequestHandler;
|
@ -1,16 +1,85 @@
|
||||
<script>
|
||||
import Icon from "@iconify/svelte";
|
||||
</script>
|
||||
|
||||
<div class="w-full h-full overflow-hidden grid grid-cols-6">
|
||||
<aside class="col-span-1">
|
||||
<nav class="list-nav p-6">
|
||||
<nav class="list-nav p-2">
|
||||
<h3 class="text-xl font-bold mb-4">MY HOME</h3>
|
||||
<ul>
|
||||
<li><a href="/me">Dashboard</a></li>
|
||||
<li><a href="/me/projects">My Projects</a></li>
|
||||
<!-- <li><a href="/me/documents">My Documents</a></li> -->
|
||||
<li><a href="/me/banking">Banking</a></li>
|
||||
<!-- <li><a href="/me/bookmarks">Bookmarks</a></li> -->
|
||||
<li><a href="/me/paperless">Paperless</a></li>
|
||||
<li><a href="/me/acc">Access Control</a></li>
|
||||
<!-- <li><a href="/me/apps">Apps</a></li> -->
|
||||
<li>
|
||||
<a href="/me">
|
||||
<Icon
|
||||
icon="iconamoon:profile-circle-fill"
|
||||
class="w-8 h-8 text-gray-500"
|
||||
/>
|
||||
Dashboard
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/me/projects">
|
||||
<Icon
|
||||
icon="iconamoon:profile-circle-fill"
|
||||
class="w-8 h-8 text-gray-500"
|
||||
/>
|
||||
My Projects
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/me/contacts">
|
||||
<Icon
|
||||
icon="iconamoon:profile-circle-fill"
|
||||
class="w-8 h-8 text-gray-500"
|
||||
/>
|
||||
Contacts
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/me/conversations">
|
||||
<Icon
|
||||
icon="iconamoon:profile-circle-fill"
|
||||
class="w-8 h-8 text-gray-500"
|
||||
/>
|
||||
Email
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/me/chatGPT">
|
||||
<Icon
|
||||
icon="iconamoon:profile-circle-fill"
|
||||
class="w-8 h-8 text-gray-500"
|
||||
/>
|
||||
ChatGPT
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/me/banking">
|
||||
<Icon
|
||||
icon="iconamoon:profile-circle-fill"
|
||||
class="w-8 h-8 text-gray-500"
|
||||
/>
|
||||
Banking
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/me/paperless">
|
||||
<Icon
|
||||
icon="iconamoon:profile-circle-fill"
|
||||
class="w-8 h-8 text-gray-500"
|
||||
/>
|
||||
Paperless
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/me/acc">
|
||||
<Icon
|
||||
icon="iconamoon:profile-circle-fill"
|
||||
class="w-8 h-8 text-gray-500"
|
||||
/>
|
||||
Access Control
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</aside>
|
||||
@ -18,3 +87,9 @@
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.collapsed {
|
||||
width: 3rem; /* Adjust as needed */
|
||||
}
|
||||
</style>
|
||||
|
5
src/routes/me/chatGPT/+page.svelte
Normal file
5
src/routes/me/chatGPT/+page.svelte
Normal file
@ -0,0 +1,5 @@
|
||||
<script>
|
||||
import Ai from "$lib/Ai.svelte";
|
||||
</script>
|
||||
|
||||
<Ai />
|
37
src/routes/me/contacts/+page.svelte
Normal file
37
src/routes/me/contacts/+page.svelte
Normal file
@ -0,0 +1,37 @@
|
||||
<script lang="ts">
|
||||
import JsonViewer from "$lib/JsonViewer.svelte";
|
||||
import HeaderMain from "$lib/layouts/HeaderMain.svelte";
|
||||
import { createQuery } from "../../../lib/wundergraph";
|
||||
|
||||
const contactsQuery = createQuery({
|
||||
operationName: "getChatwootContacts",
|
||||
variables: { page: 2 },
|
||||
});
|
||||
</script>
|
||||
|
||||
<HeaderMain>
|
||||
<div slot="header">
|
||||
<h1>Contacts</h1>
|
||||
</div>
|
||||
|
||||
<div slot="main" class="h-full w-full overflow-scroll">
|
||||
<div class="w-full h-full overflow-scroll">
|
||||
{#if $contactsQuery.isLoading}
|
||||
<p>Loading...</p>
|
||||
{:else if $contactsQuery.error}
|
||||
<pre>Error: {JSON.stringify($contactsQuery.error, null, 2)}</pre>
|
||||
{:else}
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
{#each $contactsQuery.data.payload as contact (contact.id)}
|
||||
<div class="card">
|
||||
<header class="card-header">{contact.name}</header>
|
||||
<section class="p-4">
|
||||
ID: {contact.id}<br />{contact.email}
|
||||
</section>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</HeaderMain>
|
86
src/routes/me/conversations/+page.svelte
Normal file
86
src/routes/me/conversations/+page.svelte
Normal file
@ -0,0 +1,86 @@
|
||||
<script lang="ts">
|
||||
import MailViewer from "$lib/MailViewer.svelte";
|
||||
import { createQuery } from "../../../lib/wundergraph";
|
||||
import JsonViewer from "$lib/JsonViewer.svelte";
|
||||
|
||||
const conversationsQuery = createQuery({
|
||||
operationName: "getChatwootConversations",
|
||||
});
|
||||
|
||||
let selectedConversation = null;
|
||||
function selectConversation(conversation) {
|
||||
selectedConversation = conversation;
|
||||
}
|
||||
|
||||
$: if ($conversationsQuery.data && !selectedConversation) {
|
||||
selectedConversation = $conversationsQuery.data.data.payload[0];
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="h-full w-full overflow-scroll flex">
|
||||
<div class="w-1/3 h-full overflow-scroll">
|
||||
{#if $conversationsQuery.isLoading}
|
||||
<p>Loading...</p>
|
||||
{:else if $conversationsQuery.error}
|
||||
Error: <JsonViewer json="$conversationsQuery.error}" />
|
||||
{:else}
|
||||
{#each $conversationsQuery.data.data.payload as conversation (conversation.id)}
|
||||
<div
|
||||
class="m-1 p-2 border border-gray-200 rounded-md hover:bg-gray-100 cursor-pointer"
|
||||
on:click={() => selectConversation(conversation)}
|
||||
>
|
||||
<h2 class="text-lg font-semibold">
|
||||
{conversation.meta.sender.name}
|
||||
</h2>
|
||||
<p>{conversation.messages[0].content.slice(0, 100)}...</p>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
<div class="w-2/3 h-full overflow-scroll relative">
|
||||
{#if selectedConversation}
|
||||
<div class="p-4 bg-white z-10 sticky top-0 left-0">
|
||||
<h2 class="font-bold text-xl">
|
||||
{selectedConversation.meta.sender.name}
|
||||
</h2>
|
||||
<p>
|
||||
{selectedConversation.id} - {selectedConversation.meta.sender.email}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4 px-4">
|
||||
{#each selectedConversation.messages as message (message.id)}
|
||||
{#if message.content_type == "incoming_email"}
|
||||
{#if selectedConversation.last_non_activity_message.content != message.content}
|
||||
<MailViewer
|
||||
html={selectedConversation.last_non_activity_message
|
||||
.content_attributes.email.html_content.full}
|
||||
/>{/if}
|
||||
<MailViewer
|
||||
html={message.content_attributes.email.html_content.full}
|
||||
/>
|
||||
{:else}
|
||||
{#if selectedConversation.last_non_activity_message.content != message.content}{selectedConversation
|
||||
.last_non_activity_message.content}{/if}
|
||||
<p class="bg-slate-400 py-1 px-2 rounded-sm my-2">
|
||||
{message.content}
|
||||
</p>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<p>Select a conversation to view its details.</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 0.5em 1em;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 0.25em;
|
||||
}
|
||||
</style>
|
@ -46,6 +46,9 @@
|
||||
<h2 class="text-lg font-semibold">
|
||||
{document.archived_file_name}
|
||||
</h2>
|
||||
<p>Correspondent: {document.correspondent.name}</p>
|
||||
<p>Tags: {document.tags.map((tag) => tag.name).join(", ")}</p>
|
||||
<p>{document.document_type.name}</p>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
|
34
src/routes/server/api/chat/+server.ts
Normal file
34
src/routes/server/api/chat/+server.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import OpenAI from 'openai';
|
||||
import { OpenAIStream, StreamingTextResponse } from 'ai';
|
||||
|
||||
import { env } from '$env/dynamic/private';
|
||||
// You may want to replace the above with a static private env variable
|
||||
// for dead-code elimination and build-time type-checking:
|
||||
// import { OPENAI_API_KEY } from '$env/static/private'
|
||||
|
||||
import type { RequestHandler } from '../../server/api/chat/$types';
|
||||
|
||||
// Create an OpenAI API client
|
||||
const openai = new OpenAI({
|
||||
apiKey: env.OPENAI_API_KEY || '',
|
||||
});
|
||||
|
||||
export const POST = (async ({ request }) => {
|
||||
// Extract the `prompt` from the body of the request
|
||||
const { messages } = await request.json();
|
||||
|
||||
// Ask OpenAI for a streaming chat completion given the prompt
|
||||
const response = await openai.chat.completions.create({
|
||||
model: 'gpt-3.5-turbo',
|
||||
stream: true,
|
||||
messages: messages.map((message: any) => ({
|
||||
content: message.content,
|
||||
role: message.role,
|
||||
})),
|
||||
});
|
||||
|
||||
// Convert the response into a friendly text-stream
|
||||
const stream = OpenAIStream(response);
|
||||
// Respond with the stream
|
||||
return new StreamingTextResponse(stream);
|
||||
}) satisfies RequestHandler;
|
Loading…
Reference in New Issue
Block a user