Compare commits

...

87 Commits

Author SHA1 Message Date
liuweiqing
03c2ee2dd5 feat: vocechat客服聊天 2024-07-18 17:07:44 +08:00
liuweiqing
f3faf31925 chore: 去掉coze,由于收费 2024-07-16 12:12:30 +08:00
liuweiqing
c90d8ea7ac chore: 补上gpt-4选项 2024-07-04 09:37:49 +08:00
liuweiqing
9a19a8924d chore: gpt4因为coze收费不能用了 2024-07-03 22:17:42 +08:00
14790897
a8c5392616 fix: 如果api是旧域名就改为新域名 2024-05-11 08:39:02 +08:00
liuweiqing
8ad486d2f7 Merge branch 'main' of https://github.com/14790897/paper-ai 2024-04-24 07:48:26 +08:00
liuweiqing
cd4181c897 fix: 图片源替换 2024-04-24 07:48:25 +08:00
Shi Sheng
3868ad4acf
docs: 更新了中英文的README文件 (#39)
* Update README.md

* Update README.md

* Update README_en.md

* Update README.md

* Update README.md

* Update README.md

* Update README_en.md

* Update README.md

* Update README_en.md
2024-04-20 09:33:12 +08:00
Shi Sheng
ef7c85448e
docs: 更新了英文的README (#38)
* Update README_en.md

* Update README_en.md

* Update README_en.md

* Update README_en.md

* Update README_en.md
2024-04-20 08:14:28 +08:00
Shi Sheng
a3a5274ca5
chore: 把clone-and-run-locally换成了”克隆并在本地运行“(#37) 2024-04-19 12:41:47 +08:00
dependabot[bot]
f788b2222f
chore(deps): bump the npm_and_yarn group across 1 directory with 2 updates (#34)
Bumps the npm_and_yarn group with 2 updates in the / directory: [sweetalert2](https://github.com/sweetalert2/sweetalert2) and [follow-redirects](https://github.com/follow-redirects/follow-redirects).


Updates `sweetalert2` from 11.10.5 to 11.10.6
- [Release notes](https://github.com/sweetalert2/sweetalert2/releases)
- [Changelog](https://github.com/sweetalert2/sweetalert2/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sweetalert2/sweetalert2/compare/v11.10.5...v11.10.6)

Updates `follow-redirects` from 1.15.4 to 1.15.6
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.4...v1.15.6)

---
updated-dependencies:
- dependency-name: sweetalert2
  dependency-type: direct:production
  dependency-group: npm_and_yarn-security-group
- dependency-name: follow-redirects
  dependency-type: indirect
  dependency-group: npm_and_yarn-security-group
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-19 08:30:11 +08:00
Shi Sheng
1be61f7a9a
docs: 更新了英文翻译 (#36)
* Update README_en.md

* Update README_en.md

* Update README_en.md

* Update README_en.md

* Update README_en.md

* Update README_en.md

* Update README_en.md

* Update README_en.md

* Update README_en.md

* Update README_en.md
2024-04-19 08:27:24 +08:00
Shi Sheng
f2f9448f28
更新了README (#35)
docs: 更新readme的英文链接和证书描述
2024-04-18 21:39:20 +08:00
liuweiqing
dba8ec332a chore: remove强制设置 2024-04-16 14:34:59 +08:00
liuweiqing
b3c8dc1d4a feat: 增加commandr模型 2024-04-13 18:02:38 +08:00
liuweiqing
8b8702e04d chore: 强制更新我设置的api 2024-04-13 15:47:23 +08:00
liuweiqing
fe43130b4f chore: 更新api(因为原域名过期) 2024-04-13 15:33:17 +08:00
liuweiqing
a5ec62320d fix: 去除google sigin 2024-04-02 11:05:54 +08:00
liuweiqing
9b31268cda fix: linuxdo登录环境变量 2024-04-02 10:41:55 +08:00
14790897
29e2579b1d Merge branch 'main' of github.com:14790897/paper-ai 2024-04-01 15:40:00 +08:00
14790897
9ff111edaf fix: 本地开发需要环境变量 2024-04-01 15:39:51 +08:00
liuweiqing
01b26d9115 Merge branch 'main' of https://github.com/14790897/paper-ai 2024-03-30 09:46:04 +08:00
liuweiqing
4ce386e372 chore: 完善错误提示 2024-03-30 09:45:52 +08:00
14790897
9022969ac6 Revert "chore: 更新密钥"
This reverts commit d8cdb70333.
2024-03-29 08:54:39 +08:00
14790897
d227c78b5b Merge branch 'main' of github.com:14790897/paper-ai 2024-03-28 23:02:22 +08:00
14790897
d8cdb70333 chore: 更新密钥 2024-03-28 23:01:52 +08:00
liuweiqing
9e2510d748 chore: docs 2024-03-27 12:08:07 +08:00
liuweiqing
0a232f495a chore: 尝试修复Google登录 2024-03-15 16:17:45 +08:00
liuweiqing
5ccdc5270a chore: 尝试修复Google登录 2024-03-15 16:05:18 +08:00
liuweiqing
6bf8061f0f feat: 优化未找到文献的提示 2024-03-15 15:47:56 +08:00
liuweiqing
5d61d49f05
Merge pull request #28 from 14790897/release-v1.9.0
chore: release 1.9.0
2024-03-14 16:56:39 +08:00
liuweiqing
18356b67d9 chore: release 1.9.0 2024-03-13 21:22:58 +08:00
14790897
0bfaacf6ee fix: remove .env.local 2024-03-13 21:22:31 +08:00
14790897
6243aa5401 fix: 前端环境变量需要使用NEXT_PUBLIC_ 2024-03-13 21:07:10 +08:00
14790897
64cab48ae3 fix: 应用id问题 2024-03-13 20:55:50 +08:00
14790897
0090ffd3bb feat: 完成linuxdo oauth 2024-03-13 20:51:58 +08:00
liuweiqing
8730415352 fix: 通过判断user是否登陆来决定是否one tap 2024-03-09 23:13:12 +08:00
liuweiqing
2f60e65f91 chore: 使用同步尝试去除onetap 2024-03-09 23:01:03 +08:00
liuweiqing
c8f3a94520 chore: 使用同步尝试去除onetap 2024-03-09 22:58:23 +08:00
liuweiqing
fdcadbec60 chore: 使用同步尝试去除onetap 2024-03-09 22:40:06 +08:00
liuweiqing
e0426cf5fc chore: 使用同步尝试去除onetap 2024-03-09 21:55:25 +08:00
liuweiqing
b5bd878cda fix: 点击空白页面可以可以取消论文列表页 2024-03-09 19:50:08 +08:00
liuweiqing
7f5af058cd chore: 重设密码时密码要输入两次 2024-03-09 19:07:46 +08:00
liuweiqing
939f5c28e9 feat: 允许重置密码 2024-03-09 18:51:38 +08:00
liuweiqing
f63dd8865b chore: 重置密码 2024-03-09 16:15:49 +08:00
liuweiqing
5f3252da6e fix: 谷歌登陆后不再弹出 2024-03-09 16:10:55 +08:00
14790897
d808aa3195 chore: 密码重置界面 2024-03-08 19:56:57 +08:00
14790897
84239677f5 chore: google onetap 2024-03-08 12:00:36 +08:00
14790897
04a3e64e64 chore: google onetap 2024-03-08 11:45:43 +08:00
14790897
2267c98d7a chore: google onetap 2024-03-08 11:41:54 +08:00
14790897
c91006564b google onetap 2024-03-08 11:16:26 +08:00
14790897
7243d8bc84 chore: google onetap 2024-03-08 11:08:20 +08:00
14790897
3446ce4ced chore: Google onetap 2024-03-08 10:49:45 +08:00
14790897
3fd86d788b chore: 尝试修复oauth 2024-03-07 21:55:19 +08:00
14790897
dfca412ca6 chore: google登录尝试修复 2024-03-07 18:41:55 +08:00
14790897
dfab6991e0 chore: 调试 2024-03-07 16:11:38 +08:00
14790897
15c3a1f0ac feat: google登录 2024-03-07 13:46:08 +08:00
14790897
a0ce164b15 chore: 服务条款 2024-03-07 11:45:25 +08:00
14790897
6315d48d89 chore: privacy 2024-03-07 11:38:10 +08:00
14790897
f58ce4c7c4 chore: remove nodes 2024-03-07 10:54:38 +08:00
14790897
a0e88d8c8d chore: profile表加上时间列 2024-03-07 10:47:55 +08:00
14790897
559b4010c2 fix: GitHub登入可以插入信息 2024-03-07 10:08:17 +08:00
14790897
17ce170ab3 chore: 尝试修复GitHub登录 2024-03-06 22:53:16 +08:00
14790897
c037ac1db5 chore: 尝试修复GitHub登录 2024-03-06 21:41:44 +08:00
14790897
4b64827c1d fix: 新用户没有获得编辑器焦点会导致报错
if (useEditorFlag && editor && cursorPosition !== null) {
2024-03-06 14:06:11 +08:00
14790897
f8e4cfd205 fix: remove freshwork 2024-03-06 13:04:43 +08:00
14790897
836aa49847 fix: 使用cf反代解决semantic cors问题 2024-03-06 11:33:54 +08:00
14790897
151a1aa286 chore: 加了两个模型 2024-03-06 11:02:04 +08:00
14790897
d2263c503f chore: api更新 2024-03-04 15:43:38 +08:00
14790897
a4b368c5c6 chore: 加个gemini 2024-03-01 15:04:08 +08:00
14790897
c23f83a439 chore: 优化掉不用的包 2024-02-29 22:32:42 +08:00
14790897
35dbdcc2b2 chore: api update 2024-02-29 15:54:24 +08:00
14790897
1cf4c37295 chore: 取消公告 2024-02-29 14:26:29 +08:00
14790897
94f960363c chore: api更新 2024-02-29 14:25:33 +08:00
14790897
186a6750c2 chore: api 2024-02-28 20:04:26 +08:00
14790897
103523ee52 chore: api去除蒙恬 2024-02-28 17:06:30 +08:00
14790897
79cc718951 chore: api描述 2024-02-28 15:24:29 +08:00
liuweiqing
624715afd5 chore: semantic不可用 2024-02-27 22:46:22 +08:00
liuweiqing
d5fb68ecbe chore: remove code 2024-02-27 22:45:40 +08:00
liuweiqing
a31dc819a9 chore: docker-compose部署方式 2024-02-27 17:07:35 +08:00
liuweiqing
efabb39dfc refractor: 主要的和ai交互的函数重构 2024-02-27 16:29:01 +08:00
liuweiqing
4c78494e4d chore: msft clarify 2024-02-27 13:38:39 +08:00
liuweiqing
37fa37e9ac ci: fork仓库自动更新 2024-02-27 11:28:01 +08:00
liuweiqing
b8f613525a chore: announcement 2024-02-26 23:49:46 +08:00
14790897
e7aa998ca7 fix: 读取ai响应 2024-02-26 20:33:52 +08:00
14790897
43f222a83e chore: coze api 2024-02-26 20:17:16 +08:00
liuweiqing
a72329d4a2 feat: 可以手动停止AI的输出(左下角按钮) 2024-02-26 09:57:42 +08:00
65 changed files with 1605 additions and 25090 deletions

View File

@ -12,4 +12,7 @@ NEXT_PUBLIC_PAPER_URL=/api/paper
#"https://api.openai.com/v1/chat/completions" "https://api.liuweiqing.top" "https://api.liuweiqing.top/v1/chat/completions"
#node转发设置为 /api/v1/chat/completions https://one.caifree.com sk-aiHrrRLYUUelHstX69E9484509254dBf92061d6744FfFaD1
VERCEL_URL=https://www.paperai.life
NODE_ENV=development
NODE_ENV=development
# NEXT_PUBLIC_CLIENT_ID=UrgIEI0n03tveTmaOV0IU8qRY4DttGY4
# CLIENT_SECRET=ljShbIlIrfULu4BTUVTT4azeR90PtAif
# REDIRECT_URI=http://localhost:3000/api/oauth/callback

View File

@ -7,3 +7,6 @@ NEXT_PUBLIC_SEMANTIC_API_KEY=hEQvK6ARe84dzDPcMnpzX4n9jfoqztkMfaftPWnb
NEXT_PUBLIC_PUBMED_API_KEY=057616e7ce6c722f2ae8679e38a8be9b1a09
VERCEL_URL=https://www.paperai.life
NODE_ENV=production
NEXT_PUBLIC_CLIENT_ID=RcgInz3KqEhb2KdW2yg5WUgAf3KHcJAC
CLIENT_SECRET=U4z8TgPIV1GWCXhFFNEVQyfmDotf91K6
REDIRECT_URI=https://www.paperai.life/api/oauth/callback

40
.github/workflows/sync.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: Upstream Sync
permissions:
contents: write
on:
schedule:
- cron: "0 0 * * *" # every day
workflow_dispatch:
jobs:
sync_latest_from_upstream:
name: Sync latest commits from upstream repo
runs-on: ubuntu-latest
if: ${{ github.event.repository.fork }}
steps:
# Step 1: run a standard checkout action
- name: Checkout target repo
uses: actions/checkout@v3
# Step 2: run the sync action
- name: Sync upstream changes
id: sync
uses: aormsby/Fork-Sync-With-Upstream-action@v3.4
with:
upstream_sync_repo: 14790897/paper-ai
upstream_sync_branch: main
target_sync_branch: main
target_repo_token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, no need to set
# Set test_mode true to run tests instead of the true action!!
test_mode: false
- name: Sync check
if: failure()
run: |
echo "[Error] 由于上游仓库的 workflow 文件变更,导致 GitHub 自动暂停了本次自动更新,你需要手动 Sync Fork 一次详细教程请查看https://github.com/Yidadaa/ChatGPT-Next-Web/blob/main/README_CN.md#%E6%89%93%E5%BC%80%E8%87%AA%E5%8A%A8%E6%9B%B4%E6%96%B0"
echo "[Error] Due to a change in the workflow file of the upstream repository, GitHub has automatically suspended the scheduled automatic update. You need to manually sync your fork. Please refer to the detailed tutorial for instructions: https://github.com/Yidadaa/ChatGPT-Next-Web#enable-automatic-updates"
exit 1

1
.gitignore vendored
View File

@ -37,6 +37,7 @@ next-env.d.ts
pass
.env
# .env.local
.vercel
post.md

View File

@ -1,5 +1,34 @@
# Changelog
## [1.9.0](https://www.github.com/14790897/paper-ai/compare/v1.8.0...v1.9.0) (2024-03-13)
### Features
* google登录 ([15c3a1f](https://www.github.com/14790897/paper-ai/commit/15c3a1f0acae8f5d6e610382b4fb886cc637d4f9))
* 允许重置密码 ([939f5c2](https://www.github.com/14790897/paper-ai/commit/939f5c28e9f658f2899cb262c16e78d42601a320))
* 可以手动停止AI的输出(左下角按钮) ([a72329d](https://www.github.com/14790897/paper-ai/commit/a72329d4a209aba4a0111093ece3b8cf89113ad2))
* 完成linuxdo oauth ([0090ffd](https://www.github.com/14790897/paper-ai/commit/0090ffd3bbe83a99a4de15e733619569cd78a69b))
### Bug Fixes
* GitHub登入可以插入信息 ([559b401](https://www.github.com/14790897/paper-ai/commit/559b4010c276f45dec791aaea17133d6690aac63))
* github登录无法将用户数据插入数据库 ([65db119](https://www.github.com/14790897/paper-ai/commit/65db119a9ac97009f15238e6ef26236bc6be14c7))
* quilleditor ssr加载失败 ([8a25248](https://www.github.com/14790897/paper-ai/commit/8a25248c29c578c75ec9e05fd1cdd339f131e5d6))
* remove .env.local ([0bfaacf](https://www.github.com/14790897/paper-ai/commit/0bfaacf6ee52309aaa55961037aba29a1558e6a6))
* remove freshwork ([f8e4cfd](https://www.github.com/14790897/paper-ai/commit/f8e4cfd205cfb5b5ec105f662c0ff0b6d8590429))
* seo ([72300bf](https://www.github.com/14790897/paper-ai/commit/72300bf6eb23757845734ccfcfb99d40274c9257))
* seo图片问题 ([6e807a7](https://www.github.com/14790897/paper-ai/commit/6e807a703d2a72f6ce557f043abefc44d746992c))
* 使用cf反代解决semantic cors问题 ([836aa49](https://www.github.com/14790897/paper-ai/commit/836aa49847ec7bc4fd2686a324a82ab19173fc83))
* 前端环境变量需要使用NEXT_PUBLIC_ ([6243aa5](https://www.github.com/14790897/paper-ai/commit/6243aa5401f7689aa7e4caf81a39a87578484299))
* 应用id问题 ([64cab48](https://www.github.com/14790897/paper-ai/commit/64cab48ae34ebb5500553dd3908167a95f1cbaf4))
* 新用户没有获得编辑器焦点会导致报错 ([4b64827](https://www.github.com/14790897/paper-ai/commit/4b64827c1d3c77dc05ebad359f0f4d384145211f))
* 点击空白页面可以可以取消论文列表页 ([b5bd878](https://www.github.com/14790897/paper-ai/commit/b5bd878cdafb6a54826f8aeafb16e6e6bc1e95bb))
* 读取ai响应 ([e7aa998](https://www.github.com/14790897/paper-ai/commit/e7aa998ca7dafe38a0c12ada4f168717c6e45439))
* 谷歌登陆后不再弹出 ([5f3252d](https://www.github.com/14790897/paper-ai/commit/5f3252da6e2715e4afbb7ab0b648112c22604230))
* 通过判断user是否登陆来决定是否one tap ([8730415](https://www.github.com/14790897/paper-ai/commit/87304153526200a2c3340c433c87348d5199287b))
## [1.8.0](https://www.github.com/14790897/paper-ai/compare/v1.7.0...v1.8.0) (2024-02-24)

View File

@ -1,5 +1,3 @@
[English Documentation](./README_en.md)
<a href="https://paperai.life">
<div align="center">
<img src="./public/android-chrome-192x192.png" alt="the fastest way to create a paper with real references">
@ -7,19 +5,22 @@
<h1 align="center">paper-ai</h1>
</a>
<p align="center"> <a href="./README_en.md"><b>English Documentation </b></a> </p>
<p align="center">
使用真实文献最快速完成论文的方法
</p>
<p align="center">
<a href='https://docs.paperai.life/' style='font-size: 20px;'><strong>文档网站(教程比较详细,推荐在这里观看)</strong></a>
<a href='https://docs.paperai.life/' style='font-size: 20px;'><strong>文档网站(教程比较详细,推荐阅读这里)</strong></a> ·
<a href='https://www.bilibili.com/video/BV1Ya4y1k75V'><strong>bilibili视频教程</strong></a>
</p>
<p align="center">
<a href="#功能"><strong>功能</strong></a> ·
<a href="#演示"><strong>演示</strong></a> ·
<a href="#部署到Vercel"><strong>部署到 Vercel</strong></a> ·
<a href="#克隆并在本地运行"><strong>克隆并在本地运行</strong></a> ·
<a href="#克隆并在本地运行"><strong>克隆并在本地运行</strong></a>
</p>
<br/>
@ -45,7 +46,7 @@
上述操作还会将 repo 克隆到 GitHub。
如果只想在本地开发,而不想部署到 Vercel[请按以下步骤操作](#clone-and-run-locally)。
如果只想在本地开发,而不想部署到 Vercel[请按以下步骤操作](#克隆并在本地运行)。
## 镜像运行
@ -92,7 +93,8 @@ npm run dev
1. semantic scholar api: https://api.semanticscholar.org/api-docs/#tag/Paper-Data/operation/get_graph_paper_relevance_search
2. pubmed api: https://www.ncbi.nlm.nih.gov/books/NBK25500/
3. i18n: https://locize.com/blog/next-app-dir-i18n/
## 许可证
MIT
该项目已获得[MIT License](LICENSE)的许可

View File

@ -1,17 +1,24 @@
<a href="https://paperai.life">
<img alt="Next.js and Supabase Starter Kit - the fastest way to build apps with Next.js and Supabase" src="https://paperai.life/opengraph-image.png">
<h1 align="center">paper-ai</h1>
<div align="center">
<img src="./public/android-chrome-192x192.png" alt="the fastest way to create a paper with real references">
</div>
<h1 align="center">paper-ai</h1>
</a>
<p align="center">
The fastest way to write a paper with true references
</p>
<p align="center">
<a href='https://docs.paperai.life/' style='font-size: 20px;'><strong> Website Documentation (detailed tutorials, highly recommended)</strong></a> ·
<a href='https://www.bilibili.com/video/BV1Ya4y1k75V'><strong>bilibili Video Tutorial</strong></a>
</p>
<p align="center">
<a href="#features"><strong>Features</strong></a> ·
<a href="#demo"><strong>Demo</strong></a> ·
<a href="#deploy-to-vercel"><strong>Deploy to Vercel</strong></a> ·
<a href="#clone-and-run-locally"><strong>Clone and run locally</strong></a> ·
<a href="#clone-and-run-locally"><strong>Clone and run locally</strong></a>
<!-- <a href="#feedback-and-issues"><strong>Feedback and issues</strong></a>
<a href="#more-supabase-examples"><strong>More Examples</strong></a> -->
</p>
@ -40,6 +47,31 @@ The above will also clone the repo to your GitHub, you can clone that locally an
If you wish to just develop locally and not deploy to Vercel, [follow the steps below](#clone-and-run-locally).
## Using Docker
1. Using `docker pull` command
```sh
docker pull 14790897/paperai:latest
```
2. Run Docker
```sh
docker run -d -p 3000:3000 \
-e NEXT_PUBLIC_AI_URL=CUSTOM_AI_URL \
-e NEXT_PUBLIC_OPENAI_API_KEY=CUSTOM_API_KEY \
14790897/paperai:latest
```
Replace `CUSTOM_AI_URL` and `CUSTOM_API_KEY` to your own AI URL and API key
## Environment variable description
1. NEXT_PUBLIC_OPENAI_API_KEY sets the key. Simply leave the corresponding position in the settings interface (the gear in the upper right corner) blank, the predetermined variable will be used.
2. NEXT_PUBLIC_AI_URL sets the upstream url. Simply leave the corresponding position in the settings interface (the gear in the upper right corner) blank, the predetermined variable will be used.
3. NEXT_PUBLIC_SEMANTIC_API_KEY sets the `semantic scholar` key to increase the number of requests
4. NEXT_PUBLIC_PUBMED_API_KEY sets the `pubmed` key to increase the number of requests
## Clone and run locally
```bash
@ -57,5 +89,13 @@ npm run dev
```
## Reference
1. semantic scholar api: https://api.semanticscholar.org/api-docs/#tag/Paper-Data/operation/get_graph_paper_relevance_search
2. pubmed api: https://www.ncbi.nlm.nih.gov/books/NBK25500/
3. i18n: https://locize.com/blog/next-app-dir-i18n/
## LICENSE
MIT
This repository is licensed under the MIT License
See the [LICENSE](LICENSE) file for details.

View File

@ -10,8 +10,9 @@ import { useTranslation } from "@/app/i18n";
import { FooterBase } from "@/components/Footer/FooterBase";
//supabase
import { insertUserProfile } from "@/utils/supabase/supabaseutils";
// signingithub
import { SignInGitHub } from "@/components/SignInGitHub";
// SignInWithProvider
import { SignInWithProvider } from "@/components/SignInWithProvider";
import LinuxdoSignin from "@/components/LinuxdoSignin";
export default async function Login({
searchParams,
params: { lng },
@ -127,13 +128,17 @@ export default async function Login({
required
/>
<button className="bg-green-700 rounded-md px-4 py-2 text-foreground mb-2">
Sign In
Sign In
</button>
<button
formAction={signUp}
className="border border-foreground/20 rounded-md px-4 py-2 text-foreground mb-2"
>
Sign Up
Sign Up
</button>
{/* 重置密码 */}
<button className="border border-foreground/20 rounded-md px-4 py-2 text-foreground mb-2">
<Link href="/request-reset">Reset Password</Link>
</button>
{searchParams?.message && (
<p className="mt-4 p-4 bg-foreground/10 text-foreground text-center">
@ -141,7 +146,17 @@ export default async function Login({
</p>
)}
</form>
<SignInGitHub />
<div>
<LinuxdoSignin />
<SignInWithProvider
provider="github"
redirectTo="https://www.paperai.life/welcome"
/>
<SignInWithProvider
provider="google"
redirectTo="https://www.paperai.life/welcome"
/>
</div>
<footer className="w-full border-t border-t-foreground/10 p-8 flex justify-center text-center text-xs">
<div className="flex items-center space-x-4">
{" "}

View File

@ -1,10 +0,0 @@
import { createClient } from '@/utils/supabase/server';
import { cookies } from 'next/headers';
export default async function Notes() {
const cookieStore = cookies()
const supabase = createClient(cookieStore);
const { data: notes } = await supabase.from("notes").select();
return <pre>{JSON.stringify(notes, null, 2)}</pre>
}

View File

@ -14,18 +14,19 @@ import PaperManagementWrapper from "@/components/PaperManagementWrapper";
import { useTranslation } from "@/app/i18n";
import { FooterBase } from "@/components/Footer/FooterBase";
import { IndexProps } from "@/utils/global";
import GoogleSignIn from "@/components/GoogleSignIn";
// import Error from "@/app/global-error";
export default async function Index({ params: { lng } }: IndexProps) {
const { t } = await useTranslation(lng);
const cookieStore = cookies();
let supabase: any, user;
const canInitSupabaseClient = () => {
// This function is just for the interactive tutorial.
// Feel free to remove it once you have Supabase connected.
try {
createClient(cookieStore);
supabase = createClient(cookieStore);
return true;
} catch (e) {
return false;
@ -33,7 +34,12 @@ export default async function Index({ params: { lng } }: IndexProps) {
};
const isSupabaseConnected = canInitSupabaseClient();
if (supabase) {
({
data: { user },
} = await supabase.auth.getUser());
}
console.log("user in page", user);
return (
<div className="flex-1 w-full flex flex-col gap-5 items-center">
<nav className="w-full flex justify-center border-b border-b-foreground/10 h-16">
@ -42,6 +48,8 @@ export default async function Index({ params: { lng } }: IndexProps) {
{/* 用来表示是否显示论文列表页 */}
<PaperListButtonWrapper />
{isSupabaseConnected && <AuthButton />}
{/* 如果用户没有登录会出现谷歌的sign in按钮登录之后不会出现 */}
{!user && <GoogleSignIn />}
<SettingsLink />
</div>
</nav>
@ -66,6 +74,20 @@ export default async function Index({ params: { lng } }: IndexProps) {
>
<strong>使</strong>
</a>
<a
href="./privacy"
target="_blank"
className="font-bold text-blue-500 hover:underline hover:text-blue-700"
>
<strong>PrivacyPolicy</strong>
</a>
<a
href="./service"
target="_blank"
className="font-bold text-blue-500 hover:underline hover:text-blue-700"
>
<strong>Service</strong>
</a>
<FooterBase t={t} lng={lng} />
</div>
</footer>

View File

@ -0,0 +1,70 @@
import React from "react";
export default function PrivacyPolicy() {
return (
<div className="max-w-4xl mx-auto p-4">
<h1></h1>
<p>
使paperai使
</p>
<h2>使</h2>
<p>使paperai时</p>
<ul>
<li></li>
<li></li>
</ul>
<p>使</p>
<ul>
<li></li>
<li></li>
<li>使</li>
<li>Cookie</li>
</ul>
<p>使</p>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<h2></h2>
<p>
</p>
<ul>
<li>便</li>
<li></li>
<li></li>
</ul>
<h2></h2>
<p>
访
</p>
<h2></h2>
<p>
访使
</p>
<h2></h2>
<p>
//
</p>
<h2></h2>
<p>
paperai上发布新的隐私政策来通知您任何更改
</p>
<h2></h2>
<p>
liuweiqing147@gmail.com过与我们联系
</p>
<p>2024.3.7</p>
</div>
);
}

View File

@ -0,0 +1,41 @@
"use client";
import { useState } from "react";
import { createClient } from "@/utils/supabase/client";
const RequestResetPassword = () => {
const supabase = createClient();
const [email, setEmail] = useState("");
const handleResetPassword = async () => {
const { data, error } = await supabase.auth.resetPasswordForEmail(email, {
redirectTo: `${window.location.origin}/reset-password`, // 确保这个URL是你重置密码页面的地址
});
console.log("当前链接", `${window.location.origin}/reset-password`);
if (error) {
alert("Error sending password reset email: " + error.message);
} else {
alert("Please check your email for the password reset link");
}
};
return (
<div className="flex flex-col items-center justify-center p-4">
<input
type="email"
placeholder="Your email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="px-4 py-2 border rounded-md focus:ring-blue-500 focus:border-blue-500 shadow-sm"
/>
<button
onClick={handleResetPassword}
className="mt-4 px-4 py-2 bg-blue-500 text-white rounded-md shadow hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50"
>
Reset Password
</button>
</div>
);
};
export default RequestResetPassword;

View File

@ -0,0 +1,58 @@
"use client";
import { useState } from "react";
import { createClient } from "@/utils/supabase/client";
import { useRouter } from "next/navigation";
const ResetPassword = () => {
const supabase = createClient();
const [newPassword, setNewPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const router = useRouter();
const handleNewPassword = async () => {
// 检查两次输入的密码是否一致
if (newPassword !== confirmPassword) {
alert("The passwords do not match. Please try again.");
return;
}
const { error } = await supabase.auth.updateUser({
password: newPassword,
});
if (error) {
alert("Error resetting password: " + error.message);
} else {
alert("Your password has been reset successfully.");
router.push("/login"); // 导航到登录页面或其他页面
}
};
return (
<div className="flex flex-col items-center justify-center space-y-4 bg-gray-50 p-6 rounded-lg shadow-md">
<input
type="password"
placeholder="New password新密码"
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<input
type="password"
placeholder="Confirm new password确认新密码"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<button
onClick={handleNewPassword}
className="px-4 py-2 w-full text-white bg-blue-500 hover:bg-blue-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50 transition-colors"
>
Update Password
</button>
</div>
);
};
export default ResetPassword;

View File

@ -0,0 +1,50 @@
import React from "react";
const TermsOfService = () => {
return (
<div>
<h1></h1>
<p>2024.3.7</p>
<h2>1. </h2>
<p>
使paperai使使
</p>
<h2>2. 使</h2>
<p>
使/
</p>
<h2>3. </h2>
<p>
使
</p>
<h2>4. </h2>
<p>
使使
</p>
<h2>5. </h2>
<p>
</p>
<h2>6. </h2>
<p>
使
</p>
<h2>7. </h2>
<p>USA的法律进行解释和执行</p>
<h2>8. </h2>
<p>
liuweiqing147@gmail.com与我们联系
</p>
</div>
);
};
export default TermsOfService;

View File

@ -0,0 +1,46 @@
"use server";
import { createClient } from "@/utils/supabase/server";
import Link from "next/link";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";
import LoadingIndicator from "@/components/LoadingIndicator"; // 确保路径正确
import { insertUserProfile } from "@/utils/supabase/supabaseutils";
import React from "react";
export default async function WelcomeScreen() {
// const [isLoading, setIsLoading] = React.useState(true);
const cookieStore = cookies();
const supabase = createClient(cookieStore);
const {
data,
data: { user },
} = await supabase.auth.getUser();
//profiles表 插入用户信息
await insertUserProfile(data, supabase);
// setIsLoading(false);
//1秒后跳转到首页
// setTimeout(() => {
redirect("/");
// }, 1000);
return (
<>
{user ? (
<div className="flex items-center gap-4">
Hey, {user.email}!
<div style={{ margin: "20px", textAlign: "center" }}>
<h1>welcome, {user.email}!</h1>
</div>
</div>
) : (
<Link
href="/login"
className="py-2 px-3 flex rounded-md no-underline bg-btn-background hover:bg-btn-background-hover"
>
Login
</Link>
)}
<LoadingIndicator />
</>
);
}

View File

@ -0,0 +1,106 @@
// api/oauth/callback.js
import { createClient } from "@/utils/supabase/server";
import { NextResponse } from "next/server";
import { cookies } from "next/headers";
import axios from "axios";
//supabase
import { insertUserProfile } from "@/utils/supabase/supabaseutils";
import { setVip } from "@/utils/supabase/serverutils";
export async function GET(request: Request) {
const requestUrl = new URL(request.url);
const code = requestUrl.searchParams.get("code");
if (code) {
const cookieStore = cookies();
const supabase = createClient(cookieStore);
// await supabase.auth.exchangeCodeForSession(code);
// 使用授权码请求访问令牌
const tokenResponse = await getToken(code);
const accessToken = tokenResponse!.data.access_token;
console.log("accessToekn", accessToken);
// 使用访问令牌获取用户信息
const userResponse = await axios.get("https://connect.linux.do/api/user", {
headers: { Authorization: `Bearer ${accessToken}` },
});
const userInfo = userResponse.data;
const uuid = "9e1c30b5-723c-4805-b3b8-0ac3c1923514"; //生成密码
let userId = null;
// 尝试注册新用户
const signUpResponse = await supabase.auth.signUp({
email: `${userInfo.username}@linux.do`, // 使用模板字符串构建email
password: uuid, // 使用uuid作为密码
});
if (signUpResponse.error) {
// 如果用户已存在,尝试登录来获取用户信息
await supabase.auth.signOut();
const signInResponse = await supabase.auth.signInWithPassword({
email: `${userInfo.username}@linux.do`,
password: uuid,
});
if (signInResponse.error) {
console.error("Error logging in existing user:", signInResponse.error);
// 处理登录失败的情况
} else {
//signin成功
userId = signInResponse.data.user!.id;
}
} else {
//signup成功之后可能要signin一次
const signInResponse = await supabase.auth.signInWithPassword({
email: `${userInfo.username}@linux.do`,
password: uuid,
});
console.log("signInResponse:", signInResponse);
userId = signUpResponse.data.user!.id;
}
// 如果获取到了用户ID进行后续操作
if (userId) {
// console.log("signUpResponse.data:", signUpResponse.data);
//插入信息并设置VIP
await insertUserProfile(signUpResponse.data, supabase);
await setVip(supabase, userId, true, "Linuxdo");
} else {
return new Response(
JSON.stringify({ error: "Unable to register or login the user" }),
{
status: 500,
headers: {
"Content-Type": "application/json",
},
}
);
}
// URL to redirect to after sign in process completes
return NextResponse.redirect(requestUrl.origin);
}
async function getToken(code: string) {
// 使用client_id和client_secret创建Basic Auth凭证
try {
const tokenResponse = await axios.post(
"https://connect.linux.do/oauth2/token",
`grant_type=authorization_code&code=${code}&redirect_uri=${encodeURIComponent(
process.env.REDIRECT_URI
)}`,
{
headers: {
Authorization: `Basic ${Buffer.from(
`${process.env.NEXT_PUBLIC_CLIENT_ID}:${process.env.CLIENT_SECRET}`
).toString("base64")}`,
"Content-Type": "application/x-www-form-urlencoded",
},
}
);
// 处理tokenResponse...
return tokenResponse;
} catch (error) {
// 处理错误...
console.error(error);
}
}
}

View File

@ -9,6 +9,7 @@
"生成轮数": "Generation Rounds",
"时间范围": "Range of literature release dates, from this time to this year",
"更新文中的上标,使得数字顺序排列": "Update the superscript in the text to make the numbers in order",
"停止生成": "Stop Generation",
"+ Add Paper": "+ Add Paper",
"Buy VIP TO UNLOCK Cloud Sync and Edit Mutiple Papers Simultaneously": "Buy VIP TO UNLOCK Cloud Sync and Edit Mutiple Papers Simultaneously",
"Paper Management": "Paper Management",
@ -30,8 +31,11 @@
"deepseek-chat": "deepseek-chat (Model needs to be manually changed to this one)",
"caifree": "caifree (Recommended)",
"linuxdo": "linuxdo",
"coze": "coze",
"vv佬": "vv giant(Recommended)",
"官网反代": "Official website reverse proxy",
"蒙恬大将军": "Mengtian General(Recommended)",
"oneapi": "oneapi",
"custom": "Custom"
},
"鼠标点击段落中的上标跳转到文献引用?": "Click the superscript in the paragraph to jump to the reference?",

View File

@ -9,6 +9,7 @@
"生成轮数": "生成轮数",
"时间范围": "文献发布日期范围,从这个时间到今年",
"更新文中的上标,使得数字顺序排列": "更新文中的上标,使得数字顺序排列",
"停止生成": "停止生成",
"+ Add Paper": "+ 添加新论文(会直接替换编辑器里的内容)",
"Buy VIP TO UNLOCK Cloud Sync and Edit Mutiple Papers Simultaneously": "购买VIP解锁云同步和同时编辑多篇论文",
"Paper Management": "论文管理",
@ -31,8 +32,11 @@
"deepseek-chat": "deepseek-chat需要手动修改模型为这个",
"caifree": "caifree推荐",
"linuxdo": "linuxdo",
"coze": "扣子coze(我亲自维护)",
"官网反代": "官网反代",
"vv佬": "vv佬(推荐)",
"蒙恬大将军": "蒙恬大将军(推荐)",
"oneapi": "oneapi",
"custom": "自定义"
},
"鼠标点击段落中的上标跳转到文献引用?": "鼠标点击段落中的上标跳转到文献引用?",

View File

@ -33,7 +33,7 @@ export const metadata = {
},
openGraph: {
images:
"https://file.liuweiqing.life/2024/02/540f3476ef43c831934ce0359c367acd.png",
"https://file.paperai.life/2024/02/540f3476ef43c831934ce0359c367acd.png",
},
twitter: {
card: "page",
@ -41,7 +41,7 @@ export const metadata = {
description: "The fastest way to write paper",
creator: "@hahfrank",
images: [
"https://file.liuweiqing.life/2024/02/540f3476ef43c831934ce0359c367acd.png",
"https://file.paperai.life/2024/02/540f3476ef43c831934ce0359c367acd.png",
],
},
};
@ -53,7 +53,6 @@ export default function RootLayout({
}) {
return (
<html lang="en" className={GeistSans.className}>
<Script src="//fw-cdn.com/11368617/4047428.js" chat="true"></Script>
{/* <Script>{`
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
@ -67,12 +66,44 @@ export default function RootLayout({
});
}
`}</Script> */}
{/* msft clarify */}
<Script>
{`(function (c, l, a, r, i, t, y) {
c[a] =
c[a] ||
function () {
(c[a].q = c[a].q || []).push(arguments);
};
t = l.createElement(r);
t.async = 1;
t.src = "https://www.clarity.ms/tag/" + i;
y = l.getElementsByTagName(r)[0];
y.parentNode.insertBefore(t, y);
})(window, document, "clarity", "script", "l869naiex9");`}
</Script>
{/* google一键登录 */}
<Script src="https://accounts.google.com/gsi/client" async></Script>
<body className="bg-background text-foreground">
<main className="min-h-screen flex flex-col items-center">
{children}
</main>
</body>
{/* 谷歌分析 */}
<GoogleAnalytics gaId="G-05DHTG9XQ5" />
{/* vocechat聊天 */}
<Script
data-host-id="1"
data-auto-reg="true"
data-login-token=""
data-theme-color="#3EB489"
data-close-width="48"
data-close-height="48"
data-open-width="380"
data-open-height="480"
data-welcome="欢迎提问"
src="https://voce.paperai.life/widget.js"
async
></Script>
</html>
);
}

View File

@ -10,10 +10,10 @@ export interface APIState {
}
const initialState: APIState = {
apiKey: "sk-MaEuOo9qIeWKK3PRCdCb9b3d47E64e36Ad6022724b780592", //sk-ffe19ebe9fa44d00884330ff1c18cf82
apiKey: "sk-GHuPUV6ERD8wVmmr36FeB8D809D34d93Bb857c009f6aF9Fe", //sk-ffe19ebe9fa44d00884330ff1c18cf82
referencesRedux: [],
editorContent: "",
upsreamUrl: "https://one.caifree.com", //https://api.openai.com https://one.caifree.com https://chatserver.3211000.xyz https://api.deepseek.com
upsreamUrl: "https://one.paperai.life", //https://api.openai.com https://one.caifree.com https://chatserver.3211000.xyz https://api.deepseek.com
systemPrompt: `作为论文写作助手,您的主要任务是根据用户提供的研究主题和上下文,以及相关的研究论文,来撰写和完善学术论文。在撰写过程中,请注意以下要点:
1.使
2.使 [1]***[1]*

View File

@ -1,19 +1,20 @@
// "use server";
import { createClient } from "@/utils/supabase/server";
import Link from "next/link";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";
// import { signOut } from "@/utils/supabase/serversignout";
import { insertUserProfile } from "@/utils/supabase/supabaseutils";
export default async function AuthButton() {
const cookieStore = cookies();
const supabase = createClient(cookieStore);
const {
data,
data: { user },
} = await supabase.auth.getUser();
//profiles表 插入用户信息
await insertUserProfile(data, supabase);
// console.log("1111 in AuthButton user:", user);
const signOut = async () => {
"use server";

View File

@ -2,7 +2,7 @@ export default function DeployButton() {
return (
<a
className="py-2 px-3 flex rounded-md no-underline hover:bg-btn-background-hover border"
href="https://vercel.com/new/clone?repository-url=https://github.com/14790897/paper-ai&project-name=paper-ai&repository-name=paper-ai&demo-title=paper-ai&demo-description=This%20starter%20configures%20Supabase%20Auth%20to%20use%20cookies%2C%20making%20the%20user's%20session%20available%20throughout%20the%20entire%20Next.js%20app%20-%20Client%20Components%2C%20Server%20Components%2C%20Route%20Handlers%2C%20Server%20Actions%20and%20Middleware.&demo-url=https%3A%2F%2Fdemo-nextjs-with-supabase.vercel.app%2F&external-id=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-supabase&demo-image=https://file.liuweiqing.life/2024/02/540f3476ef43c831934ce0359c367acd.png"
href="https://vercel.com/new/clone?repository-url=https://github.com/14790897/paper-ai&project-name=paper-ai&repository-name=paper-ai&demo-title=paper-ai&demo-description=This%20starter%20configures%20Supabase%20Auth%20to%20use%20cookies%2C%20making%20the%20user's%20session%20available%20throughout%20the%20entire%20Next.js%20app%20-%20Client%20Components%2C%20Server%20Components%2C%20Route%20Handlers%2C%20Server%20Actions%20and%20Middleware.&demo-url=https%3A%2F%2Fdemo-nextjs-with-supabase.vercel.app%2F&external-id=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-supabase&demo-image=https://file.paperai.life/2024/02/540f3476ef43c831934ce0359c367acd.png"
target="_blank"
rel="noreferrer"
>

View File

@ -57,7 +57,7 @@ async function getArxivPapers(
return result;
} catch (error: any) {
throw new Error(
`Error fetching data from Arxiv API:${JSON.stringify(
`Arxiv失败请使用英文并缩短关键词:${JSON.stringify(
error.response,
null,
2

View File

@ -37,7 +37,7 @@ async function getPubMedPapers(
// 这里只返回了ID列表你可能需要根据实际需要进行调整
return idList;
} catch (error) {
console.error("Error fetching data from PubMed API:", error);
console.error(" PubMed API失败(请使用英文并缩短关键词):", error);
return null; // 或根据需要处理错误
}
}

View File

@ -24,7 +24,7 @@ async function getSemanticPapers(
try {
const maxOffset = 20 - limit; // 假设总记录数为 20
if (offset === -1) offset = getRandomOffset(maxOffset);
const url = `https://api.semanticscholar.org/graph/v1/paper/search`;
const url = `https://proxy.paperai.life/proxy/https://api.semanticscholar.org/graph/v1/paper/search`;
const response = await axios.get(url, {
headers: {
"x-api-key": process.env.NEXT_PUBLIC_SEMANTIC_API_KEY,
@ -52,7 +52,7 @@ async function getSemanticPapers(
} catch (error: any) {
// console.error("Error fetching data from Semantic Scholar API:", error);
throw new Error(
`Error fetching data from Semantic Scholar API:${JSON.stringify(
`Semantic Scholar fail请使用英文并缩短关键词:${JSON.stringify(
error.response,
null,
2

View File

@ -0,0 +1,93 @@
"use client";
import React, { useEffect } from "react";
//supabase
import { createClient } from "@/utils/supabase/client";
const GoogleSignIn = () => {
const supabase = createClient();
// 加载Google身份验证库并初始化
useEffect(() => {
// 异步检查用户是否已经登录
const checkSession = async () => {
const session = await supabase.auth.getSession();
if (session) {
console.log("用户已登录", session);
} else {
loadGoogleSignInScript();
}
};
checkSession();
}, []);
const loadGoogleSignInScript = () => {
// 确保gapi脚本只被加载一次
if (!window.gapi) {
const script = document.createElement("script");
script.src = "https://accounts.google.com/gsi/client";
script.async = true;
script.defer = true;
script.onload = initGoogleSignIn;
document.body.appendChild(script);
} else {
initGoogleSignIn();
}
};
// 初始化Google登录
const initGoogleSignIn = () => {
window.google.accounts.id.initialize({
client_id:
"646783243018-m2n9qfo12k70debpmkesevt5j2hi2itb.apps.googleusercontent.com", // 替换为你的客户端ID
callback: handleSignInWithGoogle,
auto_select: false, // 根据需要设置
itp_support: true,
});
};
// 处理登录响应
const handleSignInWithGoogle = async (response) => {
const { data, error } = await supabase.auth.signInWithIdToken({
provider: "google",
token: response.credential,
nonce: "", // 如果你使用nonce请在这里设置
});
if (error) {
console.error("Login failed:", error);
return;
}
console.log("Login successful:", data);
// 在这里处理登录成功后的逻辑
};
return (
<div>
{/* <div
id="g_id_onload"
data-client_id="646783243018-m2n9qfo12k70debpmkesevt5j2hi2itb.apps.googleusercontent.com"
data-context="signin"
data-ux_mode="popup"
// data-callback="handleSignInWithGoogleccounts.id.ini"
data-nonce=""
data-auto_select="false"
data-itp_support="true"
></div> */}
<div
id="g_id_signin"
className="g_id_signin"
data-type="standard"
data-shape="pill"
data-theme="outline"
data-text="signin_with"
data-size="large"
data-logo_alignment="left"
></div>
</div>
);
};
export default GoogleSignIn;

View File

@ -0,0 +1,31 @@
"use client";
// import React from "react";
const LinuxdoSignin = () => {
console.log(
"process.env.NEXT_PUBLIC_CLIENT_ID",
process.env.NEXT_PUBLIC_CLIENT_ID
);
const handleLogin = () => {
// 构建授权URL
const responseType = "code";
const authUrl = `https://connect.linux.do/oauth2/authorize?response_type=${responseType}&client_id=${process.env.NEXT_PUBLIC_CLIENT_ID}&state=ttt1`;
// 重定向到授权页面
window.location.href = authUrl;
};
return (
<div>
<button
onClick={handleLogin}
className="bg-gradient-to-r from-yellow-400 to-yellow-500 text-white rounded-md px-4 py-2 mb-2 flex items-center justify-center gap-2 hover:from-yellow-500 hover:to-yellow-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-yellow-400 shadow-lg hover:shadow-xl transition ease-in duration-200 w-full
"
>
Login with Linuxdo(free VIP)
</button>
</div>
);
};
export default LinuxdoSignin;

View File

@ -1,6 +1,6 @@
"use client";
import { useCallback, useState, useEffect } from "react";
import { useCallback, useState, useRef, useEffect } from "react";
//redux
import { useAppDispatch, useAppSelector } from "@/app/store";
import {
@ -11,6 +11,7 @@ import {
setPaperNumberRedux,
setContentUpdatedFromNetwork,
setIsVip,
setShowPaperManagement,
} from "@/app/store/slices/stateSlice";
//supabase
import { createClient } from "@/utils/supabase/client";
@ -134,6 +135,33 @@ const PaperManagement = ({ lng }) => {
// from: { opacity: 0 },
// });
//用于判断点击有没有落在区域中
const paperManagementRef = useRef(null); // 用于引用PaperManagement组件的根元素
const handleClickOutside = (event) => {
if (
paperManagementRef.current &&
!paperManagementRef.current.contains(event.target) &&
showPaperManagement
) {
// 如果点击事件的目标不是PaperManagement组件内的元素
// 隐藏组件
console.log("Clicked outside of the PaperManagement component.");
dispatch(setShowPaperManagement());
}
};
useEffect(() => {
if (showPaperManagement) {
// 只有当组件可见时,才添加事件监听器
document.addEventListener("mousedown", handleClickOutside);
}
// 组件卸载或状态改变时移除事件监听器
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [showPaperManagement]); // 依赖项数组包含showPaperManagement状态
return (
<CSSTransition
in={showPaperManagement}
@ -144,7 +172,10 @@ const PaperManagement = ({ lng }) => {
{/* showPaperManagement ? ( */}
{/* <animated.div style={animations}> */}
<>
<div className="paper-management-container flex flex-col items-center space-y-4">
<div
ref={paperManagementRef}
className="paper-management-container flex flex-col items-center space-y-4"
>
<div className="max-w-md w-full bg-blue-gray-100 rounded overflow-hidden shadow-lg mx-auto p-5">
<h1 className="font-bold text-3xl text-center">
{" "}

View File

@ -1,9 +1,10 @@
"use client";
import React, { useState, useEffect, useRef } from "react";
import React, { useState, useEffect, useRef, use } from "react";
import Quill from "quill";
import "quill/dist/quill.snow.css";
import { useLocalStorage } from "react-use";
import * as Sentry from "@sentry/react";
// 一些工具函数导入
import getArxivPapers from "./GetArxiv";
@ -28,6 +29,8 @@ import { useAppDispatch, useAppSelector } from "@/app/store";
import {
addReferencesRedux,
setEditorContent,
setApiKey,
setUpsreamUrl,
} from "@/app/store/slices/authSlice";
import { setContentUpdatedFromNetwork } from "@/app/store/slices/stateSlice";
//类型声明
@ -93,7 +96,7 @@ const QEditor = ({ lng }) => {
//quill编辑器鼠标位置
const [cursorPosition, setCursorPosition] = useLocalStorage<number | null>(
"光标位置",
null
0
);
//
// 初始化 Quill 编辑器
@ -102,12 +105,12 @@ const QEditor = ({ lng }) => {
// 选择论文来源
const [selectedSource, setSelectedSource] = useLocalStorage(
"学术引擎",
"semanticScholar"
"pubmed"
); // 默认选项
//选择语言模型
const [selectedModel, setSelectedModel] = useLocalStorage(
"gpt语言模型",
"gpt-4"
"deepseek-chat"
); // 默认选项
const [generatedPaperNumber, setGeneratedPaperNumber] = useLocalStorage(
"生成次数",
@ -116,11 +119,12 @@ const QEditor = ({ lng }) => {
//选择时间范围
const [timeRange, setTimeRange] = useLocalStorage("时间范围", "2019");
const [generateNumber, setGenerateNumber] = useState(0); //当前任务的进行数
const [openProgressBar, setOpenProgressBar] = useState(false);
const [openProgressBar, setOpenProgressBar] = useState(false); //设置进度条是否打开
const [showAnnouncement, setShowAnnouncement] = useLocalStorage(
"显示公告",
true
false
); // 是否显示公告
const [controller, setController] = useState<AbortController | null>(null); // 创建 AbortController 的状态
//redux
const dispatch = useAppDispatch();
@ -219,7 +223,7 @@ const QEditor = ({ lng }) => {
useEffect(() => {
if (showAnnouncement) {
toast(
"📢 如果遇到模型无法响应的情况,建议右上角切换为deepseek模型强于3.5弱于4同时这里也要选择deepseek",
"📢 如果遇到模型无法响应的情况,建议右上角切换为coze模型也是gpt4",
{
position: "top-center",
autoClose: false, // 设置为 false使得公告需要用户手动关闭确保用户看到公告信息
@ -244,6 +248,19 @@ const QEditor = ({ lng }) => {
);
}
}, []);
// 强制更新为我设置的API
// useEffect(() => {
// dispatch(setApiKey("sk-GHuPUV6ERD8wVmmr36FeB8D809D34d93Bb857c009f6aF9Fe"));
// dispatch(setUpsreamUrl("https://one.paperai.life"));
// });
useEffect(() => {
if (upsreamUrl === "https://one.liuweiqing.top") {
dispatch(
setApiKey("sk-GHuPUV6ERD8wVmmr36FeB8D809D34d93Bb857c009f6aF9Fe")
);
dispatch(setUpsreamUrl("https://one.paperai.life"));
}
}, [upsreamUrl]);
const handleTextChange = debounce(async function (delta, oldDelta, source) {
if (source === "user") {
// 获取编辑器内容
@ -285,242 +302,253 @@ const QEditor = ({ lng }) => {
const newValue = parseInt(event.target.value, 10);
setGeneratedPaperNumber(newValue);
};
// 处理AI写作
const handleAIWrite = async () => {
quill!.setSelection(cursorPosition!, 0); // 将光标移动到原来的位置
const prompt = "请帮助用户完成论文写作,使用用户所说的语言完成";
await sendMessageToOpenAI(
userInput,
quill!,
selectedModel!,
apiKey,
upsreamUrl,
prompt,
cursorPosition!
);
// 清空input内容
setUserInput("");
// 重新获取更新后的内容并更新 Redux store
const updatedContent = quill!.root.innerHTML;
dispatch(setEditorContent(updatedContent));
toast.success(`AI写作完成`, {
position: "top-center",
autoClose: 2000,
pauseOnHover: true,
});
};
// 处理paper2AI
async function paper2AI(topic: string) {
// 处理handleAIAction
async function handleAIAction(topic: string, actionType: string) {
// 创建一个新的 AbortController 实例
const newController = new AbortController();
setController(newController);
quill!.setSelection(cursorPosition!, 0); // 将光标移动到原来的位置
let offset = -1;
if (generatedPaperNumber != 1) offset = 0; //如果生成的数量不为1则从0开始
setOpenProgressBar(true); //开启进度条
//如果说要评估主题是否匹配的话,就要多获取一些文献
let limit = 2;
if (isEvaluateTopicMatch) {
limit = 4;
}
for (let i = 0; i < generatedPaperNumber!; i++) {
try {
if (!topic) {
//使用ai提取当前要请求的论文主题
const prompt =
"As a topic extraction assistant, you can help me extract the current discussion of the paper topic, I will enter the content of the paper, you extract the paper topic , no more than two, Hyphenated query terms yield no matches (replace it with space to find matches) return format is: topic1 topic2";
const userMessage = getTextBeforeCursor(quill!, 2000);
topic = await sendMessageToOpenAI(
userMessage,
null,
selectedModel!,
apiKey,
upsreamUrl,
prompt,
null,
false
);
console.log("topic in AI before removeSpecialCharacters", topic);
topic = removeSpecialCharacters(topic);
topic = topic.split(" ").slice(0, 2).join(" ");
//如果超过十个字符就截断
if (topic.length > 10) {
topic = topic.slice(0, 10);
}
}
console.log("topic in AI", topic);
console.log("offset in paper2AI", offset);
console.log("limit in paper2AI", limit);
let rawData, dataString, newReferences;
if (selectedSource === "arxiv") {
rawData = await getArxivPapers(topic, limit, offset);
//判断返回的文献是否跟用户输入的主题相关
if (isEvaluateTopicMatch) {
const { relevantPapers, nonRelevantPapers } =
await evaluateTopicMatch(
rawData,
apiKey,
upsreamUrl,
selectedModel!,
topic
);
rawData = relevantPapers;
}
console.log("arxiv rawdata:", rawData);
// 将 rawData 转换为引用数组
newReferences = rawData.map((entry: any) => ({
url: entry.id,
title: entry.title,
year: entry.published,
author: entry.authors?.slice(0, 3).join(", "),
}));
dataString = rawData
.map((entry: any) => {
return `ID: ${entry.id}\nTime: ${entry.published}\nTitle: ${entry.title}\nSummary: ${entry.abstract}\n\n`;
})
.join("");
} else if (selectedSource === "semanticScholar") {
rawData = await getSemanticPapers(
topic,
`${timeRange}-2024`,
offset,
limit
);
//判断返回的文献是否跟用户输入的主题相关
if (isEvaluateTopicMatch) {
const { relevantPapers, nonRelevantPapers } =
await evaluateTopicMatch(
rawData,
apiKey,
upsreamUrl,
selectedModel!,
topic
);
rawData = relevantPapers;
}
// 将 rawData 转换为引用数组
newReferences = rawData.map((entry: any) => ({
url: entry.url,
title: entry.title,
year: entry.year,
author: entry.authors?.slice(0, 3).join(", "),
venue: entry.venue,
journal: formatJournalReference(entry),
doi: entry.externalIds.DOI,
}));
dataString = rawData
.map((entry: any) => {
return `Time: ${entry.year}\nTitle: ${entry.title}\nSummary: ${entry.abstract}\n\n`;
})
.join("");
} else if (selectedSource === "pubmed") {
rawData = await fetchPubMedData(
topic,
Number(timeRange)!,
offset,
limit
);
if (!rawData) {
throw new Error("未搜索到文献 from PubMed.");
}
//判断返回的文献是否跟用户输入的主题相关
if (isEvaluateTopicMatch) {
const { relevantPapers, nonRelevantPapers } =
await evaluateTopicMatch(
rawData,
apiKey,
upsreamUrl,
selectedModel!,
topic
);
rawData = relevantPapers;
}
newReferences = rawData.map((entry: any) => ({
id: entry.id, // 文章的 PubMed ID
title: entry.title, // 文章的标题
abstract: entry.abstract, // 文章的摘要
author: entry.authors?.slice(0, 3).join(", "), // 文章的作者列表,假设为字符串数组
year: entry.year, // 文章的发表日期
journal: entry.journal, // 文章的发表杂志
url: entry.url, // 文章的 URL
source: "PubMed", // 指示这些引用来自 PubMed
doi: entry.doi, // 文章的 DOI
}));
// 打印 newReferences
console.log(newReferences);
dataString = rawData
.map((entry: any) => {
return `Time: ${entry.year}\nTitle: ${entry.title}\nSummary: ${entry.abstract}\n\n`;
})
.join("");
}
// 确保搜索到的论文不超过 3000 个字符
const trimmedMessage =
dataString.length > 3000 ? dataString.slice(0, 3000) : dataString;
//slate的方法
// const content = `需要完成的论文主题:${topic}, 搜索到的论文内容:${trimmedMessage},之前已经完成的内容上下文:${extractText(
// editorValue
// )}`;
const content = `之前用户已经完成的内容上下文:${getTextBeforeCursor(
quill!,
800
)},搜索到的论文内容:${trimmedMessage},${topic},`;
showExpandableToast(`搜索论文完成,搜索到的论文:${trimmedMessage}`);
try {
if (actionType === "write") {
// 写作逻辑
const prompt = "请帮助用户完成论文写作,使用用户所说的语言完成";
await sendMessageToOpenAI(
content,
userInput,
quill!,
selectedModel!,
apiKey,
upsreamUrl,
systemPrompt,
cursorPosition!
prompt,
cursorPosition!,
true,
newController.signal // 传递 AbortSignal
);
setUserInput("");
// 重新获取更新后的内容并更新 Redux store
const updatedContent = quill!.root.innerHTML;
dispatch(setEditorContent(updatedContent));
//在对应的位置添加文献
const nearestNumber = getNumberBeforeCursor(quill!);
dispatch(
addReferencesRedux({
references: newReferences,
position: nearestNumber,
})
);
if (isVip) {
//在云端同步supabase
const data = await submitPaper(
supabase,
updatedContent,
references,
paperNumberRedux
);
} else if (actionType === "paper2AI") {
// paper2AI 逻辑,根据 actionParam 处理特定任务
let offset = -1;
if (generatedPaperNumber != 1) offset = 0; //如果生成的数量不为1则从0开始
//如果说要评估主题是否匹配的话,就要多获取一些文献
let limit = 2;
if (isEvaluateTopicMatch) {
limit = 4;
}
//修改offset使得按照接下来的顺序进行获取文献
offset += 2;
setGenerateNumber(i + 1);
toast.success(`AI写作完成`, {
for (let i = 0; i < generatedPaperNumber!; i++) {
if (!topic) {
//使用ai提取当前要请求的论文主题
const prompt =
"As a topic extraction assistant, you can help me extract the current discussion of the paper topic, I will enter the content of the paper, you extract the paper topic , no more than two, Hyphenated query terms yield no matches (replace it with space to find matches) return format is: topic1 topic2";
const userMessage = getTextBeforeCursor(quill!, 2000);
topic = await sendMessageToOpenAI(
userMessage,
null,
selectedModel!,
apiKey,
upsreamUrl,
prompt,
null,
false,
newController.signal // 传递 AbortSignal
);
console.log("topic in AI before removeSpecialCharacters", topic);
topic = removeSpecialCharacters(topic);
topic = topic.split(" ").slice(0, 2).join(" ");
//如果超过十个字符就截断
if (topic.length > 10) {
topic = topic.slice(0, 10);
}
}
console.log(
"topic in AI:",
topic,
"offset in paper2AI:",
offset,
"limit in paper2AI:",
limit
);
let rawData, dataString, newReferences;
if (selectedSource === "arxiv") {
rawData = await getArxivPapers(topic, limit, offset);
//判断返回的文献是否跟用户输入的主题相关
if (isEvaluateTopicMatch) {
const { relevantPapers, nonRelevantPapers } =
await evaluateTopicMatch(
rawData,
apiKey,
upsreamUrl,
selectedModel!,
topic,
newController.signal
);
rawData = relevantPapers;
}
console.log("arxiv rawdata:", rawData);
// 将 rawData 转换为引用数组
newReferences = rawData.map((entry: any) => ({
url: entry.id,
title: entry.title,
year: entry.published,
author: entry.authors?.slice(0, 3).join(", "),
}));
dataString = rawData
.map((entry: any) => {
return `ID: ${entry.id}\nTime: ${entry.published}\nTitle: ${entry.title}\nSummary: ${entry.abstract}\n\n`;
})
.join("");
} else if (selectedSource === "semanticScholar") {
rawData = await getSemanticPapers(
topic,
`${timeRange}-2024`,
offset,
limit
);
//判断返回的文献是否跟用户输入的主题相关
if (isEvaluateTopicMatch) {
const { relevantPapers, nonRelevantPapers } =
await evaluateTopicMatch(
rawData,
apiKey,
upsreamUrl,
selectedModel!,
topic,
newController.signal
);
rawData = relevantPapers;
}
// 将 rawData 转换为引用数组
newReferences = rawData.map((entry: any) => ({
url: entry.url,
title: entry.title,
year: entry.year,
author: entry.authors?.slice(0, 3).join(", "),
venue: entry.venue,
journal: formatJournalReference(entry),
doi: entry.externalIds.DOI,
}));
dataString = rawData
.map((entry: any) => {
return `Time: ${entry.year}\nTitle: ${entry.title}\nSummary: ${entry.abstract}\n\n`;
})
.join("");
} else if (selectedSource === "pubmed") {
rawData = await fetchPubMedData(
topic,
Number(timeRange)!,
offset,
limit
);
if (!rawData) {
throw new Error("未搜索到文献 from PubMed.");
}
//判断返回的文献是否跟用户输入的主题相关
if (isEvaluateTopicMatch) {
const { relevantPapers, nonRelevantPapers } =
await evaluateTopicMatch(
rawData,
apiKey,
upsreamUrl,
selectedModel!,
topic,
newController.signal
);
rawData = relevantPapers;
}
newReferences = rawData.map((entry: any) => ({
id: entry.id, // 文章的 PubMed ID
title: entry.title, // 文章的标题
abstract: entry.abstract, // 文章的摘要
author: entry.authors?.slice(0, 3).join(", "), // 文章的作者列表,假设为字符串数组
year: entry.year, // 文章的发表日期
journal: entry.journal, // 文章的发表杂志
url: entry.url, // 文章的 URL
source: "PubMed", // 指示这些引用来自 PubMed
doi: entry.doi, // 文章的 DOI
}));
// 打印 newReferences
console.log(newReferences);
dataString = rawData
.map((entry: any) => {
return `Time: ${entry.year}\nTitle: ${entry.title}\nSummary: ${entry.abstract}\n\n`;
})
.join("");
}
// 确保搜索到的论文不超过 3000 个字符
const trimmedMessage =
dataString.length > 3000 ? dataString.slice(0, 3000) : dataString;
// 生成AI PROMPT
const content = `之前用户已经完成的内容上下文:${getTextBeforeCursor(
quill!,
800
)},搜索到的论文内容:${trimmedMessage},${topic},`;
showExpandableToast(`搜索论文完成,搜索到的论文:${trimmedMessage}`);
await sendMessageToOpenAI(
content,
quill!,
selectedModel!,
apiKey,
upsreamUrl,
systemPrompt,
cursorPosition!,
true,
newController.signal // 传递 AbortSignal
);
//在对应的位置添加文献
const nearestNumber = getNumberBeforeCursor(quill!);
dispatch(
addReferencesRedux({
references: newReferences,
position: nearestNumber,
})
);
//修改offset使得按照接下来的顺序进行获取文献
offset += 2;
setGenerateNumber(i + 1);
}
setUserInput(""); // 只有在全部成功之后才清空input内容
}
toast.success(
`AI ${actionType == "write" ? "写作" : "文献获取总结"}完成`,
{
position: "top-center",
autoClose: 2000,
pauseOnHover: true,
});
} catch (error) {
console.error("Paper2AI出现错误", error);
// 在处理错误后,再次抛出这个错误
// throw new Error(`Paper2AI出现错误: ${error}`);
toast.error(`Paper2AI出现错误: ${error}`, {
position: "top-center",
autoClose: 3000,
pauseOnHover: true,
});
}
);
} catch (error) {
toast.error(`AI写作出现错误(持续无法使用请切换deepseek模型): ${error}`, {
position: "top-center",
autoClose: 3000,
pauseOnHover: true,
});
Sentry.captureMessage(`AI写作出现错误: ${error}`, "error");
} finally {
// 通用的后处理逻辑
const updatedContent = quill!.root.innerHTML;
dispatch(setEditorContent(updatedContent));
if (isVip) {
//在云端同步supabase
const data = await submitPaper(
supabase,
updatedContent,
references,
paperNumberRedux
);
}
setOpenProgressBar(false);
setGenerateNumber(0); //总的已经生成的数量设置为0 以便下次使用
}
setOpenProgressBar(false);
setGenerateNumber(0); //总的已经生成的数量
}
const handleStop = () => {
if (controller) {
controller.abort(); // 取消请求
setController(null); // 重置 controller 状态
}
};
return (
<div className="flex flex-col ">
<div id="Qtoolbar" className="space-y-2 flex justify-between">
@ -533,13 +561,13 @@ const QEditor = ({ lng }) => {
)}
/>
<button
onClick={handleAIWrite}
onClick={() => handleAIAction(userInput, "write")}
className="bg-gray-300 hover:bg-gray-400 text-black font-bold py-2 px-4 mr-2 rounded"
>
{t("AI写作")}
</button>
<button
onClick={() => paper2AI(userInput)}
onClick={() => handleAIAction(userInput, "paper2AI")}
className="bg-yellow-500 hover:bg-yellow-600 text-white font-bold py-2 px-4 mr-2 rounded"
>
{t("Paper2AI")}
@ -565,6 +593,10 @@ const QEditor = ({ lng }) => {
<option value="gpt-3.5-turbo">gpt-3.5-turbo</option>
<option value="gpt-4">gpt-4</option>
<option value="deepseek-chat">deepseek-chat</option>
<option value="commandr">commandr</option>
<option value="gemini-pro">gemini-pro</option>
<option value="mixtral-8x7b-32768">mixtral-8x7b-32768</option>
<option value="llama2-70b-4096">llama2-70b-4096</option>
</select>
{/* 进行几轮生成 */}
<input
@ -601,6 +633,16 @@ const QEditor = ({ lng }) => {
<ReferenceList editor={quill} lng={lng} />
<ExportDocx editor={quill} />
</div>
{/* 停止生成的按钮只有在开始对话之后才会出现 */}
{openProgressBar ? (
<button
onClick={handleStop}
className="fixed bottom-4 left-4 bg-red-500 hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-opacity-50 active:bg-red-700 text-white font-bold py-2 px-4 rounded transition ease-in-out duration-150 shadow-lg hover:shadow-xl"
>
{t("停止生成")}
</button>
) : null}
<ToastContainer />
</div>
);

View File

@ -25,30 +25,45 @@ const Settings = ({ lng }: { lng: string }) => {
//i18n
const { t } = useTranslation(lng);
const CONFIG_OPTIONS = [
{
name: t("configurations.蒙恬大将军"),
apiKey: "sk-jokVJ90l5Swxr5dt2f3b0988C8A442A69f97Ee4eAf7aDcF4",
upstreamUrl: "https://freeapi.iil.im",
},
// {
// name: t("configurations.蒙恬大将军"),
// apiKey: "sk-jokVJ90l5Swxr5dt2f3b0988C8A442A69f97Ee4eAf7aDcF4",
// upstreamUrl: "https://freeapi.iil.im",
// },
// {
// name: t("configurations.coze"),
// apiKey: "MTIwMjE2ODMyODA1NTk1MTM2MA",
// upstreamUrl: "https://coze.paperai.life",
// },
{
name: t("configurations.deepseek-chat"),
apiKey: "sk-ffe19ebe9fa44d00884330ff1c18cf82",
upstreamUrl: "https://api.deepseek.com",
},
// {
// name: t("configurations.caifree"),
// apiKey: "sk-MaEuOo9qIeWKK3PRCdCb9b3d47E64e36Ad6022724b780592",
// upstreamUrl: "https://one.caifree.com",
// },
// {
// name: t("configurations.官网反代"),
// apiKey: "3b73ec02-3255-4b27-a202-42ab9a6e85ba",
// upstreamUrl: "https://plus.liuweiqing.top",
// },
// {
// name: t("configurations.vv佬"),
// apiKey: "nk-23118",
// upstreamUrl: "https://cocopilot-pool.aivvm.com",
// },
// {
// name: t("configurations.linuxdo"),
// apiKey: "nk-2311676378",
// upstreamUrl: "https://chat.flss.world/api/openai",
// },
{
name: t("configurations.caifree"),
apiKey: "sk-MaEuOo9qIeWKK3PRCdCb9b3d47E64e36Ad6022724b780592",
upstreamUrl: "https://one.caifree.com",
},
{
name: t("configurations.vv佬"),
apiKey: "nk-23118",
upstreamUrl: "https://cocopilot-pool.aivvm.com",
},
{
name: t("configurations.linuxdo"),
apiKey: "nk-2311676378",
upstreamUrl: "https://chat.flss.world/api/openai",
name: t("configurations.oneapi"),
apiKey: "sk-GHuPUV6ERD8wVmmr36FeB8D809D34d93Bb857c009f6aF9Fe",
upstreamUrl: "https://one.paperai.life",
},
{
name: t("configurations.custom"),

View File

@ -1,56 +0,0 @@
"use client";
import { insertUserProfile } from "@/utils/supabase/supabaseutils";
import { createClient } from "@/utils/supabase/client";
import { useEffect } from "react";
export function SignInGitHub() {
useEffect(() => {
const supabase = createClient();
const { data: data } = supabase.auth.onAuthStateChange(
async (event, session) => {
if (event === "SIGNED_IN") {
// 用户登录成功,执行后续操作
await insertUserProfile(session!.user, supabase);
}
}
);
return () => {
// call unsubscribe to remove the callback
data.subscription.unsubscribe();
};
}, []);
const signInWithGithub = async () => {
const supabase = createClient();
const { data, error } = await supabase.auth.signInWithOAuth({
provider: "github",
});
if (error) {
console.error("GitHub authentication failed:", error.message);
return; // 如果出现错误,不再继续执行
}
//profiles表 插入用户信息
await insertUserProfile(data, supabase);
};
return (
<button
className="bg-black text-white rounded-md px-4 py-2 flex items-center justify-center"
onClick={signInWithGithub}
>
<svg
role="img"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
className="mr-2 h-4 w-4"
>
<title>GitHub icon</title>
<path
fill="currentColor"
d="M12 .3a12 12 0 0 0-3.8 23.4c.6.1.8-.3.8-.6v-2C8.7 21 8 20 8 20c-1.1 0-1.8-.9-1.8-.9-.6-1-.1-1.8.1-2 .7-.6 1.8-.4 2.7.1.1-.5.3-.9.5-1.1-2.3-.3-4.7-1.1-4.7-5 0-1.1.4-2 1-2.7 0-1 .1-2 .7-2.7 0 0 .9-.3 2.8 1a9.8 9.8 0 0 1 5.2 0c1.9-1.3 2.8-1 2.8-1 .6.7.7 1.7.7 2.7.7.7 1 1.6 1 2.7 0 3.9-2.4 4.7-4.7 5 .3.2.6.7.6 1.4v2.1c0 .3.2.7.8.6A12 12 0 0 0 12 .3"
/>
</svg>
Sign In with GitHub
</button>
);
}

View File

@ -0,0 +1,70 @@
// components/SignInWithProvider.tsx
"use client";
import { insertUserProfile } from "@/utils/supabase/supabaseutils";
import { createClient } from "@/utils/supabase/client";
import { useEffect } from "react";
import * as Sentry from "@sentry/react";
import { FaGithub, FaGoogle } from "react-icons/fa";
export function SignInWithProvider({ provider, redirectTo }) {
useEffect(() => {
const supabase = createClient();
const { data } = supabase.auth.onAuthStateChange(async (event, session) => {
if (session && session.provider_token) {
// 用户登录成功,执行后续操作
await insertUserProfile(session.user, supabase);
Sentry.captureMessage(`${provider}登录成功`, "info");
console.log(`${provider}登录成功`);
} else {
Sentry.captureMessage(
`${provider}登录中的其它的event${event}`,
"warning"
);
console.log(`${provider}登录中的其它的event`, event);
}
});
return () => data.subscription.unsubscribe();
}, [provider]);
function getProviderIcon(provider) {
switch (provider) {
case "github":
return <FaGithub />;
case "google":
return <FaGoogle />;
default:
return null;
}
}
const signIn = async () => {
const supabase = createClient();
const { data, error } = await supabase.auth.signInWithOAuth({
provider: provider,
options: {
// redirectTo: redirectTo,
queryParams: {
access_type: "offline",
prompt: "consent",
},
},
});
if (error) {
console.error(`${provider} authentication failed:`, error.message);
}
//profiles表 插入用户信息
await insertUserProfile(data, supabase);
};
return (
<button
onClick={signIn}
className="bg-black text-white rounded-md px-4 py-2 mb-2 flex items-center justify-center gap-2 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white transition ease-in duration-200 w-full"
>
{getProviderIcon(provider)} Sign In with{" "}
{provider.charAt(0).toUpperCase() + provider.slice(1)}
</button>
);
}

View File

@ -1,8 +1,5 @@
import { Transforms } from "slate";
import { Editor } from "slate";
import Quill from "quill";
import { extractText } from "@/utils/others/slateutils";
import {
updateBracketNumbersInDeltaKeepSelection,
convertToSuperscript,
@ -29,7 +26,8 @@ const sendMessageToOpenAI = async (
upsreamUrl: string,
prompt: string,
cursorPosition: number | null,
useEditorFlag = true // 新增的标志,用于决定操作
useEditorFlag = true, // 新增的标志,用于决定操作
signal: AbortSignal
) => {
//识别应该使用的模型
let model = selectedModel;
@ -37,6 +35,7 @@ const sendMessageToOpenAI = async (
// 设置API请求参数
const requestOptions = {
method: "POST",
signal: signal,
headers: {
"Content-Type": "application/json",
// "Upstream-Url": upsreamUrl,
@ -75,7 +74,7 @@ const sendMessageToOpenAI = async (
// 发送API请求
let response;
let responseClone = null; // 用于保存响应内容的变量
try {
response = await fetch(
(upsreamUrl || process.env.NEXT_PUBLIC_AI_URL) + "/v1/chat/completions",
@ -89,6 +88,8 @@ const sendMessageToOpenAI = async (
// 处理其他类型的HTTP错误
throw new Error(`HTTP错误状态码${response.status}`);
}
// 克隆响应以备后用
responseClone = response.clone();
if (useEditorFlag && editor && cursorPosition !== null) {
const reader = response.body!.getReader();
const decoder = new TextDecoder();
@ -106,60 +107,24 @@ const sendMessageToOpenAI = async (
const content = data.choices[0].message.content;
return content; // 或根据需要处理并返回数据
}
} catch (error) {
console.error("Error:", error);
// 如果有响应,返回响应的原始内容
if (response) {
const rawResponse = await response.text();
throw new Error(
`请求发生错误: ${error.message}, Response: ${rawResponse}`
);
} catch (error: any) {
if (error.name === "AbortError") {
console.log("Fetch operation was aborted");
//这里不用产生报错因为是手动停止
return;
}
// 如果没有响应,只抛出错误
throw error;
}
};
console.error("Error:", error);
const getAI = async (
userMessage: string,
systemPrompt: string,
apiKey: string,
upsreamUrl: string,
selectedModel: string
) => {
// 设置API请求参数
const requestOptions = {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization:
"Bearer " +
(isValidApiKey(apiKey)
? apiKey
: process.env.NEXT_PUBLIC_OPENAI_API_KEY),
},
body: JSON.stringify({
model: selectedModel || "gpt-3.5-turbo",
stream: false,
messages: [
{
role: "system",
content: systemPrompt,
},
{
role: "user",
content: userMessage,
},
],
}),
};
const response = await fetch(
(upsreamUrl || process.env.NEXT_PUBLIC_AI_URL) + "/v1/chat/completions",
requestOptions
);
const data = await response.json();
const topic = data.choices[0].message.content;
return topic; // 获取并返回回复
// 根据是否成功读取响应体来抛出错误
if (responseClone) {
const textResponse = await responseClone.text(); // 从克隆的响应中读取数据
throw new Error(
`请求发生错误: ${error.message}, Response: ${textResponse}`
);
} else {
throw new Error(`请求发生错误: ${error.message}`);
}
}
};
async function processResult(reader, decoder, editor) {
@ -193,8 +158,8 @@ async function processResult(reader, decoder, editor) {
// 处理 dataObject 中的 content
if (dataObject.choices && dataObject.choices.length > 0) {
let content =
dataObject.choices[0].message?.content ||
dataObject.choices[0].delta?.content;
dataObject.choices[0].delta?.content ??
dataObject.choices[0].message?.content;
if (content) {
// 在当前光标位置插入文本
// editor.focus();
@ -214,4 +179,4 @@ async function processResult(reader, decoder, editor) {
}
}
export { getAI, sendMessageToOpenAI };
export { sendMessageToOpenAI };

11
docker-compose.yml Normal file
View File

@ -0,0 +1,11 @@
version: "3.8" # 使用 Docker Compose 文件版本 3.8,根据需要可以更改
services:
paperai:
image: 14790897/paperai:latest
container_name: paperai_app
ports:
- "3000:3000" # 映射宿主机和容器的端口
# environment: # 设置环境变量
# NEXT_PUBLIC_AI_URL: "自定义AI模型地址"
# NEXT_PUBLIC_OPENAI_API_KEY: "自定义API KEY"
restart: unless-stopped # 容器退出时重启策略

View File

@ -1,268 +0,0 @@
import {
useMediaQuery
} from "./chunk-DN3Q4TEW.js";
import {
computed,
ref,
shallowRef,
watch
} from "./chunk-456JUNPJ.js";
// node_modules/vitepress/dist/client/theme-default/index.js
import "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/styles/fonts.css";
// node_modules/vitepress/dist/client/theme-default/without-fonts.js
import "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/styles/vars.css";
import "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/styles/base.css";
import "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/styles/utils.css";
import "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/styles/components/custom-block.css";
import "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code.css";
import "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code-group.css";
import "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-doc.css";
import "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-sponsor.css";
import VPBadge from "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
import Layout from "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/Layout.vue";
import { default as default2 } from "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
import { default as default3 } from "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/components/VPImage.vue";
import { default as default4 } from "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/components/VPButton.vue";
import { default as default5 } from "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeHero.vue";
import { default as default6 } from "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeFeatures.vue";
import { default as default7 } from "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeSponsors.vue";
import { default as default8 } from "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/components/VPDocAsideSponsors.vue";
import { default as default9 } from "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/components/VPSponsors.vue";
import { default as default10 } from "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPage.vue";
import { default as default11 } from "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageTitle.vue";
import { default as default12 } from "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageSection.vue";
import { default as default13 } from "C:/git-program/paper-ai/paperai-docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamMembers.vue";
// node_modules/vitepress/dist/client/shared.js
var inBrowser = typeof document !== "undefined";
// node_modules/vitepress/dist/client/theme-default/support/utils.js
import { withBase } from "vitepress";
// node_modules/vitepress/dist/client/theme-default/composables/data.js
import { useData as useData$ } from "vitepress";
var useData = useData$;
// node_modules/vitepress/dist/client/theme-default/support/utils.js
function ensureStartingSlash(path) {
return /^\//.test(path) ? path : `/${path}`;
}
// node_modules/vitepress/dist/client/theme-default/support/sidebar.js
function getSidebar(_sidebar, path) {
if (Array.isArray(_sidebar))
return addBase(_sidebar);
if (_sidebar == null)
return [];
path = ensureStartingSlash(path);
const dir = Object.keys(_sidebar).sort((a, b) => {
return b.split("/").length - a.split("/").length;
}).find((dir2) => {
return path.startsWith(ensureStartingSlash(dir2));
});
const sidebar = dir ? _sidebar[dir] : [];
return Array.isArray(sidebar) ? addBase(sidebar) : addBase(sidebar.items, sidebar.base);
}
function getSidebarGroups(sidebar) {
const groups = [];
let lastGroupIndex = 0;
for (const index in sidebar) {
const item = sidebar[index];
if (item.items) {
lastGroupIndex = groups.push(item);
continue;
}
if (!groups[lastGroupIndex]) {
groups.push({ items: [] });
}
groups[lastGroupIndex].items.push(item);
}
return groups;
}
function addBase(items, _base) {
return [...items].map((_item) => {
const item = { ..._item };
const base = item.base || _base;
if (base && item.link)
item.link = base + item.link;
if (item.items)
item.items = addBase(item.items, base);
return item;
});
}
// node_modules/vitepress/dist/client/theme-default/composables/hash.js
var hashRef = ref(inBrowser ? location.hash : "");
if (inBrowser) {
window.addEventListener("hashchange", () => {
hashRef.value = location.hash;
});
}
// node_modules/vitepress/dist/client/theme-default/composables/sidebar.js
function useSidebar() {
const { frontmatter, page, theme: theme2 } = useData();
const is960 = useMediaQuery("(min-width: 960px)");
const isOpen = ref(false);
const _sidebar = computed(() => {
const sidebarConfig = theme2.value.sidebar;
const relativePath = page.value.relativePath;
return sidebarConfig ? getSidebar(sidebarConfig, relativePath) : [];
});
const sidebar = ref(_sidebar.value);
watch(_sidebar, (next, prev) => {
if (JSON.stringify(next) !== JSON.stringify(prev))
sidebar.value = _sidebar.value;
});
const hasSidebar = computed(() => {
return frontmatter.value.sidebar !== false && sidebar.value.length > 0 && frontmatter.value.layout !== "home";
});
const leftAside = computed(() => {
if (hasAside)
return frontmatter.value.aside == null ? theme2.value.aside === "left" : frontmatter.value.aside === "left";
return false;
});
const hasAside = computed(() => {
if (frontmatter.value.layout === "home")
return false;
if (frontmatter.value.aside != null)
return !!frontmatter.value.aside;
return theme2.value.aside !== false;
});
const isSidebarEnabled = computed(() => hasSidebar.value && is960.value);
const sidebarGroups = computed(() => {
return hasSidebar.value ? getSidebarGroups(sidebar.value) : [];
});
function open() {
isOpen.value = true;
}
function close() {
isOpen.value = false;
}
function toggle() {
isOpen.value ? close() : open();
}
return {
isOpen,
sidebar,
sidebarGroups,
hasSidebar,
hasAside,
leftAside,
isSidebarEnabled,
open,
close,
toggle
};
}
// node_modules/vitepress/dist/client/theme-default/composables/local-nav.js
import { onContentUpdated } from "vitepress";
// node_modules/vitepress/dist/client/theme-default/composables/outline.js
import { getScrollOffset } from "vitepress";
var resolvedHeaders = [];
function getHeaders(range) {
const headers = [
...document.querySelectorAll(".VPDoc :where(h1,h2,h3,h4,h5,h6)")
].filter((el) => el.id && el.hasChildNodes()).map((el) => {
const level = Number(el.tagName[1]);
return {
element: el,
title: serializeHeader(el),
link: "#" + el.id,
level
};
});
return resolveHeaders(headers, range);
}
function serializeHeader(h) {
let ret = "";
for (const node of h.childNodes) {
if (node.nodeType === 1) {
if (node.classList.contains("VPBadge") || node.classList.contains("header-anchor") || node.classList.contains("ignore-header")) {
continue;
}
ret += node.textContent;
} else if (node.nodeType === 3) {
ret += node.textContent;
}
}
return ret.trim();
}
function resolveHeaders(headers, range) {
if (range === false) {
return [];
}
const levelsRange = (typeof range === "object" && !Array.isArray(range) ? range.level : range) || 2;
const [high, low] = typeof levelsRange === "number" ? [levelsRange, levelsRange] : levelsRange === "deep" ? [2, 6] : levelsRange;
headers = headers.filter((h) => h.level >= high && h.level <= low);
resolvedHeaders.length = 0;
for (const { element, link } of headers) {
resolvedHeaders.push({ element, link });
}
const ret = [];
outer:
for (let i = 0; i < headers.length; i++) {
const cur = headers[i];
if (i === 0) {
ret.push(cur);
} else {
for (let j = i - 1; j >= 0; j--) {
const prev = headers[j];
if (prev.level < cur.level) {
;
(prev.children || (prev.children = [])).push(cur);
continue outer;
}
}
ret.push(cur);
}
}
return ret;
}
// node_modules/vitepress/dist/client/theme-default/composables/local-nav.js
function useLocalNav() {
const { theme: theme2, frontmatter } = useData();
const headers = shallowRef([]);
const hasLocalNav = computed(() => {
return headers.value.length > 0;
});
onContentUpdated(() => {
headers.value = getHeaders(frontmatter.value.outline ?? theme2.value.outline);
});
return {
headers,
hasLocalNav
};
}
// node_modules/vitepress/dist/client/theme-default/without-fonts.js
var theme = {
Layout,
enhanceApp: ({ app }) => {
app.component("Badge", VPBadge);
}
};
var without_fonts_default = theme;
export {
default2 as VPBadge,
default4 as VPButton,
default8 as VPDocAsideSponsors,
default6 as VPHomeFeatures,
default5 as VPHomeHero,
default7 as VPHomeSponsors,
default3 as VPImage,
default9 as VPSponsors,
default13 as VPTeamMembers,
default10 as VPTeamPage,
default12 as VPTeamPageSection,
default11 as VPTeamPageTitle,
without_fonts_default as default,
useLocalNav,
useSidebar
};
//# sourceMappingURL=@theme_index.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,40 +0,0 @@
{
"hash": "8c371e85",
"configHash": "441e0395",
"lockfileHash": "9cf9febc",
"browserHash": "c76444d4",
"optimized": {
"vue": {
"src": "../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
"fileHash": "263297c9",
"needsInterop": false
},
"vitepress > @vue/devtools-api": {
"src": "../../../node_modules/@vue/devtools-api/dist/index.js",
"file": "vitepress___@vue_devtools-api.js",
"fileHash": "483a8161",
"needsInterop": false
},
"vitepress > @vueuse/core": {
"src": "../../../node_modules/@vueuse/core/index.mjs",
"file": "vitepress___@vueuse_core.js",
"fileHash": "5dcb9da3",
"needsInterop": false
},
"@theme/index": {
"src": "../../../node_modules/vitepress/dist/client/theme-default/index.js",
"file": "@theme_index.js",
"fileHash": "9a4b4951",
"needsInterop": false
}
},
"chunks": {
"chunk-DN3Q4TEW": {
"file": "chunk-DN3Q4TEW.js"
},
"chunk-456JUNPJ": {
"file": "chunk-456JUNPJ.js"
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,3 +0,0 @@
{
"type": "module"
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,563 +0,0 @@
import {
DefaultMagicKeysAliasMap,
StorageSerializers,
TransitionPresets,
assert,
breakpointsAntDesign,
breakpointsBootstrapV5,
breakpointsMasterCss,
breakpointsPrimeFlex,
breakpointsQuasar,
breakpointsSematic,
breakpointsTailwind,
breakpointsVuetify,
bypassFilter,
camelize,
clamp,
cloneFnJSON,
computedAsync,
computedEager,
computedInject,
computedWithControl,
containsProp,
controlledRef,
createEventHook,
createFetch,
createFilterWrapper,
createGlobalState,
createInjectionState,
createReusableTemplate,
createSharedComposable,
createSingletonPromise,
createTemplatePromise,
createUnrefFn,
customStorageEventName,
debounceFilter,
defaultDocument,
defaultLocation,
defaultNavigator,
defaultWindow,
directiveHooks,
executeTransition,
extendRef,
formatDate,
formatTimeAgo,
get,
getLifeCycleTarget,
getSSRHandler,
hasOwn,
hyphenate,
identity,
increaseWithUnit,
injectLocal,
invoke,
isClient,
isDef,
isDefined,
isIOS,
isObject,
isWorker,
makeDestructurable,
mapGamepadToXbox360Controller,
noop,
normalizeDate,
notNullish,
now,
objectEntries,
objectOmit,
objectPick,
onClickOutside,
onKeyDown,
onKeyPressed,
onKeyStroke,
onKeyUp,
onLongPress,
onStartTyping,
pausableFilter,
promiseTimeout,
provideLocal,
rand,
reactify,
reactifyObject,
reactiveComputed,
reactiveOmit,
reactivePick,
refAutoReset,
refDebounced,
refDefault,
refThrottled,
refWithControl,
resolveRef,
resolveUnref,
set,
setSSRHandler,
syncRef,
syncRefs,
templateRef,
throttleFilter,
timestamp,
toReactive,
toRef,
toRefs,
toValue,
tryOnBeforeMount,
tryOnBeforeUnmount,
tryOnMounted,
tryOnScopeDispose,
tryOnUnmounted,
unrefElement,
until,
useActiveElement,
useAnimate,
useArrayDifference,
useArrayEvery,
useArrayFilter,
useArrayFind,
useArrayFindIndex,
useArrayFindLast,
useArrayIncludes,
useArrayJoin,
useArrayMap,
useArrayReduce,
useArraySome,
useArrayUnique,
useAsyncQueue,
useAsyncState,
useBase64,
useBattery,
useBluetooth,
useBreakpoints,
useBroadcastChannel,
useBrowserLocation,
useCached,
useClipboard,
useClipboardItems,
useCloned,
useColorMode,
useConfirmDialog,
useCounter,
useCssVar,
useCurrentElement,
useCycleList,
useDark,
useDateFormat,
useDebounceFn,
useDebouncedRefHistory,
useDeviceMotion,
useDeviceOrientation,
useDevicePixelRatio,
useDevicesList,
useDisplayMedia,
useDocumentVisibility,
useDraggable,
useDropZone,
useElementBounding,
useElementByPoint,
useElementHover,
useElementSize,
useElementVisibility,
useEventBus,
useEventListener,
useEventSource,
useEyeDropper,
useFavicon,
useFetch,
useFileDialog,
useFileSystemAccess,
useFocus,
useFocusWithin,
useFps,
useFullscreen,
useGamepad,
useGeolocation,
useIdle,
useImage,
useInfiniteScroll,
useIntersectionObserver,
useInterval,
useIntervalFn,
useKeyModifier,
useLastChanged,
useLocalStorage,
useMagicKeys,
useManualRefHistory,
useMediaControls,
useMediaQuery,
useMemoize,
useMemory,
useMounted,
useMouse,
useMouseInElement,
useMousePressed,
useMutationObserver,
useNavigatorLanguage,
useNetwork,
useNow,
useObjectUrl,
useOffsetPagination,
useOnline,
usePageLeave,
useParallax,
useParentElement,
usePerformanceObserver,
usePermission,
usePointer,
usePointerLock,
usePointerSwipe,
usePreferredColorScheme,
usePreferredContrast,
usePreferredDark,
usePreferredLanguages,
usePreferredReducedMotion,
usePrevious,
useRafFn,
useRefHistory,
useResizeObserver,
useScreenOrientation,
useScreenSafeArea,
useScriptTag,
useScroll,
useScrollLock,
useSessionStorage,
useShare,
useSorted,
useSpeechRecognition,
useSpeechSynthesis,
useStepper,
useStorage,
useStorageAsync,
useStyleTag,
useSupported,
useSwipe,
useTemplateRefsList,
useTextDirection,
useTextSelection,
useTextareaAutosize,
useThrottleFn,
useThrottledRefHistory,
useTimeAgo,
useTimeout,
useTimeoutFn,
useTimeoutPoll,
useTimestamp,
useTitle,
useToNumber,
useToString,
useToggle,
useTransition,
useUrlSearchParams,
useUserMedia,
useVModel,
useVModels,
useVibrate,
useVirtualList,
useWakeLock,
useWebNotification,
useWebSocket,
useWebWorker,
useWebWorkerFn,
useWindowFocus,
useWindowScroll,
useWindowSize,
watchArray,
watchAtMost,
watchDebounced,
watchDeep,
watchIgnorable,
watchImmediate,
watchOnce,
watchPausable,
watchThrottled,
watchTriggerable,
watchWithFilter,
whenever
} from "./chunk-DN3Q4TEW.js";
import "./chunk-456JUNPJ.js";
export {
DefaultMagicKeysAliasMap,
StorageSerializers,
TransitionPresets,
assert,
computedAsync as asyncComputed,
refAutoReset as autoResetRef,
breakpointsAntDesign,
breakpointsBootstrapV5,
breakpointsMasterCss,
breakpointsPrimeFlex,
breakpointsQuasar,
breakpointsSematic,
breakpointsTailwind,
breakpointsVuetify,
bypassFilter,
camelize,
clamp,
cloneFnJSON,
computedAsync,
computedEager,
computedInject,
computedWithControl,
containsProp,
computedWithControl as controlledComputed,
controlledRef,
createEventHook,
createFetch,
createFilterWrapper,
createGlobalState,
createInjectionState,
reactify as createReactiveFn,
createReusableTemplate,
createSharedComposable,
createSingletonPromise,
createTemplatePromise,
createUnrefFn,
customStorageEventName,
debounceFilter,
refDebounced as debouncedRef,
watchDebounced as debouncedWatch,
defaultDocument,
defaultLocation,
defaultNavigator,
defaultWindow,
directiveHooks,
computedEager as eagerComputed,
executeTransition,
extendRef,
formatDate,
formatTimeAgo,
get,
getLifeCycleTarget,
getSSRHandler,
hasOwn,
hyphenate,
identity,
watchIgnorable as ignorableWatch,
increaseWithUnit,
injectLocal,
invoke,
isClient,
isDef,
isDefined,
isIOS,
isObject,
isWorker,
makeDestructurable,
mapGamepadToXbox360Controller,
noop,
normalizeDate,
notNullish,
now,
objectEntries,
objectOmit,
objectPick,
onClickOutside,
onKeyDown,
onKeyPressed,
onKeyStroke,
onKeyUp,
onLongPress,
onStartTyping,
pausableFilter,
watchPausable as pausableWatch,
promiseTimeout,
provideLocal,
rand,
reactify,
reactifyObject,
reactiveComputed,
reactiveOmit,
reactivePick,
refAutoReset,
refDebounced,
refDefault,
refThrottled,
refWithControl,
resolveRef,
resolveUnref,
set,
setSSRHandler,
syncRef,
syncRefs,
templateRef,
throttleFilter,
refThrottled as throttledRef,
watchThrottled as throttledWatch,
timestamp,
toReactive,
toRef,
toRefs,
toValue,
tryOnBeforeMount,
tryOnBeforeUnmount,
tryOnMounted,
tryOnScopeDispose,
tryOnUnmounted,
unrefElement,
until,
useActiveElement,
useAnimate,
useArrayDifference,
useArrayEvery,
useArrayFilter,
useArrayFind,
useArrayFindIndex,
useArrayFindLast,
useArrayIncludes,
useArrayJoin,
useArrayMap,
useArrayReduce,
useArraySome,
useArrayUnique,
useAsyncQueue,
useAsyncState,
useBase64,
useBattery,
useBluetooth,
useBreakpoints,
useBroadcastChannel,
useBrowserLocation,
useCached,
useClipboard,
useClipboardItems,
useCloned,
useColorMode,
useConfirmDialog,
useCounter,
useCssVar,
useCurrentElement,
useCycleList,
useDark,
useDateFormat,
refDebounced as useDebounce,
useDebounceFn,
useDebouncedRefHistory,
useDeviceMotion,
useDeviceOrientation,
useDevicePixelRatio,
useDevicesList,
useDisplayMedia,
useDocumentVisibility,
useDraggable,
useDropZone,
useElementBounding,
useElementByPoint,
useElementHover,
useElementSize,
useElementVisibility,
useEventBus,
useEventListener,
useEventSource,
useEyeDropper,
useFavicon,
useFetch,
useFileDialog,
useFileSystemAccess,
useFocus,
useFocusWithin,
useFps,
useFullscreen,
useGamepad,
useGeolocation,
useIdle,
useImage,
useInfiniteScroll,
useIntersectionObserver,
useInterval,
useIntervalFn,
useKeyModifier,
useLastChanged,
useLocalStorage,
useMagicKeys,
useManualRefHistory,
useMediaControls,
useMediaQuery,
useMemoize,
useMemory,
useMounted,
useMouse,
useMouseInElement,
useMousePressed,
useMutationObserver,
useNavigatorLanguage,
useNetwork,
useNow,
useObjectUrl,
useOffsetPagination,
useOnline,
usePageLeave,
useParallax,
useParentElement,
usePerformanceObserver,
usePermission,
usePointer,
usePointerLock,
usePointerSwipe,
usePreferredColorScheme,
usePreferredContrast,
usePreferredDark,
usePreferredLanguages,
usePreferredReducedMotion,
usePrevious,
useRafFn,
useRefHistory,
useResizeObserver,
useScreenOrientation,
useScreenSafeArea,
useScriptTag,
useScroll,
useScrollLock,
useSessionStorage,
useShare,
useSorted,
useSpeechRecognition,
useSpeechSynthesis,
useStepper,
useStorage,
useStorageAsync,
useStyleTag,
useSupported,
useSwipe,
useTemplateRefsList,
useTextDirection,
useTextSelection,
useTextareaAutosize,
refThrottled as useThrottle,
useThrottleFn,
useThrottledRefHistory,
useTimeAgo,
useTimeout,
useTimeoutFn,
useTimeoutPoll,
useTimestamp,
useTitle,
useToNumber,
useToString,
useToggle,
useTransition,
useUrlSearchParams,
useUserMedia,
useVModel,
useVModels,
useVibrate,
useVirtualList,
useWakeLock,
useWebNotification,
useWebSocket,
useWebWorker,
useWebWorkerFn,
useWindowFocus,
useWindowScroll,
useWindowSize,
watchArray,
watchAtMost,
watchDebounced,
watchDeep,
watchIgnorable,
watchImmediate,
watchOnce,
watchPausable,
watchThrottled,
watchTriggerable,
watchWithFilter,
whenever
};
//# sourceMappingURL=vitepress___@vueuse_core.js.map

View File

@ -1,7 +0,0 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}

View File

@ -1,323 +0,0 @@
import {
BaseTransition,
BaseTransitionPropsValidators,
Comment,
DeprecationTypes,
EffectScope,
ErrorCodes,
ErrorTypeStrings,
Fragment,
KeepAlive,
ReactiveEffect,
Static,
Suspense,
Teleport,
Text,
TrackOpTypes,
Transition,
TransitionGroup,
TriggerOpTypes,
VueElement,
assertNumber,
callWithAsyncErrorHandling,
callWithErrorHandling,
camelize,
capitalize,
cloneVNode,
compatUtils,
compile,
computed,
createApp,
createBaseVNode,
createBlock,
createCommentVNode,
createElementBlock,
createHydrationRenderer,
createPropsRestProxy,
createRenderer,
createSSRApp,
createSlots,
createStaticVNode,
createTextVNode,
createVNode,
customRef,
defineAsyncComponent,
defineComponent,
defineCustomElement,
defineEmits,
defineExpose,
defineModel,
defineOptions,
defineProps,
defineSSRCustomElement,
defineSlots,
devtools,
effect,
effectScope,
getCurrentInstance,
getCurrentScope,
getTransitionRawChildren,
guardReactiveProps,
h,
handleError,
hasInjectionContext,
hydrate,
initCustomFormatter,
initDirectivesForSSR,
inject,
isMemoSame,
isProxy,
isReactive,
isReadonly,
isRef,
isRuntimeOnly,
isShallow,
isVNode,
markRaw,
mergeDefaults,
mergeModels,
mergeProps,
nextTick,
normalizeClass,
normalizeProps,
normalizeStyle,
onActivated,
onBeforeMount,
onBeforeUnmount,
onBeforeUpdate,
onDeactivated,
onErrorCaptured,
onMounted,
onRenderTracked,
onRenderTriggered,
onScopeDispose,
onServerPrefetch,
onUnmounted,
onUpdated,
openBlock,
popScopeId,
provide,
proxyRefs,
pushScopeId,
queuePostFlushCb,
reactive,
readonly,
ref,
registerRuntimeCompiler,
render,
renderList,
renderSlot,
resolveComponent,
resolveDirective,
resolveDynamicComponent,
resolveFilter,
resolveTransitionHooks,
setBlockTracking,
setDevtoolsHook,
setTransitionHooks,
shallowReactive,
shallowReadonly,
shallowRef,
ssrContextKey,
ssrUtils,
stop,
toDisplayString,
toHandlerKey,
toHandlers,
toRaw,
toRef,
toRefs,
toValue,
transformVNodeArgs,
triggerRef,
unref,
useAttrs,
useCssModule,
useCssVars,
useModel,
useSSRContext,
useSlots,
useTransitionState,
vModelCheckbox,
vModelDynamic,
vModelRadio,
vModelSelect,
vModelText,
vShow,
version,
warn,
watch,
watchEffect,
watchPostEffect,
watchSyncEffect,
withAsyncContext,
withCtx,
withDefaults,
withDirectives,
withKeys,
withMemo,
withModifiers,
withScopeId
} from "./chunk-456JUNPJ.js";
export {
BaseTransition,
BaseTransitionPropsValidators,
Comment,
DeprecationTypes,
EffectScope,
ErrorCodes,
ErrorTypeStrings,
Fragment,
KeepAlive,
ReactiveEffect,
Static,
Suspense,
Teleport,
Text,
TrackOpTypes,
Transition,
TransitionGroup,
TriggerOpTypes,
VueElement,
assertNumber,
callWithAsyncErrorHandling,
callWithErrorHandling,
camelize,
capitalize,
cloneVNode,
compatUtils,
compile,
computed,
createApp,
createBlock,
createCommentVNode,
createElementBlock,
createBaseVNode as createElementVNode,
createHydrationRenderer,
createPropsRestProxy,
createRenderer,
createSSRApp,
createSlots,
createStaticVNode,
createTextVNode,
createVNode,
customRef,
defineAsyncComponent,
defineComponent,
defineCustomElement,
defineEmits,
defineExpose,
defineModel,
defineOptions,
defineProps,
defineSSRCustomElement,
defineSlots,
devtools,
effect,
effectScope,
getCurrentInstance,
getCurrentScope,
getTransitionRawChildren,
guardReactiveProps,
h,
handleError,
hasInjectionContext,
hydrate,
initCustomFormatter,
initDirectivesForSSR,
inject,
isMemoSame,
isProxy,
isReactive,
isReadonly,
isRef,
isRuntimeOnly,
isShallow,
isVNode,
markRaw,
mergeDefaults,
mergeModels,
mergeProps,
nextTick,
normalizeClass,
normalizeProps,
normalizeStyle,
onActivated,
onBeforeMount,
onBeforeUnmount,
onBeforeUpdate,
onDeactivated,
onErrorCaptured,
onMounted,
onRenderTracked,
onRenderTriggered,
onScopeDispose,
onServerPrefetch,
onUnmounted,
onUpdated,
openBlock,
popScopeId,
provide,
proxyRefs,
pushScopeId,
queuePostFlushCb,
reactive,
readonly,
ref,
registerRuntimeCompiler,
render,
renderList,
renderSlot,
resolveComponent,
resolveDirective,
resolveDynamicComponent,
resolveFilter,
resolveTransitionHooks,
setBlockTracking,
setDevtoolsHook,
setTransitionHooks,
shallowReactive,
shallowReadonly,
shallowRef,
ssrContextKey,
ssrUtils,
stop,
toDisplayString,
toHandlerKey,
toHandlers,
toRaw,
toRef,
toRefs,
toValue,
transformVNodeArgs,
triggerRef,
unref,
useAttrs,
useCssModule,
useCssVars,
useModel,
useSSRContext,
useSlots,
useTransitionState,
vModelCheckbox,
vModelDynamic,
vModelRadio,
vModelSelect,
vModelText,
vShow,
version,
warn,
watch,
watchEffect,
watchPostEffect,
watchSyncEffect,
withAsyncContext,
withCtx,
withDefaults,
withDirectives,
withKeys,
withMemo,
withModifiers,
withScopeId
};
//# sourceMappingURL=vue.js.map

View File

@ -1,7 +0,0 @@
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}

View File

@ -1,36 +0,0 @@
import { defineConfig } from "vitepress";
// https://vitepress.dev/reference/site-config
export default defineConfig({
title: "paperai-docs",
description: "paperai docs",
base: "/paper-ai/",
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
nav: [
{ text: "Home", link: "/" },
{
text: "GitHub",
link: "https://github.com/14790897/paper-ai",
},
],
sidebar: [
{
text: "Examples",
items: [
// { text: "Markdown Examples", link: "/markdown-examples" },
// { text: "Runtime API Examples", link: "/api-examples" },
{ text: "功能介绍 function", link: "/paperai-function" },
{ text: "部署方法 deploy", link: "/paperai-deploy" },
{ text: "环境变量 env", link: "/paperai-env" },
{ text: "界面展示 show", link: "/paperai-interface" },
],
},
],
socialLinks: [
{ icon: "github", link: "https://github.com/vuejs/vitepress" },
],
},
});

View File

@ -1,49 +0,0 @@
---
outline: deep
---
# Runtime API Examples
This page demonstrates usage of some of the runtime APIs provided by VitePress.
The main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files:
```md
<script setup>
import { useData } from 'vitepress'
const { theme, page, frontmatter } = useData()
</script>
## Results
### Theme Data
<pre>{{ theme }}</pre>
### Page Data
<pre>{{ page }}</pre>
### Page Frontmatter
<pre>{{ frontmatter }}</pre>
```
<script setup>
import { useData } from 'vitepress'
const { site, theme, page, frontmatter } = useData()
</script>
## Results
### Theme Data
<pre>{{ theme }}</pre>
### Page Data
<pre>{{ page }}</pre>
### Page Frontmatter
<pre>{{ frontmatter }}</pre>
## More
Check out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata).

View File

@ -1,30 +0,0 @@
---
# https://vitepress.dev/reference/default-theme-home-page
layout: home
hero:
name: "paperai-docs"
text: "paperai docs"
tagline: My great project tagline
actions:
- theme: brand
text: paperai-function
link: /paperai-function
- theme: brand
text: paperai-deploy
link: /paperai-deploy
- theme: brand
text: paperai-env
link: /paperai-env
- theme: alt
text: API Examples
link: /api-examples
features:
- title: Feature 1 使用真实文献
details: 从各种文献网站获取真实文献
- title: Feature 2 AI写作
details: 内置免费AI模型
- title: Feature 3 文献管理
details: 将文献有序地排列
---

View File

@ -1,85 +0,0 @@
# Markdown Extension Examples
This page demonstrates some of the built-in markdown extensions provided by VitePress.
## Syntax Highlighting
VitePress provides Syntax Highlighting powered by [Shiki](https://github.com/shikijs/shiki), with additional features like line-highlighting:
**Input**
````md
```js{4}
export default {
data () {
return {
msg: 'Highlighted!'
}
}
}
```
````
**Output**
```js{4}
export default {
data () {
return {
msg: 'Highlighted!'
}
}
}
```
## Custom Containers
**Input**
```md
::: info
This is an info box.
:::
::: tip
This is a tip.
:::
::: warning
This is a warning.
:::
::: danger
This is a dangerous warning.
:::
::: details
This is a details block.
:::
```
**Output**
::: info
This is an info box.
:::
::: tip
This is a tip.
:::
::: warning
This is a warning.
:::
::: danger
This is a dangerous warning.
:::
::: details
This is a details block.
:::
## More
Check out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown).

View File

@ -1,10 +0,0 @@
{
"devDependencies": {
"vitepress": "^1.0.0-rc.42"
},
"scripts": {
"docs:dev": "vitepress dev",
"docs:build": "vitepress build",
"docs:preview": "vitepress preview"
}
}

View File

@ -1,36 +0,0 @@
## 镜像运行
1. 拉取镜像
```sh
docker pull 14790897/paperai:latest
```
2. 运行镜像
```sh
docker run -d -p 3000:3000 \
-e NEXT_PUBLIC_AI_URL=自定义AI模型地址\
-e NEXT_PUBLIC_OPENAI_API_KEY=自定义API KEY \
14790897/paperai:latest
```
## vercel 部署
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/14790897/paper-ai&project-name=paper-ai&repository-name=paper-ai&demo-title=paper-ai&demo-description=This%20starter%20configures%20Supabase%20Auth%20to%20use%20cookies%2C%20making%20the%20user's%20session%20available%20throughout%20the%20entire%20Next.js%20app%20-%20Client%20Components%2C%20Server%20Components%2C%20Route%20Handlers%2C%20Server%20Actions%20and%20Middleware.&demo-url=https%3A%2F%2Fdemo-nextjs-with-supabase.vercel.app%2F&external-id=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-supabase&demo-image=https%3A%2F%2Fpaperai.life%2Fopengraph-image.png)
## 克隆在本地运行
```bash
# 克隆版本库
git clone https://github.com/14790897/paper-ai.git
# 进入项目目录
cd paper-ai
# 安装依赖项
npm install
# 运行项目
npm run dev
```

View File

@ -1,7 +0,0 @@
## 环境变量说明
1. NEXT_PUBLIC_OPENAI_API_KEY 设置key只要在设置界面右上角齿轮对应的位置留空就会使用预定的变量
2. NEXT_PUBLIC_AI_URL 设置上游url只要在设置界面右上角齿轮对应的位置留空就会使用预定的变量
3. NEXT_PUBLIC_SEMANTIC_API_KEY 设置semantic scholar的key可以增加请求量
4. NEXT_PUBLIC_PUBMED_API_KEY 设置pubmed的key可以增加请求量

View File

@ -1,29 +0,0 @@
---
title: 介绍
sidebar: auto
---
## 功能介绍
- **人工智能书写功能** 点击 "AI 写作 "进行正常对话互动。人工智能将根据您的输入提供写作建议或回答问题。
- **寻找文献功能** 点击 "寻找文献",根据输入的关键词在 Semantic Scholar 或 arxiv 或 PubMed通过下拉框选择 中搜索论文。系统将把信息整合到您的论文中。一次搜索两篇,无搜索结果时会显示错误提示。
- **文献整理功能** 每次获得的文献都会被整理到页面下方
- **导出到 word** 页面最下方的导出 word 按钮可以将论文和文献引用直接导出到 word十分方便
- **内置多个免费 AI 模型**:请在右上角设置界面查看
- **云同步及多篇论文编辑功能**:此功能暂定收费二十元人民币永久开通,请点击左上角列表按钮进行购买,购买前需要注册账号
![](https://file.liuweiqing.life/2024/02/558e11d675d6a07dedbcfdc5ab8d072f.png)
## 具体使用方法
- 左边第一个输入框有两种用法
1. 点击 AI 写作时会读取输入框的内容进行正常的对话交流
2. 点击寻找文献会根据输入的主题词去寻找对应论文(如果输入的是英文关键词就会出现英文文献,中文关键词就是中文文献)
- 寻找文献按钮旁边是一个选择框,用于选择从哪个网站获取论文,目前可以选择 arxivsemantic scholar推荐pubmed比较推荐
- 之后是一个选择模型的选择框,用于选择对话的 AI 模型,支持哪些模型由你的 api 决定
- 往下看是一个大的输入框这里用户可以修改内容AI 生成内容
- 最下面是文献管理区域,用于整理搜索到的文献,符合中文引用格式

View File

@ -1,20 +0,0 @@
## 主界面
![](https://file.liuweiqing.life/2024/02/8efc91ee5f0eff0238b96c8f7c564c05.png)
![](https://file.liuweiqing.life/2024/02/56c022ad42fffc76dcf4215f1948cbb6.png)
## 设置界面
![](https://file.liuweiqing.life/2024/02/0955a53c01c412bdfd447b74c64585e3.png)
## 登录/注册界面
![](https://file.liuweiqing.life/2024/02/2f692952aca0263846e933a8ad9ad22a.png)
## 商店购买界面
![](https://file.liuweiqing.life/2024/02/b87d0022933462957ccf52d83c9b77ab.png)
## VIP 功能(云端同步,多篇文章编辑)
![](https://file.liuweiqing.life/2024/02/fd3b4fd44450a2276466b01b57b11c95.png)

View File

@ -69,6 +69,6 @@ export const config = {
* - favicon.ico (favicon file)
* Feel free to modify this pattern to include more paths.
*/
"/((?!_next/static|_next/image|favicon.ico|twitter-image.png|opengraph-image.png|manifest.json|site.webmanifest|favicon-32x32.png|favicon-16x16.png|apple-touch-icon.png|android-chrome-512x512.png|android-chrome-192x192.png|service-worker.js|serviceregister.js|global.css|sitemap.xml|robots.txt).*)",
"/((?!_next/static|_next/image|favicon.ico|twitter-image.png|opengraph-image.png|manifest.json|site.webmanifest|favicon-32x32.png|favicon-16x16.png|apple-touch-icon.png|android-chrome-512x512.png|android-chrome-192x192.png|service-worker.js|serviceregister.js|global.css|sitemap.xml|robots.txt|api/oauth/callback).*)",
],
};

View File

@ -6,13 +6,18 @@ const nextConfig = {
};
module.exports = nextConfig;
// 配置 @next/bundle-analyzer
const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: process.env.ANALYZE === "true",
});
// 首先使用withBundleAnalyzer包装nextConfig
const enhancedConfig = withBundleAnalyzer(nextConfig);
// Injected content via Sentry wizard below
const { withSentryConfig } = require("@sentry/nextjs");
// 然后使用withSentryConfig包装已增强的配置
module.exports = withSentryConfig(
module.exports,
enhancedConfig,
{
// For all available options, see:
// https://github.com/getsentry/sentry-webpack-plugin#options

594
package-lock.json generated
View File

@ -1,11 +1,11 @@
{
"name": "paper-ai",
"version": "1.8.0",
"version": "1.9.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"version": "1.8.0",
"version": "1.9.0",
"dependencies": {
"@formatjs/intl-localematcher": "^0.5.4",
"@fortawesome/free-solid-svg-icons": "^6.5.1",
@ -15,8 +15,8 @@
"@next/third-parties": "^14.1.0",
"@reduxjs/toolkit": "^2.0.1",
"@sentry/nextjs": "^7.101.1",
"@supabase/ssr": "latest",
"@supabase/supabase-js": "latest",
"@supabase/ssr": "*",
"@supabase/supabase-js": "*",
"@types/react-toastify": "^4.1.0",
"add": "^2.0.6",
"autoprefixer": "10.4.15",
@ -30,7 +30,7 @@
"i18next-resources-to-backend": "^1.2.0",
"lodash": "^4.17.21",
"negotiator": "^0.6.3",
"next": "latest",
"next": "*",
"next-redux-wrapper": "^8.1.0",
"openai": "^4.24.3",
"postcss": "8.4.35",
@ -42,7 +42,7 @@
"react-cookie": "^7.0.2",
"react-dom": "^18.2.0",
"react-i18next": "^14.0.5",
"react-quill": "^2.0.0",
"react-icons": "^5.0.1",
"react-redux": "^9.1.0",
"react-toastify": "^10.0.4",
"react-transition-group": "^4.4.5",
@ -50,16 +50,13 @@
"redux": "^5.0.1",
"redux-logger": "^3.0.6",
"redux-persist": "^6.0.0",
"slate": "^0.101.5",
"slate-history": "^0.100.0",
"slate-hyperscript": "^0.100.0",
"slate-react": "^0.101.5",
"sweetalert2": "^11.10.5",
"sweetalert2": "^11.10.6",
"tailwindcss": "3.3.3",
"typescript": "5.1.3",
"xml2js": "^0.6.2"
},
"devDependencies": {
"@next/bundle-analyzer": "^14.1.0",
"@types/file-saver": "^2.0.7",
"@types/negotiator": "^0.6.3",
"@types/node": "^20.3.1",
@ -242,6 +239,15 @@
"@citation-js/core": "^0.7.0"
}
},
"node_modules/@discoveryjs/json-ext": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
"integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
"dev": true,
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/@formatjs/intl-localematcher": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz",
@ -368,6 +374,15 @@
"node": ">=18"
}
},
"node_modules/@next/bundle-analyzer": {
"version": "14.1.0",
"resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-14.1.0.tgz",
"integrity": "sha512-RJWjnlMp/1WSW0ahAdawV22WgJiC6BVaFS5Xfhw6gP7NJEX3cAJjh4JqSHKGr8GnLNRaFCVTQdDPoX84E421BA==",
"dev": true,
"dependencies": {
"webpack-bundle-analyzer": "4.10.1"
}
},
"node_modules/@next/env": {
"version": "14.0.4",
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.4.tgz",
@ -561,6 +576,12 @@
"node": ">=14"
}
},
"node_modules/@polka/url": {
"version": "1.0.0-next.24",
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.24.tgz",
"integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==",
"dev": true
},
"node_modules/@reduxjs/toolkit": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.0.1.tgz",
@ -996,11 +1017,6 @@
"hoist-non-react-statics": "^3.3.0"
}
},
"node_modules/@types/is-hotkey": {
"version": "0.1.10",
"resolved": "https://registry.npmjs.org/@types/is-hotkey/-/is-hotkey-0.1.10.tgz",
"integrity": "sha512-RvC8KMw5BCac1NvRRyaHgMMEtBaZ6wh0pyPTBu7izn4Sj/AX9Y4aXU5c7rX8PnM/knsuUpC1IeoBkANtxBypsQ=="
},
"node_modules/@types/js-cookie": {
"version": "2.2.7",
"resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.7.tgz",
@ -1015,11 +1031,6 @@
"jszip": "*"
}
},
"node_modules/@types/lodash": {
"version": "4.14.202",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
"integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ=="
},
"node_modules/@types/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/@types/negotiator/-/negotiator-0.6.3.tgz",
@ -1050,14 +1061,6 @@
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz",
"integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng=="
},
"node_modules/@types/quill": {
"version": "1.3.10",
"resolved": "https://registry.npmjs.org/@types/quill/-/quill-1.3.10.tgz",
"integrity": "sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw==",
"dependencies": {
"parchment": "^1.1.2"
}
},
"node_modules/@types/react": {
"version": "18.2.48",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.48.tgz",
@ -1139,6 +1142,27 @@
"node": ">=6.5"
}
},
"node_modules/acorn": {
"version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-walk": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
"integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
"dev": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/add": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/add/-/add-2.0.6.tgz",
@ -1591,11 +1615,6 @@
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="
},
"node_modules/compute-scroll-into-view": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz",
"integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg=="
},
"node_modules/cookie": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
@ -1674,6 +1693,12 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/debounce": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
"integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==",
"dev": true
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -1773,18 +1798,6 @@
"md5": "^2.3.0"
}
},
"node_modules/direction": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz",
"integrity": "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==",
"bin": {
"direction": "cli.js"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/dlv": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
@ -1820,6 +1833,12 @@
"csstype": "^3.0.2"
}
},
"node_modules/duplexer": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
"dev": true
},
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@ -1860,6 +1879,18 @@
"node": ">=6"
}
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
@ -1986,9 +2017,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"funding": [
{
"type": "individual",
@ -2178,6 +2209,21 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
},
"node_modules/gzip-size": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz",
"integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==",
"dev": true,
"dependencies": {
"duplexer": "^0.1.2"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@ -2252,6 +2298,12 @@
"react-is": "^16.7.0"
}
},
"node_modules/html-escaper": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
"node_modules/html-parse-stringify": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
@ -2492,11 +2544,6 @@
"node": ">=0.10.0"
}
},
"node_modules/is-hotkey": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz",
"integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw=="
},
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@ -2509,6 +2556,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -2769,6 +2817,15 @@
"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
"integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q=="
},
"node_modules/mrmime": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
"integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@ -3043,6 +3100,15 @@
"undici-types": "~5.26.4"
}
},
"node_modules/opener": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
"integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
"dev": true,
"bin": {
"opener": "bin/opener-bin.js"
}
},
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
@ -3437,25 +3503,19 @@
}
}
},
"node_modules/react-icons": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.0.1.tgz",
"integrity": "sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==",
"peerDependencies": {
"react": "*"
}
},
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/react-quill": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz",
"integrity": "sha512-4qQtv1FtCfLgoD3PXAur5RyxuUbPXQGOHgTlFie3jtxp43mXDtzCKaOgQ3mLyZfi1PUlyjycfivKelFhy13QUg==",
"dependencies": {
"@types/quill": "^1.3.10",
"lodash": "^4.17.4",
"quill": "^1.3.7"
},
"peerDependencies": {
"react": "^16 || ^17 || ^18",
"react-dom": "^16 || ^17 || ^18"
}
},
"node_modules/react-redux": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.0.tgz",
@ -3739,14 +3799,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/scroll-into-view-if-needed": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz",
"integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==",
"dependencies": {
"compute-scroll-into-view": "^3.0.2"
}
},
"node_modules/set-function-length": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
@ -3836,57 +3888,18 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/slate": {
"version": "0.101.5",
"resolved": "https://registry.npmjs.org/slate/-/slate-0.101.5.tgz",
"integrity": "sha512-ZZt1ia8ayRqxtpILRMi2a4MfdvwdTu64CorxTVq9vNSd0GQ/t3YDkze6wKjdeUtENmBlq5wNIDInZbx38Hfu5Q==",
"node_modules/sirv": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
"integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==",
"dev": true,
"dependencies": {
"immer": "^10.0.3",
"is-plain-object": "^5.0.0",
"tiny-warning": "^1.0.3"
}
},
"node_modules/slate-history": {
"version": "0.100.0",
"resolved": "https://registry.npmjs.org/slate-history/-/slate-history-0.100.0.tgz",
"integrity": "sha512-x5rUuWLNtH97hs9PrFovGgt3Qc5zkTm/5mcUB+0NR/TK923eLax4HsL6xACLHMs245nI6aJElyM1y6hN0y5W/Q==",
"dependencies": {
"is-plain-object": "^5.0.0"
"@polka/url": "^1.0.0-next.24",
"mrmime": "^2.0.0",
"totalist": "^3.0.0"
},
"peerDependencies": {
"slate": ">=0.65.3"
}
},
"node_modules/slate-hyperscript": {
"version": "0.100.0",
"resolved": "https://registry.npmjs.org/slate-hyperscript/-/slate-hyperscript-0.100.0.tgz",
"integrity": "sha512-fb2KdAYg6RkrQGlqaIi4wdqz3oa0S4zKNBJlbnJbNOwa23+9FLD6oPVx9zUGqCSIpy+HIpOeqXrg0Kzwh/Ii4A==",
"dependencies": {
"is-plain-object": "^5.0.0"
},
"peerDependencies": {
"slate": ">=0.65.3"
}
},
"node_modules/slate-react": {
"version": "0.101.5",
"resolved": "https://registry.npmjs.org/slate-react/-/slate-react-0.101.5.tgz",
"integrity": "sha512-KfnC1Je7dIZo1Uv4g5d1+No8hKkgXKcSEGGOH7zzZEX9iYGckSg6aBgO0hFmoilidowSiSU45/baL5aeYma9Vg==",
"dependencies": {
"@juggle/resize-observer": "^3.4.0",
"@types/is-hotkey": "^0.1.8",
"@types/lodash": "^4.14.200",
"direction": "^1.0.4",
"is-hotkey": "^0.2.0",
"is-plain-object": "^5.0.0",
"lodash": "^4.17.21",
"scroll-into-view-if-needed": "^3.1.0",
"tiny-invariant": "1.3.1"
},
"peerDependencies": {
"react": ">=18.2.0",
"react-dom": ">=18.2.0",
"slate": ">=0.99.0"
"engines": {
"node": ">= 10"
}
},
"node_modules/source-map": {
@ -4139,9 +4152,9 @@
}
},
"node_modules/sweetalert2": {
"version": "11.10.5",
"resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.10.5.tgz",
"integrity": "sha512-q9eE3EKhMcpIDU/Xcz7z5lk8axCGkgxwK47gXGrrfncnBJWxHPPHnBVAjfsVXcTt8Yi8U6HNEcBRSu+qGeyFdA==",
"version": "11.10.6",
"resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.10.6.tgz",
"integrity": "sha512-CINZPLZXZRSZqSOE7H7j1F7X8e8O1kLOiXPmtJn1DYxvXsKBr3d16d90+IcwTTs7dJww20h8r8QIxIwsLGX+6A==",
"funding": {
"type": "individual",
"url": "https://github.com/sponsors/limonte"
@ -4227,16 +4240,6 @@
"node": ">=10"
}
},
"node_modules/tiny-invariant": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz",
"integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw=="
},
"node_modules/tiny-warning": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@ -4261,6 +4264,15 @@
"node": ">=0.6"
}
},
"node_modules/totalist": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
"integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@ -4406,6 +4418,63 @@
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/webpack-bundle-analyzer": {
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz",
"integrity": "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==",
"dev": true,
"dependencies": {
"@discoveryjs/json-ext": "0.5.7",
"acorn": "^8.0.4",
"acorn-walk": "^8.0.0",
"commander": "^7.2.0",
"debounce": "^1.2.1",
"escape-string-regexp": "^4.0.0",
"gzip-size": "^6.0.0",
"html-escaper": "^2.0.2",
"is-plain-object": "^5.0.0",
"opener": "^1.5.2",
"picocolors": "^1.0.0",
"sirv": "^2.0.3",
"ws": "^7.3.1"
},
"bin": {
"webpack-bundle-analyzer": "lib/bin/analyzer.js"
},
"engines": {
"node": ">= 10.13.0"
}
},
"node_modules/webpack-bundle-analyzer/node_modules/commander": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"dev": true,
"engines": {
"node": ">= 10"
}
},
"node_modules/webpack-bundle-analyzer/node_modules/ws": {
"version": "7.5.9",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
"dev": true,
"engines": {
"node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/webpack-sources": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
@ -4723,6 +4792,12 @@
"wikidata-sdk": "^8.0.0"
}
},
"@discoveryjs/json-ext": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
"integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
"dev": true
},
"@formatjs/intl-localematcher": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz",
@ -4818,6 +4893,15 @@
"resolved": "https://registry.npmjs.org/@lemonsqueezy/lemonsqueezy.js/-/lemonsqueezy.js-2.0.0.tgz",
"integrity": "sha512-eZcc463vc2qDoRHZE/NKi/wduryl1aHe2T+pVER2H2up8Ed5A4+IYK7KD2S5MPZwVUzVQGPmWJu6mPonh6xreQ=="
},
"@next/bundle-analyzer": {
"version": "14.1.0",
"resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-14.1.0.tgz",
"integrity": "sha512-RJWjnlMp/1WSW0ahAdawV22WgJiC6BVaFS5Xfhw6gP7NJEX3cAJjh4JqSHKGr8GnLNRaFCVTQdDPoX84E421BA==",
"dev": true,
"requires": {
"webpack-bundle-analyzer": "4.10.1"
}
},
"@next/env": {
"version": "14.0.4",
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.4.tgz",
@ -4914,6 +4998,12 @@
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
"optional": true
},
"@polka/url": {
"version": "1.0.0-next.24",
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.24.tgz",
"integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==",
"dev": true
},
"@reduxjs/toolkit": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.0.1.tgz",
@ -5240,11 +5330,6 @@
"hoist-non-react-statics": "^3.3.0"
}
},
"@types/is-hotkey": {
"version": "0.1.10",
"resolved": "https://registry.npmjs.org/@types/is-hotkey/-/is-hotkey-0.1.10.tgz",
"integrity": "sha512-RvC8KMw5BCac1NvRRyaHgMMEtBaZ6wh0pyPTBu7izn4Sj/AX9Y4aXU5c7rX8PnM/knsuUpC1IeoBkANtxBypsQ=="
},
"@types/js-cookie": {
"version": "2.2.7",
"resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.7.tgz",
@ -5258,11 +5343,6 @@
"jszip": "*"
}
},
"@types/lodash": {
"version": "4.14.202",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
"integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ=="
},
"@types/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/@types/negotiator/-/negotiator-0.6.3.tgz",
@ -5293,14 +5373,6 @@
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz",
"integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng=="
},
"@types/quill": {
"version": "1.3.10",
"resolved": "https://registry.npmjs.org/@types/quill/-/quill-1.3.10.tgz",
"integrity": "sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw==",
"requires": {
"parchment": "^1.1.2"
}
},
"@types/react": {
"version": "18.2.48",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.48.tgz",
@ -5380,6 +5452,18 @@
"event-target-shim": "^5.0.0"
}
},
"acorn": {
"version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"dev": true
},
"acorn-walk": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
"integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
"dev": true
},
"add": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/add/-/add-2.0.6.tgz",
@ -5665,11 +5749,6 @@
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="
},
"compute-scroll-into-view": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz",
"integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg=="
},
"cookie": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
@ -5730,6 +5809,12 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"debounce": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
"integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==",
"dev": true
},
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -5800,11 +5885,6 @@
"md5": "^2.3.0"
}
},
"direction": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz",
"integrity": "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ=="
},
"dlv": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
@ -5839,6 +5919,12 @@
"csstype": "^3.0.2"
}
},
"duplexer": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
"dev": true
},
"eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@ -5876,6 +5962,12 @@
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
},
"escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true
},
"estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
@ -5983,9 +6075,9 @@
}
},
"follow-redirects": {
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw=="
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA=="
},
"foreground-child": {
"version": "3.1.1",
@ -6108,6 +6200,15 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
},
"gzip-size": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz",
"integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==",
"dev": true,
"requires": {
"duplexer": "^0.1.2"
}
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@ -6155,6 +6256,12 @@
"react-is": "^16.7.0"
}
},
"html-escaper": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
"html-parse-stringify": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
@ -6324,11 +6431,6 @@
"is-extglob": "^2.1.1"
}
},
"is-hotkey": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz",
"integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw=="
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
@ -6337,7 +6439,8 @@
"is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"dev": true
},
"is-reference": {
"version": "1.2.1",
@ -6543,6 +6646,12 @@
"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
"integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q=="
},
"mrmime": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
"integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==",
"dev": true
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@ -6711,6 +6820,12 @@
}
}
},
"opener": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
"integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
"dev": true
},
"pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
@ -6960,21 +7075,17 @@
"html-parse-stringify": "^3.0.1"
}
},
"react-icons": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.0.1.tgz",
"integrity": "sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==",
"requires": {}
},
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"react-quill": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz",
"integrity": "sha512-4qQtv1FtCfLgoD3PXAur5RyxuUbPXQGOHgTlFie3jtxp43mXDtzCKaOgQ3mLyZfi1PUlyjycfivKelFhy13QUg==",
"requires": {
"@types/quill": "^1.3.10",
"lodash": "^4.17.4",
"quill": "^1.3.7"
}
},
"react-redux": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.0.tgz",
@ -7177,14 +7288,6 @@
"resolved": "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz",
"integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA=="
},
"scroll-into-view-if-needed": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz",
"integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==",
"requires": {
"compute-scroll-into-view": "^3.0.2"
}
},
"set-function-length": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
@ -7254,46 +7357,15 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="
},
"slate": {
"version": "0.101.5",
"resolved": "https://registry.npmjs.org/slate/-/slate-0.101.5.tgz",
"integrity": "sha512-ZZt1ia8ayRqxtpILRMi2a4MfdvwdTu64CorxTVq9vNSd0GQ/t3YDkze6wKjdeUtENmBlq5wNIDInZbx38Hfu5Q==",
"sirv": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
"integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==",
"dev": true,
"requires": {
"immer": "^10.0.3",
"is-plain-object": "^5.0.0",
"tiny-warning": "^1.0.3"
}
},
"slate-history": {
"version": "0.100.0",
"resolved": "https://registry.npmjs.org/slate-history/-/slate-history-0.100.0.tgz",
"integrity": "sha512-x5rUuWLNtH97hs9PrFovGgt3Qc5zkTm/5mcUB+0NR/TK923eLax4HsL6xACLHMs245nI6aJElyM1y6hN0y5W/Q==",
"requires": {
"is-plain-object": "^5.0.0"
}
},
"slate-hyperscript": {
"version": "0.100.0",
"resolved": "https://registry.npmjs.org/slate-hyperscript/-/slate-hyperscript-0.100.0.tgz",
"integrity": "sha512-fb2KdAYg6RkrQGlqaIi4wdqz3oa0S4zKNBJlbnJbNOwa23+9FLD6oPVx9zUGqCSIpy+HIpOeqXrg0Kzwh/Ii4A==",
"requires": {
"is-plain-object": "^5.0.0"
}
},
"slate-react": {
"version": "0.101.5",
"resolved": "https://registry.npmjs.org/slate-react/-/slate-react-0.101.5.tgz",
"integrity": "sha512-KfnC1Je7dIZo1Uv4g5d1+No8hKkgXKcSEGGOH7zzZEX9iYGckSg6aBgO0hFmoilidowSiSU45/baL5aeYma9Vg==",
"requires": {
"@juggle/resize-observer": "^3.4.0",
"@types/is-hotkey": "^0.1.8",
"@types/lodash": "^4.14.200",
"direction": "^1.0.4",
"is-hotkey": "^0.2.0",
"is-plain-object": "^5.0.0",
"lodash": "^4.17.21",
"scroll-into-view-if-needed": "^3.1.0",
"tiny-invariant": "1.3.1"
"@polka/url": "^1.0.0-next.24",
"mrmime": "^2.0.0",
"totalist": "^3.0.0"
}
},
"source-map": {
@ -7475,9 +7547,9 @@
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
},
"sweetalert2": {
"version": "11.10.5",
"resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.10.5.tgz",
"integrity": "sha512-q9eE3EKhMcpIDU/Xcz7z5lk8axCGkgxwK47gXGrrfncnBJWxHPPHnBVAjfsVXcTt8Yi8U6HNEcBRSu+qGeyFdA=="
"version": "11.10.6",
"resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.10.6.tgz",
"integrity": "sha512-CINZPLZXZRSZqSOE7H7j1F7X8e8O1kLOiXPmtJn1DYxvXsKBr3d16d90+IcwTTs7dJww20h8r8QIxIwsLGX+6A=="
},
"sync-fetch": {
"version": "0.4.5",
@ -7543,16 +7615,6 @@
"resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-3.0.1.tgz",
"integrity": "sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg=="
},
"tiny-invariant": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz",
"integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw=="
},
"tiny-warning": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@ -7571,6 +7633,12 @@
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
},
"totalist": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
"integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
"dev": true
},
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@ -7671,6 +7739,42 @@
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"webpack-bundle-analyzer": {
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz",
"integrity": "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==",
"dev": true,
"requires": {
"@discoveryjs/json-ext": "0.5.7",
"acorn": "^8.0.4",
"acorn-walk": "^8.0.0",
"commander": "^7.2.0",
"debounce": "^1.2.1",
"escape-string-regexp": "^4.0.0",
"gzip-size": "^6.0.0",
"html-escaper": "^2.0.2",
"is-plain-object": "^5.0.0",
"opener": "^1.5.2",
"picocolors": "^1.0.0",
"sirv": "^2.0.3",
"ws": "^7.3.1"
},
"dependencies": {
"commander": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"dev": true
},
"ws": {
"version": "7.5.9",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
"dev": true,
"requires": {}
}
}
},
"webpack-sources": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",

View File

@ -41,7 +41,7 @@
"react-cookie": "^7.0.2",
"react-dom": "^18.2.0",
"react-i18next": "^14.0.5",
"react-quill": "^2.0.0",
"react-icons": "^5.0.1",
"react-redux": "^9.1.0",
"react-toastify": "^10.0.4",
"react-transition-group": "^4.4.5",
@ -49,16 +49,13 @@
"redux": "^5.0.1",
"redux-logger": "^3.0.6",
"redux-persist": "^6.0.0",
"slate": "^0.101.5",
"slate-history": "^0.100.0",
"slate-hyperscript": "^0.100.0",
"slate-react": "^0.101.5",
"sweetalert2": "^11.10.5",
"sweetalert2": "^11.10.6",
"tailwindcss": "3.3.3",
"typescript": "5.1.3",
"xml2js": "^0.6.2"
},
"devDependencies": {
"@next/bundle-analyzer": "^14.1.0",
"@types/file-saver": "^2.0.7",
"@types/negotiator": "^0.6.3",
"@types/node": "^20.3.1",
@ -68,5 +65,5 @@
"@types/redux-logger": "^3.0.12",
"encoding": "^0.1.13"
},
"version": "1.8.0"
"version": "1.9.0"
}

View File

@ -18,7 +18,13 @@ if (process.env.NODE_ENV === "production") {
// This sets the sample rate to be 10%. You may want this to be 100% while
// in development and sample at a lower rate in production
replaysSessionSampleRate: 0.1,
beforeSend(event, hint) {
// 检查事件是否为通过 `captureMessage` 发送的
if (event.logger === "javascript" && event.message) {
return event; // 允许发送消息事件
}
return null; // 过滤掉其他类型的事件
},
// You can remove this option if you're not planning to use the Sentry Session Replay feature:
integrations: [
Sentry.replayIntegration({

View File

@ -74,7 +74,8 @@ export async function evaluateTopicMatch(
apiKey: string,
upsreamUrl: string,
selectedModel: string,
topic: string
topic: string,
signal: AbortSignal
): Promise<{ relevantPapers: string[]; nonRelevantPapers: string[] }> {
const prompt =
"请判断文献是否跟用户输入的主题相关,只需要返回true或false的数组";
@ -117,7 +118,8 @@ export async function evaluateTopicMatch(
upsreamUrl,
prompt,
null,
false
false,
signal
);
console.log("isrelevantResults in 相关性检查", isRelevantResults);
// 处理每篇文献的相关性结果

View File

@ -0,0 +1,47 @@
import { NextResponse } from "next/server";
import { SupabaseClient } from "@supabase/supabase-js";
export async function setVip(
supabaseAdmin: SupabaseClient,
userId: string,
isVip = true,
source = "Linuxdo",
startDate = new Date(),
endDate = new Date()
) {
if (!userId)
return NextResponse.json({ message: "No user found" }, { status: 403 });
const { data, error } = await supabaseAdmin.from("vip_statuses").upsert(
{
user_id: userId,
is_vip: isVip,
source: source,
start_date: startDate,
end_date: endDate,
},
{ onConflict: "user_id" }
);
if (error) {
console.error("设置 VIP 失败:", error);
return NextResponse.json(
{ message: "Failed to set VIP 设置 VIP 状态失败" },
{ status: 403 }
);
}
return NextResponse.json({ message: "Success VIP 状态已更新:" });
}
async function getUserId(supabaseAdmin: SupabaseClient, email: string) {
const { data, error } = await supabaseAdmin
.from("profiles")
.select("id")
.eq("email", email)
.single();
if (error) {
console.error("查询用户 ID 失败:", error);
return null;
}
return data.id;
}

View File

@ -178,20 +178,36 @@ export async function fetchUserVipStatus(userId: string) {
//profiles表 插入用户信息
export async function insertUserProfile(data: any, supabase: SupabaseClient) {
const user = data?.user;
let user;
if (data.user) {
user = data.user;
} else {
user = data;
}
if (user) {
// console.log("user in insertUserProfile:", user);
const currentTime = new Date().toISOString(); // 生成ISO格式的时间字符串
const { data, error: profileError } = await supabase
.from("profiles")
.upsert([{ id: user.id, email: user.email }]);
.upsert([
{
id: user.id,
email: user.email,
created_at: currentTime, // 添加创建时间
},
]);
if (profileError) {
console.error("Failed to create user profile:", profileError);
Sentry.captureException(profileError);
}
//sentry
Sentry.setUser({
email: user.email,
id: user.id,
ip_address: "{{auto}}}",
ip_address: "{{auto}}",
});
}
}