Skip to content

Commit 9ecb3cf

Browse files
committed
initial commit
1 parent 63ae912 commit 9ecb3cf

36 files changed

+2196
-54
lines changed

assets/icon.png

-62.8 KB
Loading

assets/illustration.png

7.18 KB
Loading

package.json

+15-3
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,42 @@
22
"name": "chatgpt-to-notion",
33
"displayName": "Chatgpt to notion",
44
"version": "0.0.0",
5-
"description": "A basic Plasmo extension.",
6-
"author": "lrtig",
5+
"description": "Save your discussions with ChatGPT directly into Notion!",
6+
"author": "Théo Lartigau",
77
"scripts": {
88
"dev": "plasmo dev",
99
"build": "plasmo build",
1010
"package": "plasmo package"
1111
},
1212
"dependencies": {
13+
"@headlessui/react": "^1.7.7",
14+
"@notionhq/client": "^2.2.3",
15+
"@plasmohq/storage": "^0.13.1",
16+
"@tryfabric/martian": "^1.2.4",
17+
"node-html-markdown": "^1.3.0",
1318
"plasmo": "0.60.2",
1419
"react": "18.2.0",
15-
"react-dom": "18.2.0"
20+
"react-dom": "18.2.0",
21+
"shrink-string": "^3.1.2"
1622
},
1723
"devDependencies": {
1824
"@plasmohq/prettier-plugin-sort-imports": "3.6.0",
1925
"@types/chrome": "0.0.202",
2026
"@types/node": "18.11.9",
2127
"@types/react": "18.0.25",
2228
"@types/react-dom": "18.0.9",
29+
"autoprefixer": "^10.4.13",
30+
"postcss": "^8.4.20",
2331
"prettier": "2.7.1",
32+
"tailwindcss": "^3.2.4",
2433
"typescript": "4.9.3"
2534
},
2635
"manifest": {
2736
"host_permissions": [
2837
"https://*/*"
38+
],
39+
"permissions": [
40+
"tabs"
2941
]
3042
}
3143
}

popup.tsx

-28
This file was deleted.

postcss.config.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
plugins: {
3+
tailwindcss: {},
4+
autoprefixer: {},
5+
},
6+
}

src/api/generateToken.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { Storage } from "@plasmohq/storage"
2+
3+
export const generateToken = async (code: string) => {
4+
console.log(code)
5+
const storage = new Storage({
6+
area: "session"
7+
})
8+
const response = await fetch(
9+
"https://chatgpt-to-notion.onrender.com/token/new",
10+
{
11+
method: "POST",
12+
headers: {
13+
"Content-Type": "application/json"
14+
},
15+
body: JSON.stringify({
16+
code,
17+
grant_type: "authorization-code",
18+
redirect_uri: "https://github.com/L-a-r-t/chatgpt-to-notion"
19+
})
20+
}
21+
)
22+
const { token } = await response.json()
23+
return token
24+
}

src/api/getToken.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export const getToken = async ({ workspace_id, user_id }: GetTokenParams) => {
2+
const response = await fetch("https://chatgpt-to-notion.onrender.com/token", {
3+
method: "POST",
4+
headers: {
5+
"Content-Type": "application/json"
6+
},
7+
body: JSON.stringify({
8+
workspace_id,
9+
user_id
10+
})
11+
})
12+
const { token } = await response.json()
13+
return token
14+
}
15+
16+
type GetTokenParams = {
17+
workspace_id: string
18+
user_id: string
19+
}

src/api/saveAnswer.ts

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { decompress } from "shrink-string"
2+
3+
import notion from "~config/notion"
4+
import { generateBlocks } from "~utils/functions/notion"
5+
6+
// save new page to notion database
7+
export const saveAnswer = async ({
8+
prompt,
9+
answer,
10+
title,
11+
url,
12+
database_id
13+
}: SaveAnswerParams) => {
14+
const decompressedAnswer = await decompress(answer)
15+
const decompressedPrompt = await decompress(prompt)
16+
const { answerBlocks, promptBlocks } = generateBlocks(
17+
decompressedPrompt,
18+
decompressedAnswer
19+
)
20+
21+
const searchRes = await notion.databases.query({
22+
database_id,
23+
filter: {
24+
property: "Name",
25+
title: {
26+
equals: title
27+
}
28+
}
29+
})
30+
31+
if (searchRes.results.length > 0) {
32+
const page = searchRes.results[0]
33+
const block_id = page.id
34+
const response = await notion.blocks.children.append({
35+
block_id,
36+
children: [...promptBlocks, ...answerBlocks]
37+
})
38+
return response
39+
}
40+
41+
const response = await notion.pages.create({
42+
parent: {
43+
database_id: database_id
44+
},
45+
icon: {
46+
type: "external",
47+
external: {
48+
url: "https://openai.com/content/images/2022/05/openai-avatar.png"
49+
}
50+
},
51+
properties: {
52+
Name: {
53+
title: [
54+
{
55+
text: {
56+
content: title
57+
}
58+
}
59+
]
60+
},
61+
URL: {
62+
url
63+
}
64+
},
65+
children: [
66+
{
67+
object: "block",
68+
type: "table_of_contents",
69+
table_of_contents: {}
70+
},
71+
...promptBlocks,
72+
...answerBlocks
73+
]
74+
})
75+
return response
76+
}
77+
78+
type SaveAnswerParams = {
79+
prompt: string
80+
answer: string
81+
title: string
82+
database_id: string
83+
url: string
84+
}

