├── .gitignore ├── README.md └── apps ├── functional_chat ├── .editorconfig ├── .env ├── .eslintrc.json ├── .lintstagedrc.mjs ├── .nvm ├── .prettierignore ├── .prettierrc ├── README.md ├── app │ ├── (routes) │ │ ├── layout.tsx │ │ └── page.tsx │ ├── components │ │ ├── chat │ │ │ ├── ChatInferenceModule.tsx │ │ │ ├── ChatScrollAnchor.tsx │ │ │ ├── CodeBlock.tsx │ │ │ ├── chat-actions.tsx │ │ │ ├── chat-avatar.tsx │ │ │ ├── chat-input.tsx │ │ │ ├── chat-message.tsx │ │ │ ├── chat-messages.tsx │ │ │ ├── chat.interface.ts │ │ │ ├── empty-llm-state.tsx │ │ │ ├── index.ts │ │ │ ├── markdown.tsx │ │ │ ├── toggle.tsx │ │ │ └── use-copy-to-clipboard.tsx │ │ ├── common │ │ │ ├── CodeBlock.tsx │ │ │ ├── code.module.css │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ └── ui │ │ │ ├── alert.tsx │ │ │ ├── button.tsx │ │ │ ├── card.tsx │ │ │ ├── form.tsx │ │ │ ├── input.tsx │ │ │ ├── label.tsx │ │ │ ├── select.tsx │ │ │ └── textarea.tsx │ ├── hooks │ │ ├── use-at-bottom.ts │ │ └── useAutosizeTextArea.ts │ ├── lib │ │ ├── cache.ts │ │ └── utils.ts │ └── styles │ │ ├── globals.css │ │ └── mdx.css ├── components.json ├── next-env.d.ts ├── next.config.js ├── package-lock.json ├── package.json ├── pages │ └── api │ │ ├── audio-transcription.ts │ │ ├── chatCompletion.ts │ │ ├── functionSpecs.ts │ │ ├── functions │ │ ├── flightPrices.ts │ │ ├── generateImage.ts │ │ ├── imageProcessing.ts │ │ ├── newsSearch.ts │ │ ├── popularDestinations.ts │ │ ├── renderChart.ts │ │ ├── stockQuote.ts │ │ ├── weatherHistory.ts │ │ └── webSearch.ts │ │ └── upload-image.ts ├── public │ ├── images │ │ ├── LogoWithName.svg │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ └── favicon.ico │ └── site.webmanifest ├── tailwind.config.js └── tsconfig.json ├── transcription_chat ├── .eslintrc.json ├── .gitignore ├── README.md ├── app │ ├── api │ │ └── qa │ │ │ └── route.ts │ ├── favicon.ico │ ├── globals.css │ ├── layout.tsx │ └── page.tsx ├── components.json ├── components │ ├── DocumentPicker.tsx │ ├── QASection.tsx │ └── ui │ │ ├── button.tsx │ │ ├── carousel.tsx │ │ └── input.tsx ├── lib │ └── utils.ts ├── next.config.mjs ├── package-lock.json ├── package.json ├── postcss.config.mjs ├── public │ ├── documents │ │ ├── MPRA-POA.pdf │ │ │ ├── 1.jpg │ │ │ └── 2.jpg │ │ ├── NY_State_DOH_1.pdf │ │ │ ├── 1.jpg │ │ │ ├── 10.jpg │ │ │ ├── 11.jpg │ │ │ ├── 12.jpg │ │ │ ├── 2.jpg │ │ │ ├── 3.jpg │ │ │ ├── 4.jpg │ │ │ ├── 5.jpg │ │ │ ├── 6.jpg │ │ │ ├── 7.jpg │ │ │ ├── 8.jpg │ │ │ └── 9.jpg │ │ └── brown-fd.pdf │ │ │ ├── 1.jpg │ │ │ ├── 10.jpg │ │ │ ├── 2.jpg │ │ │ ├── 3.jpg │ │ │ ├── 4.jpg │ │ │ ├── 5.jpg │ │ │ ├── 6.jpg │ │ │ ├── 7.jpg │ │ │ ├── 8.jpg │ │ │ └── 9.jpg │ ├── fireworks-logo.png │ ├── mongodb-logo.png │ ├── next.svg │ └── vercel.svg ├── tailwind.config.ts ├── tsconfig.json ├── utils │ └── api.ts └── yarn.lock └── transcription_demo ├── .env ├── .eslintrc.json ├── .gitignore ├── README.md ├── app ├── api │ └── transcribe │ │ └── route.ts ├── components │ ├── DocumentViewer.tsx │ ├── FileUpload.tsx │ ├── Fragment.tsx │ └── Page.tsx ├── favicon.ico ├── globals.css ├── layout.tsx ├── lib │ └── transcribe.ts ├── page.tsx └── types │ └── index.ts ├── next.config.ts ├── package-lock.json ├── package.json ├── postcss.config.js ├── postcss.config.mjs ├── public └── fireworks-ai-wordmark-color-dark.svg ├── tailwind.config.js └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env.development.local 77 | .env.test.local 78 | .env.production.local 79 | .env.local 80 | 81 | # parcel-bundler cache (https://parceljs.org/) 82 | .cache 83 | .parcel-cache 84 | 85 | # Next.js build output 86 | .next 87 | out 88 | 89 | # Nuxt.js build / generate output 90 | .nuxt 91 | dist 92 | 93 | # Gatsby files 94 | .cache/ 95 | # Comment in the public line in if your project uses Gatsby and not Next.js 96 | # https://nextjs.org/blog/next-9-1#public-directory-support 97 | # public 98 | 99 | # vuepress build output 100 | .vuepress/dist 101 | 102 | # vuepress v2.x temp and cache directory 103 | .temp 104 | .cache 105 | 106 | # Docusaurus cache and generated files 107 | .docusaurus 108 | 109 | # Serverless directories 110 | .serverless/ 111 | 112 | # FuseBox cache 113 | .fusebox/ 114 | 115 | # DynamoDB Local files 116 | .dynamodb/ 117 | 118 | # TernJS port file 119 | .tern-port 120 | 121 | # Stores VSCode versions used for testing VSCode extensions 122 | .vscode-test 123 | 124 | # yarn v2 125 | .yarn/cache 126 | .yarn/unplugged 127 | .yarn/build-state.yml 128 | .yarn/install-state.gz 129 | .pnp.* 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fireworks Demo Apps 2 | 3 | This repository contains demo apps illustrating the capabilities of large language and image models. Individual apps are self-contained and easy to expand. 4 | 5 | Have fun! 6 | 7 | ## List of apps ( :construction: more apps coming soon) 8 | 9 | - [Functional chat](https://github.com/fw-ai/forge/tree/main/apps/functional_chat) - an LLM powered chat with function calling capabilities. 10 | 11 | ## External apps leveraging Fireworks models 12 | 13 | - [VexaSearch](https://github.com/n4ze3m/vexasearch/tree/main) - a simple AI-powered search application designed to determine the actions to perform based on a function call. 14 | -------------------------------------------------------------------------------- /apps/functional_chat/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | indent_style = space 8 | trim_trailing_whitespace = true 9 | 10 | [*.{ts,js,json,yml}] 11 | indent_size = 2 12 | -------------------------------------------------------------------------------- /apps/functional_chat/.env: -------------------------------------------------------------------------------- 1 | # Global settings 2 | DEFAULT_CACHE_TTL_SEC=0 3 | 4 | # Functions 5 | ACTIVE_FUNCTIONS="generateImage,renderChart,stockQuote,newsSearch,imageProcessing" 6 | 7 | # Chat model 8 | # FIREWORKS_CHAT_MODEL="accounts/fireworks/models/firefunction-v1" 9 | FIREWORKS_CHAT_MODEL="accounts/fireworks/models/firefunction-v2" 10 | FIREWORKS_IMAGE_GEN_MODEL="accounts/fireworks/models/stable-diffusion-xl-1024-v1-0" 11 | FIREWORKS_VISION_MODEL="accounts/fireworks/models/llama-v3p2-11b-vision-instruct" 12 | 13 | # API keys 14 | FIREWORKS_API_KEY="set the key in .env.local" 15 | BING_SEARCH_KEY="set the key in .env.local" 16 | ALPHAVANTAGE_KEY="set the key in .env.local" 17 | TRAVELPAYOUTS_KEY="set the key in .env.local" 18 | RAPIDAPI_KEY="set the key in .env.local" 19 | VISUALCROSSING_KEY="set the key in .env.local" 20 | -------------------------------------------------------------------------------- /apps/functional_chat/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "project": [ 5 | "./tsconfig.json" 6 | ] 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "extends": [ 12 | "plugin:@next/next/recommended" 13 | ], 14 | "settings": { 15 | "next": { 16 | "rootDir": "." 17 | } 18 | }, 19 | "rules": { 20 | "import/unambiguous": "off", 21 | "import/no-default-export": "off", 22 | "promise/prefer-await-to-then": "off", 23 | "padding-line-between-statements": "off", 24 | "no-param-reassign": "off", 25 | "no-empty": "off", 26 | "class-methods-use-this": "off", 27 | "unicorn/no-null": "off", 28 | "import/extensions": "off", 29 | "import/no-unassigned-import": "off", 30 | "no-implicit-coercion": "off", 31 | "line-comment-position": "off", 32 | "no-inline-comments": "off", 33 | "camelcase": "off", 34 | "@typescript-eslint/prefer-nullish-coalescing": "off", 35 | "@typescript-eslint/no-unsafe-argument": "off", 36 | "@typescript-eslint/no-empty-interface": "warn", 37 | "@typescript-eslint/strict-boolean-expressions": "off", 38 | "@typescript-eslint/consistent-type-definitions": "off", 39 | "import/no-extraneous-dependencies": "off", 40 | "@typescript-eslint/no-floating-promises": "off", 41 | "@typescript-eslint/no-unnecessary-type-arguments": "off", 42 | "@typescript-eslint/no-unnecessary-condition": "off", 43 | "@typescript-eslint/no-explicit-any": "off", 44 | "@typescript-eslint/no-unsafe-assignment": "off", 45 | "@typescript-eslint/no-use-before-define": "off", 46 | "@typescript-eslint/no-unsafe-member-access": "off", 47 | "@typescript-eslint/no-unsafe-call": "off", 48 | "@typescript-eslint/no-unsafe-return": "off", 49 | "@typescript-eslint/non-nullable-type-assertion-style": "off", 50 | "@typescript-eslint/no-misused-promises": [ 51 | "error", 52 | { 53 | "checksVoidReturn": false 54 | } 55 | ] 56 | } 57 | } -------------------------------------------------------------------------------- /apps/functional_chat/.lintstagedrc.mjs: -------------------------------------------------------------------------------- 1 | const joinFileNames = (files) => files.map((name) => `"${name}"`).join(' '); 2 | 3 | export default { 4 | 'ts/**/*.ts?(x)': () => 'yarn ts:check:all', 5 | 'ts/**/*.{js,jsx,ts,tsx}': (files) => `yarn ts:lint:fix ${joinFileNames(files)}`, 6 | }; 7 | -------------------------------------------------------------------------------- /apps/functional_chat/.nvm: -------------------------------------------------------------------------------- 1 | v18.17.0 -------------------------------------------------------------------------------- /apps/functional_chat/.prettierignore: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------------------------------------------- 2 | # Keep this section in sync with .gitignore/.prettierignore 3 | #------------------------------------------------------------------------------------------------------------------- 4 | 5 | ## Python 6 | 7 | # Byte-compiled / optimized / DLL files 8 | __pycache__/ 9 | *.py[cod] 10 | *$py.class 11 | 12 | # C extensions 13 | *.so 14 | 15 | # Distribution / packaging 16 | .Python 17 | env/ 18 | develop-eggs/ 19 | dist/ 20 | downloads/ 21 | eggs/ 22 | .eggs/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | *.egg-info/ 29 | .installed.cfg 30 | *.egg 31 | out/ 32 | 33 | # PyInstaller 34 | # Usually these files are written by a python script from a template 35 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 36 | *.manifest 37 | *.spec 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | 43 | # Unit test / coverage reports 44 | htmlcov/ 45 | .tox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | .hypothesis/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | target/ 74 | 75 | # Jupyter Notebook 76 | .ipynb_checkpoints 77 | 78 | # pyenv 79 | .python-version 80 | 81 | # celery beat schedule file 82 | celerybeat-schedule 83 | 84 | # SageMath parsed files 85 | *.sage.py 86 | 87 | # virtualenv 88 | .venv 89 | venv/ 90 | ENV/ 91 | 92 | # Spyder project settings 93 | .spyderproject 94 | .spyproject 95 | 96 | # Rope project settings 97 | .ropeproject 98 | 99 | # mkdocs documentation 100 | /site 101 | 102 | # mypy 103 | .mypy_cache/ 104 | 105 | # yarn no zero-installs 106 | node_modules/ 107 | .pnp.* 108 | .yarn/* 109 | !.yarn/patches 110 | !.yarn/plugins 111 | !.yarn/releases 112 | !.yarn/sdks 113 | !.yarn/versions 114 | 115 | # macOS 116 | .DS_Store 117 | 118 | # ESLint 119 | .eslintcache 120 | 121 | # Typescript 122 | tsconfig.tsbuildinfo 123 | 124 | # NextJS 125 | .next 126 | ts/web/.vscode 127 | 128 | # Firebase cache 129 | .firebase/ 130 | .packages/ 131 | 132 | # vsix files 133 | *.vsix 134 | 135 | # Vercel 136 | .vercel 137 | 138 | #------------------------------------------------------------------------------------------------------------------- 139 | # Prettier-specific overrides 140 | #------------------------------------------------------------------------------------------------------------------- 141 | 142 | # Yarn files 143 | .yarn 144 | yarn.lock 145 | .yarnrc.yml 146 | 147 | # Generated 148 | ts/protos/ 149 | 150 | # Directories not to be formatted 151 | fireworks-protos/ 152 | flint-instrumentation/ 153 | flint-lsp-router/ 154 | flint-protos/ 155 | worker-vscode-extension/ 156 | -------------------------------------------------------------------------------- /apps/functional_chat/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "singleQuote": true, 4 | "trailingComma": "all" 5 | } 6 | -------------------------------------------------------------------------------- /apps/functional_chat/README.md: -------------------------------------------------------------------------------- 1 | # Functional Chat Demo App ( :rocket: [Try it!](http://functional-chat.fireworks.ai)) 2 | 3 | https://github.com/fw-ai/forge/assets/5000576/ce83463e-e898-46a9-9e84-d13d4a12d474 4 | 5 | ## Quick start 6 | 7 | If you need to install Node.js, follow [these instructions](https://github.com/fw-ai/forge/tree/main/apps/functional_chat#configuring-the-environment). 8 | 9 | Install the dependencies: 10 | ```bash 11 | npm install 12 | ``` 13 | 14 | Either edit `.env` or create a new file called `.env.local` (recommended) with api keys to the services you want to call. 15 | 16 | Run the server in dev mode: 17 | ```bash 18 | npm run dev 19 | ``` 20 | 21 | ## Capabilities 22 | 23 | A simple chat with function calling. Functions can perform tasks that typically involve calling external services. An LLM interprets user messages and decides which function to call and with what parameter values. The model is capable of multi-turn conversations combining the output from multiple functions, refining the calls based on additional instructions and making new calls with parameter values extracted from other function output. 24 | 25 | ## Included functions 26 | 27 | The demo app includes the following functions (new functions are easy to add - see the next section): 28 | - image generation with an SDXL model, 29 | - getting stock quotes curtesy of [alphavantage](https://www.alphavantage.co/), 30 | - charting datasets with chart.js curtesy of [quickchart](https://quickchart.io). 31 | 32 | ## Adding a new function 33 | 34 | To add a new function to the chat follow these steps: 35 | 1. Create a file under [functions](https://github.com/fw-ai/forge/tree/main/apps/functional_chat/pages/api/functions) directory. By convention, the file name follows the function name, 36 | 2. Implement a `handler` that supports `spec` and `call` query actions. `spec` should return the description of the function parameters in [`json_schema`](https://json-schema.org/) format. `call` performs the function call - often times invoking an external API - and returns the responses in a descriptive format (typically JSON). There are several function spec and call [examples](https://github.com/fw-ai/forge/tree/main/apps/functional_chat/pages/api/functions) that you can copy and modify based on your needs. 37 | 3. Include the name of the newly added function in the [`ACTIVE_FUNCTIONS`](https://github.com/fw-ai/forge/blob/main/apps/functional_chat/.env) environment variable. 38 | 4. Redeploy your app and have fun! 39 | 40 | ## Configuring the environment 41 | 42 | If you are starting from scratch, here are the steps to follow to set up a Node.js on your host: 43 | 44 | 1. [Install](https://github.com/nvm-sh/nvm#installing-and-updating) Node Version Manager (nvm) 45 | 46 | 2. Install the latest Node.js: 47 | ```bash 48 | nvm install stable 49 | ``` 50 | 51 | 3. Optional: to make this version your default version, run the following: 52 | ```bash 53 | nvm alias default stable 54 | ``` 55 | 56 | 4. Optional: To check what version of Node.js that you're running, run the following: 57 | ```bash 58 | node -v 59 | ``` 60 | -------------------------------------------------------------------------------- /apps/functional_chat/app/(routes)/layout.tsx: -------------------------------------------------------------------------------- 1 | import '~/styles/globals.css'; 2 | 3 | export interface RootLayoutProps { 4 | readonly children: React.ReactNode; 5 | } 6 | export default async function RootLayout({ children }: RootLayoutProps) { 7 | return ( 8 | 9 | 10 | 11 | 12 | 13 | {children} 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /apps/functional_chat/app/(routes)/page.tsx: -------------------------------------------------------------------------------- 1 | import { ChatInferenceModule } from '~/components/chat/ChatInferenceModule'; 2 | /* eslint camelcase: 0 */ 3 | import { cn } from '~/lib/utils'; 4 | 5 | // eslint-disable-next-line complexity 6 | export default async function Page() { 7 | return ( 8 | <> 9 |
10 |
11 |
12 |
13 | 14 |
15 |
16 |
17 |
18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /apps/functional_chat/app/components/chat/ChatScrollAnchor.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | 5 | import { useInView } from 'react-intersection-observer'; 6 | import { useAtBottom } from '~/hooks/use-at-bottom'; 7 | 8 | interface ChatScrollAnchorProps { 9 | trackVisibility?: boolean; 10 | } 11 | 12 | export function ChatScrollAnchor({ trackVisibility }: ChatScrollAnchorProps) { 13 | const isAtBottom = useAtBottom(); 14 | const { ref, entry, inView } = useInView({ 15 | trackVisibility, 16 | delay: 100, 17 | rootMargin: '0px 0px -150px 0px', 18 | }); 19 | 20 | React.useEffect(() => { 21 | if (isAtBottom && trackVisibility && !inView) { 22 | entry?.target.scrollIntoView({ 23 | block: 'start', 24 | }); 25 | } 26 | }, [inView, entry, isAtBottom, trackVisibility]); 27 | 28 | return
; 29 | } 30 | -------------------------------------------------------------------------------- /apps/functional_chat/app/components/chat/CodeBlock.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React, { 4 | FC, 5 | memo, 6 | useState, 7 | } from 'react'; 8 | 9 | import { 10 | CheckIcon, 11 | CopyIcon, 12 | EyeClosedIcon, 13 | EyeOpenIcon, 14 | } from '@radix-ui/react-icons'; 15 | 16 | import { Button } from '../ui/button'; 17 | import { useCopyToClipboard } from './use-copy-to-clipboard'; 18 | 19 | import SyntaxHighlighter from 'react-syntax-highlighter'; 20 | import { atelierDuneLight } from 'react-syntax-highlighter/dist/esm/styles/hljs'; 21 | 22 | interface Props { 23 | language: string; 24 | value: string; 25 | copyValue?: string; 26 | apiKeyToHide?: string; 27 | header?: boolean; 28 | showLineNumbers?: boolean; 29 | } 30 | 31 | type languageMap = Record; 32 | 33 | export const programmingLanguages: languageMap = { 34 | javascript: '.js', 35 | python: '.py', 36 | java: '.java', 37 | c: '.c', 38 | cpp: '.cpp', 39 | 'c++': '.cpp', 40 | 'c#': '.cs', 41 | ruby: '.rb', 42 | php: '.php', 43 | swift: '.swift', 44 | 'objective-c': '.m', 45 | kotlin: '.kt', 46 | typescript: '.ts', 47 | go: '.go', 48 | perl: '.pl', 49 | rust: '.rs', 50 | scala: '.scala', 51 | haskell: '.hs', 52 | lua: '.lua', 53 | shell: '.sh', 54 | sql: '.sql', 55 | html: '.html', 56 | css: '.css', 57 | // add more file extensions here, make sure the key is same as language prop in CodeBlock.tsx component 58 | }; 59 | 60 | export const generateRandomString = (length: number, lowercase = false) => { 61 | // excluding similar looking characters like Z, 2, I, 1, O, 0 62 | const chars = 'ABCDEFGHJKLMNPQRSTUVWXY3456789'; 63 | let result = ''; 64 | // eslint-disable-next-line no-plusplus 65 | for (let i = 0; i < length; i++) { 66 | result += chars.charAt(Math.floor(Math.random() * chars.length)); 67 | } 68 | return lowercase ? result.toLowerCase() : result; 69 | }; 70 | 71 | const CodeBlock: FC = memo(({ language, value, copyValue, apiKeyToHide, header = true, showLineNumbers = true }) => { 72 | const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 }); 73 | const [showAPIKey, setShowAPIKey] = useState(false); 74 | const onCopy = () => { 75 | if (isCopied) return; 76 | copyToClipboard(copyValue || value); 77 | }; 78 | 79 | const showHideAPIKey = () => { 80 | setShowAPIKey(!showAPIKey); 81 | }; 82 | 83 | return ( 84 |
85 | {header ? ( 86 |
87 | {language} 88 |
89 | {apiKeyToHide ? ( 90 | 94 | ) : null} 95 | 99 |
100 |
101 | ) : null} 102 | 125 | {apiKeyToHide && !showAPIKey ? value.replace(apiKeyToHide, '*'.repeat(apiKeyToHide.length)) : value} 126 | 127 |
128 | ); 129 | }); 130 | CodeBlock.displayName = 'CodeBlock'; 131 | 132 | export { CodeBlock }; 133 | -------------------------------------------------------------------------------- /apps/functional_chat/app/components/chat/chat-actions.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | PauseIcon, 3 | ReloadIcon, 4 | } from '@radix-ui/react-icons'; 5 | 6 | import { Button } from '../ui/button'; 7 | import { ChatHandler } from './chat.interface'; 8 | 9 | export default function ChatActions( 10 | props: Pick & { 11 | showReload?: boolean; 12 | showStop?: boolean; 13 | }, 14 | ) { 15 | return ( 16 |
17 | {props.showStop && ( 18 | 22 | )} 23 | {props.showReload && ( 24 | 28 | )} 29 |
30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /apps/functional_chat/app/components/chat/chat-avatar.tsx: -------------------------------------------------------------------------------- 1 | import { FaRobot } from "react-icons/fa"; 2 | import { FaUser } from "react-icons/fa"; 3 | 4 | export default function ChatAvatar({ role }: { role: string }) { 5 | if (role === "user") { 6 | return ( 7 |
8 | 9 |
10 | ); 11 | } 12 | 13 | return ( 14 |
15 | 16 |
17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /apps/functional_chat/app/components/chat/chat-input.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | useRef, 3 | useState, 4 | } from 'react'; 5 | 6 | import { useAutosizeTextArea } from '~/hooks/useAutosizeTextArea'; 7 | 8 | import { PaperPlaneIcon } from '@radix-ui/react-icons'; 9 | 10 | import { Button } from '../ui/button'; 11 | import { Textarea } from '../ui/textarea'; 12 | 13 | export default function ChatInput(props: { 14 | onSubmit: (text: string, base64Files?: string[]) => void; 15 | multiModal?: boolean; 16 | isLoading?: boolean; 17 | onFileUpload?: (file: File) => void; 18 | onFileError?: (error: string) => void; 19 | }) { 20 | const [imageUrl, setImageUrl] = useState(null); 21 | const [value, setValue] = useState(''); 22 | const textAreaRef = useRef(null); 23 | 24 | useAutosizeTextArea(textAreaRef.current, value); 25 | 26 | const handleChange = (evt: React.ChangeEvent) => { 27 | const val = evt.target?.value; 28 | 29 | setValue(val); 30 | }; 31 | 32 | const onSubmit = (e: React.FormEvent) => { 33 | e.preventDefault(); 34 | const message = e.currentTarget.elements.namedItem('message') as HTMLInputElement; 35 | if (imageUrl) { 36 | props.onSubmit(message.value, [imageUrl]); 37 | setImageUrl(null); 38 | setValue(''); 39 | return; 40 | } 41 | props.onSubmit(message.value); 42 | setTimeout(() => { 43 | setValue(''); 44 | }, 10); 45 | }; 46 | 47 | const handleKeyDown = (event: React.KeyboardEvent) => { 48 | // ignore if the user is using IME 49 | if (event.nativeEvent.isComposing || event.keyCode === 229) { 50 | return; 51 | } 52 | // Prevents adding a new line 53 | 54 | if ( 55 | ((event.which || event.keyCode) === 13 || event.key === 'Enter') && 56 | !event.shiftKey && 57 | !event.altKey && 58 | !event.ctrlKey && 59 | !event.metaKey 60 | ) { 61 | event.currentTarget.form?.requestSubmit(); 62 | } else if (event.key === 'Enter') { 63 | // Adds a new line 64 | setValue(`${value}`); 65 | } else { 66 | setValue(event.currentTarget.value); 67 | } 68 | }; 69 | 70 | return ( 71 |
75 |
76 |