├── .env.local.example ├── .eslintignore ├── .eslintrc.cjs ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── playwright.config.ts ├── postcss.config.cjs ├── src ├── app.d.ts ├── app.html ├── app.postcss ├── hooks.client.ts ├── hooks.server.ts ├── index.test.ts ├── lib │ ├── components │ │ └── Chat │ │ │ ├── Chat.svelte │ │ │ ├── ChatHeader.svelte │ │ │ ├── ChatInput.svelte │ │ │ └── ChatMessage.svelte │ ├── helpers │ │ ├── datetime.ts │ │ ├── debounce.ts │ │ ├── pagination.test.ts │ │ ├── pagination.ts │ │ ├── text.ts │ │ └── triggerToast.ts │ ├── stores.ts │ ├── supabaseClient.ts │ ├── themes │ │ └── theme-chatjournal.css │ └── types │ │ ├── chatTypes.ts │ │ └── supabaseTypes.ts ├── lib_skeleton │ ├── AppBar │ │ ├── AppBar.svelte │ │ └── AppBarMinimal.svelte │ ├── Footer │ │ └── DocsFooter.svelte │ ├── Logo │ │ ├── DocsLogoAnim.svelte │ │ ├── DocsLogoIcon.svelte │ │ └── LogoFull.svelte │ ├── Navigation │ │ ├── DocsDrawer.svelte │ │ ├── Sidebar.svelte │ │ └── links.ts │ └── Shell │ │ ├── Shell.svelte │ │ ├── sveldMapper.ts │ │ └── types.ts └── routes │ ├── (inner) │ ├── +layout.ts │ ├── chat │ │ ├── +page.svelte │ │ └── +page.ts │ ├── journal │ │ ├── +page.server.ts │ │ ├── +page.svelte │ │ ├── JournalEntriesList.svelte │ │ ├── JournalEntry.svelte │ │ ├── Pagination.svelte │ │ ├── Sidebar.svelte │ │ └── [id] │ │ │ ├── +page.server.ts │ │ │ ├── +page.svelte │ │ │ ├── EditJournalEntryForm.svelte │ │ │ └── Suggestions.svelte │ └── profile │ │ ├── +page.server.ts │ │ ├── +page.svelte │ │ └── +page.ts │ ├── +error.svelte │ ├── +layout.server.ts │ ├── +layout.svelte │ ├── +layout.ts │ ├── +page.svelte │ ├── api │ ├── journal │ │ ├── +server.ts │ │ ├── [id] │ │ │ └── +server.ts │ │ └── embeddings │ │ │ └── +server.ts │ └── userProfile │ │ ├── private │ │ └── +server.ts │ │ └── public │ │ └── +server.ts │ └── auth │ ├── +layout.svelte │ ├── signin │ ├── +page.server.ts │ └── +page.svelte │ └── signup │ ├── +page.server.ts │ └── +page.svelte ├── static ├── chatjournal-logo-no-bg-large.webp ├── chatjournal-logo-no-bg-tiny.webp ├── chatjournal-logo-no-bg.webp ├── favicon.png ├── favicon.webp └── icons8-customer-96.png ├── supabase ├── .branches │ └── _current_branch ├── config.toml ├── functions │ ├── _shared │ │ └── cors.ts │ ├── chat-stream │ │ ├── agents.json │ │ ├── deno.json │ │ └── index.ts │ ├── create-embeddings-for-all │ │ ├── deno.json │ │ └── index.ts │ └── import_map.json └── migrations │ ├── 20230218152302_remote_commit.sql │ ├── 20230218180752_add_dbfunction_match_entries.sql │ ├── 20230218195541_remote_commit.sql │ ├── 20230221170247_chat-columns.sql │ ├── 20230221183618_remote_commit.sql │ └── 20230221183923_remote_commit.sql ├── svelte.config.js ├── tailwind.config.cjs ├── tests └── test.ts ├── tsconfig.json └── vite.config.ts /.env.local.example: -------------------------------------------------------------------------------- 1 | # Created by Vercel CLI 2 | VERCEL="1" 3 | VERCEL_ENV="development" 4 | TURBO_REMOTE_ONLY="true" 5 | NX_DAEMON="false" 6 | VERCEL_URL="" 7 | VERCEL_GIT_PROVIDER="" 8 | VERCEL_GIT_PREVIOUS_SHA="" 9 | VERCEL_GIT_REPO_SLUG="" 10 | VERCEL_GIT_REPO_OWNER="" 11 | VERCEL_GIT_REPO_ID="" 12 | VERCEL_GIT_COMMIT_REF="" 13 | VERCEL_GIT_COMMIT_SHA="" 14 | VERCEL_GIT_COMMIT_MESSAGE="" 15 | VERCEL_GIT_COMMIT_AUTHOR_LOGIN="" 16 | VERCEL_GIT_COMMIT_AUTHOR_NAME="" 17 | VERCEL_GIT_PULL_REQUEST_ID="" 18 | VERCEL_ANALYTICS_ID="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 19 | OPENAI_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 20 | SUPABASE_SERVICE_ROLE_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 21 | VITE_SUPABASE_ANON_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 22 | VITE_SUPABASE_URL="http://localhost:54321" 23 | SUPABASE_PROJECT_ID="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 24 | VITE_SUPABASE_FUNCTIONS_URL="http://localhost:54321/functions/v1" 25 | VITE_POSTHOG_KEY="" 26 | VITE_POSTHOG_HOST="" 27 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 5 | plugins: ['svelte3', '@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 8 | settings: { 9 | 'svelte3/typescript': () => require('typescript') 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: alexpunct 4 | patreon: alexbejan 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.local.example 9 | !.env.example 10 | vite.config.js.timestamp-* 11 | vite.config.ts.timestamp-* 12 | coverage 13 | pnpm-lock.yaml 14 | .vscode 15 | .temp 16 | src/lib/tailwind/generated 17 | .vercel 18 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte"], 7 | "pluginSearchDirs": ["."], 8 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Skeleton Labs, LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chat Journal (ChatGPT + Your journal/diary) 2 | 3 | This is the Open Source application that powers [ChatJournal.Ai](https://www.chatjournal.ai). Chat Journal allows users to store their journal/diary and chat with ChatGPT (using a few different agents/prompts) about it. 4 | 5 | The application is built using: 6 | 7 | - [Svelte](https://github.com/sveltejs/svelte) and [Sveltekit](https://github.com/sveltejs/kit) 8 | - [SkeletonUI](https://github.com/skeletonlabs/skeleton) and [TailwindCSS](https://github.com/tailwindlabs/tailwindcss) (a big part of the UI layout is based on their Docs website) 9 | - [Supabase](https://github.com/supabase/supabase-js) 10 | - The ChatGPT interactions are built using Supabase edge functions which you can find in the `supabase/functions` folder in this repo (you need to [deploy them yourself](https://github.com/supabase/supabase/tree/master/examples/edge-functions)) 11 | 12 | # Setup Dev environment 13 | 14 | - Sign up to Supabase or setup it locally using the Docker containers (use the migrations in the `supabase` folder) 15 | - Add the environment variables (see the `.env.local.example` file) 16 | - Start the app (`npm run dev`) 17 | 18 | # Deployment to production 19 | 20 | Currently, chatjournal.ai is deployed to Vercel using their Sveltekit recipe for building the app. 21 | 22 | # Community 23 | 24 | Contributions are welcome! 25 | 26 | # Discord 27 | 28 | [Join the Discord here](https://discord.gg/REYCS3HuM4) 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chatjournal-skeleton", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite dev", 7 | "build": "vite build", 8 | "preview": "vite preview", 9 | "test": "playwright test", 10 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 11 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 12 | "test:unit": "vitest", 13 | "lint": "prettier --plugin-search-dir . --check . && eslint .", 14 | "format": "prettier --plugin-search-dir . --write .", 15 | "types": "npx supabase gen types typescript --project-id $(grep SUPABASE_PROJECT_ID .env | cut -d '=' -d '\"' -f2) --schema public > src/lib/types/supabaseTypes.ts" 16 | }, 17 | "devDependencies": { 18 | "@playwright/test": "^1.28.1", 19 | "@skeletonlabs/skeleton": "^0.132.5", 20 | "@sveltejs/adapter-auto": "^2.0.0", 21 | "@sveltejs/kit": "^1.5.0", 22 | "@tailwindcss/forms": "^0.5.3", 23 | "@tailwindcss/line-clamp": "^0.4.2", 24 | "@tailwindcss/typography": "^0.5.9", 25 | "@testing-library/svelte": "^3.2.2", 26 | "@typescript-eslint/eslint-plugin": "^5.45.0", 27 | "@typescript-eslint/parser": "^5.45.0", 28 | "autoprefixer": "^10.4.13", 29 | "eslint": "^8.28.0", 30 | "eslint-config-prettier": "^8.5.0", 31 | "eslint-plugin-svelte3": "^4.0.0", 32 | "postcss": "^8.4.21", 33 | "prettier": "^2.8.0", 34 | "prettier-plugin-svelte": "^2.8.1", 35 | "svelte": "^3.54.0", 36 | "svelte-check": "^3.0.1", 37 | "svelte-preprocess": "^5.0.1", 38 | "tailwindcss": "^3.2.4", 39 | "tslib": "^2.4.1", 40 | "typescript": "^4.9.3", 41 | "vite": "^4.0.0", 42 | "vitest": "^0.29.2" 43 | }, 44 | "type": "module", 45 | "dependencies": { 46 | "@floating-ui/dom": "^1.2.1", 47 | "@sajuthankappan/sveltekit-google-analytics": "^0.1.3", 48 | "@supabase/auth-helpers-sveltekit": "^0.8.7", 49 | "@supabase/supabase-js": "^2.7.1", 50 | "posthog-js": "^1.248.0", 51 | "sse.js": "^0.6.1" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /playwright.config.ts: -------------------------------------------------------------------------------- 1 | import type { PlaywrightTestConfig } from '@playwright/test'; 2 | 3 | const config: PlaywrightTestConfig = { 4 | webServer: { 5 | command: 'npm run build && npm run preview', 6 | port: 4173 7 | }, 8 | testDir: 'tests' 9 | }; 10 | 11 | export default config; 12 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } -------------------------------------------------------------------------------- /src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | // and what to do when importing types 4 | /// 5 | declare namespace App { 6 | // interface Locals {} 7 | // interface Error {} 8 | // interface Platform {} 9 | interface Supabase { 10 | Database: import('./lib/types/supabaseTypes').Database; 11 | SchemaName: 'public'; 12 | } 13 | 14 | // interface Locals {} 15 | interface PageData { 16 | session: import('@supabase/supabase-js').Session | null; 17 | } 18 | } 19 | 20 | declare module 'sse.js' { 21 | export type SSEOptions = EventSourceInit & { 22 | headers?: Record; 23 | payload?: string; 24 | method?: string; 25 | }; 26 | 27 | export class SSE extends EventSource { 28 | constructor(url: string | URL, sseOptions?: SSEOptions); 29 | stream(): void; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | %sveltekit.head% 10 | 11 | 12 |
%sveltekit.body%
13 | 14 | 15 | -------------------------------------------------------------------------------- /src/app.postcss: -------------------------------------------------------------------------------- 1 | /*place global styles here */ 2 | html, 3 | body { 4 | @apply h-full overflow-hidden; 5 | } 6 | 7 | /* Page Styles */ 8 | .page-container { 9 | @apply container mx-auto p-2 md:p-12 space-y-8 md:space-y-12; 10 | } 11 | 12 | /* Label Text Override */ 13 | label:not(.unstyled) span:first-of-type:not(.unstyled):is(:not(.input-chip *)) { 14 | @apply text-surface-700-200-token text-sm; 15 | } 16 | 17 | .float-div-bottom-left { 18 | position: absolute; 19 | bottom: 10%; 20 | left: 0; 21 | } 22 | 23 | .gradient-heading { 24 | @apply bg-clip-text text-transparent box-decoration-clone; 25 | /* Direction */ 26 | @apply bg-gradient-to-br; 27 | /* Color Stops */ 28 | @apply from-tertiary-900 via-primary-600 to-secondary-700; 29 | } 30 | .dark .gradient-heading { 31 | @apply from-secondary-300 via-primary-500 to-success-300; 32 | } 33 | 34 | ::selection { 35 | @apply bg-primary-500/40; 36 | } 37 | 38 | .btn-gradient-primary { 39 | @apply bg-gradient-to-tl from-primary-700 via-primary-600 to-primary-400 text-black; 40 | } 41 | .btn-gradient-primary, 42 | .btn-gradient-secondary { 43 | @apply hover:bg-gradient-to-tr; 44 | } 45 | .bg-gradient-secondary, 46 | .btn-gradient-secondary { 47 | @apply bg-gradient-to-tl from-secondary-900 via-secondary-800 to-secondary-700 text-black; 48 | } 49 | .bg-gradient-success, 50 | .btn-gradient-success { 51 | @apply bg-gradient-to-tr from-success-900 via-success-800 to-success-700 text-black; 52 | } 53 | .btn-gradient-success { 54 | @apply hover:bg-gradient-to-tl; 55 | } 56 | 57 | .bg-gradient-error { 58 | @apply bg-gradient-to-tr from-error-900 via-error-700 to-error-500; 59 | } 60 | 61 | .textarea#edit-form { 62 | @apply text-lg font-light leading-6 tracking-wide !overflow-y-auto !bg-transparent !border-none !outline-none resize-none absolute w-full h-full top-0; 63 | } 64 | 65 | /* Chat Styles */ 66 | .bg-chat-user { 67 | @apply bg-blue-900; 68 | } 69 | .bg-chat-bot { 70 | @apply bg-teal-900; 71 | } 72 | .bg-gradient-chat-user { 73 | @apply bg-gradient-to-t from-blue-900 via-indigo-800 to-indigo-900; 74 | } 75 | 76 | .bg-gradient-chat-bot { 77 | @apply bg-gradient-to-t from-emerald-900 via-teal-800 to-teal-900; 78 | } 79 | -------------------------------------------------------------------------------- /src/hooks.client.ts: -------------------------------------------------------------------------------- 1 | import '$lib/supabaseClient'; 2 | 3 | // In newer versions of SvelteKit a `handleError` hook is expected on the 4 | // client. Without this export the build fails when `app` tries to import it. 5 | export const handleError = ({ error }: { error: unknown }) => { 6 | console.error(error); 7 | }; 8 | -------------------------------------------------------------------------------- /src/hooks.server.ts: -------------------------------------------------------------------------------- 1 | import '$lib/supabaseClient'; 2 | -------------------------------------------------------------------------------- /src/index.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | describe('sum test', () => { 4 | it('adds 1 + 2 to equal 3', () => { 5 | expect(1 + 2).toBe(3); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /src/lib/components/Chat/Chat.svelte: -------------------------------------------------------------------------------- 1 | 86 | 87 |
88 |
89 |
    90 | {#each conversation as message, i (message.time)} 91 | {#if message.content} 92 |
  • 93 | 94 |
  • 95 | {/if} 96 | {/each} 97 | {#if answer} 98 |
  • 99 | 106 |
  • 107 | {/if} 108 |
109 |
110 | 111 |
112 | 113 | 126 | -------------------------------------------------------------------------------- /src/lib/components/Chat/ChatHeader.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 |
11 |
{title}
12 | 15 |
16 |
17 | 18 | 21 | -------------------------------------------------------------------------------- /src/lib/components/Chat/ChatInput.svelte: -------------------------------------------------------------------------------- 1 | 17 | 18 |
21 |
22 |
25 |