Skip to content

Commit 80af58d

Browse files
committed
Updated examples
1 parent 3eae32d commit 80af58d

File tree

11 files changed

+209
-2
lines changed

11 files changed

+209
-2
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ __pycache__/
44
*.spec
55
dist/
66
build/
7+
*.dtBase2/
78
*.egg-info/
8-
examples/
99
docs/

README.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ tell application "DEVONthink 3"
2020
end tell
2121
```
2222

23-
Many of the APIs are generated with help of ChatGTP 3.5 from the AppleScript dictionary of DEVONthink 3.
23+
Many of the APIs are generated by ChatGTP from the DEVONthink's AppleScript dictionary.
2424

2525
The Applescript bridging part is inspired by [py-applescript](https://github.com/rdhyee/py-applescript).
2626

27+
Notes used as examples are imported from [The Blue Book](https://github.com/lyz-code/blue-book), a personal wiki shared by [lyz-code](https://github.com/lyz-code).
28+
2729
## Installation
2830

2931
```bash
@@ -60,6 +62,32 @@ record = dtp3.create_record_with({
6062
}, inbox)
6163
```
6264

65+
## Work With ChatGTP
66+
67+
### Add Tags to Selected Records Using ChatGTP
68+
69+
Put the script into `~/Library/Application Scripts/com.devon-technologies.think3/Contextual Menu` and run it from contextual menu in DEVONthink (The record must be in selected state).
70+
71+
![add_tags_contextual_menu](images/add_tags_contextual_menu.png)
72+
73+
And voilà, the tags are added based on contents automatically.
74+
75+
![generated_tags](images/generated_tags.png)
76+
77+
Note: You are required to have an [API key](https://platform.openai.com/account/api-keys) from OpenAI. The first time you run the script, a prompt will ask you to enter key.
78+
79+
![api_key_prompt](images/api_key_prompt.png)
80+
81+
The key will be store in Incoming group for DEVONthink (usually `Inbox`). You can see the file `__openai_api_key__` generated there. You can move it to other opened database but don't change it's name.
82+
83+
### Auto Writing / Summarizing Using ChatGTP
84+
85+
This script lets you to insert `<<TOKEN>>` into your text and then generate the text based on the token.
86+
87+
![before_expansion](images/before_expansion.png)
88+
89+
![after_expansion](images/after_expansion.png)
90+
6391
## Documentation
6492

6593
Unlike many other API wrapper projects, PyDT3 is well documented thanks to the detailed AppleScript dictionary by DEVONthink team and the code generation ability of ChatGTP.

examples/chatgtp/add_tags.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import os
2+
import openai
3+
import sys
4+
import json
5+
import re
6+
7+
sys.path.insert(0, '.')
8+
from pydt3 import DEVONthink3
9+
10+
dtp = DEVONthink3()
11+
def get_api_key():
12+
result = dtp.search("name==__openai_api_key__")
13+
if result:
14+
api_key = result[0].plain_text
15+
else:
16+
response = dtp.display_dialog("Please enter your OpenAI API key", "")
17+
api_key = response["textReturned"]
18+
dtp.create_record_with({
19+
"name": "__openai_api_key__",
20+
"type": "txt",
21+
"plain text": api_key,
22+
})
23+
24+
return api_key
25+
26+
def generate_tags(content) -> list[str]:
27+
completion = openai.ChatCompletion.create(
28+
model="gpt-3.5-turbo",
29+
messages=[
30+
{"role": "user", "content": f"Generate the tags for the following content. Tags should be concise and accurate and no more than 10. output the tags directly seperateted by ',':\n {content}"},
31+
]
32+
)
33+
response = completion.choices[0]['message']['content']
34+
print(response)
35+
return [tag.strip() for tag in response.split(",")]
36+
37+
38+
def add_tags_to_selected_records():
39+
records = dtp.selected_records
40+
for recod in records:
41+
tags = generate_tags(recod.plain_text)
42+
recod.tags = tags
43+
44+
45+
if __name__ == '__main__':
46+
openai.api_key = get_api_key()
47+
add_tags_to_selected_records()

examples/chatgtp/expand_content.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import os
2+
import openai
3+
import sys
4+
import json
5+
import re
6+
7+
sys.path.insert(0, '.')
8+
from pydt3 import DEVONthink3
9+
10+
dtp = DEVONthink3()
11+
def get_api_key():
12+
result = dtp.search("name==__openai_api_key__")
13+
if result:
14+
api_key = result[0].plain_text
15+
else:
16+
response = dtp.display_dialog("Please enter your OpenAI API key", "")
17+
api_key = response["textReturned"]
18+
dtp.create_record_with({
19+
"name": "__openai_api_key__",
20+
"type": "txt",
21+
"plain text": api_key,
22+
})
23+
24+
return api_key
25+
26+
27+
def expand_content(content) -> str:
28+
system = '''You are a skillful writer. Replace the angle brackets you see with the content you generated. Outputs should follow the hints in angle brackets. \n
29+
30+
eg.
31+
32+
User: "Today I watched a famous British movie <<Movie Name>>. Its's written by <<Author>>. It's about <<Plot>>. I like it very much.
33+
34+
AI: {"Movie Name": "The Godfather.", "Author": "Mario Puzo", "Plot": "a mafia family"}
35+
"'''
36+
37+
completion = openai.ChatCompletion.create(
38+
model="gpt-3.5-turbo",
39+
messages=[
40+
{"role": "user", "content": system,},
41+
{"role": "user", "content": content,},
42+
{"role": "assistant", "content": "Okay, I'll gie the answer in json format.",},
43+
44+
]
45+
)
46+
print(completion.choices)
47+
response = completion.choices[0]['message']['content']
48+
results = json.loads(response)
49+
print("=======", results)
50+
for key in results:
51+
content = re.sub(f'<<{key}>>', f'=={results[key]}==', content, count=1)
52+
return content
53+
54+
def expand_current_record():
55+
retry_count = 3
56+
record = dtp.think_windows[0].content_record
57+
58+
for _ in range(retry_count):
59+
try:
60+
record.plain_text = expand_content(record.plain_text)
61+
break
62+
except json.decoder.JSONDecodeError as e:
63+
print(e)
64+
print("retrying...")
65+
continue
66+
67+
if __name__ == '__main__':
68+
openai.api_key = get_api_key()
69+
expand_current_record()

examples/chatgtp/requirements.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pydt3==0.0.1
2+
pyobjc-core==9.1.1
3+
pyobjc-framework-AppleScriptKit==9.1.1
4+
pyobjc-framework-AppleScriptObjC==9.1.1
5+
openai==0.27.6
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import jieba
2+
from wordcloud import WordCloud
3+
import random
4+
import matplotlib.pyplot as plt
5+
6+
from pydt3 import DEVONthink3
7+
8+
ignore_words = """function return var value if else for while break continue switch case default element object key array https component"""\
9+
.split()
10+
11+
def generate_wordcloud(text, output_file='wordcloud.png'):
12+
# 对文本进行分词
13+
word_list = list(jieba.cut(text))
14+
text = ''
15+
for word in word_list:
16+
if len(word) <= 2 or word in ignore_words:
17+
continue
18+
text += word + ' '
19+
20+
# 创建词云对象
21+
wc = WordCloud(
22+
background_color='white',
23+
width=800,
24+
height=600,
25+
max_words=200,
26+
max_font_size=100,
27+
random_state=42
28+
)
29+
30+
wc.generate(text)
31+
32+
wc.to_file(output_file)
33+
34+
plt.imshow(wc, interpolation='bilinear')
35+
plt.axis('off')
36+
plt.show()
37+
38+
if __name__ == '__main__':
39+
texts = []
40+
dtp3 = DEVONthink3()
41+
db = dtp3.ext.db_by_name('blue-book')
42+
contents = db.contents
43+
print(len(contents))
44+
sampled_records = random.sample(db.contents, min(40, len(db.contents)))
45+
names = []
46+
texts = []
47+
for record in sampled_records:
48+
if record.type == 'picture':
49+
continue
50+
if 'newsletter' in record.location:
51+
continue
52+
name = record.name
53+
names.append(name)
54+
texts.append(name)
55+
texts.append(record.rich_text.splitlines()[0])
56+
57+
samples = texts
58+
generate_wordcloud(' '.join(samples), 'wordcloud.png')
169 KB
Loading

images/after_expansion.png

930 KB
Loading

images/api_key_prompt.png

142 KB
Loading

images/before_expansion.png

716 KB
Loading

0 commit comments

Comments
 (0)