github-actions[bot] commited on
Commit
913d114
·
0 Parent(s):

GitHub deploy: fe3a9c4cecbd9cba7d18b8a7c1f8af7c90bed87d

Browse files
.gitattributes ADDED
@@ -0,0 +1 @@
 
 
1
+ *.ttf filter=lfs diff=lfs merge=lfs -text
.github/PULL_REQUEST_TEMPLATE.md ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!--
2
+ ### Free SaaS Offering Submission
3
+
4
+ Thank you for contributing to this list. This list is for **SaaS**
5
+ services that offer a **free tier** to help developers evaluate and
6
+ build something that users can later use and get support for.
7
+
8
+ The focus of this list is quite broad but we try to keep things
9
+ limited to that which infrastructure developers, like DevOps Practitioners,
10
+ would find useful.
11
+
12
+ This list is the result of more than a thousand people contributing
13
+ to make something useful, we appreciate your efforts.
14
+
15
+ ### Code of Conduct
16
+
17
+ We are not here to argue with you. If you are argumentative, abusive,
18
+ lie or missrepresent your service or are otherwise anti-social we will
19
+ block you.
20
+
21
+ ### Services we do not accept
22
+
23
+ * cPanel like PHP + MySQL hosting services.
24
+ * Free dns services that are generic frontends to CloudFlare or similar
25
+ * Services that are verbatim copy pastes of others while adding no value
26
+ * Fake / Temporary / Ephemeral email generators, we have enough of those
27
+ -->
28
+
29
+ ## Requirements
30
+
31
+ <!-- This is only for new submissions -->
32
+ <!-- Please ensure your submission ticks all of the requirements -->
33
+
34
+ * [ ] This is Software as a Service not self hosted
35
+ * [ ] It has a free tier not just a free trial
36
+ * [ ] Pricing information is clearly visible without signup or phone calls
37
+ * [ ] The submission mentions what is free
38
+ * [ ] The submission is not already present in the list
39
+ * [ ] The service has contact details of those running it and a privacy policy
.github/workflows/deploy-to-hf-spaces.yml ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: 部署到抱抱脸空间
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - dev
7
+ - main
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ check-secret:
12
+ runs-on: ubuntu-latest
13
+ outputs:
14
+ token-set: ${{ steps.check-key.outputs.defined }}
15
+ steps:
16
+ - id: check-key
17
+ env:
18
+ HF_TOKEN: ${{ secrets.HF_TOKEN }}
19
+ if: "${{ env.HF_TOKEN != '' }}"
20
+ run: echo "defined=true" >> $GITHUB_OUTPUT
21
+
22
+ deploy:
23
+ runs-on: ubuntu-latest
24
+ needs: [check-secret]
25
+ if: needs.check-secret.outputs.token-set == 'true'
26
+ env:
27
+ HF_TOKEN: ${{ secrets.HF_TOKEN }}
28
+ HF_REPO: ${{ secrets.HF_REPO }}
29
+ HF_USER: ${{ secrets.HF_USER }}
30
+ steps:
31
+ - name: 检测仓库
32
+ uses: actions/checkout@v4
33
+
34
+ - name: 移除git历史记录
35
+ run: rm -rf .git
36
+
37
+ - name: 将YAML前言添加到README.md中
38
+ run: |
39
+ echo "---" > temp_readme.md
40
+ echo "title: Free For Dev" >> temp_readme.md
41
+ echo "emoji: 🐳" >> temp_readme.md
42
+ echo "colorFrom: purple" >> temp_readme.md
43
+ echo "colorTo: gray" >> temp_readme.md
44
+ echo "sdk: docker" >> temp_readme.md
45
+ echo "app_port: 8080" >> temp_readme.md
46
+ echo "---" >> temp_readme.md
47
+ cat README.md >> temp_readme.md
48
+ mv temp_readme.md README.md
49
+
50
+ - name: 配置git
51
+ run: |
52
+ git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
53
+ git config --global user.name "github-actions[bot]"
54
+ - name: 设置Git并推送到空间
55
+ run: |
56
+ git init --initial-branch=main
57
+ git lfs track "*.ttf"
58
+ git add .
59
+ git commit -m "GitHub deploy: ${{ github.sha }}"
60
+ git push --force https://${HF_USER}:${HF_TOKEN}@huggingface.co/spaces/${HF_USER}/${HF_REPO} main
.github/workflows/docker-image.yml ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: 构建并推送Docker镜像
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
10
+ workflow_dispatch:
11
+
12
+ jobs:
13
+ build:
14
+ runs-on: ubuntu-latest
15
+
16
+ steps:
17
+ - name: 检出代码
18
+ uses: actions/checkout@v3
19
+
20
+ - name: 登录到GitHub容器注册表
21
+ uses: docker/login-action@v2
22
+ with:
23
+ registry: ghcr.io
24
+ username: ${{ github.actor }}
25
+ password: ${{ secrets.GITHUB_TOKEN }}
26
+
27
+ - name: 设置小写的用户名和仓库名称
28
+ run: |
29
+ REPO_FULL_NAME=${{ github.repository }}
30
+ REPO_OWNER=$(echo "${REPO_FULL_NAME}" | cut -d'/' -f1 | tr '[:upper:]' '[:lower:]')
31
+ REPO_NAME=$(echo "${REPO_FULL_NAME}" | cut -d'/' -f2 | tr '[:upper:]' '[:lower:]')
32
+ echo "REPO_NAME_LOWER=${REPO_OWNER}/${REPO_NAME}" >> $GITHUB_ENV
33
+
34
+ - name: 构建Docker镜像
35
+ run: |
36
+ docker build . -t ghcr.io/$REPO_NAME_LOWER:latest
37
+ shell: bash
38
+
39
+ - name: 推送Docker镜像
40
+ run: |
41
+ docker push ghcr.io/$REPO_NAME_LOWER:latest
42
+ shell: bash
.github/workflows/translate-readme.yml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Translate README
2
+ # 注意需要推送..所以要开启写入权限 Settings -> Actions -> General -> Workflow permissions:Read and write permissions
3
+
4
+ on:
5
+ workflow_dispatch:
6
+ schedule:
7
+ - cron: '0 1 * * 1' # 每周运行
8
+
9
+ jobs:
10
+ translate:
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - name: Checkout code
15
+ uses: actions/checkout@v4
16
+ with:
17
+ token: ${{ secrets.GITHUB_TOKEN }}
18
+
19
+ - name: Clone ripienaar/free-for-dev
20
+ run: |
21
+ git clone https://github.com/zhezzma/free-for-dev-cn.git free-for-dev
22
+
23
+ - name: Setup Node.js
24
+ uses: actions/setup-node@v4
25
+ with:
26
+ node-version: '18'
27
+
28
+ - name: Install dependencies
29
+ run: |
30
+ npm install
31
+
32
+ - name: Commit and push if changed
33
+ env:
34
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
35
+ run: |
36
+ git config --local user.email "[email protected]"
37
+ git config --local user.name "GitHub Action"
38
+ git add README.md
39
+ git commit -m "Update README.md" || echo "No changes to commit"
40
+ git push
.gitignore ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
77
+ .env.development.local
78
+ .env.test.local
79
+ .env.production.local
80
+ .env.local
81
+
82
+ # parcel-bundler cache (https://parceljs.org/)
83
+ .cache
84
+ .parcel-cache
85
+
86
+ # Next.js build output
87
+ .next
88
+ out
89
+
90
+ # Nuxt.js build / generate output
91
+ .nuxt
92
+ dist
93
+
94
+ # Gatsby files
95
+ .cache/
96
+ # Comment in the public line in if your project uses Gatsby and not Next.js
97
+ # https://nextjs.org/blog/next-9-1#public-directory-support
98
+ # public
99
+
100
+ # vuepress build output
101
+ .vuepress/dist
102
+
103
+ # vuepress v2.x temp and cache directory
104
+ .temp
105
+ .cache
106
+
107
+ # Docusaurus cache and generated files
108
+ .docusaurus
109
+
110
+ # Serverless directories
111
+ .serverless/
112
+
113
+ # FuseBox cache
114
+ .fusebox/
115
+
116
+ # DynamoDB Local files
117
+ .dynamodb/
118
+
119
+ # TernJS port file
120
+ .tern-port
121
+
122
+ # Stores VSCode versions used for testing VSCode extensions
123
+ .vscode-test
124
+
125
+ # yarn v2
126
+ .yarn/cache
127
+ .yarn/unplugged
128
+ .yarn/build-state.yml
129
+ .yarn/install-state.gz
130
+ .pnp.*
131
+
132
+
133
+ # app
134
+ free-for-dev
.htaccess ADDED
@@ -0,0 +1 @@
 
 
1
+
.vscode/launch.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": "0.2.0",
3
+ "configurations": [
4
+ {
5
+ "type": "node",
6
+ "request": "launch",
7
+ "name": "test",
8
+ "runtimeExecutable": "npm",
9
+ "runtimeArgs": [
10
+ "run",
11
+ "test"
12
+ ],
13
+ "console": "internalConsole",
14
+ "internalConsoleOptions": "neverOpen",
15
+ }
16
+ ]
17
+ }
Dockerfile ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM php:8.3-apache
2
+
3
+ RUN a2enmod rewrite
4
+
5
+ RUN sed -i 's/Listen 80/Listen 8080/' /etc/apache2/ports.conf && \
6
+ sed -i 's/:80>/:8080>/' /etc/apache2/sites-available/000-default.conf
7
+
8
+ RUN echo '<Directory /var/www/html>\n\
9
+ AllowOverride All\n\
10
+ </Directory>' >> /etc/apache2/sites-available/000-default.conf
11
+
12
+ RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
13
+
14
+ WORKDIR /var/www/html
15
+
16
+ COPY . /var/www/html
17
+
18
+ RUN chmod -R 777 /var/www/html
19
+
20
+ COPY .htaccess /var/www/html/.htaccess
21
+
22
+ EXPOSE 8080
23
+
24
+ CMD ["apache2-foreground"]
README.md ADDED
The diff for this file is too large to render. See raw diff
 
