├── .nvmrc ├── .eslintignore ├── CNAME ├── firebase ├── functions │ ├── .nvmrc │ ├── .env.local.example │ ├── tsconfig.dev.json │ ├── .gitignore │ ├── tsconfig.json │ ├── .eslintrc.js │ └── package.json ├── .firebaserc └── firebase.json ├── types ├── index.ts ├── tags.ts ├── error.ts ├── filter_sortby.ts ├── teacher-portal-sub-route.ts ├── pagination.ts ├── drag.ts ├── UserFile.ts ├── env.ts ├── folder.ts ├── teacher-settings.ts ├── google.ts ├── one-time-code.ts ├── data.ts ├── share-messages-by-teacher-profile.ts ├── referral.ts ├── notion.ts ├── google-storage.ts └── storage.ts ├── public ├── locales │ ├── ar │ │ ├── common.json │ │ ├── markdown.json │ │ ├── promptbar.json │ │ └── sidebar.json │ ├── bn │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── de │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── en │ │ ├── common.json │ │ ├── form.json │ │ ├── mjImage.json │ │ └── roles.json │ ├── es │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── fr │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── he │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── hi │ │ ├── common.json │ │ ├── news.json │ │ ├── features.json │ │ ├── markdown.json │ │ ├── feature.json │ │ ├── roles.json │ │ ├── promptbar.json │ │ └── sidebar.json │ ├── id │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── it │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── ja │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── ko │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── pl │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── pt │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── ro │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── ru │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── si │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── sv │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── te │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── vi │ │ ├── common.json │ │ ├── markdown.json │ │ ├── sidebar.json │ │ └── promptbar.json │ ├── zh │ │ └── chat.json │ ├── zh-Hans │ │ ├── form.json │ │ ├── features.json │ │ ├── news.json │ │ ├── markdown.json │ │ ├── imageToPrompt.json │ │ ├── roles.json │ │ ├── sidebar.json │ │ ├── feature.json │ │ ├── mjImage.json │ │ ├── common.json │ │ ├── prompts.json │ │ ├── auth.json │ │ └── promptbar.json │ └── zh-Hant │ │ ├── form.json │ │ ├── features.json │ │ ├── news.json │ │ ├── markdown.json │ │ ├── imageToPrompt.json │ │ ├── roles.json │ │ ├── sidebar.json │ │ ├── feature.json │ │ ├── mjImage.json │ │ ├── common.json │ │ ├── auth.json │ │ └── promptbar.json ├── favicon.ico ├── icons │ ├── icon_192.png │ ├── icon_512.png │ └── maskable_icon_384.png ├── assets │ ├── line-icon.webp │ ├── posters │ │ ├── 20240326.png │ │ ├── 20240331.jpg │ │ └── 20240504.jpg │ └── teacher_portal_qrcode.jpg ├── server-busy-image.png ├── splash-screens │ ├── icon.png │ ├── 10.2__iPad_landscape.png │ ├── 10.2__iPad_portrait.png │ ├── iPhone_14_Pro_portrait.png │ ├── 10.5__iPad_Air_landscape.png │ ├── 10.5__iPad_Air_portrait.png │ ├── 10.9__iPad_Air_landscape.png │ ├── 10.9__iPad_Air_portrait.png │ ├── 12.9__iPad_Pro_landscape.png │ ├── 12.9__iPad_Pro_portrait.png │ ├── 8.3__iPad_Mini_landscape.png │ ├── 8.3__iPad_Mini_portrait.png │ ├── iPhone_14_Pro_landscape.png │ ├── iPhone_14_Pro_Max_landscape.png │ ├── iPhone_14_Pro_Max_portrait.png │ ├── iPhone_11__iPhone_XR_landscape.png │ ├── iPhone_11__iPhone_XR_portrait.png │ ├── 11__iPad_Pro__10.5__iPad_Pro_portrait.png │ ├── 11__iPad_Pro__10.5__iPad_Pro_landscape.png │ ├── iPhone_11_Pro_Max__iPhone_XS_Max_landscape.png │ ├── iPhone_11_Pro_Max__iPhone_XS_Max_portrait.png │ ├── 4__iPhone_SE__iPod_touch_5th_generation_and_later_landscape.png │ ├── 4__iPhone_SE__iPod_touch_5th_generation_and_later_portrait.png │ ├── iPhone_14_Plus__iPhone_13_Pro_Max__iPhone_12_Pro_Max_landscape.png │ ├── iPhone_14_Plus__iPhone_13_Pro_Max__iPhone_12_Pro_Max_portrait.png │ ├── 9.7__iPad_Pro__7.9__iPad_mini__9.7__iPad_Air__9.7__iPad_landscape.png │ ├── 9.7__iPad_Pro__7.9__iPad_mini__9.7__iPad_Air__9.7__iPad_portrait.png │ ├── iPhone_8__iPhone_7__iPhone_6s__iPhone_6__4.7__iPhone_SE_landscape.png │ ├── iPhone_8__iPhone_7__iPhone_6s__iPhone_6__4.7__iPhone_SE_portrait.png │ ├── iPhone_14__iPhone_13_Pro__iPhone_13__iPhone_12_Pro__iPhone_12_portrait.png │ ├── iPhone_8_Plus__iPhone_7_Plus__iPhone_6s_Plus__iPhone_6_Plus_landscape.png │ ├── iPhone_8_Plus__iPhone_7_Plus__iPhone_6s_Plus__iPhone_6_Plus_portrait.png │ ├── iPhone_14__iPhone_13_Pro__iPhone_13__iPhone_12_Pro__iPhone_12_landscape.png │ ├── iPhone_13_mini__iPhone_12_mini__iPhone_11_Pro__iPhone_XS__iPhone_X_portrait.png │ └── iPhone_13_mini__iPhone_12_mini__iPhone_11_Pro__iPhone_XS__iPhone_X_landscape.png ├── ads.txt └── manifest.json ├── .husky └── pre-commit ├── supabase ├── .gitignore ├── migrations │ ├── 20240217011736_update_get_temp_account_teacher_profile_func.sql │ ├── 20230629020705_add_email_to_profiles.sql │ ├── 20230407204520_add_title_to_share_conversation_table.sql │ ├── 20231113230350_add_referral_code_column_to_referral_table.sql │ ├── 20231130170254_add_line_access_token_to_profiles_table.sql │ ├── 20240219172608_update_default_one_time_code_duration.sql │ ├── 20230509223549_add_email_to_user_survey_table.sql │ ├── 20240227053120_add_default_mode_column_to_teacher_prompts_table.sql │ ├── 20240503093738_remove_func_check_otc_quota_and_validity.sql │ ├── 20231205150920_add_column_to_mqtt_connections_table.sql │ ├── 20240214031433_add_max_temp_account_quota.sql │ ├── 20240516132704_add_enabled_pirority_endpoint_column.sql │ ├── 20240214005905_add_is_teacher_account_to_profile.sql │ ├── 20240215032311_add_one_time_code_duration_to_profile.sql │ ├── 20230423221327_add_subscription_id_to_profiles.sql │ ├── 20240524085844_add_teacher_profile_id_to_temporary_account_profile_for_quick_access.sql │ ├── 20230611214129_add_token_column_to_api_usages_table.sql │ ├── 20240501204214_add_sort_key_and_sort_order_in_teacher_settings.sql │ ├── 20240321144917_add-should_clear_conversations_on_logout-to-table.sql │ ├── 20230524201425_add_rls_to_image_buckets.sql │ ├── 20240426173706_add-items-per-page-teacher-setting.sql │ ├── 20231205234205_add_receiver_column_to_mqtt_connections.sql │ ├── 20240209063553_add_temporary_account_profiles_policy.sql │ ├── 20231117210236_add_polling_columns_to_conversations.sql │ ├── 20230412222654_add_conversation_feedback_table.sql │ ├── 20240317025511_add-first-message-to-gpt-column-to-teacher-prompt.sql │ ├── 20230407194143_create_share_conversation_table.sql │ ├── 20230504192707_add_columns_to_user_profile_table.sql │ ├── 20240103161827_add_new_plan_to_plan_column.sql │ ├── 20240321144723_add-hidden_chateverywhere_default_character_prompt-to-table.sql │ ├── 20230629040944_update_handle_new_user_trigger.sql │ ├── 20230622052759_add_refresh_referral_codes_method.sql │ ├── 20240210014312_add_teacher_profile_id_as_fk_to_student_message_submissions.sql │ ├── 20240414040757_add_index_for_student_shared_message.sql │ ├── 20230408030930_remote_commit.sql │ ├── 20230430203710_create_api_usages_table.sql │ ├── 20240226040743_add_get_teacher_tag_and_tag_count.sql │ ├── 20240410161016_add_get_student_messages_count.sql │ ├── 20230422210643_setup_user_conversations_table.sql │ ├── 20230724222753_create_conversations_table.sql │ ├── 20240215123357_update_student_message_submission_table.sql │ ├── 20240210015418_add_get_temp_account_teacher_profile_func.sql │ ├── 20230629084710_add_get_referees_profile_by_referrer_id_function.sql │ ├── 20240226020313_add_func_set_tags_to_one_time_code.sql │ ├── 20230625030805_update_refresh_referral_codes_method.sql │ ├── 20240315144507_add-teacher-setting-table.sql │ ├── 20240219030522_update_get_temp_profile_func.sql │ ├── 20240214031523_add_check_otc_quota_and_validity_func.sql │ ├── 20230724223204_create_instant_message_app_users_table.sql │ ├── 20230804220405_create_files_table.sql.sql │ ├── 20230430214139_create_user_credits_table.sql │ ├── 20240226143640_add_teacher_prompts_table.sql │ ├── 20240414041214_optimize_get_student_messages_count.sql │ ├── 20231110001826_create_user_v2_conversations_table.sql │ ├── 20231203023251_add_mqtt_connections_tables.sql │ ├── 20240215123703_update_temporary_account_profiles.sql │ └── 20240216024404_update_check_otc_quota_and_validity_func.sql └── seed.sql ├── components ├── Folder │ └── index.ts ├── Search │ └── index.ts ├── Sidebar │ ├── index.ts │ └── SidebarButton.tsx ├── Spinner │ ├── index.ts │ └── Spinner.tsx ├── Promptbar │ ├── index.ts │ ├── components │ │ ├── PromptbarSettings.tsx │ │ └── PromptIcon.tsx │ ├── Promptbar.state.tsx │ └── PromptBar.context.tsx ├── Buttons │ └── SidebarActionButton │ │ ├── index.ts │ │ └── SidebarActionButton.tsx ├── TeacherPortal │ ├── teacher-portal.context.tsx │ ├── Tags │ │ ├── Tag.tsx │ │ └── EditableTagSelector.tsx │ ├── HelpTagTooltip.tsx │ └── TeacherPrompt.tsx ├── Markdown │ └── MemoizedReactMarkdown.tsx ├── Chatbar │ ├── Chatbar.state.tsx │ ├── components │ │ ├── ClearConversations.tsx │ │ └── ClearConversationsModal.context.ts │ └── Chatbar.context.tsx ├── v2Chat │ ├── ui │ │ ├── markdown.tsx │ │ ├── label.tsx │ │ ├── textarea.tsx │ │ ├── separator.tsx │ │ ├── input.tsx │ │ ├── suggestion-container.tsx │ │ └── tooltip.tsx │ ├── empty-screen.tsx │ └── button-scroll-to-bottom.tsx ├── ui │ ├── preview-version-flag.tsx │ ├── label.tsx │ ├── default-toaster.tsx │ ├── separator.tsx │ ├── input.tsx │ └── checkbox.tsx ├── Chat │ ├── AdMessage.tsx │ ├── VisibilityWrapper.tsx │ ├── components │ │ ├── GeneralHtmlComponentParser.tsx │ │ ├── ContinueChat.tsx │ │ └── MjImageSelectorV2.tsx │ ├── ChatLoader.tsx │ ├── UserFileItemIcon.tsx │ ├── ErrorMessageDiv.tsx │ └── Regenerate.tsx ├── Files │ ├── RelativeTimeComponent.tsx │ ├── TrashButton.tsx │ └── CustomUploadToast.tsx ├── Features │ └── TierTag.tsx ├── Voice │ └── VoiceInputActiveOverlay.tsx ├── Hooks │ └── useLogger.ts └── User │ └── File │ └── UploadProgress.tsx ├── postcss.config.js ├── cypress ├── fixtures │ └── example.json ├── e2e │ └── account.ts └── support │ ├── e2e.ts │ └── commands.ts ├── lib └── utils.ts ├── utils ├── app │ ├── folders.ts │ ├── speechRecognitionLanguage.ts.ts │ ├── outputLanguage.ts │ ├── mj_const.ts │ ├── prompts.ts │ ├── codeblock.ts │ └── mjServiceHelper.ts ├── server │ ├── upstashRedisClient.ts │ ├── supabase │ │ └── shared-message-with-teacher.ts │ ├── deleteUserById.ts │ ├── stripe │ │ ├── handleCustomerSubscriptionDeleted.ts │ │ └── getCustomerEmailByCustomerID.ts │ ├── usagesTracking.ts │ └── fetchWebSummary.ts ├── config.ts ├── data │ ├── truncateText.ts │ ├── taggingHelper.ts │ ├── throttle.ts │ └── onlineOutputModifier.ts └── v2Chat │ └── utils.ts ├── vitest.config.ts ├── styles └── transitionGroup.css ├── hooks ├── usePreviousState.ts ├── useDebounce.ts ├── useWindowWidth.ts ├── v2Chat │ ├── use-at-bottom.tsx │ ├── use-enter-submit.tsx │ └── use-copy-to-clipboard.tsx ├── useHomeLoadingBar.ts ├── useOrientation.ts ├── teacherPortal │ ├── useTeacherPortalLoading.ts │ ├── useTeacherSettingsForStudent.ts │ └── useTeacherPromptForStudent.ts ├── useIsStreaming.ts └── useMediaQuery.ts ├── pages ├── 500.html ├── index.tsx ├── teacher-portal │ └── index.tsx └── api │ ├── mj-queue │ └── process.ts │ ├── teacher-portal │ ├── teacher-tags.ts │ ├── get-teacher-settings.ts │ ├── get-teacher-prompt.ts │ ├── update-teacher-settings.ts │ ├── remove-teacher-tags.ts │ └── get-code-tags.ts │ ├── cron │ └── update-referral-codes.ts │ ├── referral │ ├── get-code.ts │ └── regenerate-code.ts │ ├── notion │ └── [id].ts │ └── teacher-settings-for-student-logout.ts ├── cypress.config.ts ├── components.json ├── docker-compose.yml ├── .prettierrc ├── docs └── google_search.md ├── vercel.json ├── tsconfig.json ├── README_v2.md ├── next-i18next.config.js └── .gitignore /.nvmrc: -------------------------------------------------------------------------------- 1 | 18.18 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | firebase/* 2 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | intro.chateverywhere.app -------------------------------------------------------------------------------- /firebase/functions/.nvmrc: -------------------------------------------------------------------------------- 1 | 18 2 | -------------------------------------------------------------------------------- /types/index.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /public/locales/ar/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/bn/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/de/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/en/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/es/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/fr/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/he/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/hi/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/id/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/it/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/ja/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/ko/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/pl/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/pt/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/ro/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/ru/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/si/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/sv/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/te/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/vi/common.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /public/locales/zh/chat.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npm run pre-commit 2 | -------------------------------------------------------------------------------- /supabase/.gitignore: -------------------------------------------------------------------------------- 1 | # Supabase 2 | .branches 3 | .temp 4 | -------------------------------------------------------------------------------- /components/Folder/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Folder'; 2 | -------------------------------------------------------------------------------- /components/Search/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Search'; 2 | -------------------------------------------------------------------------------- /components/Sidebar/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Sidebar'; 2 | -------------------------------------------------------------------------------- /components/Spinner/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Spinner'; 2 | -------------------------------------------------------------------------------- /components/Promptbar/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './Promptbar'; 2 | -------------------------------------------------------------------------------- /firebase/functions/.env.local.example: -------------------------------------------------------------------------------- 1 | WEB_CONTENT_FUNCTION_SECRET=SECRET -------------------------------------------------------------------------------- /public/locales/hi/news.json: -------------------------------------------------------------------------------- 1 | { 2 | "Latest Updates": "नवीनतम अपडेट" 3 | } 4 | -------------------------------------------------------------------------------- /firebase/functions/tsconfig.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [".eslintrc.js"] 3 | } 4 | -------------------------------------------------------------------------------- /public/locales/en/form.json: -------------------------------------------------------------------------------- 1 | { 2 | "isRequired": "{{field}} is required" 3 | } 4 | -------------------------------------------------------------------------------- /public/locales/zh-Hans/form.json: -------------------------------------------------------------------------------- 1 | { 2 | "isRequired": "{{field}}是必填的" 3 | } 4 | -------------------------------------------------------------------------------- /public/locales/zh-Hant/form.json: -------------------------------------------------------------------------------- 1 | { 2 | "isRequired": "{{field}}是必填的" 3 | } 4 | -------------------------------------------------------------------------------- /supabase/migrations/20240217011736_update_get_temp_account_teacher_profile_func.sql: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/locales/hi/features.json: -------------------------------------------------------------------------------- 1 | { 2 | "Feature Introduction": "Feature परिचय" 3 | } 4 | -------------------------------------------------------------------------------- /components/Buttons/SidebarActionButton/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './SidebarActionButton'; 2 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/locales/zh-Hans/features.json: -------------------------------------------------------------------------------- 1 | { 2 | "Feature Introduction": "功能介绍", 3 | "Back": "上一页" 4 | } 5 | -------------------------------------------------------------------------------- /public/locales/zh-Hans/news.json: -------------------------------------------------------------------------------- 1 | { 2 | "Latest Updates": "最新消息", 3 | "All Updates": "全部消息" 4 | } 5 | -------------------------------------------------------------------------------- /public/locales/zh-Hant/features.json: -------------------------------------------------------------------------------- 1 | { 2 | "Feature Introduction": "功能介紹", 3 | "Back": "上一頁" 4 | } 5 | -------------------------------------------------------------------------------- /public/locales/zh-Hant/news.json: -------------------------------------------------------------------------------- 1 | { 2 | "Latest Updates": "最新消息", 3 | "All Updates": "全部消息" 4 | } 5 | -------------------------------------------------------------------------------- /public/icons/icon_192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/icons/icon_192.png -------------------------------------------------------------------------------- /public/icons/icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/icons/icon_512.png -------------------------------------------------------------------------------- /types/tags.ts: -------------------------------------------------------------------------------- 1 | export interface Tag { 2 | id: number; 3 | name: string; 4 | message_count?: number; 5 | } 6 | -------------------------------------------------------------------------------- /public/assets/line-icon.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/assets/line-icon.webp -------------------------------------------------------------------------------- /public/server-busy-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/server-busy-image.png -------------------------------------------------------------------------------- /public/splash-screens/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/icon.png -------------------------------------------------------------------------------- /public/locales/zh-Hans/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "复制代码", 3 | "Copied!": "已复制!", 4 | "Enter file name": "输入文件名" 5 | } 6 | -------------------------------------------------------------------------------- /supabase/migrations/20230629020705_add_email_to_profiles.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."profiles" add column "email" text; 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/posters/20240326.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/assets/posters/20240326.png -------------------------------------------------------------------------------- /public/assets/posters/20240331.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/assets/posters/20240331.jpg -------------------------------------------------------------------------------- /public/assets/posters/20240504.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/assets/posters/20240504.jpg -------------------------------------------------------------------------------- /public/icons/maskable_icon_384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/icons/maskable_icon_384.png -------------------------------------------------------------------------------- /public/locales/ja/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "コードをコピー", 3 | "Copied!": "コピーしました!", 4 | "Enter file name": "ファイル名を入力" 5 | } 6 | -------------------------------------------------------------------------------- /public/locales/ko/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "코드 복사", 3 | "Copied!": "복사 완료!", 4 | "Enter file name": "파일 이름을 입력하세요" 5 | } 6 | -------------------------------------------------------------------------------- /public/locales/zh-Hant/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "複製代碼", 3 | "Copied!": "已複製!", 4 | "Enter file name": "輸入檔案名稱" 5 | } 6 | -------------------------------------------------------------------------------- /types/error.ts: -------------------------------------------------------------------------------- 1 | export interface ErrorMessage { 2 | code: String | null; 3 | title: String; 4 | messageLines: String[]; 5 | } 6 | -------------------------------------------------------------------------------- /types/filter_sortby.ts: -------------------------------------------------------------------------------- 1 | export interface SortBy { 2 | sortKey: 'created_at' | 'student_name'; 3 | sortOrder: 'asc' | 'desc'; 4 | } 5 | -------------------------------------------------------------------------------- /supabase/migrations/20230407204520_add_title_to_share_conversation_table.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE share_conversations 2 | ADD COLUMN title TEXT; 3 | -------------------------------------------------------------------------------- /public/assets/teacher_portal_qrcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/assets/teacher_portal_qrcode.jpg -------------------------------------------------------------------------------- /public/locales/ar/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "نسخ الكود", 3 | "Copied!": "تم النسخ!", 4 | "Enter file name": "أدخل اسم الملف" 5 | } 6 | -------------------------------------------------------------------------------- /public/locales/he/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "העתק קוד", 3 | "Copied!": "נשמר בזכרון", 4 | "Enter file name": "הקלד שם לקובץ" 5 | } 6 | -------------------------------------------------------------------------------- /public/locales/sv/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "Kopiera kod", 3 | "Copied!": "Kopierad!", 4 | "Enter file name": "Ange filnamn" 5 | } 6 | -------------------------------------------------------------------------------- /supabase/migrations/20231113230350_add_referral_code_column_to_referral_table.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."referral" add column "referral_code" text; -------------------------------------------------------------------------------- /supabase/migrations/20231130170254_add_line_access_token_to_profiles_table.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."profiles" add column "line_access_token" text; -------------------------------------------------------------------------------- /public/locales/vi/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "Sao chép mã", 3 | "Copied!": "Đã sao chép!", 4 | "Enter file name": "Nhập tên file" 5 | } 6 | -------------------------------------------------------------------------------- /firebase/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "chat-everywhere-api-staging", 4 | "production": "chat-everywhere-api" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /public/locales/bn/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "কোড কপি করুন", 3 | "Copied!": "কপি করা হয়েছে!", 4 | "Enter file name": "ফাইল নাম লিখুন" 5 | } 6 | -------------------------------------------------------------------------------- /public/locales/de/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "Code kopieren", 3 | "Copied!": "Kopiert!", 4 | "Enter file name": "Dateinamen eingeben" 5 | } 6 | -------------------------------------------------------------------------------- /public/locales/id/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "Salin kode", 3 | "Copied!": "Kode disalin!", 4 | "Enter file name": "Masukkan nama file" 5 | } 6 | -------------------------------------------------------------------------------- /public/locales/pl/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "Skopiuj kod", 3 | "Copied!": "Skopiowany", 4 | "Enter file name": "Wprowadź nazwę pliku" 5 | } 6 | -------------------------------------------------------------------------------- /public/splash-screens/10.2__iPad_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/10.2__iPad_landscape.png -------------------------------------------------------------------------------- /public/splash-screens/10.2__iPad_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/10.2__iPad_portrait.png -------------------------------------------------------------------------------- /types/teacher-portal-sub-route.ts: -------------------------------------------------------------------------------- 1 | export type RouteType = string & 2 | ('one-time-code' | 'shared-message' | 'tags' | 'teacher-prompt' | 'settings'); 3 | -------------------------------------------------------------------------------- /public/locales/fr/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "Copier le code", 3 | "Copied!": "Copié !", 4 | "Enter file name": "Entrez le nom du fichier" 5 | } 6 | -------------------------------------------------------------------------------- /public/locales/hi/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "कोड कॉपी करें", 3 | "Copied!": "कॉपी किया गया!", 4 | "Enter file name": "फ़ाइल नाम दर्ज करें" 5 | } 6 | -------------------------------------------------------------------------------- /public/locales/it/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "Copia codice", 3 | "Copied!": "Copiato!", 4 | "Enter file name": "Inserisci il nome del file" 5 | } 6 | -------------------------------------------------------------------------------- /public/locales/pt/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "Copiar código", 3 | "Copied!": "Copiado!", 4 | "Enter file name": "Insira o nome do arquivo" 5 | } 6 | -------------------------------------------------------------------------------- /public/splash-screens/iPhone_14_Pro_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_14_Pro_portrait.png -------------------------------------------------------------------------------- /supabase/migrations/20240219172608_update_default_one_time_code_duration.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."profiles" alter column "one_time_code_duration" set default 7200; -------------------------------------------------------------------------------- /public/locales/es/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "Copiar código", 3 | "Copied!": "¡Copiado!", 4 | "Enter file name": "Ingrese el nombre del archivo" 5 | } 6 | -------------------------------------------------------------------------------- /public/locales/ro/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "Copiați codul", 3 | "Copied!": "Copiat!", 4 | "Enter file name": "Introduceți numele fișierului" 5 | } 6 | -------------------------------------------------------------------------------- /public/locales/ru/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "Скопировать", 3 | "Copied!": "Скопировано!", 4 | "Enter file name": "Введите имя файла для загрузки" 5 | } 6 | -------------------------------------------------------------------------------- /public/locales/si/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "කේතය පිටපත් කරන්න", 3 | "Copied!": "පිටපත් කළා!", 4 | "Enter file name": "ගොනු නාමය ඇතුළත් කරන්න" 5 | } 6 | -------------------------------------------------------------------------------- /public/splash-screens/10.5__iPad_Air_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/10.5__iPad_Air_landscape.png -------------------------------------------------------------------------------- /public/splash-screens/10.5__iPad_Air_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/10.5__iPad_Air_portrait.png -------------------------------------------------------------------------------- /public/splash-screens/10.9__iPad_Air_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/10.9__iPad_Air_landscape.png -------------------------------------------------------------------------------- /public/splash-screens/10.9__iPad_Air_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/10.9__iPad_Air_portrait.png -------------------------------------------------------------------------------- /public/splash-screens/12.9__iPad_Pro_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/12.9__iPad_Pro_landscape.png -------------------------------------------------------------------------------- /public/splash-screens/12.9__iPad_Pro_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/12.9__iPad_Pro_portrait.png -------------------------------------------------------------------------------- /public/splash-screens/8.3__iPad_Mini_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/8.3__iPad_Mini_landscape.png -------------------------------------------------------------------------------- /public/splash-screens/8.3__iPad_Mini_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/8.3__iPad_Mini_portrait.png -------------------------------------------------------------------------------- /public/splash-screens/iPhone_14_Pro_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_14_Pro_landscape.png -------------------------------------------------------------------------------- /supabase/migrations/20230509223549_add_email_to_user_survey_table.sql: -------------------------------------------------------------------------------- 1 | -- Add email optional field to user_survey table 2 | alter table user_survey add column email text; -------------------------------------------------------------------------------- /types/pagination.ts: -------------------------------------------------------------------------------- 1 | export interface Pagination { 2 | current_page: number; 3 | total_pages: number; 4 | next_page: number; 5 | prev_page: number; 6 | } 7 | -------------------------------------------------------------------------------- /public/locales/te/markdown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Copy code": "కోడ్‌ను కాపీ చేయండి", 3 | "Copied!": "కాపీ చేయబడింది!", 4 | "Enter file name": "ఫైల్ పేరు నమోదు చేయండి" 5 | } 6 | -------------------------------------------------------------------------------- /public/splash-screens/iPhone_14_Pro_Max_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_14_Pro_Max_landscape.png -------------------------------------------------------------------------------- /public/splash-screens/iPhone_14_Pro_Max_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_14_Pro_Max_portrait.png -------------------------------------------------------------------------------- /supabase/migrations/20240227053120_add_default_mode_column_to_teacher_prompts_table.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."teacher_prompts" add column "default_mode" text; 2 | 3 | 4 | -------------------------------------------------------------------------------- /supabase/migrations/20240503093738_remove_func_check_otc_quota_and_validity.sql: -------------------------------------------------------------------------------- 1 | drop function if exists "public"."check_otc_quota_and_validity"(otc_code character varying); -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | 'tailwindcss/nesting': 'postcss-nesting', 4 | tailwindcss: {}, 5 | autoprefixer: {}, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /public/splash-screens/iPhone_11__iPhone_XR_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_11__iPhone_XR_landscape.png -------------------------------------------------------------------------------- /public/splash-screens/iPhone_11__iPhone_XR_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_11__iPhone_XR_portrait.png -------------------------------------------------------------------------------- /supabase/migrations/20231205150920_add_column_to_mqtt_connections_table.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."mqtt_connections" add column "dynamic_input" boolean not null default false; 2 | -------------------------------------------------------------------------------- /supabase/migrations/20240214031433_add_max_temp_account_quota.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."profiles" add column "max_temp_account_quota" integer not null default 0; 2 | 3 | 4 | -------------------------------------------------------------------------------- /supabase/migrations/20240516132704_add_enabled_pirority_endpoint_column.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."profiles" add column "enabled_priority_endpoint" boolean not null default false; -------------------------------------------------------------------------------- /public/locales/zh-Hans/imageToPrompt.json: -------------------------------------------------------------------------------- 1 | { 2 | "Image to Prompt": "图片转提示", 3 | "Please upload only 1 image": "请上传1张图片", 4 | "The Max Image Size is 20MB": "图片最大20MB" 5 | } 6 | -------------------------------------------------------------------------------- /supabase/migrations/20240214005905_add_is_teacher_account_to_profile.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."profiles" add column "is_teacher_account" boolean not null default false; 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/locales/zh-Hant/imageToPrompt.json: -------------------------------------------------------------------------------- 1 | { 2 | "Image to Prompt": "圖片轉提示", 3 | "Please upload only 1 image": "請上傳一張圖片", 4 | "The Max Image Size is 20MB": "圖片大小上限為20MB" 5 | } 6 | -------------------------------------------------------------------------------- /supabase/migrations/20240215032311_add_one_time_code_duration_to_profile.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."profiles" add column "one_time_code_duration" integer not null default 0; 2 | 3 | 4 | -------------------------------------------------------------------------------- /types/drag.ts: -------------------------------------------------------------------------------- 1 | export interface DragData { 2 | id: string; 3 | type: DragDataType; 4 | } 5 | 6 | export type DragDataType = 'chat' | 'prompt' | 'chat-folder' | 'prompt-folder'; 7 | -------------------------------------------------------------------------------- /public/splash-screens/11__iPad_Pro__10.5__iPad_Pro_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/11__iPad_Pro__10.5__iPad_Pro_portrait.png -------------------------------------------------------------------------------- /supabase/migrations/20230423221327_add_subscription_id_to_profiles.sql: -------------------------------------------------------------------------------- 1 | -- Add stripe_subscription_id column to profiles table 2 | ALTER TABLE profiles 3 | ADD COLUMN stripe_subscription_id text; -------------------------------------------------------------------------------- /public/splash-screens/11__iPad_Pro__10.5__iPad_Pro_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/11__iPad_Pro__10.5__iPad_Pro_landscape.png -------------------------------------------------------------------------------- /supabase/migrations/20240524085844_add_teacher_profile_id_to_temporary_account_profile_for_quick_access.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."temporary_account_profiles" add column "teacher_profile_id" uuid; -------------------------------------------------------------------------------- /types/UserFile.ts: -------------------------------------------------------------------------------- 1 | export interface UserFile { 2 | id: string; 3 | filename: string; 4 | filetype: string; 5 | timeCreated: string; 6 | objectPath: string; 7 | size: string; 8 | } 9 | -------------------------------------------------------------------------------- /public/splash-screens/iPhone_11_Pro_Max__iPhone_XS_Max_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_11_Pro_Max__iPhone_XS_Max_landscape.png -------------------------------------------------------------------------------- /public/splash-screens/iPhone_11_Pro_Max__iPhone_XS_Max_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_11_Pro_Max__iPhone_XS_Max_portrait.png -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from 'clsx'; 2 | import { twMerge } from 'tailwind-merge'; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /supabase/migrations/20230611214129_add_token_column_to_api_usages_table.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE api_usages 2 | ADD COLUMN length INTEGER; 3 | 4 | ALTER TABLE api_usages 5 | ALTER COLUMN user_id DROP NOT NULL; 6 | -------------------------------------------------------------------------------- /components/Promptbar/components/PromptbarSettings.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react'; 2 | 3 | interface Props {} 4 | 5 | export const PromptbarSettings: FC = () => { 6 | return
; 7 | }; 8 | -------------------------------------------------------------------------------- /supabase/migrations/20240501204214_add_sort_key_and_sort_order_in_teacher_settings.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE teacher_settings 2 | ADD COLUMN sort_key TEXT DEFAULT 'created_at', 3 | ADD COLUMN sort_order TEXT DEFAULT 'desc'; -------------------------------------------------------------------------------- /firebase/functions/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled JavaScript files 2 | lib/**/*.js 3 | lib/**/*.js.map 4 | 5 | # TypeScript v1 declaration files 6 | typings/ 7 | 8 | # Node.js dependency directory 9 | node_modules/ 10 | -------------------------------------------------------------------------------- /utils/app/folders.ts: -------------------------------------------------------------------------------- 1 | import type { FolderInterface } from '@/types/folder'; 2 | 3 | export const saveFolders = (folders: FolderInterface[]) => { 4 | localStorage.setItem('folders', JSON.stringify(folders)); 5 | }; 6 | -------------------------------------------------------------------------------- /supabase/migrations/20240321144917_add-should_clear_conversations_on_logout-to-table.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."teacher_settings" add column "should_clear_conversations_on_logout" boolean not null default false; 2 | 3 | 4 | -------------------------------------------------------------------------------- /types/env.ts: -------------------------------------------------------------------------------- 1 | export interface ProcessEnv { 2 | OPENAI_API_KEY: string; 3 | OPENAI_API_HOST?: string; 4 | OPENAI_API_TYPE?: 'openai' | 'azure'; 5 | OPENAI_API_VERSION?: string; 6 | OPENAI_ORGANIZATION?: string; 7 | } 8 | -------------------------------------------------------------------------------- /public/splash-screens/4__iPhone_SE__iPod_touch_5th_generation_and_later_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/4__iPhone_SE__iPod_touch_5th_generation_and_later_landscape.png -------------------------------------------------------------------------------- /public/splash-screens/4__iPhone_SE__iPod_touch_5th_generation_and_later_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/4__iPhone_SE__iPod_touch_5th_generation_and_later_portrait.png -------------------------------------------------------------------------------- /supabase/migrations/20230524201425_add_rls_to_image_buckets.sql: -------------------------------------------------------------------------------- 1 | create policy "Public Access for read" 2 | on storage.objects for select 3 | using ( bucket_id = 'public' ); 4 | 5 | alter table storage.buckets enable row level security; -------------------------------------------------------------------------------- /public/splash-screens/iPhone_14_Plus__iPhone_13_Pro_Max__iPhone_12_Pro_Max_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_14_Plus__iPhone_13_Pro_Max__iPhone_12_Pro_Max_landscape.png -------------------------------------------------------------------------------- /public/splash-screens/iPhone_14_Plus__iPhone_13_Pro_Max__iPhone_12_Pro_Max_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_14_Plus__iPhone_13_Pro_Max__iPhone_12_Pro_Max_portrait.png -------------------------------------------------------------------------------- /supabase/migrations/20240426173706_add-items-per-page-teacher-setting.sql: -------------------------------------------------------------------------------- 1 | -- migrations/20240316144508_add_items_per_page_to_teacher_settings.sql 2 | 3 | ALTER TABLE "public"."teacher_settings" 4 | ADD COLUMN "items_per_page" INT DEFAULT 20; -------------------------------------------------------------------------------- /public/locales/en/mjImage.json: -------------------------------------------------------------------------------- 1 | { 2 | "U1": "Select", 3 | "U2": "Select", 4 | "U3": "Select", 5 | "U4": "Select", 6 | "V1": "Variations", 7 | "V2": "Variations", 8 | "V3": "Variations", 9 | "V4": "Variations" 10 | } 11 | -------------------------------------------------------------------------------- /public/splash-screens/9.7__iPad_Pro__7.9__iPad_mini__9.7__iPad_Air__9.7__iPad_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/9.7__iPad_Pro__7.9__iPad_mini__9.7__iPad_Air__9.7__iPad_landscape.png -------------------------------------------------------------------------------- /public/splash-screens/9.7__iPad_Pro__7.9__iPad_mini__9.7__iPad_Air__9.7__iPad_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/9.7__iPad_Pro__7.9__iPad_mini__9.7__iPad_Air__9.7__iPad_portrait.png -------------------------------------------------------------------------------- /public/splash-screens/iPhone_8__iPhone_7__iPhone_6s__iPhone_6__4.7__iPhone_SE_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_8__iPhone_7__iPhone_6s__iPhone_6__4.7__iPhone_SE_landscape.png -------------------------------------------------------------------------------- /public/splash-screens/iPhone_8__iPhone_7__iPhone_6s__iPhone_6__4.7__iPhone_SE_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_8__iPhone_7__iPhone_6s__iPhone_6__4.7__iPhone_SE_portrait.png -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | resolve: { 6 | alias: { 7 | '@': path.resolve(__dirname, './'), 8 | }, 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /public/locales/hi/feature.json: -------------------------------------------------------------------------------- 1 | { 2 | "Syncing ...": "सिंकिंग हो रही है...", 3 | "Synced": "सिंक हो गया", 4 | "Sync failed": "सिंक विफल हुआ", 5 | "Cloud sync disabled": "क्लाउड सिंक अक्षम है", 6 | "Conversation mode": "संभारक मोड" 7 | } 8 | -------------------------------------------------------------------------------- /supabase/migrations/20231205234205_add_receiver_column_to_mqtt_connections.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."mqtt_connections" add column "receiver" boolean not null default false; 2 | alter table "public"."mqtt_connections" alter column "payload" drop not null; -------------------------------------------------------------------------------- /utils/server/upstashRedisClient.ts: -------------------------------------------------------------------------------- 1 | import { Redis } from '@upstash/redis'; 2 | 3 | const redis = new Redis({ 4 | url: process.env.UPSTASH_REDIS_REST_URL!, 5 | token: process.env.UPSTASH_REDIS_REST_TOKEN!, 6 | }); 7 | 8 | export default redis; 9 | -------------------------------------------------------------------------------- /public/splash-screens/iPhone_14__iPhone_13_Pro__iPhone_13__iPhone_12_Pro__iPhone_12_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_14__iPhone_13_Pro__iPhone_13__iPhone_12_Pro__iPhone_12_portrait.png -------------------------------------------------------------------------------- /public/splash-screens/iPhone_8_Plus__iPhone_7_Plus__iPhone_6s_Plus__iPhone_6_Plus_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_8_Plus__iPhone_7_Plus__iPhone_6s_Plus__iPhone_6_Plus_landscape.png -------------------------------------------------------------------------------- /public/splash-screens/iPhone_8_Plus__iPhone_7_Plus__iPhone_6s_Plus__iPhone_6_Plus_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_8_Plus__iPhone_7_Plus__iPhone_6s_Plus__iPhone_6_Plus_portrait.png -------------------------------------------------------------------------------- /public/splash-screens/iPhone_14__iPhone_13_Pro__iPhone_13__iPhone_12_Pro__iPhone_12_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_14__iPhone_13_Pro__iPhone_13__iPhone_12_Pro__iPhone_12_landscape.png -------------------------------------------------------------------------------- /public/splash-screens/iPhone_13_mini__iPhone_12_mini__iPhone_11_Pro__iPhone_XS__iPhone_X_portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_13_mini__iPhone_12_mini__iPhone_11_Pro__iPhone_XS__iPhone_X_portrait.png -------------------------------------------------------------------------------- /supabase/migrations/20240209063553_add_temporary_account_profiles_policy.sql: -------------------------------------------------------------------------------- 1 | create policy "Enable read access for all users" 2 | on "public"."temporary_account_profiles" 3 | as permissive 4 | for select 5 | to public 6 | using (true); 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /public/splash-screens/iPhone_13_mini__iPhone_12_mini__iPhone_11_Pro__iPhone_XS__iPhone_X_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exploratortech/chat-everywhere/HEAD/public/splash-screens/iPhone_13_mini__iPhone_12_mini__iPhone_11_Pro__iPhone_XS__iPhone_X_landscape.png -------------------------------------------------------------------------------- /components/TeacherPortal/teacher-portal.context.tsx: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | interface PortalState { 4 | startLoading: () => void; 5 | completeLoading: () => void; 6 | } 7 | export const TeacherPortalContext = createContext(undefined!); 8 | -------------------------------------------------------------------------------- /supabase/migrations/20231117210236_add_polling_columns_to_conversations.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."user_v2_conversations" add column "processLock" boolean not null default false; 2 | 3 | alter table "public"."user_v2_conversations" add column "runInProgress" boolean not null default false; -------------------------------------------------------------------------------- /utils/app/speechRecognitionLanguage.ts.ts: -------------------------------------------------------------------------------- 1 | export const saveSpeechRecognitionLanguage = (lang: string) => { 2 | if (!lang) { 3 | localStorage.setItem('speechRecognitionLanguage', 'en-US'); 4 | return; 5 | } 6 | localStorage.setItem('speechRecognitionLanguage', lang); 7 | }; 8 | -------------------------------------------------------------------------------- /components/Markdown/MemoizedReactMarkdown.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react'; 2 | import { memo } from 'react'; 3 | import type { Options } from 'react-markdown'; 4 | import ReactMarkdown from 'react-markdown'; 5 | 6 | export const MemoizedReactMarkdown: FC = memo(ReactMarkdown); 7 | -------------------------------------------------------------------------------- /types/folder.ts: -------------------------------------------------------------------------------- 1 | export interface FolderInterface { 2 | id: string; 3 | name: string; 4 | type: FolderType; 5 | lastUpdateAtUTC: number; // timestamp in UTC in milliseconds 6 | rank: number; 7 | deleted?: boolean; 8 | } 9 | 10 | export type FolderType = 'chat' | 'prompt'; 11 | -------------------------------------------------------------------------------- /styles/transitionGroup.css: -------------------------------------------------------------------------------- 1 | .item-enter { 2 | opacity: 0; 3 | } 4 | .item-enter-active { 5 | opacity: 1; 6 | transition: opacity 500ms ease-in; 7 | } 8 | .item-exit { 9 | opacity: 1; 10 | } 11 | .item-exit-active { 12 | opacity: 0; 13 | transition: opacity 500ms ease-in; 14 | } 15 | -------------------------------------------------------------------------------- /supabase/migrations/20230412222654_add_conversation_feedback_table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE conversation_feedback ( 2 | id SERIAL PRIMARY KEY, 3 | opinion TEXT, 4 | conversation JSON NOT NULL, 5 | positive BOOLEAN NOT NULL, 6 | created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP 7 | ); 8 | -------------------------------------------------------------------------------- /supabase/migrations/20240317025511_add-first-message-to-gpt-column-to-teacher-prompt.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."teacher_prompts" add column "first_message_to_gpt" text default 'Provide a short welcome message based on your prompt, the role you are playing is based on the prompt'::text; 2 | 3 | 4 | -------------------------------------------------------------------------------- /components/Promptbar/Promptbar.state.tsx: -------------------------------------------------------------------------------- 1 | import type { Prompt } from '@/types/prompt'; 2 | 3 | export interface PromptbarInitialState { 4 | searchTerm: string; 5 | filteredPrompts: Prompt[]; 6 | } 7 | 8 | export const initialState: PromptbarInitialState = { 9 | searchTerm: '', 10 | filteredPrompts: [], 11 | }; 12 | -------------------------------------------------------------------------------- /hooks/usePreviousState.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react'; 2 | 3 | function usePreviousState(value: T): T | undefined { 4 | const ref = useRef(); 5 | 6 | useEffect(() => { 7 | ref.current = value; 8 | }, [value]); 9 | 10 | return ref.current; 11 | } 12 | 13 | export default usePreviousState; 14 | -------------------------------------------------------------------------------- /utils/config.ts: -------------------------------------------------------------------------------- 1 | import { PluginID } from '@/types/plugin'; 2 | 3 | // Amount of credit will be added to all user's account on the 1st day of every month 4 | export const DefaultMonthlyCredits = { 5 | [PluginID.LANGCHAIN_CHAT]: 0, 6 | [PluginID.GPT4]: 50, 7 | [PluginID.IMAGE_GEN]: 50, 8 | [PluginID.mqtt]: 0, 9 | }; 10 | -------------------------------------------------------------------------------- /supabase/migrations/20230407194143_create_share_conversation_table.sql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION IF NOT EXISTS "pgcrypto"; 2 | 3 | CREATE TABLE share_conversations ( 4 | id SERIAL PRIMARY KEY, 5 | accessible_id UUID UNIQUE NOT NULL DEFAULT gen_random_uuid(), 6 | prompts JSONB NOT NULL, 7 | created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() 8 | ); 9 | -------------------------------------------------------------------------------- /components/Chatbar/Chatbar.state.tsx: -------------------------------------------------------------------------------- 1 | import type { Conversation } from '@/types/chat'; 2 | 3 | export interface ChatbarInitialState { 4 | searchTerm: string; 5 | filteredConversations: Conversation[]; 6 | } 7 | 8 | export const initialState: ChatbarInitialState = { 9 | searchTerm: '', 10 | filteredConversations: [], 11 | }; 12 | -------------------------------------------------------------------------------- /supabase/migrations/20230504192707_add_columns_to_user_profile_table.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."profiles" add column "occupation" text; 2 | 3 | alter table "public"."profiles" add column "preferred_choice" jsonb; 4 | 5 | alter table "public"."profiles" add column "use_case" jsonb; 6 | 7 | alter table "public"."profiles" add column "value_features" jsonb; -------------------------------------------------------------------------------- /supabase/migrations/20240103161827_add_new_plan_to_plan_column.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."profiles" drop constraint "profiles_plan_check"; 2 | alter table "public"."profiles" add constraint "profiles_plan_check" CHECK ((plan = ANY (ARRAY['free'::text, 'pro'::text, 'edu'::text, 'ultra'::text]))) not valid; 3 | alter table "public"."profiles" validate constraint "profiles_plan_check"; -------------------------------------------------------------------------------- /utils/data/truncateText.ts: -------------------------------------------------------------------------------- 1 | export const truncateText = (text: string, limit: number): string => { 2 | const words = text.split(' '); 3 | if (words.length <= limit) return text; 4 | 5 | const startWords = words.slice(0, Math.ceil(limit / 2)).join(' '); 6 | const endWords = words.slice(-Math.floor(limit / 2)).join(' '); 7 | return `${startWords} ... ${endWords}`; 8 | }; 9 | -------------------------------------------------------------------------------- /types/teacher-settings.ts: -------------------------------------------------------------------------------- 1 | export interface TeacherSettings { 2 | allow_student_use_line?: boolean; 3 | hidden_chateverywhere_default_character_prompt?: boolean; 4 | } 5 | export interface TeacherSettingsInPortal extends TeacherSettings { 6 | should_clear_conversations_on_logout?: boolean; 7 | items_per_page?: number; 8 | sort_key?: string; 9 | sort_order?: string; 10 | } 11 | -------------------------------------------------------------------------------- /firebase/functions/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "module": "commonjs", 5 | "noImplicitReturns": true, 6 | "noUnusedLocals": true, 7 | "outDir": "lib", 8 | "sourceMap": true, 9 | "strict": true, 10 | "target": "es2017", 11 | "skipLibCheck": true 12 | }, 13 | "compileOnSave": true, 14 | "include": ["src"] 15 | } 16 | -------------------------------------------------------------------------------- /pages/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Error 500 7 | 8 | 9 |