src/api/saveChat.ts

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { decompress } from "shrink-string"
2+
3+
import notion from "~config/notion"
4+
import { generateBlocks } from "~utils/functions/notion"
5+
6+
// save new page to notion database
7+
export const saveChat = async ({
8+
prompts,
9+
answers,
10+
title,
11+
url,
12+
database_id
13+
}: SaveChatParams) => {
14+
const blocks = []
15+
for (let i = 0; i < prompts.length; i++) {
16+
const { answerBlocks, promptBlocks } = generateBlocks(
17+
prompts[i],
18+
answers[i]
19+
)
20+
blocks.push(...promptBlocks, ...answerBlocks)
21+
}
22+
23+
const searchRes = await notion.databases.query({
24+
database_id,
25+
filter: {
26+
property: "Name",
27+
title: {
28+
equals: title
29+
}
30+
}
31+
})
32+
33+
if (searchRes.results.length > 0) {
34+
const page = searchRes.results[0]
35+
const page_id = page.id
36+
await notion.pages.update({
37+
page_id,
38+
archived: true
39+
})
40+
}
41+
42+
const response = await notion.pages.create({
43+
parent: {
44+
database_id: database_id
45+
},
46+
icon: {
47+
type: "external",
48+
external: {
49+
url: "https://openai.com/content/images/2022/05/openai-avatar.png"
50+
}
51+
},
52+
properties: {
53+
Name: {
54+
title: [
55+
{
56+
text: {
57+
content: title
58+
}
59+
}
60+
]
61+
},
62+
URL: {
63+
url
64+
}
65+
},
66+
children: [
67+
{
68+
object: "block",
69+
type: "table_of_contents",
70+
table_of_contents: {}
71+
},
72+
...blocks
73+
]
74+
})
75+
return response
76+
}
77+
78+
type SaveChatParams = {
79+
prompts: string[]
80+
answers: string[]
81+
title: string
82+
database_id: string
83+
url: string
84+
}

src/api/search.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import notion from "~config/notion"
2+
import { parseSearchResponse } from "~utils/functions/notion"
3+
4+
// Search notion using the notion sdk
5+
export const searchNotion = async (query: string) => {
6+
const response = await notion.search({
7+
query,
8+
page_size: 6,
9+
filter: {
10+
property: "object",
11+
value: "database"
12+
}
13+
})
14+
const parsed = parseSearchResponse(response.results)
15+
return parsed
16+
}

src/background/index.ts

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Storage } from "@plasmohq/storage"
2+
3+
import { generateToken } from "~api/generateToken"
4+
import { getToken } from "~api/getToken"
5+
import { saveAnswer } from "~api/saveAnswer"
6+
import { searchNotion } from "~api/search"
7+
8+
// API calls that can be made from content scripts transit trough the background script
9+
// This is done to prevent CORS errors
10+
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
11+
switch (message.type) {
12+
case "search":
13+
searchNotion(message.body.query).then((res) => {
14+
sendResponse(res)
15+
})
16+
break
17+
case "saveAnswer":
18+
saveAnswer(message.body).then((res) => {
19+
sendResponse(res)
20+
})
21+
break
22+
case "generateToken":
23+
generateToken(message.body.code).then((res) => {
24+
sendResponse(res)
25+
})
26+
break
27+
default:
28+
return true
29+
}
30+
return true
31+
})
32+
33+
const authenticate = async () => {
34+
const storage = new Storage({
35+
secretKeyList: ["token"]
36+
})
37+
const [workspace_id, user_id] = await Promise.all([
38+
storage.get("workspace_id"),
39+
storage.get("user_id")
40+
])
41+
const token = await getToken({
42+
workspace_id,
43+
user_id
44+
})
45+
await storage.set("token", token)
46+
}
47+
48+
authenticate()
49+
50+
export default {}

0 commit comments

Comments
 (0)