24 | {editing() && (
25 |
32 | )}
33 | {!editing() && value() && (
34 |
{value()}
35 | )}
36 | {!editing() && !value() && (
37 |
38 | )}
39 |
40 | )
41 | }
42 |
--------------------------------------------------------------------------------
/src/utils/auth.ts:
--------------------------------------------------------------------------------
1 | import { sha256 } from 'js-sha256'
2 | interface AuthPayload {
3 | t: number
4 | m: string
5 | }
6 |
7 | async function digestMessage(message: string) {
8 | if (typeof crypto !== 'undefined' && crypto?.subtle?.digest) {
9 | const msgUint8 = new TextEncoder().encode(message)
10 | const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8)
11 | const hashArray = Array.from(new Uint8Array(hashBuffer))
12 | return hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
13 | } else {
14 | return sha256(message).toString()
15 | }
16 | }
17 |
18 | export const generateSignature = async(payload: AuthPayload) => {
19 | const { t: timestamp, m: lastMessage } = payload
20 | const secretKey = import.meta.env.PUBLIC_SECRET_KEY as string || ''
21 | const signText = `${timestamp}:${lastMessage}:${secretKey}`
22 | // eslint-disable-next-line no-return-await
23 | return await digestMessage(signText)
24 | }
25 |
26 | export const verifySignature = async(payload: AuthPayload, sign: string) => {
27 | // if (Math.abs(payload.t - Date.now()) > 1000 * 60 * 5) {
28 | // return false
29 | // }
30 | const payloadSign = await generateSignature(payload)
31 | return payloadSign === sign
32 | }
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: 🚀 Feature request
2 | description: Suggest a feature or an improvement
3 | labels: ['enhancement']
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | ### Before submitting...
9 | Thank you for taking the time to fill out this feature request! Please confirm the following points before submitting:
10 |
11 | ✅ I have checked the feature was not already submitted by searching on GitHub under issues or discussions.
12 | ✅ Use English. This allows more people to search and participate in the issue.
13 | - type: textarea
14 | id: feature-description
15 | attributes:
16 | label: Describe the feature
17 | description: A clear and concise description of what you think would be a helpful addition.
18 | validations:
19 | required: true
20 | - type: textarea
21 | id: additional-context
22 | attributes:
23 | label: Additional context
24 | description: Any other context or screenshots about the feature request here.
25 | - type: checkboxes
26 | id: will-pr
27 | attributes:
28 | label: Participation
29 | options:
30 | - label: I am willing to submit a pull request for this feature.
31 | required: false
32 |
--------------------------------------------------------------------------------
/hack/docker-env-replace.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Your API Key for OpenAI
4 | gemini_api_key=$GEMINI_API_KEY
5 | # Provide proxy for OpenAI API. e.g. http://127.0.0.1:7890
6 | https_proxy=$HTTPS_PROXY
7 | # Custom base url for OpenAI API. default: https://api.openai.com
8 | openai_api_base_url=$OPENAI_API_BASE_URL
9 | # Inject analytics or other scripts before of the page
10 | head_scripts=$HEAD_SCRIPTS
11 | # Secret string for the project. Use for generating signatures for API calls
12 | public_secret_key=$PUBLIC_SECRET_KEY
13 | # Set password for site, support multiple password separated by comma. If not set, site will be public
14 | site_password=$SITE_PASSWORD
15 | # ID of the model to use. https://platform.openai.com/docs/api-reference/models/list
16 | openai_api_model=$OPENAI_API_MODEL
17 |
18 | for file in $(find ./dist -type f -name "*.mjs"); do
19 | sed "s|({}).GEMINI_API_KEY|\"$gemini_api_key\"|g;
20 | s|({}).HTTPS_PROXY|\"$https_proxy\"|g;
21 | s|({}).OPENAI_API_BASE_URL|\"$openai_api_base_url\"|g;
22 | s|({}).HEAD_SCRIPTS|\"$head_scripts\"|g;
23 | s|({}).PUBLIC_SECRET_KEY|\"$public_secret_key\"|g;
24 | s|({}).OPENAI_API_MODEL|\"$openai_api_model\"|g;
25 | s|({}).SITE_PASSWORD|\"$site_password\"|g" $file > tmp
26 | mv tmp $file
27 | done
28 |
29 | rm -rf tmp
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chatgpt-api-demo",
3 | "version": "0.0.1",
4 | "packageManager": "pnpm@7.28.0",
5 | "scripts": {
6 | "dev": "astro dev",
7 | "start": "astro dev",
8 | "build": "astro build",
9 | "build:vercel": "OUTPUT=vercel astro build",
10 | "build:netlify": "OUTPUT=netlify astro build",
11 | "preview": "astro preview",
12 | "astro": "astro",
13 | "lint": "eslint . --ext .js,.jsx,.ts,.tsx,.astro",
14 | "lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx,.astro --fix"
15 | },
16 | "dependencies": {
17 | "@astrojs/netlify": "2.3.0",
18 | "@astrojs/node": "^5.3.0",
19 | "@astrojs/solid-js": "^2.2.0",
20 | "@astrojs/vercel": "^3.5.0",
21 | "@fuyun/generative-ai": "0.1.1",
22 | "@zag-js/slider": "^0.16.0",
23 | "@zag-js/solid": "^0.16.0",
24 | "astro": "^2.7.0",
25 | "eslint": "^8.43.0",
26 | "eventsource-parser": "^1.0.0",
27 | "highlight.js": "^11.8.0",
28 | "js-sha256": "^0.9.0",
29 | "katex": "^0.16.7",
30 | "markdown-it": "^13.0.1",
31 | "markdown-it-highlightjs": "^4.0.1",
32 | "markdown-it-katex": "^2.0.3",
33 | "solid-js": "1.7.6",
34 | "solidjs-use": "^2.1.0",
35 | "undici": "^5.22.1"
36 | },
37 | "devDependencies": {
38 | "@evan-yang/eslint-config": "^1.0.9",
39 | "@iconify-json/carbon": "^1.1.18",
40 | "@types/markdown-it": "^12.2.3",
41 | "@typescript-eslint/parser": "^5.60.0",
42 | "@vite-pwa/astro": "^0.1.1",
43 | "eslint-plugin-astro": "^0.27.1",
44 | "punycode": "^2.3.0",
45 | "unocss": "^0.50.8"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bus_report_when_deploying.yml:
--------------------------------------------------------------------------------
1 | name: 🐞 Bug report (When self-deploying)
2 | description: Report an issue or possible bug when deploy to your own server or cloud.
3 | labels: ['pending triage', 'deploy']
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | ### Before submitting...
9 | Thanks for taking the time to fill out this bug report! Please confirm the following points before submitting:
10 |
11 | ✅ I am using **latest version of chatgpt-demo**.
12 | ✅ I have checked the bug was not already reported by searching on GitHub under issues.
13 | ✅ Use English to ask questions. This allows more people to search and participate in the issue.
14 | - type: dropdown
15 | id: server
16 | attributes:
17 | label: How is Gemini Pro Chat deployed?
18 | description: Select the used deployment method.
19 | options:
20 | - Node
21 | - Docker
22 | - Vercel
23 | - Netlify
24 | - Railway
25 | - Others (Specify in description)
26 | validations:
27 | required: true
28 | - type: textarea
29 | id: bug-description
30 | attributes:
31 | label: Describe the bug
32 | description: A clear and concise description of what the bug is.
33 | placeholder: Bug description
34 | validations:
35 | required: true
36 | - type: textarea
37 | id: console-logs
38 | attributes:
39 | label: Console Logs
40 | description: Please check your browser and node console, fill in the error message if it exists.
41 | - type: checkboxes
42 | id: will-pr
43 | attributes:
44 | label: Participation
45 | options:
46 | - label: I am willing to submit a pull request for this issue.
47 | required: false
--------------------------------------------------------------------------------
/src/components/Slider.tsx:
--------------------------------------------------------------------------------
1 | import * as slider from '@zag-js/slider'
2 | import { normalizeProps, useMachine } from '@zag-js/solid'
3 | import { createMemo, createUniqueId, mergeProps } from 'solid-js'
4 | import type { Accessor } from 'solid-js'
5 | import '../slider.css'
6 |
7 | interface Props {
8 | value: Accessor