index.html ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <meta charset="UTF-8">
7
+
8
+ <!-- HTML Meta Tags -->
9
+ <title>Free for Developers</title>
10
+ <meta name="description" content="Developers and Open Source authors now have a massive amount of services offering free tiers, but it can be hard to find them all to make informed decisions.">
11
+
12
+ <!-- Google / Search Engine Tags -->
13
+ <meta itemprop="name" content="Free for Developers">
14
+ <meta itemprop="description" content="Developers and Open Source authors now have a massive amount of services offering free tiers, but it can be hard to find them all to make informed decisions.">
15
+ <meta itemprop="image" content="https://raw.githubusercontent.com/foss-android/free-for-dev-cn/main/logo.webp">
16
+
17
+ <!-- Facebook Meta Tags -->
18
+ <meta property="og:url" content="https://free-for.dev">
19
+ <meta property="og:type" content="website">
20
+ <meta property="og:title" content="Free for Developers">
21
+ <meta property="og:description" content="Developers and Open Source authors now have a massive amount of services offering free tiers, but it can be hard to find them all to make informed decisions.">
22
+ <meta property="og:image" content="https://raw.githubusercontent.com/foss-android/free-for-dev-cn/main/logo.webp">
23
+
24
+ <!-- Twitter Meta Tags -->
25
+ <meta name="twitter:card" content="summary_large_image">
26
+ <meta name="twitter:title" content="Free for Developers">
27
+ <meta name="twitter:description" content="Developers and Open Source authors now have a massive amount of services offering free tiers, but it can be hard to find them all to make informed decisions.">
28
+ <meta name="twitter:image" content="https://raw.githubusercontent.com/foss-android/free-for-dev-cn/main/logo.webp">
29
+
30
+ <!-- Stylesheets -->
31
+ <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/themes/vue.css">
32
+ <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify-darklight-theme@latest/dist/style.min.css" title="docsify-darklight-theme" type="text/css">
33
+
34
+ <!-- Favicon -->
35
+ <link rel="icon" href="logo.webp" type="image/gif">
36
+
37
+ <!-- Google Analytics -->
38
+ <script async src="https://www.googletagmanager.com/gtag/js?id=G-DLYKZXPL9J"></script>
39
+ <script>
40
+ window.dataLayer = window.dataLayer || [];
41
+ function gtag(){dataLayer.push(arguments);}
42
+ gtag('js', new Date());
43
+
44
+ gtag('config', 'G-DLYKZXPL9J');
45
+ </script>
46
+ </head>
47
+
48
+ <body>
49
+ <noscript>This page requires JavaScript to work, please enable it or read <a href="https://github.com/foss-android/free-for-dev-cn">here</a>.</noscript>
50
+
51
+ <div id="app">Loading...</div>
52
+
53
+ <script>
54
+ window.$docsify = {
55
+ name: "Free for Developers",
56
+ repo: "zhezzma/free-for-dev-cn",
57
+ search: ["/"],
58
+ darklightTheme: {
59
+ siteFont : "Source Sans Pro, Helvetica Neue",
60
+ defaultTheme : "light",
61
+ codeFontFamily : "Roboto Mono, Monaco, courier, monospace",
62
+ bodyFontSize: "15px"
63
+ }
64
+ }
65
+ </script>
66
+
67
+ <script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
68
+ <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
69
+ <script src="//cdn.jsdelivr.net/npm/docsify-darklight-theme@latest/dist/index.min.js" type="text/javascript"></script>
70
+
71
+ <style>
72
+ blockquote:first-of-type {
73
+ background-color: rgba(235, 248, 242, 0.363);
74
+ }
75
+ </style>
76
+ </body>
77
+ </html>
logo.webp ADDED
package-lock.json ADDED
@@ -0,0 +1,494 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "free-for-dev-cn",
3
+ "version": "1.0.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "free-for-dev-cn",
9
+ "version": "1.0.0",
10
+ "license": "ISC",
11
+ "dependencies": {
12
+ "dotenv": "^16.4.5",
13
+ "openai": "^4.61.0"
14
+ }
15
+ },
16
+ "node_modules/@types/node": {
17
+ "version": "18.19.50",
18
+ "resolved": "https://registry.npmmirror.com/@types/node/-/node-18.19.50.tgz",
19
+ "integrity": "sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==",
20
+ "license": "MIT",
21
+ "dependencies": {
22
+ "undici-types": "~5.26.4"
23
+ }
24
+ },
25
+ "node_modules/@types/node-fetch": {
26
+ "version": "2.6.11",
27
+ "resolved": "https://registry.npmmirror.com/@types/node-fetch/-/node-fetch-2.6.11.tgz",
28
+ "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==",
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "@types/node": "*",
32
+ "form-data": "^4.0.0"
33
+ }
34
+ },
35
+ "node_modules/@types/qs": {
36
+ "version": "6.9.16",
37
+ "resolved": "https://registry.npmmirror.com/@types/qs/-/qs-6.9.16.tgz",
38
+ "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==",
39
+ "license": "MIT"
40
+ },
41
+ "node_modules/abort-controller": {
42
+ "version": "3.0.0",
43
+ "resolved": "https://registry.npmmirror.com/abort-controller/-/abort-controller-3.0.0.tgz",
44
+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
45
+ "license": "MIT",
46
+ "dependencies": {
47
+ "event-target-shim": "^5.0.0"
48
+ },
49
+ "engines": {
50
+ "node": ">=6.5"
51
+ }
52
+ },
53
+ "node_modules/agentkeepalive": {
54
+ "version": "4.5.0",
55
+ "resolved": "https://registry.npmmirror.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz",
56
+ "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==",
57
+ "license": "MIT",
58
+ "dependencies": {
59
+ "humanize-ms": "^1.2.1"
60
+ },
61
+ "engines": {
62
+ "node": ">= 8.0.0"
63
+ }
64
+ },
65
+ "node_modules/asynckit": {
66
+ "version": "0.4.0",
67
+ "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
68
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
69
+ "license": "MIT"
70
+ },
71
+ "node_modules/call-bind": {
72
+ "version": "1.0.7",
73
+ "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.7.tgz",
74
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
75
+ "license": "MIT",
76
+ "dependencies": {
77
+ "es-define-property": "^1.0.0",
78
+ "es-errors": "^1.3.0",
79
+ "function-bind": "^1.1.2",
80
+ "get-intrinsic": "^1.2.4",
81
+ "set-function-length": "^1.2.1"
82
+ },
83
+ "engines": {
84
+ "node": ">= 0.4"
85
+ },
86
+ "funding": {
87
+ "url": "https://github.com/sponsors/ljharb"
88
+ }
89
+ },
90
+ "node_modules/combined-stream": {
91
+ "version": "1.0.8",
92
+ "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
93
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
94
+ "license": "MIT",
95
+ "dependencies": {
96
+ "delayed-stream": "~1.0.0"
97
+ },
98
+ "engines": {
99
+ "node": ">= 0.8"
100
+ }
101
+ },
102
+ "node_modules/define-data-property": {
103
+ "version": "1.1.4",
104
+ "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz",
105
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
106
+ "license": "MIT",
107
+ "dependencies": {
108
+ "es-define-property": "^1.0.0",
109
+ "es-errors": "^1.3.0",
110
+ "gopd": "^1.0.1"
111
+ },
112
+ "engines": {
113
+ "node": ">= 0.4"
114
+ },
115
+ "funding": {
116
+ "url": "https://github.com/sponsors/ljharb"
117
+ }
118
+ },
119
+ "node_modules/delayed-stream": {
120
+ "version": "1.0.0",
121
+ "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
122
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
123
+ "license": "MIT",
124
+ "engines": {
125
+ "node": ">=0.4.0"
126
+ }
127
+ },
128
+ "node_modules/dotenv": {
129
+ "version": "16.4.5",
130
+ "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.4.5.tgz",
131
+ "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
132
+ "license": "BSD-2-Clause",
133
+ "engines": {
134
+ "node": ">=12"
135
+ },
136
+ "funding": {
137
+ "url": "https://dotenvx.com"
138
+ }
139
+ },
140
+ "node_modules/es-define-property": {
141
+ "version": "1.0.0",
142
+ "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.0.tgz",
143
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
144
+ "license": "MIT",
145
+ "dependencies": {
146
+ "get-intrinsic": "^1.2.4"
147
+ },
148
+ "engines": {
149
+ "node": ">= 0.4"
150
+ }
151
+ },
152
+ "node_modules/es-errors": {
153
+ "version": "1.3.0",
154
+ "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz",
155
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
156
+ "license": "MIT",
157
+ "engines": {
158
+ "node": ">= 0.4"
159
+ }
160
+ },
161
+ "node_modules/event-target-shim": {
162
+ "version": "5.0.1",
163
+ "resolved": "https://registry.npmmirror.com/event-target-shim/-/event-target-shim-5.0.1.tgz",
164
+ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
165
+ "license": "MIT",
166
+ "engines": {
167
+ "node": ">=6"
168
+ }
169
+ },
170
+ "node_modules/form-data": {
171
+ "version": "4.0.0",
172
+ "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz",
173
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
174
+ "license": "MIT",
175
+ "dependencies": {
176
+ "asynckit": "^0.4.0",
177
+ "combined-stream": "^1.0.8",
178
+ "mime-types": "^2.1.12"
179
+ },
180
+ "engines": {
181
+ "node": ">= 6"
182
+ }
183
+ },
184
+ "node_modules/form-data-encoder": {
185
+ "version": "1.7.2",
186
+ "resolved": "https://registry.npmmirror.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz",
187
+ "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==",
188
+ "license": "MIT"
189
+ },
190
+ "node_modules/formdata-node": {
191
+ "version": "4.4.1",
192
+ "resolved": "https://registry.npmmirror.com/formdata-node/-/formdata-node-4.4.1.tgz",
193
+ "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==",
194
+ "license": "MIT",
195
+ "dependencies": {
196
+ "node-domexception": "1.0.0",
197
+ "web-streams-polyfill": "4.0.0-beta.3"
198
+ },
199
+ "engines": {
200
+ "node": ">= 12.20"
201
+ }
202
+ },
203
+ "node_modules/function-bind": {
204
+ "version": "1.1.2",
205
+ "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
206
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
207
+ "license": "MIT",
208
+ "funding": {
209
+ "url": "https://github.com/sponsors/ljharb"
210
+ }
211
+ },
212
+ "node_modules/get-intrinsic": {
213
+ "version": "1.2.4",
214
+ "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
215
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
216
+ "license": "MIT",
217
+ "dependencies": {
218
+ "es-errors": "^1.3.0",
219
+ "function-bind": "^1.1.2",
220
+ "has-proto": "^1.0.1",
221
+ "has-symbols": "^1.0.3",
222
+ "hasown": "^2.0.0"
223
+ },
224
+ "engines": {
225
+ "node": ">= 0.4"
226
+ },
227
+ "funding": {
228
+ "url": "https://github.com/sponsors/ljharb"
229
+ }
230
+ },
231
+ "node_modules/gopd": {
232
+ "version": "1.0.1",
233
+ "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz",
234
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
235
+ "license": "MIT",
236
+ "dependencies": {
237
+ "get-intrinsic": "^1.1.3"
238
+ },
239
+ "funding": {
240
+ "url": "https://github.com/sponsors/ljharb"
241
+ }
242
+ },
243
+ "node_modules/has-property-descriptors": {
244
+ "version": "1.0.2",
245
+ "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
246
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
247
+ "license": "MIT",
248
+ "dependencies": {
249
+ "es-define-property": "^1.0.0"
250
+ },
251
+ "funding": {
252
+ "url": "https://github.com/sponsors/ljharb"
253
+ }
254
+ },
255
+ "node_modules/has-proto": {
256
+ "version": "1.0.3",
257
+ "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.3.tgz",
258
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
259
+ "license": "MIT",
260
+ "engines": {
261
+ "node": ">= 0.4"
262
+ },
263
+ "funding": {
264
+ "url": "https://github.com/sponsors/ljharb"
265
+ }
266
+ },
267
+ "node_modules/has-symbols": {
268
+ "version": "1.0.3",
269
+ "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz",
270
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
271
+ "license": "MIT",
272
+ "engines": {
273
+ "node": ">= 0.4"
274
+ },
275
+ "funding": {
276
+ "url": "https://github.com/sponsors/ljharb"
277
+ }
278
+ },
279
+ "node_modules/hasown": {
280
+ "version": "2.0.2",
281
+ "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
282
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
283
+ "license": "MIT",
284
+ "dependencies": {
285
+ "function-bind": "^1.1.2"
286
+ },
287
+ "engines": {
288
+ "node": ">= 0.4"
289
+ }
290
+ },
291
+ "node_modules/humanize-ms": {
292
+ "version": "1.2.1",
293
+ "resolved": "https://registry.npmmirror.com/humanize-ms/-/humanize-ms-1.2.1.tgz",
294
+ "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
295
+ "license": "MIT",
296
+ "dependencies": {
297
+ "ms": "^2.0.0"
298
+ }
299
+ },
300
+ "node_modules/mime-db": {
301
+ "version": "1.52.0",
302
+ "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
303
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
304
+ "license": "MIT",
305
+ "engines": {
306
+ "node": ">= 0.6"
307
+ }
308
+ },
309
+ "node_modules/mime-types": {
310
+ "version": "2.1.35",
311
+ "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
312
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
313
+ "license": "MIT",
314
+ "dependencies": {
315
+ "mime-db": "1.52.0"
316
+ },
317
+ "engines": {
318
+ "node": ">= 0.6"
319
+ }
320
+ },
321
+ "node_modules/ms": {
322
+ "version": "2.1.3",
323
+ "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
324
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
325
+ "license": "MIT"
326
+ },
327
+ "node_modules/node-domexception": {
328
+ "version": "1.0.0",
329
+ "resolved": "https://registry.npmmirror.com/node-domexception/-/node-domexception-1.0.0.tgz",
330
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
331
+ "funding": [
332
+ {
333
+ "type": "github",
334
+ "url": "https://github.com/sponsors/jimmywarting"
335
+ },
336
+ {
337
+ "type": "github",
338
+ "url": "https://paypal.me/jimmywarting"
339
+ }
340
+ ],
341
+ "license": "MIT",
342
+ "engines": {
343
+ "node": ">=10.5.0"
344
+ }
345
+ },
346
+ "node_modules/node-fetch": {
347
+ "version": "2.7.0",
348
+ "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz",
349
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
350
+ "license": "MIT",
351
+ "dependencies": {
352
+ "whatwg-url": "^5.0.0"
353
+ },
354
+ "engines": {
355
+ "node": "4.x || >=6.0.0"
356
+ },
357
+ "peerDependencies": {
358
+ "encoding": "^0.1.0"
359
+ },
360
+ "peerDependenciesMeta": {
361
+ "encoding": {
362
+ "optional": true
363
+ }
364
+ }
365
+ },
366
+ "node_modules/object-inspect": {
367
+ "version": "1.13.2",
368
+ "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.2.tgz",
369
+ "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
370
+ "license": "MIT",
371
+ "engines": {
372
+ "node": ">= 0.4"
373
+ },
374
+ "funding": {
375
+ "url": "https://github.com/sponsors/ljharb"
376
+ }
377
+ },
378
+ "node_modules/openai": {
379
+ "version": "4.61.0",
380
+ "resolved": "https://registry.npmmirror.com/openai/-/openai-4.61.0.tgz",
381
+ "integrity": "sha512-xkygRBRLIUumxzKGb1ug05pWmJROQsHkGuj/N6Jiw2dj0dI19JvbFpErSZKmJ/DA+0IvpcugZqCAyk8iLpyM6Q==",
382
+ "license": "Apache-2.0",
383
+ "dependencies": {
384
+ "@types/node": "^18.11.18",
385
+ "@types/node-fetch": "^2.6.4",
386
+ "@types/qs": "^6.9.15",
387
+ "abort-controller": "^3.0.0",
388
+ "agentkeepalive": "^4.2.1",
389
+ "form-data-encoder": "1.7.2",
390
+ "formdata-node": "^4.3.2",
391
+ "node-fetch": "^2.6.7",
392
+ "qs": "^6.10.3"
393
+ },
394
+ "bin": {
395
+ "openai": "bin/cli"
396
+ },
397
+ "peerDependencies": {
398
+ "zod": "^3.23.8"
399
+ },
400
+ "peerDependenciesMeta": {
401
+ "zod": {
402
+ "optional": true
403
+ }
404
+ }
405
+ },
406
+ "node_modules/qs": {
407
+ "version": "6.13.0",
408
+ "resolved": "https://registry.npmmirror.com/qs/-/qs-6.13.0.tgz",
409
+ "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
410
+ "license": "BSD-3-Clause",
411
+ "dependencies": {
412
+ "side-channel": "^1.0.6"
413
+ },
414
+ "engines": {
415
+ "node": ">=0.6"
416
+ },
417
+ "funding": {
418
+ "url": "https://github.com/sponsors/ljharb"
419
+ }
420
+ },
421
+ "node_modules/set-function-length": {
422
+ "version": "1.2.2",
423
+ "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz",
424
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
425
+ "license": "MIT",
426
+ "dependencies": {
427
+ "define-data-property": "^1.1.4",
428
+ "es-errors": "^1.3.0",
429
+ "function-bind": "^1.1.2",
430
+ "get-intrinsic": "^1.2.4",
431
+ "gopd": "^1.0.1",
432
+ "has-property-descriptors": "^1.0.2"
433
+ },
434
+ "engines": {
435
+ "node": ">= 0.4"
436
+ }
437
+ },
438
+ "node_modules/side-channel": {
439
+ "version": "1.0.6",
440
+ "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.6.tgz",
441
+ "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
442
+ "license": "MIT",
443
+ "dependencies": {
444
+ "call-bind": "^1.0.7",
445
+ "es-errors": "^1.3.0",
446
+ "get-intrinsic": "^1.2.4",
447
+ "object-inspect": "^1.13.1"
448
+ },
449
+ "engines": {
450
+ "node": ">= 0.4"
451
+ },
452
+ "funding": {
453
+ "url": "https://github.com/sponsors/ljharb"
454
+ }
455
+ },
456
+ "node_modules/tr46": {
457
+ "version": "0.0.3",
458
+ "resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz",
459
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
460
+ "license": "MIT"
461
+ },
462
+ "node_modules/undici-types": {
463
+ "version": "5.26.5",
464
+ "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-5.26.5.tgz",
465
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
466
+ "license": "MIT"
467
+ },
468
+ "node_modules/web-streams-polyfill": {
469
+ "version": "4.0.0-beta.3",
470
+ "resolved": "https://registry.npmmirror.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
471
+ "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==",
472
+ "license": "MIT",
473
+ "engines": {
474
+ "node": ">= 14"
475
+ }
476
+ },
477
+ "node_modules/webidl-conversions": {
478
+ "version": "3.0.1",
479
+ "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
480
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
481
+ "license": "BSD-2-Clause"
482
+ },
483
+ "node_modules/whatwg-url": {
484
+ "version": "5.0.0",
485
+ "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz",
486
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
487
+ "license": "MIT",
488
+ "dependencies": {
489
+ "tr46": "~0.0.3",
490
+ "webidl-conversions": "^3.0.0"
491
+ }
492
+ }
493
+ }
494
+ }
package.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "free-for-dev-cn",
3
+ "version": "1.0.0",
4
+ "main": "translate.js",
5
+ "type": "module",
6
+ "scripts": {
7
+ "test": "node translate.js free-for-dev/README.md README.md"
8
+ },
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "ISC",
12
+ "description": "",
13
+ "dependencies": {
14
+ "dotenv": "^16.4.5",
15
+ "openai": "^4.61.0"
16
+ }
17
+ }
translate.js ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { readFileSync, writeFileSync } from 'fs';
2
+ import { OpenAI } from 'openai';
3
+ import dotenv from 'dotenv';
4
+
5
+ dotenv.config();
6
+
7
+ function delay(ms) {
8
+ return new Promise(resolve => setTimeout(resolve, ms));
9
+ }
10
+
11
+
12
+ const openai = new OpenAI({
13
+ baseURL: process.env.OPENAI_BASE_URL,
14
+ apiKey: process.env.OPENAI_API_KEY,
15
+ });
16
+
17
+
18
+
19
+ const maxSectionLength = 8000;
20
+
21
+ function convertToId(header) {
22
+ return header.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
23
+ }
24
+ function splitContent(content) {
25
+ // 首先,统一换行符为 \n
26
+ content = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
27
+
28
+ const sections = content.split(/^(#{1,2}\s.+(?:\n+|$))/m);
29
+ let result = [];
30
+ let currentSection = null;
31
+
32
+ for (let i = 1; i < sections.length; i += 2) {
33
+ const headerWithNewlines = sections[i];
34
+ const [header, ...newlines] = headerWithNewlines.split('\n');
35
+ const text = sections[i + 1] || '';
36
+
37
+ currentSection = {
38
+ id: convertToId(header.replace(/^#+\s/, '')),
39
+ header: header,
40
+ text: text,
41
+ sections: [],
42
+ leadingSpaces: [],
43
+ translations: []
44
+ };
45
+
46
+ const lines = text.split('\n');
47
+ let currentSubSection = '';
48
+ let currentLeadingSpace = '';
49
+
50
+ for (let line of lines) {
51
+ const lineLeadingSpace = line.match(/^(\s*)/)[1];
52
+
53
+ if (currentSubSection.length + line.length > maxSectionLength) {
54
+ currentSection.sections.push(currentSubSection);
55
+ currentSection.leadingSpaces.push(currentLeadingSpace);
56
+ currentSubSection = '';
57
+ currentLeadingSpace = '';
58
+ continue;
59
+ }
60
+
61
+ if (currentSubSection === '') {
62
+ currentLeadingSpace = lineLeadingSpace;
63
+ }
64
+
65
+ currentSubSection += line + '\n';
66
+ }
67
+
68
+ if (currentSubSection.trim().length > 0) {
69
+ currentSection.sections.push(currentSubSection);
70
+ currentSection.leadingSpaces.push(currentLeadingSpace);
71
+ }
72
+
73
+ result.push(currentSection);
74
+ }
75
+
76
+ return result;
77
+ }
78
+
79
+ async function translateTableOfContents(sections, openai) {
80
+ const tocSection = sections.find(section => section.id === 'table-of-contents');
81
+ if (!tocSection) {
82
+ console.log("Table of Contents not found");
83
+ return {};
84
+ }
85
+
86
+ const linkRegex = /^\s*\*\s\[(.+)\]\(#(.+)\)\s*$/;
87
+ const idTextMap = {};
88
+
89
+ const translatedSections = await Promise.all(tocSection.sections.map(async (section, index) => {
90
+ const response = await openai.chat.completions.create({
91
+ model: process.env.OPENAI_MODEL_ID,
92
+ messages: [
93
+ {
94
+ role: "system",
95
+ content: `请翻译以下目录项,保持原有的格式:
96
+ 1. 保持星号和缩进不变
97
+ 2. 只翻译方括号[]内的文本
98
+ 3. 保持圆括号()内的链接不变`
99
+ },
100
+ { role: "user", content: section }
101
+ ],
102
+ });
103
+
104
+ const translatedContent = response.choices[0].message.content;
105
+ console.log(`Translated TOC section ${index + 1} of ${tocSection.sections.length}`);
106
+
107
+ const translatedLines = translatedContent.split('\n').map(line => {
108
+ const match = line.match(linkRegex);
109
+ if (match) {
110
+ let [, translatedText, id] = match;
111
+ translatedText = translatedText.replace(/\s+/g, '');
112
+ idTextMap[id] = translatedText;
113
+ return `${tocSection.leadingSpaces[index]}* [${translatedText}](#${translatedText})`;
114
+ }
115
+ return line;
116
+ });
117
+
118
+ return translatedLines.join('\n');
119
+ }));
120
+
121
+ tocSection.translations = translatedSections;
122
+
123
+ // 替换链接
124
+ Object.entries(idTextMap).forEach(([id, text]) => {
125
+ const encodedText = encodeURIComponent(text.toLowerCase().replace(/\s+/g, '-'));
126
+ tocSection.translations = tocSection.translations.map(translation =>
127
+ translation.replace(new RegExp(`\\(#${id}\\)`, 'g'), `(#${encodedText})`));
128
+ });
129
+
130
+ return idTextMap;
131
+ }
132
+ async function translateToChineseAndSave(inputFile, outputFile) {
133
+ try {
134
+ const content = readFileSync(inputFile, 'utf8');
135
+ const sections = splitContent(content);
136
+ console.log(`Split into ${sections.length} sections`);
137
+
138
+ const idTextMap = await translateTableOfContents(sections, openai);
139
+
140
+ // 提取所有需要翻译的部分
141
+ const allSectionsToTranslate = sections.filter(section => section.id !== 'table-of-contents')
142
+ .flatMap(section =>
143
+ section.sections.map((text, index) => ({ sectionId: section.id, index, text }))
144
+ );
145
+
146
+ console.log(`Preparing to translate ${allSectionsToTranslate.length} subsections`);
147
+
148
+ // 批��翻译
149
+ const translatedSections = await Promise.all(allSectionsToTranslate.map(async ({ sectionId, index, text }) => {
150
+ const response = await openai.chat.completions.create({
151
+ model: process.env.OPENAI_MODEL_ID,
152
+ messages: [
153
+ {
154
+ role: "system", content: `
155
+ 请将Markdown文本翻译成中文,同时遵守以下规则:
156
+ 1. 严格保持原文的Markdown格式不变,包括但不限于标题、列表、代码块、引用等。
157
+ 2. 专有名词、缩写等可以保留英文,但在首次出现时可在括号内提供中文解释。
158
+ 3. 代码块、命令行指令等技术内容保持原样不翻译。
159
+ 4. 注意调整语序,使翻译后的文本符合中文的表达习惯,同时保持原意。
160
+ 5. 保持原文的链接格式不变,只翻译链接文本。
161
+ ​`
162
+ },
163
+ { role: "user", content: text.trim() }
164
+ ],
165
+ });
166
+ console.log(`Translated subsection ${index + 1} of section ${sectionId}`);
167
+ return { sectionId, index, content: response.choices[0].message.content };
168
+ }));
169
+
170
+ // 将翻译结果存储到相应的 section 对象中
171
+ sections.forEach(section => {
172
+ if (section.id !== 'table-of-contents') {
173
+ section.translations = translatedSections
174
+ .filter(ts => ts.sectionId === section.id)
175
+ .sort((a, b) => a.index - b.index)
176
+ .map(ts => section.leadingSpaces[ts.index] + ts.content);
177
+ }
178
+ });
179
+
180
+ // 替换 header 并组合成完整的翻译结果
181
+ const translatedContent = sections.map(section => {
182
+ const headerLevel = section.header.match(/^(#+)/)[1];
183
+ const newHeader = idTextMap[section.id] ? `${headerLevel} ${idTextMap[section.id]}` : section.header;
184
+ return [newHeader, ...section.translations].join('\n\n');
185
+ }).join('\n\n');
186
+
187
+ // // 更新链接
188
+ // const updatedContent = translatedContent.replace(/\[([^\]]+)\]\(#([^)]+)\)/g, (match, linkText, linkId) => {
189
+ // const translatedLinkText = idTextMap[linkId] || linkText;
190
+ // const encodedLinkText = encodeURIComponent(translatedLinkText.toLowerCase().replace(/\s+/g, '-'));
191
+ // return `[${translatedLinkText}](#${encodedLinkText})`;
192
+ // });
193
+
194
+ writeFileSync(outputFile, translatedContent.trim());
195
+ console.log(`Translation completed and saved to ${outputFile}`);
196
+ } catch (error) {
197
+ console.error('Error:', error);
198
+ }
199
+ }
200
+ // 获取命令行参数
201
+ const inputFile = process.argv[2];
202
+ const outputFile = process.argv[3] || 'README.md';
203
+
204
+ translateToChineseAndSave(inputFile, outputFile);