Error 500: Internal Server Error

10 |

Sorry, something went wrong on our end. Please try again later.

11 | 12 | 13 | -------------------------------------------------------------------------------- /cypress.config.ts: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('cypress'); 2 | 3 | module.exports = defineConfig({ 4 | retries: 1, 5 | e2e: { 6 | setupNodeEvents(on: any, config: any) { 7 | require('cypress-terminal-report/src/installLogsPrinter')(on); 8 | return config; 9 | }, 10 | baseUrl: process.env.CYPRESS_HOST_URL || 'http://localhost:3000', 11 | }, 12 | }); 13 | 14 | export {}; 15 | -------------------------------------------------------------------------------- /public/locales/ko/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "새 폴더", 3 | "New chat": "새 채팅", 4 | "No conversations.": "대화가 없습니다.", 5 | "Search conversations...": "대화 검색...", 6 | "OpenAI API Key": "OpenAI API 키", 7 | "Import data": "대화 가져오기", 8 | "Are you sure?": "확실합니까?", 9 | "Clear conversations": "대화 지우기", 10 | "Export data": "대화 내보내기", 11 | "Dark mode": "다크 모드", 12 | "Light mode": "라이트 모드" 13 | } 14 | -------------------------------------------------------------------------------- /utils/app/outputLanguage.ts: -------------------------------------------------------------------------------- 1 | import markdownToTxt from 'markdown-to-txt'; 2 | 3 | export const saveOutputLanguage = (lang: string) => { 4 | if (!lang || lang === 'default') { 5 | localStorage.setItem('outputLanguage', ''); 6 | return; 7 | } 8 | localStorage.setItem('outputLanguage', lang); 9 | }; 10 | 11 | export const convertMarkdownToText = (markdown: string): string => 12 | markdownToTxt(markdown); 13 | -------------------------------------------------------------------------------- /pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { withCommonServerSideProps } from '@/utils/withCommonServerSideProps'; 2 | 3 | import Home from '../components/home/home'; 4 | import DefaultLayout from '@/components/layout/default'; 5 | 6 | export default function Index() { 7 | return ( 8 | 9 | 10 | 11 | ); 12 | } 13 | 14 | export const getServerSideProps = withCommonServerSideProps(); 15 | -------------------------------------------------------------------------------- /components/v2Chat/ui/markdown.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react'; 2 | import { memo } from 'react'; 3 | import type { Options } from 'react-markdown'; 4 | import ReactMarkdown from 'react-markdown'; 5 | 6 | export const MemoizedReactMarkdown: FC = memo( 7 | ReactMarkdown, 8 | (prevProps, nextProps) => 9 | prevProps.children === nextProps.children && 10 | prevProps.className === nextProps.className, 11 | ); 12 | -------------------------------------------------------------------------------- /public/locales/ja/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "新規フォルダ", 3 | "New chat": "新規チャット", 4 | "No conversations.": "会話履歴はありません。", 5 | "Search conversations...": "会話を検索...", 6 | "OpenAI API Key": "OpenAI API Key", 7 | "Import data": "会話履歴をインポート", 8 | "Are you sure?": "よろしいですか?", 9 | "Clear conversations": " 会話をクリア", 10 | "Export data": "会話履歴をエクスポート", 11 | "Dark mode": "ダークモード", 12 | "Light mode": "ライトモード" 13 | } 14 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "styles/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /public/ads.txt: -------------------------------------------------------------------------------- 1 | # SOVRN 2 | lijit.com, 447574, DIRECT, fafdf38b16bf6b2b #SOVRN 3 | lijit.com, 447574-eb, DIRECT, fafdf38b16bf6b2b #SOVRN 4 | openx.com, 538959099, RESELLER, 6a698e2ec38604c6 5 | pubmatic.com, 137711, RESELLER, 5d62403b186f2ace 6 | pubmatic.com, 156212, RESELLER, 5d62403b186f2ace 7 | rubiconproject.com, 17960, RESELLER, 0bfd66d529a55807 8 | appnexus.com, 1019, RESELLER, f5ab79cb980f11d1 9 | video.unrulymedia.com, 12444764291, RESELLER -------------------------------------------------------------------------------- /supabase/migrations/20240321144723_add-hidden_chateverywhere_default_character_prompt-to-table.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."teacher_prompts" alter column "first_message_to_gpt" set default 'Provide a very short welcome message based on your prompt, the role your are playing is based on the prompt.'::text; 2 | 3 | alter table "public"."teacher_settings" add column "hidden_chateverywhere_default_character_prompt" boolean not null default false; 4 | 5 | 6 | -------------------------------------------------------------------------------- /types/google.ts: -------------------------------------------------------------------------------- 1 | import type { ChatBody, Message } from './chat'; 2 | 3 | export interface GoogleBody extends ChatBody { 4 | googleAPIKey: string; 5 | googleCSEId: string; 6 | } 7 | 8 | export interface GoogleResponse { 9 | message: Message; 10 | } 11 | 12 | export interface GoogleSource { 13 | title: string; 14 | link: string; 15 | displayLink: string; 16 | snippet: string; 17 | image: string; 18 | text: string; 19 | } 20 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | redis: 4 | image: redis 5 | ports: 6 | - '6379:6379' 7 | serverless-redis-http: 8 | ports: 9 | - '8079:80' 10 | image: hiett/serverless-redis-http:latest 11 | environment: 12 | SRH_MODE: env 13 | SRH_TOKEN: example_token 14 | SRH_CONNECTION_STRING: 'redis://redis:6379' # Using `redis` hostname since they're in the same Docker network. 15 | 16 | -------------------------------------------------------------------------------- /firebase/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "functions": [ 3 | { 4 | "source": "functions", 5 | "codebase": "default", 6 | "ignore": [ 7 | "node_modules", 8 | ".git", 9 | "firebase-debug.log", 10 | "firebase-debug.*.log" 11 | ], 12 | "predeploy": [ 13 | "npm --prefix \"$RESOURCE_DIR\" run lint", 14 | "npm --prefix \"$RESOURCE_DIR\" run build" 15 | ] 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /public/locales/he/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "תיקיה חדשה", 3 | "New chat": "שיחה חדשה", 4 | "No conversations.": "אין שיחות חדשות", 5 | "Search conversations...": "חיפוש שיחות...", 6 | "OpenAI API Key": "מפתח אישי ל openAI", 7 | "Import data": "ייבוא שיחות", 8 | "Are you sure?": "אתה בטוח?", 9 | "Clear conversations": "ניקוי שיחות", 10 | "Export data": "ייצוא שיחות", 11 | "Dark mode": "מצב כהה", 12 | "Light mode": "מצב בהיר" 13 | } 14 | -------------------------------------------------------------------------------- /types/one-time-code.ts: -------------------------------------------------------------------------------- 1 | export interface TempAccountProfiles { 2 | id: number; 3 | code: string; 4 | uniqueId: string; 5 | created_at: string; 6 | expired_at: string; 7 | profile_id: string; 8 | is_expired: boolean; 9 | } 10 | export type OneTimeCodeInfoPayload = { 11 | code_id: string; 12 | code: string; 13 | expiresAt: string; 14 | tempAccountProfiles: TempAccountProfiles[]; 15 | maxQuota: number; 16 | totalActiveTempAccount: number; 17 | }; 18 | -------------------------------------------------------------------------------- /supabase/migrations/20230629040944_update_handle_new_user_trigger.sql: -------------------------------------------------------------------------------- 1 | set check_function_bodies = off; 2 | 3 | CREATE OR REPLACE FUNCTION public.handle_new_user() 4 | RETURNS trigger 5 | LANGUAGE plpgsql 6 | SECURITY DEFINER 7 | AS $function$ 8 | begin 9 | insert into public.profiles (id, plan, email) 10 | values (new.id, 'free', new.email); -- Set the plan to 'free' by default when a new user is created 11 | return new; 12 | end; 13 | $function$ 14 | ; 15 | 16 | 17 | -------------------------------------------------------------------------------- /public/locales/ru/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "Новая папка", 3 | "New chat": "Новый чат", 4 | "No conversations.": "Нет чатов.", 5 | "Search conversations...": "Поиск чатов...", 6 | "OpenAI API Key": "API-ключ OpenAI", 7 | "Import data": "Импортировать чаты", 8 | "Are you sure?": "Вы уверены?", 9 | "Clear conversations": "Удалить чаты", 10 | "Export data": "Экспортировать чаты", 11 | "Dark mode": "Темный режим", 12 | "Light mode": "Светлый режим" 13 | } 14 | -------------------------------------------------------------------------------- /types/data.ts: -------------------------------------------------------------------------------- 1 | export interface KeyValuePair { 2 | key: string; 3 | value: any; 4 | } 5 | 6 | export type mqttConnectionType = { 7 | id: string; 8 | name?: string; 9 | description?: string; 10 | topic?: string; 11 | payload?: string; 12 | dynamicInput?: boolean; 13 | receiver?: boolean; 14 | }; 15 | 16 | export type newMqttConnectionType = Pick< 17 | mqttConnectionType, 18 | 'description' | 'topic' | 'payload' | 'name' | 'dynamicInput' | 'receiver' 19 | >; 20 | -------------------------------------------------------------------------------- /hooks/useDebounce.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | function useDebounce(value: T, delay?: number): T { 4 | const [debouncedValue, setDebouncedValue] = useState(value); 5 | 6 | useEffect(() => { 7 | const timer = setTimeout(() => setDebouncedValue(value), delay || 500); 8 | 9 | return () => { 10 | clearTimeout(timer); 11 | }; 12 | }, [value, delay]); 13 | 14 | return debouncedValue; 15 | } 16 | 17 | export default useDebounce; 18 | -------------------------------------------------------------------------------- /public/locales/pl/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "Nowy folder", 3 | "New chat": "Nowy chat", 4 | "No conversations.": "Brak rozmów.", 5 | "Search conversations...": "Szukaj rozmów...", 6 | "OpenAI API Key": "Klucz do OpenAI API", 7 | "Import data": "Import rozmów", 8 | "Are you sure?": "Czy jesteś pewien?", 9 | "Clear conversations": "Usuń rozmowy", 10 | "Export data": "Eksport rozmów", 11 | "Dark mode": "Tryb ciemny", 12 | "Light mode": "Tryb jasny" 13 | } 14 | -------------------------------------------------------------------------------- /public/locales/si/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "නව ෆෝල්ඩරය", 3 | "New chat": "නව සංවාදයක්", 4 | "No conversations.": "සංවාද නැත.", 5 | "Search conversations...": "සංවාද සොයන්න...", 6 | "OpenAI API Key": "OpenAI API යතුර", 7 | "Import data": "සංවාද ආයාත කරන්න", 8 | "Are you sure?": "ඔබට විශ්වාස ද?", 9 | "Clear conversations": "සංවාද මකන්න", 10 | "Export data": "සංවාද නිර්යාත කරන්න", 11 | "Dark mode": "අඳුරු මාදිලිය", 12 | "Light mode": "ආලෝක මාදිලිය" 13 | } 14 | -------------------------------------------------------------------------------- /public/locales/zh-Hant/roles.json: -------------------------------------------------------------------------------- 1 | { 2 | "Accountant": "會計師", 3 | "Writing Tutor": "寫作導師", 4 | "Life Coach": "人生導師", 5 | "Psychologist": "心理學家", 6 | "Social Media Influencer": "網紅", 7 | "Career Counselor": "職涯顧問", 8 | "Personal Trainer": "私人教練", 9 | "Mental Health Adviser": "心理健康顧問", 10 | "Web Design Consultant": "網頁設計顧問", 11 | "Automobile Mechanic": "汽車技工", 12 | "Financial Analyst": "財務分析師", 13 | "Dream Interpreter": "夢境解釋師", 14 | "IELTS Tester": "雅思英語測試員" 15 | } 16 | -------------------------------------------------------------------------------- /components/Promptbar/components/PromptIcon.tsx: -------------------------------------------------------------------------------- 1 | import { IconBulb, IconBulbFilled } from '@tabler/icons-react'; 2 | 3 | import type { Prompt } from '@/types/prompt'; 4 | 5 | const PromptIcon = ({ 6 | prompt, 7 | size = 18, 8 | }: { 9 | prompt: Prompt; 10 | size?: number; 11 | }) => { 12 | return prompt.isCustomInstruction ? ( 13 | 14 | ) : ( 15 | 16 | ); 17 | }; 18 | 19 | export default PromptIcon; 20 | -------------------------------------------------------------------------------- /components/ui/preview-version-flag.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '../../lib/utils'; 2 | 3 | import { type ClassValue } from 'clsx'; 4 | 5 | const PreviewVersionFlag = ({ className = '' }: { className?: ClassValue }) => { 6 | return ( 7 |
13 | PREVIEW 14 |
15 | ); 16 | }; 17 | 18 | export default PreviewVersionFlag; 19 | -------------------------------------------------------------------------------- /public/locales/pt/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "Nova pasta", 3 | "New chat": "Novo chat", 4 | "No conversations.": "Não há conversas.", 5 | "Search conversations...": "Buscar conversas...", 6 | "OpenAI API Key": "API Key da OpenAI", 7 | "Import data": "Importar conversas", 8 | "Are you sure?": "Tem certeza?", 9 | "Clear conversations": "Apagar conversas", 10 | "Export data": "Exportar conversas", 11 | "Dark mode": "Modo escuro", 12 | "Light mode": "Modo claro" 13 | } 14 | -------------------------------------------------------------------------------- /public/locales/zh-Hans/roles.json: -------------------------------------------------------------------------------- 1 | { 2 | "Accountant": "会计师", 3 | "Writing Tutor": "写作导师", 4 | "Life Coach": "生活导师", 5 | "Psychologist": "心理学家", 6 | "Social Media Influencer": "社交媒体影响者", 7 | "Career Counselor": "职业顾问", 8 | "Personal Trainer": "私人教练", 9 | "Mental Health Adviser": "心理健康顾问", 10 | "Web Design Consultant": "网页设计顾问", 11 | "Automobile Mechanic": "汽车机械师", 12 | "Financial Analyst": "金融分析师", 13 | "Dream Interpreter": "梦境解释师", 14 | "IELTS Tester": "雅思英文测试员" 15 | } 16 | -------------------------------------------------------------------------------- /utils/data/taggingHelper.ts: -------------------------------------------------------------------------------- 1 | import { v4 as uuidv4 } from 'uuid'; 2 | 3 | const localStorageKey = 'unique_user_id'; 4 | 5 | export const getOrGenerateUserId = (): string => { 6 | let uniqueId = localStorage.getItem(localStorageKey); 7 | if (!uniqueId) { 8 | uniqueId = uuidv4(); 9 | localStorage.setItem(localStorageKey, uniqueId); 10 | } 11 | 12 | return uniqueId; 13 | }; 14 | 15 | export const clearLocalUserId = () => { 16 | localStorage.removeItem(localStorageKey); 17 | }; 18 | -------------------------------------------------------------------------------- /public/locales/bn/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "নতুন ফোল্ডার", 3 | "New chat": "নতুন আড্ডা", 4 | "No conversations.": "কোনো আলাপচারিতা নেই।", 5 | "Search conversations...": "আলাপচারিতা খুঁজুন...", 6 | "OpenAI API Key": "OpenAI API Key", 7 | "Import data": "আলাপচারিতা ইমপোর্ট", 8 | "Are you sure?": "আপনি কি নিশ্চিত?", 9 | "Clear conversations": "কথোপকথন পরিষ্কার করুন", 10 | "Export data": "আলাপচারিতা এক্সপোর্ট", 11 | "Dark mode": "ডার্ক মোড", 12 | "Light mode": "লাইট মোড" 13 | } 14 | -------------------------------------------------------------------------------- /public/locales/id/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "Folder baru", 3 | "New chat": "Percakapan baru", 4 | "No conversations.": "Tidak ada percakapan.", 5 | "Search conversations...": "Cari percakapan...", 6 | "OpenAI API Key": "Kunci API OpenAI", 7 | "Import data": "Impor percakapan", 8 | "Are you sure?": "Apakah Anda yakin?", 9 | "Clear conversations": "Hapus percakapan", 10 | "Export data": "Ekspor percakapan", 11 | "Dark mode": "Mode gelap", 12 | "Light mode": "Mode terang" 13 | } 14 | -------------------------------------------------------------------------------- /utils/app/mj_const.ts: -------------------------------------------------------------------------------- 1 | export const MJ_INVALID_USER_ACTION_LIST = [ 2 | 'BANNED_PROMPT', 3 | 'BLOCKED', 4 | 'IMAGE_BLOCKED', 5 | 'INVALID_LINK', 6 | 'INVALID_PARAMETER', 7 | 'JOB_ACTION_RESTRICTED', 8 | 'MODERATION_OUTAGE', 9 | 'Vary (Region)', 10 | ]; 11 | export const MJ_ALLOWED_COMMAND_LIST = [ 12 | '🪄 Make Variations', 13 | '🔍 Zoom Out 2x', 14 | '🔍 Zoom Out 1.5x', 15 | 'U1', 16 | 'U2', 17 | 'U3', 18 | 'U4', 19 | 'V1', 20 | 'V2', 21 | 'V3', 22 | 'V4', 23 | ]; 24 | -------------------------------------------------------------------------------- /public/locales/sv/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "Ny mapp", 3 | "New chat": "Ny chatt", 4 | "No conversations.": "Inga konversationer.", 5 | "Search conversations...": "Sök konversationer...", 6 | "OpenAI API Key": "OpenAI API-nyckel", 7 | "Import data": "Importera konversationer", 8 | "Are you sure?": "Är du säker?", 9 | "Clear conversations": "Radera konversationer", 10 | "Export data": "Exportera konversationer", 11 | "Dark mode": "Mörkt läge", 12 | "Light mode": "Ljust läge" 13 | } 14 | -------------------------------------------------------------------------------- /public/locales/it/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "Nuova cartella", 3 | "New chat": "Nuova conversazione", 4 | "No conversations.": "Nessuna conversazione.", 5 | "Search conversations...": "Cerca conversazioni...", 6 | "OpenAI API Key": "Chiave API OpenAI", 7 | "Import data": "Importa dati", 8 | "Are you sure?": "Sei sicuro?", 9 | "Clear conversations": "Elimina conversazioni", 10 | "Export data": "Esporta dati", 11 | "Dark mode": "Modalità scura", 12 | "Light mode": "Modalità chiara" 13 | } 14 | -------------------------------------------------------------------------------- /types/share-messages-by-teacher-profile.ts: -------------------------------------------------------------------------------- 1 | import type { Tag } from './tags'; 2 | 3 | import type { Pagination } from '@supabase/supabase-js'; 4 | 5 | export interface StudentMessageSubmission { 6 | id: number; 7 | message_content: string; 8 | image_file_url: string; 9 | created_at: string; 10 | student_name: string; 11 | message_tags: Tag[]; 12 | } 13 | 14 | export type ShareMessagesByTeacherProfilePayload = { 15 | submissions: StudentMessageSubmission[]; 16 | pagination: Pagination; 17 | }; 18 | -------------------------------------------------------------------------------- /public/locales/te/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "కొత్త ఫోల్డర్", 3 | "New chat": "కొత్త చాట్", 4 | "No conversations.": "సంభాషణలు లేవు.", 5 | "Search conversations...": "సంభాషణలు వెతకండి...", 6 | "OpenAI API Key": "ఒపెన్ ఎయి ఐ API కీ ", 7 | "Import data": "సంభాషణలు దిగుమతి చేయండి", 8 | "Are you sure?": "మీరు ఖచ్చితంగా ఉన్నారా?", 9 | "Clear conversations": "సంభాషణలు తొలగించు", 10 | "Export data": "సంభాషణలు ఎగుమతి చేయండి", 11 | "Dark mode": "డార్క్ మోడ్", 12 | "Light mode": "లైట్ మోడ్" 13 | } 14 | -------------------------------------------------------------------------------- /public/locales/ro/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "Folder nou", 3 | "New chat": "Conversație nouă", 4 | "No conversations.": "Nicio conversație.", 5 | "Search conversations...": "Căutați conversații...", 6 | "OpenAI API Key": "Cheia API OpenAI", 7 | "Import data": "Importați conversații", 8 | "Are you sure?": "Esti sigur?", 9 | "Clear conversations": "Ștergeți conversațiile", 10 | "Export data": "Exportați conversații", 11 | "Dark mode": "Modul întunecat", 12 | "Light mode": "Modul de golire" 13 | } 14 | -------------------------------------------------------------------------------- /public/locales/ar/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "مطلب جديد", 3 | "New folder": "مجلد جديد", 4 | "No prompts.": "لا يوجد مطالبات.", 5 | "Search prompts...": "...البحث عن مطالبات", 6 | "Name": "الاسم", 7 | "Description": "الوصف", 8 | "A description for your prompt.": "وصف لمطلبك", 9 | "Prompt": "مطلب", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "محتوى المطلب. استخدم {{}} للإشارة إلى متغير. مثال: {{الاسم}} هي {{صفة}} {{اسم}}", 11 | "Save": "حفظ" 12 | } 13 | -------------------------------------------------------------------------------- /supabase/migrations/20230622052759_add_refresh_referral_codes_method.sql: -------------------------------------------------------------------------------- 1 | set check_function_bodies = off; 2 | 3 | CREATE OR REPLACE FUNCTION public.refresh_referral_codes(payload json) 4 | RETURNS SETOF profiles 5 | LANGUAGE sql 6 | AS $function$ 7 | update profiles as p set referral_code = x.referral_code 8 | from ( 9 | select id, referral_code from json_populate_recordset(null::profiles, payload) 10 | ) as x(id, referral_code) 11 | where p.id = x.id 12 | returning p.*; 13 | $function$ 14 | ; 15 | 16 | 17 | -------------------------------------------------------------------------------- /public/locales/ar/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "مجلد جديد", 3 | "New chat": "محادثة جديدة", 4 | "No conversations.": "لا يوجد محادثات", 5 | "Search conversations...": "...البحث عن المحادثات", 6 | "OpenAI API Key": " (أوبن أيه أي) OpenAI API Key (مفتاح واجهة برمجة تطبيقات)", 7 | "Import data": "استيراد المحادثات", 8 | "Are you sure?": "هل أنت متأكد؟", 9 | "Clear conversations": "مسح المحادثات", 10 | "Export data": "تصدير المحادثات", 11 | "Dark mode": "الوضع الداكن", 12 | "Light mode": "الوضع الفاتح" 13 | } 14 | -------------------------------------------------------------------------------- /pages/teacher-portal/index.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | 3 | import { useRouter } from 'next/router'; 4 | 5 | import { withCommonServerSideProps } from '@/utils/withCommonServerSideProps'; 6 | 7 | const TeacherPortalIndex = () => { 8 | const router = useRouter(); 9 | 10 | useEffect(() => { 11 | router.push('/teacher-portal/one-time-code'); 12 | }, [router]); 13 | 14 | return null; 15 | }; 16 | 17 | export default TeacherPortalIndex; 18 | 19 | export const getServerSideProps = withCommonServerSideProps(); 20 | -------------------------------------------------------------------------------- /public/locales/de/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "Neuer Ordner", 3 | "New chat": "Neue Konversation", 4 | "No conversations.": "Keine Konversationen.", 5 | "Search conversations...": "Konversationen suchen...", 6 | "OpenAI API Key": "OpenAI API-Schlüssel", 7 | "Import data": "Konversationen importieren", 8 | "Are you sure?": "Bist du sicher?", 9 | "Clear conversations": "Konversationen löschen", 10 | "Export data": "Konversationen exportieren", 11 | "Dark mode": "Dark Mode", 12 | "Light mode": "Light Mode" 13 | } 14 | -------------------------------------------------------------------------------- /public/locales/es/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "Nueva carpeta", 3 | "New chat": "Nueva conversación", 4 | "No conversations.": "No hay conversaciones.", 5 | "Search conversations...": "Buscar conversaciones...", 6 | "OpenAI API Key": "Llave de API de OpenAI", 7 | "Import data": "Importar conversaciones", 8 | "Are you sure?": "¿Estás seguro?", 9 | "Clear conversations": "Borrar conversaciones", 10 | "Export data": "Exportar conversaciones", 11 | "Dark mode": "Modo oscuro", 12 | "Light mode": "Modo claro" 13 | } 14 | -------------------------------------------------------------------------------- /public/locales/vi/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "Thư mục mới", 3 | "New chat": "Tạo hội thoại mới", 4 | "No conversations.": "Không có hội thoại nào.", 5 | "Search conversations...": "Tìm kiếm các cuộc hội thoại...", 6 | "OpenAI API Key": "OpenAI API Key", 7 | "Import data": "Nhập dữ liệu hội thoại", 8 | "Are you sure?": "Bạn chắc chắn chứ?", 9 | "Clear conversations": "Xoá các đoạn hội thoại", 10 | "Export data": "Xuất dữ liệu hội thoại", 11 | "Dark mode": "Chế độ tối", 12 | "Light mode": "Chế độ sáng" 13 | } 14 | -------------------------------------------------------------------------------- /components/Buttons/SidebarActionButton/SidebarActionButton.tsx: -------------------------------------------------------------------------------- 1 | import type { MouseEventHandler, ReactElement } from 'react'; 2 | 3 | interface Props { 4 | handleClick: MouseEventHandler; 5 | children: ReactElement; 6 | } 7 | 8 | const SidebarActionButton = ({ handleClick, children }: Props) => ( 9 | 15 | ); 16 | 17 | export default SidebarActionButton; 18 | -------------------------------------------------------------------------------- /public/locales/fr/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "Nouveau dossier", 3 | "New chat": "Nouvelle discussion", 4 | "No conversations.": "Aucune conversation.", 5 | "Search conversations...": "Rechercher des conversations...", 6 | "OpenAI API Key": "Clé API OpenAI", 7 | "Import data": "Importer des conversations", 8 | "Are you sure?": "Êtes-vous sûr ?", 9 | "Clear conversations": "Effacer les conversations", 10 | "Export data": "Exporter les conversations", 11 | "Dark mode": "Mode sombre", 12 | "Light mode": "Mode clair" 13 | } 14 | -------------------------------------------------------------------------------- /components/Chat/AdMessage.tsx: -------------------------------------------------------------------------------- 1 | import { Adsense } from '@ctrl/react-adsense'; 2 | import React from 'react'; 3 | 4 | const AdMessage = ({ googleAdSenseId }: { googleAdSenseId: string }) => ( 5 |
9 | 16 |
17 | ); 18 | 19 | export default AdMessage; 20 | -------------------------------------------------------------------------------- /public/locales/he/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "פקודת מכונה חדשה", 3 | "New folder": "תיקיה חדשה", 4 | "No prompts.": "לא נמצאו פקודות מכונות", 5 | "Search prompts...": "חיפוש פקודות...", 6 | "Name": "שם", 7 | "Description": "תיאור", 8 | "A description for your prompt.": "תיאור שורת הפקודה למכונה", 9 | "Prompt": "פקודה", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "תיאור הפקודה. השתמש {{}} להגדרת משתנים. לדוגמא {{שם משתנה}} הוא {{תואר}} {{שם עצם}}", 11 | "Save": "Save" 12 | } 13 | -------------------------------------------------------------------------------- /pages/api/mj-queue/process.ts: -------------------------------------------------------------------------------- 1 | import { MjQueueService } from '@/utils/server/mjQueueService'; 2 | 3 | export const config = { 4 | runtime: 'edge', 5 | preferredRegion: 'icn1', 6 | }; 7 | 8 | const handler = async (): Promise => { 9 | await MjQueueService.processNextBatch(); 10 | 11 | try { 12 | return new Response(JSON.stringify({}), { 13 | status: 200, 14 | }); 15 | } catch (error) { 16 | console.error(error); 17 | return new Response('Error', { status: 500 }); 18 | } 19 | }; 20 | 21 | export default handler; 22 | -------------------------------------------------------------------------------- /public/locales/de/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "New prompt", 3 | "New folder": "New folder", 4 | "No prompts.": "No prompts.", 5 | "Search prompts...": "Search prompts...", 6 | "Name": "Name", 7 | "Description": "Description", 8 | "A description for your prompt.": "A description for your prompt.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}", 11 | "Save": "Save" 12 | } 13 | -------------------------------------------------------------------------------- /public/locales/fr/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "New prompt", 3 | "New folder": "New folder", 4 | "No prompts.": "No prompts.", 5 | "Search prompts...": "Search prompts...", 6 | "Name": "Name", 7 | "Description": "Description", 8 | "A description for your prompt.": "A description for your prompt.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}", 11 | "Save": "Save" 12 | } 13 | -------------------------------------------------------------------------------- /public/locales/id/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "New prompt", 3 | "New folder": "New folder", 4 | "No prompts.": "No prompts.", 5 | "Search prompts...": "Search prompts...", 6 | "Name": "Name", 7 | "Description": "Description", 8 | "A description for your prompt.": "A description for your prompt.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}", 11 | "Save": "Save" 12 | } 13 | -------------------------------------------------------------------------------- /public/locales/ja/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "New prompt", 3 | "New folder": "New folder", 4 | "No prompts.": "No prompts.", 5 | "Search prompts...": "Search prompts...", 6 | "Name": "Name", 7 | "Description": "Description", 8 | "A description for your prompt.": "A description for your prompt.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}", 11 | "Save": "Save" 12 | } 13 | -------------------------------------------------------------------------------- /public/locales/ko/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "New prompt", 3 | "New folder": "New folder", 4 | "No prompts.": "No prompts.", 5 | "Search prompts...": "Search prompts...", 6 | "Name": "Name", 7 | "Description": "Description", 8 | "A description for your prompt.": "A description for your prompt.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}", 11 | "Save": "Save" 12 | } 13 | -------------------------------------------------------------------------------- /public/locales/pt/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "New prompt", 3 | "New folder": "New folder", 4 | "No prompts.": "No prompts.", 5 | "Search prompts...": "Search prompts...", 6 | "Name": "Name", 7 | "Description": "Description", 8 | "A description for your prompt.": "A description for your prompt.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}", 11 | "Save": "Save" 12 | } 13 | -------------------------------------------------------------------------------- /public/locales/ru/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "New prompt", 3 | "New folder": "New folder", 4 | "No prompts.": "No prompts.", 5 | "Search prompts...": "Search prompts...", 6 | "Name": "Name", 7 | "Description": "Description", 8 | "A description for your prompt.": "A description for your prompt.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}", 11 | "Save": "Save" 12 | } 13 | -------------------------------------------------------------------------------- /public/locales/si/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "New prompt", 3 | "New folder": "New folder", 4 | "No prompts.": "No prompts.", 5 | "Search prompts...": "Search prompts...", 6 | "Name": "Name", 7 | "Description": "Description", 8 | "A description for your prompt.": "A description for your prompt.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}", 11 | "Save": "Save" 12 | } 13 | -------------------------------------------------------------------------------- /public/locales/te/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "New prompt", 3 | "New folder": "New folder", 4 | "No prompts.": "No prompts.", 5 | "Search prompts...": "Search prompts...", 6 | "Name": "Name", 7 | "Description": "Description", 8 | "A description for your prompt.": "A description for your prompt.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}", 11 | "Save": "Save" 12 | } 13 | -------------------------------------------------------------------------------- /supabase/migrations/20240210014312_add_teacher_profile_id_as_fk_to_student_message_submissions.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."student_message_submissions" add column "teacher_profile_id" uuid not null; 2 | 3 | alter table "public"."student_message_submissions" add constraint "student_message_submissions_teacher_profile_id_fkey" FOREIGN KEY (teacher_profile_id) REFERENCES profiles(id) ON UPDATE CASCADE ON DELETE CASCADE not valid; 4 | 5 | alter table "public"."student_message_submissions" validate constraint "student_message_submissions_teacher_profile_id_fkey"; 6 | 7 | 8 | -------------------------------------------------------------------------------- /components/Chat/VisibilityWrapper.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactElement } from 'react'; 2 | import { useState } from 'react'; 3 | import { InView } from 'react-intersection-observer'; 4 | 5 | interface Props { 6 | children: (inView: boolean) => ReactElement; 7 | } 8 | 9 | const VisibilityWrapper = ({ children }: Props) => { 10 | const [inView, setInView] = useState(false); 11 | return ( 12 | setInView(inView)}> 13 | {children(inView)} 14 | 15 | ); 16 | }; 17 | 18 | export default VisibilityWrapper; 19 | -------------------------------------------------------------------------------- /hooks/useWindowWidth.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | const useWindowWidth = () => { 4 | const [windowWidth, setWindowWidth] = useState(window.innerWidth); 5 | 6 | useEffect(() => { 7 | const handleResize = () => { 8 | setWindowWidth(window.innerWidth); 9 | }; 10 | 11 | window.addEventListener('resize', handleResize); 12 | 13 | return () => { 14 | window.removeEventListener('resize', handleResize); 15 | }; 16 | }, []); 17 | 18 | return windowWidth; 19 | }; 20 | 21 | export default useWindowWidth; 22 | -------------------------------------------------------------------------------- /public/locales/pl/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "Nowy prompt", 3 | "New folder": "Nowy folder", 4 | "No prompts.": "Brak promptów.", 5 | "Search prompts...": "Szukaj promptów...", 6 | "Name": "Nazwa", 7 | "Description": "Opis", 8 | "A description for your prompt.": "Opis Twojego prompta.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Zawartość prompta. Użyj {{}} żeby oznaczyć zmienną. Np.: {{nazwa}} jest {{przymiotnik}} {{rzeczownik}}", 11 | "Save": "Zapisz" 12 | } 13 | -------------------------------------------------------------------------------- /supabase/migrations/20240414040757_add_index_for_student_shared_message.sql: -------------------------------------------------------------------------------- 1 | CREATE INDEX idx_mt_message_submission_id ON public.message_tags USING btree (message_submission_id); 2 | 3 | CREATE INDEX idx_mt_tag_id ON public.message_tags USING btree (tag_id); 4 | 5 | CREATE INDEX idx_sms_sorting ON public.student_message_submissions USING btree (created_at, student_name); 6 | 7 | CREATE INDEX idx_sms_teacher_profile_id ON public.student_message_submissions USING btree (teacher_profile_id); 8 | 9 | CREATE INDEX idx_tags_id ON public.tags USING btree (id); 10 | 11 | 12 | -------------------------------------------------------------------------------- /public/locales/sv/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "Ny prompt", 3 | "New folder": "Ny mapp", 4 | "No prompts.": "Inga prompts.", 5 | "Search prompts...": "Sök prompts...", 6 | "Name": "Namn", 7 | "Description": "Beskrivning", 8 | "A description for your prompt.": "En beskrivning för din prompt.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Prompt-innehåll. Använd {{}} för att beteckna en variabel. Ex: {{namn}} är ett {{adjektiv}} {{substantiv}}", 11 | "Save": "Spara" 12 | } 13 | -------------------------------------------------------------------------------- /public/locales/vi/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "Prompt mới", 3 | "New folder": "Thư mục mới", 4 | "No prompts.": "Không có Prompt nào.", 5 | "Search prompts...": "Tìm kiếm các Prompt...", 6 | "Name": "Tên", 7 | "Description": "Mô tả", 8 | "A description for your prompt.": "Một mô tả cho Prompt của bạn.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Nội dung Prompt. Sử dụng {{}} để biểu thị một biến. Ví dụ: {{name}} là một {{adjective}} {{noun}}", 11 | "Save": "Lưu" 12 | } 13 | -------------------------------------------------------------------------------- /types/referral.ts: -------------------------------------------------------------------------------- 1 | import type { SubscriptionPlan } from './user'; 2 | 3 | export interface RawRefereeProfile { 4 | id: string; 5 | plan: SubscriptionPlan; 6 | stripe_subscription_id: string; 7 | pro_plan_expiration_date: string | null; 8 | referral_code: string | null; 9 | referral_code_expiration_date: string | null; 10 | email: string; 11 | referral_date: string; 12 | } 13 | 14 | export interface RefereeProfile { 15 | plan: SubscriptionPlan; 16 | email: string; 17 | referralDate: string; 18 | isInTrial: string; 19 | hasPaidForPro: string; 20 | } 21 | -------------------------------------------------------------------------------- /public/locales/bn/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "নতুন prompt", 3 | "New folder": "নতুন ফোল্ডার", 4 | "No prompts.": "কোনো prompts নেই।", 5 | "Search prompts...": "prompts অনুসন্ধান হচ্ছে...", 6 | "Name": "নাম", 7 | "Description": "বর্ণনা", 8 | "A description for your prompt.": "আপনার Prompt জন্য একটি বিবরণ লিখুন.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}", 11 | "Save": "সংরক্ষণ করুন" 12 | } 13 | -------------------------------------------------------------------------------- /types/notion.ts: -------------------------------------------------------------------------------- 1 | export interface ChatEverywhereNews { 2 | id: string; 3 | title: string; 4 | createdTime: string; 5 | } 6 | 7 | export interface ChatEverywhereNewsPage { 8 | id: string; 9 | title: string; 10 | createdTime: string; 11 | content: string; 12 | } 13 | 14 | export interface ChatEverywhereFeatures { 15 | id: string; 16 | title: string; 17 | lastEditedTime: string; 18 | tier: string[]; 19 | } 20 | 21 | export interface ChatEverywhereFeaturesPage { 22 | id: string; 23 | title: string; 24 | createdTime: string; 25 | content: string; 26 | } 27 | -------------------------------------------------------------------------------- /public/locales/es/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "Nuevo prompt", 3 | "New folder": "Nueva carpeta", 4 | "No prompts.": "No hay prompts.", 5 | "Search prompts...": "Buscar prompts...", 6 | "Name": "Nombre", 7 | "Description": "Descripción", 8 | "A description for your prompt.": "Descripción de su prompt.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Contenido del prompt. Utilice {{}} para indicar una variable. Ej: {{nombre}} es un {{adjetivo}} {{nombre}}", 11 | "Save": "Guardar" 12 | } 13 | -------------------------------------------------------------------------------- /supabase/migrations/20230408030930_remote_commit.sql: -------------------------------------------------------------------------------- 1 | set check_function_bodies = off; 2 | 3 | CREATE OR REPLACE FUNCTION storage.can_insert_object(bucketid text, name text, owner uuid, metadata jsonb) 4 | RETURNS void 5 | LANGUAGE plpgsql 6 | AS $function$ 7 | BEGIN 8 | INSERT INTO "storage"."objects" ("bucket_id", "name", "owner", "metadata") VALUES (bucketid, name, owner, metadata); 9 | -- hack to rollback the successful insert 10 | RAISE sqlstate 'PT200' using 11 | message = 'ROLLBACK', 12 | detail = 'rollback successful insert'; 13 | END 14 | $function$ 15 | ; 16 | 17 | 18 | -------------------------------------------------------------------------------- /public/locales/it/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "Nuovo prompt", 3 | "New folder": "Nuova cartella", 4 | "No prompts.": "Nessun prompt.", 5 | "Search prompts...": "Cerca prompts...", 6 | "Name": "Nome", 7 | "Description": "Descrizione", 8 | "A description for your prompt.": "Descrizione del tuo prompt.", 9 | "Prompt": "Prompt", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Contenuto del prompt. Utilizza {{}} per indicare una variabile. Per esempio: {{nome}} è un {{aggettivo}} {{sostantivo}}", 11 | "Save": "Salva" 12 | } 13 | -------------------------------------------------------------------------------- /utils/server/supabase/shared-message-with-teacher.ts: -------------------------------------------------------------------------------- 1 | import { getAdminSupabaseClient } from '../supabase'; 2 | 3 | const supabase = getAdminSupabaseClient(); 4 | 5 | export async function removeSharedMessagesWithTeacher( 6 | teacher_profile_id: string, 7 | message_ids: string[], 8 | ) { 9 | const { error } = await supabase 10 | .from('student_message_submissions') 11 | .delete() 12 | .eq('teacher_profile_id', teacher_profile_id) 13 | .in('id', message_ids); 14 | 15 | if (error) { 16 | console.log(error); 17 | throw error; 18 | } 19 | 20 | return true; 21 | } 22 | -------------------------------------------------------------------------------- /public/locales/ro/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "Noua solicitare", 3 | "New folder": "Dosar nou", 4 | "No prompts.": "Fără solicitări.", 5 | "Search prompts...": "Cereri de căutare...", 6 | "Name": "Nume", 7 | "Description": "Descriere", 8 | "A description for your prompt.": "Descrierea solicitării prompt.", 9 | "Prompt": "Îndemnuri", 10 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "Conținut prompt. Utilizați {{}} pentru a indica o variabilă. De exemplu: {{nume}} este un {{adjectiv}} {{substantiv}}", 11 | "Save": "Salvați" 12 | } 13 | -------------------------------------------------------------------------------- /types/google-storage.ts: -------------------------------------------------------------------------------- 1 | interface Metadata { 2 | 'user-id': string; 3 | 'file-name': string; 4 | } 5 | 6 | export interface StorageObject { 7 | kind: string; 8 | id: string; 9 | selfLink: string; 10 | mediaLink: string; 11 | name: string; 12 | bucket: string; 13 | generation: string; 14 | metageneration: string; 15 | contentType: string; 16 | storageClass: string; 17 | size: string; 18 | md5Hash: string; 19 | crc32c: string; 20 | etag: string; 21 | timeCreated: string; 22 | updated: string; 23 | timeStorageClassUpdated: string; 24 | metadata: Metadata; 25 | } 26 | -------------------------------------------------------------------------------- /public/locales/hi/roles.json: -------------------------------------------------------------------------------- 1 | { 2 | "Accountant": "लेखाकार", 3 | "Writing Tutor": "लेखन शिक्षक", 4 | "Life Coach": "जीवन कोच", 5 | "Psychologist": "मनोविज्ञानी", 6 | "Social Media Influencer": "सोशल मीडिया प्रभावक", 7 | "Career Counselor": "करियर सलाहकार", 8 | "Personal Trainer": "निजी प्रशिक्षक", 9 | "Mental Health Adviser": "मानसिक स्वास्थ्य सलाहकार", 10 | "Web Design Consultant": "वेब डिजाइन सलाहकार", 11 | "Automobile Mechanic": "ऑटोमोबाइल मैकेनिक", 12 | "Financial Analyst": "वित्तीय विश्लेषक", 13 | "Dream Interpreter": "सपना व्याख्याता", 14 | "IELTS Tester": "आईईएलटीएस परीक्षणकर्ता" 15 | } 16 | -------------------------------------------------------------------------------- /public/locales/zh-Hans/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "新建文件夹", 3 | "New chat": "新建对话", 4 | "No conversations.": "无对话", 5 | "Search conversations...": "搜索对话...", 6 | "OpenAI API Key": "OpenAI API 密钥", 7 | "Import data": "导入对话", 8 | "Are you sure?": "确定吗?", 9 | "Clear conversations": "清空对话", 10 | "Follow for updates!": "反馈和功能介绍", 11 | "Sign in": "登录", 12 | "Account": "账户设置", 13 | "Usage & credit": "点数余额", 14 | "Latest Updates": "最新消息", 15 | "Referral Program": "推荐计划", 16 | "Settings": "设置", 17 | "Teacher Portal": "教师专区", 18 | "One-time code login": "使用代码登录", 19 | "File Portal": "档案平台" 20 | } 21 | -------------------------------------------------------------------------------- /public/locales/zh-Hant/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "新建資料夾", 3 | "New chat": "新建對話", 4 | "No conversations.": "無對話", 5 | "Search conversations...": "搜尋對話...", 6 | "OpenAI API Key": "OpenAI API 金鑰", 7 | "Import data": "導入對話", 8 | "Are you sure?": "確定嗎?", 9 | "Clear conversations": "清空對話", 10 | "Follow for updates!": "反饋和功能介紹", 11 | "Sign in": "登入", 12 | "Account": "帳戶設定", 13 | "Usage & credit": "點數餘額", 14 | "Latest Updates": "最新消息", 15 | "Referral Program": "推廣計劃", 16 | "Settings": "設定", 17 | "Teacher Portal": "教師專區", 18 | "One-time code login": "使用代碼登入", 19 | "File Portal": "檔案平台" 20 | } 21 | -------------------------------------------------------------------------------- /types/storage.ts: -------------------------------------------------------------------------------- 1 | import type { Conversation } from './chat'; 2 | import type { FolderInterface } from './folder'; 3 | import type { Prompt } from './prompt'; 4 | 5 | // keep track of local storage schema 6 | export interface LocalStorage { 7 | apiKey: string; 8 | conversationHistory: Conversation[]; 9 | selectedConversation: Conversation; 10 | theme: 'light' | 'dark'; 11 | // added folders (3/23/23) 12 | folders: FolderInterface[]; 13 | // added prompts (3/26/23) 14 | prompts: Prompt[]; 15 | // added showChatbar and showPromptbar (3/26/23) 16 | showChatbar: boolean; 17 | showPromptbar: boolean; 18 | } 19 | -------------------------------------------------------------------------------- /public/locales/en/roles.json: -------------------------------------------------------------------------------- 1 | { 2 | "Accountant": "Accountant", 3 | "Writing Tutor": "Writing Tutor", 4 | "Life Coach": "Life Coach", 5 | "Psychologist": "Psychologist", 6 | "Social Media Influencer": "Social Media Influencer", 7 | "Career Counselor": "Career Counselor", 8 | "Personal Trainer": "Personal Trainer", 9 | "Mental Health Adviser": "Mental Health Adviser", 10 | "Web Design Consultant": "Web Design Consultant", 11 | "Automobile Mechanic": "Automobile Mechanic", 12 | "Financial Analyst": "Financial Analyst", 13 | "Dream Interpreter": "Dream Interpreter", 14 | "IELTS Tester": "IELTS Tester" 15 | } 16 | -------------------------------------------------------------------------------- /components/Chat/components/GeneralHtmlComponentParser.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | // NOTE: THE COMPONENT IS USED FOR STATIC HTML GENERATION, SO DON'T USE HOOKS OR STATE 4 | 5 | const GeneralHtmlComponentParser = ({ 6 | id, 7 | componentState, 8 | identifier = undefined, 9 | }: { 10 | id: string; 11 | componentState: object; 12 | identifier?: string | undefined; 13 | }) => { 14 | return ( 15 |
20 | ); 21 | }; 22 | 23 | export default GeneralHtmlComponentParser; 24 | -------------------------------------------------------------------------------- /public/locales/hi/promptbar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New prompt": "नया प्रम्प्ट", 3 | "New folder": "नया फ़ोल्डर", 4 | "No prompts.": "कोई प्रम्प्ट नहीं।", 5 | "Search prompts...": "प्रम्प्ट खोजें...", 6 | "Name": "नाम", 7 | "A name for your prompt.": "आपके प्रम्प्ट के लिए एक नाम।", 8 | "Description": "विवरण", 9 | "A description for your prompt.": "आपके प्रम्प्ट के लिए एक विवरण।", 10 | "Prompt": "प्रम्प्ट", 11 | "Prompt content. Use {{}} to denote a variable. Ex: {{name}} is a {{adjective}} {{noun}}": "प्रम्प्ट सामग्री। एक चर को दर्शाने के लिए {{}} का उपयोग करें। उदाहरण: {{name}} एक {{adjective}} {{noun}} है।", 12 | "Save": "Save" 13 | } 14 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "singleQuote": true, 4 | "endOfLine": "auto", 5 | "printWidth": 80, 6 | "plugins": [ 7 | "prettier-plugin-tailwindcss", 8 | "@trivago/prettier-plugin-sort-imports" 9 | ], 10 | "importOrder": [ 11 | "react", 12 | "^react-.*$", 13 | "^next", 14 | "^next-.*$", 15 | "^next/.*$", 16 | "^.*/hooks/.*$", 17 | "^.*/services/.*$", 18 | "^.*/utils/.*$", 19 | "^.*/types/.*$", 20 | "^.*/pages/.*$", 21 | "^.*/components/.*$", 22 | "^[./]", 23 | ".*" 24 | ], 25 | "importOrderSeparation": true, 26 | "importOrderSortSpecifiers": true 27 | } 28 | -------------------------------------------------------------------------------- /hooks/v2Chat/use-at-bottom.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export function useAtBottom(offset = 0) { 4 | const [isAtBottom, setIsAtBottom] = React.useState(false); 5 | 6 | React.useEffect(() => { 7 | const handleScroll = () => { 8 | setIsAtBottom( 9 | window.innerHeight + window.scrollY >= 10 | document.body.offsetHeight - offset, 11 | ); 12 | }; 13 | 14 | window.addEventListener('scroll', handleScroll, { passive: true }); 15 | handleScroll(); 16 | 17 | return () => { 18 | window.removeEventListener('scroll', handleScroll); 19 | }; 20 | }, [offset]); 21 | 22 | return isAtBottom; 23 | } 24 | -------------------------------------------------------------------------------- /utils/data/throttle.ts: -------------------------------------------------------------------------------- 1 | export function throttle any>( 2 | func: T, 3 | limit: number, 4 | ): T { 5 | let lastFunc: ReturnType; 6 | let lastRan: number; 7 | 8 | return ((...args) => { 9 | if (!lastRan) { 10 | func(...args); 11 | lastRan = Date.now(); 12 | } else { 13 | clearTimeout(lastFunc); 14 | lastFunc = setTimeout( 15 | () => { 16 | if (Date.now() - lastRan >= limit) { 17 | func(...args); 18 | lastRan = Date.now(); 19 | } 20 | }, 21 | limit - (Date.now() - lastRan), 22 | ); 23 | } 24 | }) as T; 25 | } 26 | -------------------------------------------------------------------------------- /supabase/migrations/20230430203710_create_api_usages_table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS api_usages ( 2 | id UUID PRIMARY KEY DEFAULT gen_random_uuid(), 3 | user_id UUID NOT NULL, 4 | api_type TEXT NOT NULL, 5 | timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW() 6 | ); 7 | 8 | ALTER TABLE api_usages 9 | ADD FOREIGN KEY (user_id) 10 | REFERENCES auth.users(id) 11 | ON DELETE CASCADE; 12 | 13 | -- Enable RLS and set default access 14 | ALTER TABLE api_usages FORCE ROW LEVEL SECURITY; 15 | ALTER TABLE api_usages ENABLE ROW LEVEL SECURITY; 16 | 17 | -- Restrict access to the table 18 | REVOKE ALL ON api_usages FROM public; 19 | REVOKE ALL ON api_usages FROM authenticated; -------------------------------------------------------------------------------- /public/locales/zh-Hant/feature.json: -------------------------------------------------------------------------------- 1 | { 2 | "Syncing ...": "同步中 ...", 3 | "Synced": "已同步", 4 | "Sync failed": "同步失敗", 5 | "Cloud sync disabled": "雲端同步未啟用", 6 | "This is a Pro only feature. Please sign-up to use it if you don't have an account.": "這是Pro版的獨享功能, 請先登入和升級。", 7 | "Please connect with your Line account first.": "請先連接您的LINE帳戶", 8 | "Failed to share message, please try again later": "轉發失敗,請稍後再試", 9 | "Your Line connection has expired, please re-connect on the setting page": "您的Line連接已失效, 請重新連接", 10 | "Message shared successfully": "轉發成功!", 11 | "Share to LINE": "轉發到LINE", 12 | "Sharing message to LINE...": "正在轉發到LINE...", 13 | "Share to Teacher": "轉發給教師" 14 | } 15 | -------------------------------------------------------------------------------- /public/locales/hi/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "New folder": "नया फ़ोल्डर", 3 | "New chat": "नया चैट", 4 | "No conversations.": "कोई बातचीत नहीं।", 5 | "Search conversations...": "बातचीत खोजें...", 6 | "OpenAI API Key": "OpenAI API कुंजी", 7 | "Import data": "डेटा Import करें", 8 | "Are you sure?": "क्या आपको पक्का विश्वास है?", 9 | "Clear conversations": "बातचीत साफ़ करें", 10 | "Export data": "डेटा Export करें", 11 | "Dark mode": "डार्क मोड", 12 | "Light mode": "लाइट मोड", 13 | "Follow for updates!": "अपडेट के लिए फ़ॉलो करें!", 14 | "Sign in": "साइन इन करें", 15 | "Account": "खाता", 16 | "Usage & credit": "उपयोग और क्रेडिट", 17 | "Latest Updates": "नवीनतम अपडेट" 18 | } 19 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Chat Everywhere", 3 | "short_name": "Chat Everywhere", 4 | "icons": [ 5 | { 6 | "src": "/icons/icon_192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/icons/icon_512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | }, 15 | { 16 | "src": "/icons/maskable_icon_384.png", 17 | "sizes": "384x384", 18 | "type": "image/png", 19 | "purpose": "maskable" 20 | } 21 | ], 22 | "theme_color": "#202123", 23 | "background_color": "#202123", 24 | "start_url": "/", 25 | "display": "standalone", 26 | "orientation": "portrait" 27 | } 28 | -------------------------------------------------------------------------------- /components/Promptbar/PromptBar.context.tsx: -------------------------------------------------------------------------------- 1 | import type { Dispatch } from 'react'; 2 | import { createContext } from 'react'; 3 | 4 | import type { ActionType } from '@/hooks/useCreateReducer'; 5 | 6 | import type { Prompt } from '@/types/prompt'; 7 | 8 | import type { PromptbarInitialState } from './Promptbar.state'; 9 | 10 | export interface PromptbarContextProps { 11 | state: PromptbarInitialState; 12 | dispatch: Dispatch>; 13 | handleDeletePrompt: (prompt: Prompt) => void; 14 | handleUpdatePrompt: (prompt: Prompt) => void; 15 | } 16 | 17 | const PromptbarContext = createContext(undefined!); 18 | 19 | export default PromptbarContext; 20 | -------------------------------------------------------------------------------- /cypress/e2e/account.ts: -------------------------------------------------------------------------------- 1 | const FREE_USER = { 2 | email: 'cypress@exploratorlabs.com', 3 | password: 'chateverywhere', 4 | }; 5 | 6 | const PRO_USER = { 7 | email: 'cypress+pro@exploratorlabs.com', 8 | password: 'chateverywhere', 9 | }; 10 | 11 | const ULTRA_USER = { 12 | email: 'cypress+ultra@exploratorlabs.com', 13 | password: 'chateverywhere', 14 | }; 15 | 16 | const TEACHER_USER = { 17 | email: 'cypress+teacher@exploratorlabs.com', 18 | password: 'chateverywhere', 19 | }; 20 | 21 | const PRIORITY_USER = { 22 | email: 'cypress+priority@exploratorlabs.com', 23 | password: 'chateverywhere', 24 | }; 25 | 26 | export { FREE_USER, PRO_USER, ULTRA_USER, TEACHER_USER, PRIORITY_USER }; 27 | -------------------------------------------------------------------------------- /utils/server/deleteUserById.ts: -------------------------------------------------------------------------------- 1 | import { getAdminSupabaseClient } from './supabase'; 2 | 3 | export async function deleteUserById(id: string) { 4 | // delete profile first 5 | const supabase = getAdminSupabaseClient(); 6 | const { error: deleteProfileError } = await supabase 7 | .from('profiles') 8 | .delete() 9 | .eq('id', id); 10 | if (deleteProfileError) { 11 | console.error({ deleteProfileError }); 12 | throw deleteProfileError; 13 | } 14 | // finally delete supabase user 15 | const { error } = await supabase.auth.admin.deleteUser(id); 16 | if (error) { 17 | console.error({ supabaseDeleteErrer: error }); 18 | throw error; 19 | } 20 | return true; 21 | } 22 | -------------------------------------------------------------------------------- /supabase/migrations/20240226040743_add_get_teacher_tag_and_tag_count.sql: -------------------------------------------------------------------------------- 1 | set check_function_bodies = off; 2 | 3 | CREATE OR REPLACE FUNCTION public.get_teacher_tag_and_tag_count(teacher_profile_id_param uuid) 4 | RETURNS TABLE(name character varying, id integer, message_count bigint) 5 | LANGUAGE plpgsql 6 | STABLE 7 | AS $function$ 8 | BEGIN 9 | RETURN QUERY 10 | SELECT t.name, tt.tag_id, COUNT(mt.message_submission_id) AS message_count 11 | FROM teacher_tags tt 12 | JOIN tags t ON tt.tag_id = t.id 13 | LEFT JOIN message_tags mt ON tt.tag_id = mt.tag_id 14 | WHERE tt.teacher_profile_id = teacher_profile_id_param 15 | GROUP BY t.name, tt.tag_id; 16 | END; 17 | $function$ 18 | ; 19 | 20 | 21 | -------------------------------------------------------------------------------- /hooks/v2Chat/use-enter-submit.tsx: -------------------------------------------------------------------------------- 1 | import { type RefObject, useRef } from 'react'; 2 | 3 | export function useEnterSubmit(): { 4 | formRef: RefObject; 5 | onKeyDown: (event: React.KeyboardEvent) => void; 6 | } { 7 | const formRef = useRef(null); 8 | 9 | const handleKeyDown = ( 10 | event: React.KeyboardEvent, 11 | ): void => { 12 | if ( 13 | event.key === 'Enter' && 14 | !event.shiftKey && 15 | !event.nativeEvent.isComposing 16 | ) { 17 | formRef.current?.requestSubmit(); 18 | event.preventDefault(); 19 | } 20 | }; 21 | 22 | return { formRef, onKeyDown: handleKeyDown }; 23 | } 24 | -------------------------------------------------------------------------------- /pages/api/teacher-portal/teacher-tags.ts: -------------------------------------------------------------------------------- 1 | import { 2 | fetchUserProfileWithAccessToken, 3 | unauthorizedResponse, 4 | } from '@/utils/server/auth'; 5 | import { getTeacherTags } from '@/utils/server/supabase/tags'; 6 | 7 | export const config = { 8 | runtime: 'edge', 9 | }; 10 | 11 | const handler = async (req: Request): Promise => { 12 | const userProfile = await fetchUserProfileWithAccessToken(req); 13 | if (!userProfile || !userProfile.isTeacherAccount) 14 | return unauthorizedResponse; 15 | 16 | return new Response( 17 | JSON.stringify({ 18 | tags: await getTeacherTags(userProfile.id), 19 | }), 20 | { status: 200 }, 21 | ); 22 | }; 23 | export default handler; 24 | -------------------------------------------------------------------------------- /utils/app/prompts.ts: -------------------------------------------------------------------------------- 1 | import type { Prompt } from '@/types/prompt'; 2 | 3 | import dayjs from 'dayjs'; 4 | 5 | export const updatePrompt = (updatedPrompt: Prompt, allPrompts: Prompt[]) => { 6 | const updatedPrompts = allPrompts.map((c) => { 7 | if (c.id === updatedPrompt.id) { 8 | return { 9 | ...updatedPrompt, 10 | lastUpdateAtUTC: dayjs().valueOf(), 11 | }; 12 | } 13 | 14 | return c; 15 | }); 16 | 17 | savePrompts(updatedPrompts); 18 | 19 | return { 20 | single: updatedPrompt, 21 | all: updatedPrompts, 22 | }; 23 | }; 24 | 25 | export const savePrompts = (prompts: Prompt[]) => { 26 | localStorage.setItem('prompts', JSON.stringify(prompts)); 27 | }; 28 | -------------------------------------------------------------------------------- /pages/api/cron/update-referral-codes.ts: -------------------------------------------------------------------------------- 1 | import { batchRefreshReferralCodes } from '../../../utils/server/supabase'; 2 | 3 | import dayjs from 'dayjs'; 4 | import timezone from 'dayjs/plugin/timezone'; 5 | import utc from 'dayjs/plugin/utc'; 6 | 7 | dayjs.extend(utc); 8 | dayjs.extend(timezone); 9 | 10 | export const config = { 11 | runtime: 'edge', 12 | }; 13 | 14 | const handler = async (): Promise => { 15 | try { 16 | await batchRefreshReferralCodes(); 17 | return new Response(JSON.stringify({ success: true }), { status: 200 }); 18 | } catch (error) { 19 | console.error(error); 20 | return new Response('Error', { status: 500 }); 21 | } 22 | }; 23 | 24 | export default handler; 25 | -------------------------------------------------------------------------------- /supabase/migrations/20240410161016_add_get_student_messages_count.sql: -------------------------------------------------------------------------------- 1 | set check_function_bodies = off; 2 | 3 | CREATE OR REPLACE FUNCTION public.get_student_messages_count(input_tag_ids integer[], input_teacher_profile_id uuid) 4 | RETURNS bigint 5 | LANGUAGE plpgsql 6 | AS $function$ 7 | DECLARE 8 | total_count BIGINT; 9 | BEGIN 10 | SELECT COUNT(*) 11 | INTO total_count 12 | FROM student_message_submissions sms 13 | LEFT JOIN message_tags mt ON sms.id = mt.message_submission_id 14 | WHERE sms.teacher_profile_id = input_teacher_profile_id 15 | AND (cardinality(input_tag_ids) = 0 OR mt.tag_id = ANY(input_tag_ids)); 16 | 17 | RETURN total_count; 18 | END; 19 | $function$ 20 | ; 21 | 22 | 23 | -------------------------------------------------------------------------------- /public/locales/zh-Hans/feature.json: -------------------------------------------------------------------------------- 1 | { 2 | "Syncing ...": "正在同步...", 3 | "Synced": "已同步", 4 | "Sync failed": "同步失败", 5 | "Cloud sync disabled": "云同步已禁用", 6 | "Conversation mode": "对话模式", 7 | "This is a Pro only feature. Please sign-up to use it if you don't have an account.": "这是Pro版的独享功能, 请先登录和升级。", 8 | "Please connect with your Line account first.": "请先连接您的LINE帐户", 9 | "Failed to share message, please try again later": "转发失败, 请稍后再试", 10 | "Your Line connection has expired, please re-connect on the setting page": "您的Line连接已失效, 请重新连接", 11 | "Message shared successfully": "转发成功!", 12 | "Share to LINE": "转发到LINE", 13 | "Sharing message to LINE...": "正在转发到LINE...", 14 | "Share to Teacher": "转发给教师" 15 | } 16 | -------------------------------------------------------------------------------- /supabase/migrations/20230422210643_setup_user_conversations_table.sql: -------------------------------------------------------------------------------- 1 | -- Create user_conversations table 2 | CREATE TABLE user_conversations ( 3 | id SERIAL PRIMARY KEY, 4 | uid UUID NOT NULL REFERENCES auth.users ON DELETE CASCADE, 5 | conversations JSONB NOT NULL, 6 | last_updated TIMESTAMPTZ NOT NULL DEFAULT NOW() 7 | ); 8 | 9 | -- Enable RLS 10 | ALTER TABLE user_conversations FORCE ROW LEVEL SECURITY; 11 | ALTER TABLE user_conversations ENABLE ROW LEVEL SECURITY; 12 | 13 | -- Owner policy 14 | CREATE POLICY user_conversations_owner_policy 15 | ON user_conversations 16 | FOR ALL 17 | USING ( 18 | uid = auth.uid() 19 | ); 20 | 21 | -- Apply the policy 22 | ALTER TABLE user_conversations FORCE ROW LEVEL SECURITY; 23 | -------------------------------------------------------------------------------- /pages/api/teacher-portal/get-teacher-settings.ts: -------------------------------------------------------------------------------- 1 | import { 2 | fetchUserProfileWithAccessToken, 3 | unauthorizedResponse, 4 | } from '@/utils/server/auth'; 5 | import { getTeacherSettings } from '@/utils/server/supabase/teacher-settings'; 6 | 7 | export const config = { 8 | runtime: 'edge', 9 | }; 10 | 11 | const handler = async (req: Request): Promise => { 12 | const userProfile = await fetchUserProfileWithAccessToken(req); 13 | if (!userProfile || !userProfile.isTeacherAccount) 14 | return unauthorizedResponse; 15 | 16 | return new Response( 17 | JSON.stringify({ 18 | settings: await getTeacherSettings(userProfile.id), 19 | }), 20 | { status: 200 }, 21 | ); 22 | }; 23 | export default handler; 24 | -------------------------------------------------------------------------------- /components/Files/RelativeTimeComponent.tsx: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'react-i18next'; 2 | 3 | import dayjs from 'dayjs'; 4 | import 'dayjs/locale/en'; 5 | import 'dayjs/locale/zh-cn'; 6 | import 'dayjs/locale/zh-tw'; 7 | 8 | const RelativeTimeComponent = ({ time }: { time: string }) => { 9 | const { i18n } = useTranslation(); 10 | 11 | switch (i18n.language) { 12 | case 'zh-Hant': 13 | case 'zh': 14 | return {dayjs(time).locale('zh-tw').fromNow()}; 15 | case 'zh-Hans': 16 | case 'cn': 17 | return {dayjs(time).locale('zh-cn').fromNow()}; 18 | default: 19 | return {dayjs(time).locale('en').fromNow()}; 20 | } 21 | }; 22 | 23 | export default RelativeTimeComponent; 24 | -------------------------------------------------------------------------------- /hooks/useHomeLoadingBar.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | 3 | import HomeContext from '@/components/home/home.context'; 4 | 5 | const useHomeLoadingBar = () => { 6 | const { startLoadingBar, completeLoadingBar } = useContext(HomeContext); 7 | const withLoading = async ( 8 | asyncFunction: (...args: A) => Promise, 9 | ...args: A 10 | ): Promise => { 11 | startLoadingBar(); 12 | try { 13 | const result = await asyncFunction(...args); 14 | return result; 15 | } catch (error) { 16 | throw error; 17 | } finally { 18 | completeLoadingBar(); 19 | } 20 | }; 21 | 22 | return { startLoadingBar, completeLoadingBar, withLoading }; 23 | }; 24 | 25 | export default useHomeLoadingBar; 26 | -------------------------------------------------------------------------------- /components/Features/TierTag.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from 'react'; 2 | 3 | interface Props { 4 | tier: string; 5 | } 6 | 7 | function TierTag({ tier }: Props) { 8 | const tierColor = useMemo(() => { 9 | switch (tier.toLowerCase()) { 10 | case 'free': 11 | return 'bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300'; 12 | case 'pro': 13 | return 'bg-blue-100 text-blue-800 dark:bg-blue-800 dark:text-blue-300'; 14 | default: 15 | return 'bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300'; 16 | } 17 | }, [tier]); 18 | 19 | return ( 20 | 21 | {tier} 22 | 23 | ); 24 | } 25 | 26 | export default TierTag; 27 | -------------------------------------------------------------------------------- /public/locales/zh-Hans/mjImage.json: -------------------------------------------------------------------------------- 1 | { 2 | "🪄 Make Variations": "🪄 创建不同的图像", 3 | "U1": "选择图片", 4 | "U2": "选择图片", 5 | "U3": "选择图片", 6 | "U4": "选择图片", 7 | "V1": "延伸变化", 8 | "V2": "延伸变化", 9 | "V3": "延伸变化", 10 | "V4": "延伸变化", 11 | "View Image": "打开图像", 12 | "Download Image": "下载图像", 13 | "Image processing... ": "图像处理中...", 14 | "Request expired, please click regenerate to retry": "请求已过期,请点击重新生成以重试", 15 | "QUEUED": "排队中", 16 | "FAILED": "失败", 17 | "COMPLETED": "完成", 18 | "PROCESSING": "处理中", 19 | "GENERATING": "生成中", 20 | "AI Image service is processing your request...": "AI Image service 正在处理您的请求...", 21 | "Enqueued At": "排队时间", 22 | "Enhancing your prompt...": "正在优化您的提示...", 23 | "Prompt used": "使用的提示词", 24 | "Queue Position": "排队位置" 25 | } 26 | -------------------------------------------------------------------------------- /public/locales/zh-Hant/mjImage.json: -------------------------------------------------------------------------------- 1 | { 2 | "🪄 Make Variations": "🪄 創建不同的圖像", 3 | "U1": "選擇圖像", 4 | "U2": "選擇圖像", 5 | "U3": "選擇圖像", 6 | "U4": "選擇圖像", 7 | "V1": "延伸變化", 8 | "V2": "延伸變化", 9 | "V3": "延伸變化", 10 | "V4": "延伸變化", 11 | "View Image": "查看圖像", 12 | "Download Image": "下載圖像", 13 | "Image processing... ": "圖像處理中...", 14 | "Request expired, please click regenerate to retry": "請求已過期,請點擊重新生成以重試", 15 | "QUEUED": "排隊中", 16 | "FAILED": "失敗", 17 | "COMPLETED": "完成", 18 | "PROCESSING": "處理中", 19 | "GENERATING": "生成中", 20 | "AI Image service is processing your request...": "AI Image service 正在處理您的請求...", 21 | "Enqueued At": "排隊時間", 22 | "Enhancing your prompt...": "正在優化您的提示...", 23 | "Prompt used": "使用的提示詞", 24 | "Queue Position": "排隊位置" 25 | } 26 | -------------------------------------------------------------------------------- /components/Files/TrashButton.tsx: -------------------------------------------------------------------------------- 1 | import { IconTrash } from '@tabler/icons-react'; 2 | import { useTranslation } from 'react-i18next'; 3 | 4 | import { useDeleteObject } from '@/hooks/file/useDeleteObject'; 5 | 6 | import { Button } from '../ui/button'; 7 | 8 | function TrashButton({ objectPath }: { objectPath: string }) { 9 | const { mutateAsync: deleteFile } = useDeleteObject(); 10 | const { t } = useTranslation('model'); 11 | return ( 12 | 23 | ); 24 | } 25 | 26 | export default TrashButton; 27 | -------------------------------------------------------------------------------- /hooks/useOrientation.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | const useOrientation = (): boolean | null => { 4 | const [landscape, setLandscape] = useState(null); 5 | 6 | useEffect(() => { 7 | const calculateOrientation = (): void => { 8 | setLandscape( 9 | typeof window !== 'undefined' && Math.abs(window.orientation) === 90, 10 | ); 11 | }; 12 | if (typeof window !== 'undefined') { 13 | calculateOrientation(); 14 | window.addEventListener('orientationchange', calculateOrientation); 15 | 16 | return () => { 17 | window.removeEventListener('orientationchange', calculateOrientation); 18 | }; 19 | } 20 | }, []); 21 | 22 | return landscape; 23 | }; 24 | export default useOrientation; 25 | -------------------------------------------------------------------------------- /components/Files/CustomUploadToast.tsx: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'react-i18next'; 2 | 3 | import { UploadProgress } from '../User/File/UploadProgress'; 4 | 5 | const CustomUploadToast = ({ 6 | fileName, 7 | progress, 8 | isSuccessUpload, 9 | }: { 10 | fileName: string; 11 | progress: number; 12 | isSuccessUpload: boolean | null; 13 | }) => { 14 | const { t } = useTranslation('model'); 15 | return ( 16 |
17 |
{`${t('Uploading')}: ${fileName}`}
18 |
19 | 23 |
24 |
25 | ); 26 | }; 27 | export default CustomUploadToast; 28 | -------------------------------------------------------------------------------- /components/Chatbar/components/ClearConversations.tsx: -------------------------------------------------------------------------------- 1 | import { IconTrash } from '@tabler/icons-react'; 2 | import type { FC } from 'react'; 3 | import { useContext } from 'react'; 4 | 5 | import { useTranslation } from 'next-i18next'; 6 | 7 | import { SidebarButton } from '@/components/Sidebar/SidebarButton'; 8 | import HomeContext from '@/components/home/home.context'; 9 | 10 | export const ClearConversations: FC = () => { 11 | const { dispatch } = useContext(HomeContext); 12 | 13 | const { t } = useTranslation('sidebar'); 14 | 15 | return ( 16 | } 19 | onClick={() => 20 | dispatch({ field: 'showClearConversationsModal', value: true }) 21 | } 22 | /> 23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /utils/server/stripe/handleCustomerSubscriptionDeleted.ts: -------------------------------------------------------------------------------- 1 | import getCustomerEmailByCustomerID from './getCustomerEmailByCustomerID'; 2 | import updateUserAccount from './updateUserAccount'; 3 | 4 | import type Stripe from 'stripe'; 5 | 6 | export default async function handleCustomerSubscriptionDeleted( 7 | session: Stripe.Subscription, 8 | ): Promise { 9 | const stripeSubscriptionId = session.id; 10 | 11 | if (!stripeSubscriptionId) { 12 | const customerId = session.customer as string; 13 | const email = await getCustomerEmailByCustomerID(customerId); 14 | await updateUserAccount({ 15 | upgrade: false, 16 | email, 17 | }); 18 | } else { 19 | await updateUserAccount({ 20 | upgrade: false, 21 | stripeSubscriptionId, 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /components/Chat/ChatLoader.tsx: -------------------------------------------------------------------------------- 1 | import { IconRobot } from '@tabler/icons-react'; 2 | import { IconDots } from '@tabler/icons-react'; 3 | import type { FC } from 'react'; 4 | 5 | interface Props {} 6 | 7 | export const ChatLoader: FC = () => { 8 | return ( 9 |
13 |
14 |
15 | 16 |
17 | 18 |
19 |
20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /components/Chat/components/ContinueChat.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useTranslation } from 'react-i18next'; 3 | 4 | import { getLastChunkOfText } from '@/utils/app/ui'; 5 | 6 | import { Button } from '@/components/ui/button'; 7 | 8 | const ContinueChat = ({ 9 | originalMessage, 10 | onContinue, 11 | }: { 12 | originalMessage: string; 13 | onContinue: (lastWords: string) => void; 14 | }) => { 15 | const { t } = useTranslation('common'); 16 | return ( 17 |
18 | 26 |
27 | ); 28 | }; 29 | 30 | export default ContinueChat; 31 | -------------------------------------------------------------------------------- /hooks/teacherPortal/useTeacherPortalLoading.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | 3 | import { TeacherPortalContext } from '@/components/TeacherPortal/teacher-portal.context'; 4 | 5 | const useTeacherPortalLoading = () => { 6 | const { startLoading, completeLoading } = useContext(TeacherPortalContext); 7 | const withLoading = async ( 8 | asyncFunction: (...args: A) => Promise, 9 | ...args: A 10 | ): Promise => { 11 | startLoading(); 12 | try { 13 | const result = await asyncFunction(...args); 14 | return result; 15 | } catch (error) { 16 | throw error; 17 | } finally { 18 | completeLoading(); 19 | } 20 | }; 21 | 22 | return { startLoading, completeLoading, withLoading }; 23 | }; 24 | 25 | export default useTeacherPortalLoading; 26 | -------------------------------------------------------------------------------- /docs/google_search.md: -------------------------------------------------------------------------------- 1 | # Google Search Tool 2 | 3 | Use the Google Search API to search the web in Chatbot UI. 4 | 5 | ## How To Enable 6 | 7 | 1. Create a new project at https://console.developers.google.com/apis/dashboard 8 | 9 | 2. Create a new API key at https://console.developers.google.com/apis/credentials 10 | 11 | 3. Enable the Custom Search API at https://console.developers.google.com/apis/library/customsearch.googleapis.com 12 | 13 | 4. Create a new Custom Search Engine at https://cse.google.com/cse/all 14 | 15 | 5. Add your API Key and your Custom Search Engine ID to your .env.local file 16 | 17 | 6. You can now select the Google Search Tool in the search tools dropdown 18 | 19 | ## Usage Limits 20 | 21 | Google gives you 100 free searches per day. You can increase this limit by creating a billing account. 22 | -------------------------------------------------------------------------------- /components/Chatbar/Chatbar.context.tsx: -------------------------------------------------------------------------------- 1 | import type { Dispatch } from 'react'; 2 | import { createContext } from 'react'; 3 | 4 | import type { ActionType } from '@/hooks/useCreateReducer'; 5 | 6 | import type { Conversation } from '@/types/chat'; 7 | import type { SupportedExportFormats } from '@/types/export'; 8 | 9 | import type { ChatbarInitialState } from './Chatbar.state'; 10 | 11 | export interface ChatbarContextProps { 12 | state: ChatbarInitialState; 13 | dispatch: Dispatch>; 14 | handleDeleteConversation: (conversation: Conversation) => void; 15 | handleExportData: () => void; 16 | handleImportConversations: (data: SupportedExportFormats) => void; 17 | } 18 | 19 | const ChatbarContext = createContext(undefined!); 20 | 21 | export default ChatbarContext; 22 | -------------------------------------------------------------------------------- /utils/server/stripe/getCustomerEmailByCustomerID.ts: -------------------------------------------------------------------------------- 1 | import Stripe from 'stripe'; 2 | 3 | export default async function getCustomerEmailByCustomerID( 4 | customerID: string, 5 | ): Promise { 6 | try { 7 | const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { 8 | apiVersion: '2022-11-15', 9 | }); 10 | 11 | // We get the customer id from webhook, so we know the customer is not deleted 12 | const customer = (await stripe.customers.retrieve( 13 | customerID, 14 | )) as Stripe.Customer; 15 | if (!customer.email) { 16 | throw new Error( 17 | `the customer does not have an email, customer id is ${customerID}`, 18 | ); 19 | } 20 | return customer.email; 21 | } catch (e) { 22 | throw new Error(`getCustomerEmailByCustomerID failed: ${e}`); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | import * as LabelPrimitive from '@radix-ui/react-label'; 2 | import * as React from 'react'; 3 | 4 | import { cn } from '@/lib/utils'; 5 | import { type VariantProps, cva } from 'class-variance-authority'; 6 | 7 | const labelVariants = cva( 8 | 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70', 9 | ); 10 | 11 | const Label = React.forwardRef< 12 | React.ElementRef, 13 | React.ComponentPropsWithoutRef & 14 | VariantProps 15 | >(({ className, ...props }, ref) => ( 16 | 21 | )); 22 | Label.displayName = LabelPrimitive.Root.displayName; 23 | 24 | export { Label }; 25 | -------------------------------------------------------------------------------- /hooks/v2Chat/use-copy-to-clipboard.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | 5 | export interface useCopyToClipboardProps { 6 | timeout?: number; 7 | } 8 | 9 | export function useCopyToClipboard({ 10 | timeout = 2000, 11 | }: useCopyToClipboardProps) { 12 | const [isCopied, setIsCopied] = React.useState(false); 13 | 14 | const copyToClipboard = (value: string) => { 15 | if (typeof window === 'undefined' || !navigator.clipboard?.writeText) { 16 | return; 17 | } 18 | 19 | if (!value) { 20 | return; 21 | } 22 | 23 | navigator.clipboard.writeText(value).then(() => { 24 | setIsCopied(true); 25 | 26 | setTimeout(() => { 27 | setIsCopied(false); 28 | }, timeout); 29 | }); 30 | }; 31 | 32 | return { isCopied, copyToClipboard }; 33 | } 34 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "crons": [ 3 | { 4 | "path": "/api/cron/update-referral-codes", 5 | "schedule": "0 * * * *" 6 | }, 7 | { 8 | "path": "/api/cron/delete-expired-temp-accounts-and-code", 9 | "schedule": "0 * * * *" 10 | }, 11 | { 12 | "path": "/api/cron/update-pro-accounts-plan", 13 | "schedule": "0 16 * * *" 14 | }, 15 | { 16 | "path": "/api/cron/clean-up-mj-processing-queue", 17 | "schedule": "*/5 * * * *" 18 | }, 19 | { 20 | "path": "/api/cron/clean-up-mj-completed-failed-job-info", 21 | "schedule": "0 0 * * 0" 22 | } 23 | ], 24 | "functions": { 25 | "pages/api/v2/**/*": { 26 | "maxDuration": 300 27 | }, 28 | "pages/api/mqtt/**/*": { 29 | "maxDuration": 120 30 | } 31 | }, 32 | "regions": ["icn1"] 33 | } 34 | -------------------------------------------------------------------------------- /components/v2Chat/empty-screen.tsx: -------------------------------------------------------------------------------- 1 | import { Badge } from './ui/badge'; 2 | 3 | export function EmptyScreen() { 4 | return ( 5 |
6 |
7 |
8 |

9 | Welcome to Chat Everywhere v2 10 |

11 | 12 | Beta 13 | 14 |
15 |

16 | This will be the new chat interface for Chat Everywhere. We are 17 | working on adding more features on the upcoming weeks. 18 |
19 |

20 |
21 |
22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /components/ui/default-toaster.tsx: -------------------------------------------------------------------------------- 1 | import { IconX } from '@tabler/icons-react'; 2 | import toast, { ToastBar, Toaster } from 'react-hot-toast'; 3 | 4 | const DefaultToaster = () => { 5 | return ( 6 | 7 | {(t) => ( 8 | 9 | {({ icon, message }) => ( 10 | <> 11 | {icon} 12 | {message} 13 | {t.className?.includes('toast-with-close-button') && ( 14 | 20 | )} 21 | 22 | )} 23 | 24 | )} 25 | 26 | ); 27 | }; 28 | export default DefaultToaster; 29 | -------------------------------------------------------------------------------- /supabase/migrations/20230724222753_create_conversations_table.sql: -------------------------------------------------------------------------------- 1 | create table "public"."conversations" ( 2 | "id" uuid not null, 3 | "created_at" timestamp with time zone default now(), 4 | "user_id" uuid not null, 5 | "content" jsonb not null default '{}'::jsonb 6 | ); 7 | 8 | 9 | alter table "public"."conversations" enable row level security; 10 | 11 | CREATE UNIQUE INDEX conversations_pkey ON public.conversations USING btree (id); 12 | 13 | alter table "public"."conversations" add constraint "conversations_pkey" PRIMARY KEY using index "conversations_pkey"; 14 | 15 | alter table "public"."conversations" add constraint "conversations_user_id_fkey" FOREIGN KEY (user_id) REFERENCES profiles(id) ON DELETE CASCADE not valid; 16 | 17 | alter table "public"."conversations" validate constraint "conversations_user_id_fkey"; 18 | 19 | 20 | -------------------------------------------------------------------------------- /hooks/useIsStreaming.ts: -------------------------------------------------------------------------------- 1 | import { useContext, useEffect } from 'react'; 2 | 3 | import type { MjJob } from '@/types/mjJob'; 4 | 5 | import HomeContext from '@/components/home/home.context'; 6 | 7 | const useIsStreaming = (job: MjJob) => { 8 | const { 9 | state: { messageIsStreaming }, 10 | dispatch: homeDispatch, 11 | } = useContext(HomeContext); 12 | useEffect(() => { 13 | if (job.status === 'PROCESSING' || job.status === 'QUEUED') { 14 | homeDispatch({ field: 'loading', value: true }); 15 | homeDispatch({ field: 'messageIsStreaming', value: true }); 16 | } else { 17 | homeDispatch({ field: 'loading', value: false }); 18 | homeDispatch({ field: 'messageIsStreaming', value: false }); 19 | } 20 | }, [homeDispatch, job]); 21 | return messageIsStreaming; 22 | }; 23 | 24 | export default useIsStreaming; 25 | -------------------------------------------------------------------------------- /supabase/migrations/20240215123357_update_student_message_submission_table.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."student_message_submissions" drop constraint "student_message_submissions_temporary_account_profile_id_fkey"; 2 | 3 | alter table "public"."student_message_submissions" add column "student_name" text not null default ''::text; 4 | 5 | alter table "public"."student_message_submissions" alter column "temporary_account_profile_id" drop not null; 6 | 7 | alter table "public"."student_message_submissions" add constraint "student_message_submissions_temporary_account_profile_id_fkey" FOREIGN KEY (temporary_account_profile_id) REFERENCES temporary_account_profiles(id) ON UPDATE CASCADE ON DELETE SET NULL not valid; 8 | 9 | alter table "public"."student_message_submissions" validate constraint "student_message_submissions_temporary_account_profile_id_fkey"; 10 | 11 | 12 | -------------------------------------------------------------------------------- /cypress/support/e2e.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/e2e.ts is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | // Import commands.js using ES2015 syntax: 16 | import './commands'; 17 | 18 | import 'cypress-real-events/support'; 19 | 20 | // Alternatively you can use CommonJS syntax: 21 | // require('./commands') 22 | require('cypress-terminal-report/src/installLogsCollector')(); 23 | -------------------------------------------------------------------------------- /supabase/migrations/20240210015418_add_get_temp_account_teacher_profile_func.sql: -------------------------------------------------------------------------------- 1 | set check_function_bodies = off; 2 | 3 | CREATE OR REPLACE FUNCTION public.get_temp_account_teacher_profile(p_profile_id uuid) 4 | RETURNS TABLE(profile_id uuid, temp_account_id bigint, code character varying, teacher_profile_id uuid) 5 | LANGUAGE plpgsql 6 | AS $function$ 7 | BEGIN 8 | RETURN QUERY 9 | SELECT 10 | profiles.id AS profile_id, 11 | temporary_account_profiles.id AS temp_account_id, 12 | one_time_codes.code, 13 | one_time_codes.teacher_profile_id 14 | FROM profiles 15 | JOIN temporary_account_profiles ON profiles.id = temporary_account_profiles.profile_id 16 | JOIN one_time_codes ON temporary_account_profiles.one_time_code_id = one_time_codes.id 17 | WHERE profiles.id = p_profile_id; 18 | END; 19 | $function$ 20 | ; 21 | 22 | 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "types": ["vitest/globals", "cypress", "node", "cypress-real-events"], 18 | "baseUrl": ".", 19 | "paths": { 20 | "@/*": ["./*"] 21 | } 22 | }, 23 | "include": [ 24 | "notion-compat.d.ts", 25 | "next-env.d.ts", 26 | "**/*.ts", 27 | "**/*.tsx", 28 | "utils/app/azureAppInsights.ts" 29 | ], 30 | "exclude": ["node_modules", "firebase"] 31 | } 32 | -------------------------------------------------------------------------------- /components/v2Chat/ui/label.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as LabelPrimitive from '@radix-ui/react-label'; 4 | import * as React from 'react'; 5 | 6 | import { cn } from '@/utils/v2Chat/utils'; 7 | 8 | import { type VariantProps, cva } from 'class-variance-authority'; 9 | 10 | const labelVariants = cva( 11 | 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70', 12 | ); 13 | 14 | const Label = React.forwardRef< 15 | React.ElementRef, 16 | React.ComponentPropsWithoutRef & 17 | VariantProps 18 | >(({ className, ...props }, ref) => ( 19 | 24 | )); 25 | Label.displayName = LabelPrimitive.Root.displayName; 26 | 27 | export { Label }; 28 | -------------------------------------------------------------------------------- /supabase/migrations/20230629084710_add_get_referees_profile_by_referrer_id_function.sql: -------------------------------------------------------------------------------- 1 | set check_function_bodies = off; 2 | 3 | CREATE OR REPLACE FUNCTION public.get_referees_profile_by_referrer_id(referrer uuid) 4 | RETURNS TABLE(id uuid, plan text, stripe_subscription_id text, pro_plan_expiration_date timestamp with time zone, referral_code character varying, referral_code_expiration_date timestamp with time zone, email text, referral_date timestamp with time zone) 5 | LANGUAGE plpgsql 6 | AS $function$ 7 | BEGIN 8 | RETURN QUERY 9 | SELECT P.id, P.plan, P.stripe_subscription_id, P.pro_plan_expiration_date, P.referral_code, P.referral_code_expiration_date, P.email, R.referral_date 10 | FROM public.profiles P 11 | INNER JOIN public.referral R ON P.id = R.referee_id 12 | WHERE R.referrer_id = referrer; 13 | END; 14 | $function$ 15 | ; 16 | 17 | 18 | -------------------------------------------------------------------------------- /supabase/migrations/20240226020313_add_func_set_tags_to_one_time_code.sql: -------------------------------------------------------------------------------- 1 | 2 | set check_function_bodies = off; 3 | 4 | CREATE OR REPLACE FUNCTION public.set_tags_to_one_time_code(one_time_code_id_param uuid, tag_ids_param integer[]) 5 | RETURNS boolean 6 | LANGUAGE plpgsql 7 | AS $function$ 8 | BEGIN 9 | -- Start a transaction block 10 | -- Delete existing tags for the one-time code 11 | DELETE FROM one_time_code_tags 12 | WHERE one_time_code_id = one_time_code_id_param; 13 | 14 | -- Insert new tags for the one-time code 15 | INSERT INTO one_time_code_tags (one_time_code_id, tag_id) 16 | SELECT one_time_code_id_param, UNNEST(tag_ids_param) 17 | ON CONFLICT DO NOTHING; 18 | 19 | RETURN TRUE; 20 | EXCEPTION 21 | WHEN OTHERS THEN 22 | -- In case of any exception, return false 23 | RETURN FALSE; 24 | END; 25 | $function$ 26 | ; 27 | -------------------------------------------------------------------------------- /pages/api/referral/get-code.ts: -------------------------------------------------------------------------------- 1 | import { getReferralCode, getUserProfile } from '@/utils/server/supabase'; 2 | 3 | export const config = { 4 | runtime: 'edge', 5 | }; 6 | 7 | const unauthorizedResponse = new Response('Unauthorized', { status: 401 }); 8 | 9 | const handler = async (req: Request): Promise => { 10 | try { 11 | const userId = req.headers.get('user-id'); 12 | if (!userId) return unauthorizedResponse; 13 | const userProfile = await getUserProfile(userId); 14 | 15 | if (!userProfile || userProfile.plan !== 'edu') return unauthorizedResponse; 16 | 17 | const { code, expiresAt } = await getReferralCode(userId); 18 | return new Response(JSON.stringify({ code, expiresAt }), { status: 200 }); 19 | } catch (error) { 20 | console.error(error); 21 | return new Response('Error', { status: 500 }); 22 | } 23 | }; 24 | 25 | export default handler; 26 | -------------------------------------------------------------------------------- /components/Voice/VoiceInputActiveOverlay.tsx: -------------------------------------------------------------------------------- 1 | import { useCognitiveService } from '../CognitiveService/CognitiveServiceProvider'; 2 | 3 | import { cn } from '@/lib/utils'; 4 | 5 | type VoiceInputActiveOverlayProps = { 6 | interactable?: boolean; 7 | }; 8 | 9 | const VoiceInputActiveOverlay = ({ 10 | interactable = false, 11 | }: VoiceInputActiveOverlayProps) => { 12 | const { isConversing, isSpeechRecognitionActive } = useCognitiveService(); 13 | 14 | if (!isConversing && !isSpeechRecognitionActive) return null; 15 | 16 | return ( 17 |
e.stopPropagation()} 23 | onClick={(e) => e.stopPropagation()} 24 | /> 25 | ); 26 | }; 27 | 28 | export default VoiceInputActiveOverlay; 29 | -------------------------------------------------------------------------------- /components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | import * as SeparatorPrimitive from '@radix-ui/react-separator'; 2 | import * as React from 'react'; 3 | 4 | import { cn } from '@/lib/utils'; 5 | 6 | const Separator = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >( 10 | ( 11 | { className, orientation = 'horizontal', decorative = true, ...props }, 12 | ref, 13 | ) => ( 14 | 25 | ), 26 | ); 27 | Separator.displayName = SeparatorPrimitive.Root.displayName; 28 | 29 | export { Separator }; 30 | -------------------------------------------------------------------------------- /pages/api/notion/[id].ts: -------------------------------------------------------------------------------- 1 | import type { NextApiRequest, NextApiResponse } from 'next'; 2 | 3 | import { NotionAPI } from 'notion-client'; 4 | 5 | export default async function handler( 6 | req: NextApiRequest, 7 | res: NextApiResponse, 8 | ) { 9 | if (req.method !== 'GET') { 10 | res.status(405).json({ message: 'Method not allowed' }); 11 | return; 12 | } 13 | 14 | const { id } = req.query; 15 | if (!id) { 16 | res.status(400).json({ message: 'Missing id' }); 17 | return; 18 | } 19 | 20 | const api = new NotionAPI(); 21 | try { 22 | const recordMap = await api.getPage(id as string); 23 | res.setHeader('Cache-Control', 's-maxage=3600, stale-while-revalidate'); 24 | res.status(200).json({ 25 | recordMap, 26 | }); 27 | } catch (error) { 28 | console.error(error); 29 | res.status(500).json({ message: 'Internal server error' }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /components/Hooks/useLogger.ts: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | 3 | import { event } from 'nextjs-google-analytics/dist/interactions'; 4 | 5 | import { getOrGenerateUserId } from '@/utils/data/taggingHelper'; 6 | 7 | import HomeContext from '@/components/home/home.context'; 8 | 9 | export const useLogger = () => { 10 | const { 11 | state: { user }, 12 | } = useContext(HomeContext); 13 | 14 | const logGeneralEvent = (eventName: string) => { 15 | // Fail silently to avoid impacting user experience 16 | try { 17 | let eventPayload = { 18 | category: 'Usages', 19 | userEmail: user?.email || 'N/A', 20 | user_type: user ? user?.plan : 'no-login', 21 | user_id: user ? user?.email : getOrGenerateUserId(), 22 | } as any; 23 | 24 | event(eventName, eventPayload); 25 | } catch (e) {} 26 | }; 27 | 28 | return { logGeneralEvent }; 29 | }; 30 | -------------------------------------------------------------------------------- /components/v2Chat/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { cn } from '@/utils/v2Chat/utils'; 4 | 5 | export interface TextareaProps 6 | extends React.TextareaHTMLAttributes {} 7 | 8 | const Textarea = React.forwardRef( 9 | ({ className, ...props }, ref) => { 10 | return ( 11 |