Skip to content

Commit

Permalink
Updated examples
Browse files Browse the repository at this point in the history
  • Loading branch information
thekoc committed May 2, 2023
1 parent 3eae32d commit 80af58d
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ __pycache__/
*.spec
dist/
build/
*.dtBase2/
*.egg-info/
examples/
docs/
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ tell application "DEVONthink 3"
end tell
```

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

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

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).

## Installation

```bash
Expand Down Expand Up @@ -60,6 +62,32 @@ record = dtp3.create_record_with({
}, inbox)
```

## Work With ChatGTP

### Add Tags to Selected Records Using ChatGTP

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).

![add_tags_contextual_menu](images/add_tags_contextual_menu.png)

And voilà, the tags are added based on contents automatically.

![generated_tags](images/generated_tags.png)

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.

![api_key_prompt](images/api_key_prompt.png)

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.

### Auto Writing / Summarizing Using ChatGTP

This script lets you to insert `<<TOKEN>>` into your text and then generate the text based on the token.

![before_expansion](images/before_expansion.png)

![after_expansion](images/after_expansion.png)

## Documentation

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.
Expand Down
47 changes: 47 additions & 0 deletions examples/chatgtp/add_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import os
import openai
import sys
import json
import re

sys.path.insert(0, '.')
from pydt3 import DEVONthink3

dtp = DEVONthink3()
def get_api_key():
result = dtp.search("name==__openai_api_key__")
if result:
api_key = result[0].plain_text
else:
response = dtp.display_dialog("Please enter your OpenAI API key", "")
api_key = response["textReturned"]
dtp.create_record_with({
"name": "__openai_api_key__",
"type": "txt",
"plain text": api_key,
})

return api_key

def generate_tags(content) -> list[str]:
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"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}"},
]
)
response = completion.choices[0]['message']['content']
print(response)
return [tag.strip() for tag in response.split(",")]


def add_tags_to_selected_records():
records = dtp.selected_records
for recod in records:
tags = generate_tags(recod.plain_text)
recod.tags = tags


if __name__ == '__main__':
openai.api_key = get_api_key()
add_tags_to_selected_records()
69 changes: 69 additions & 0 deletions examples/chatgtp/expand_content.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import os
import openai
import sys
import json
import re

sys.path.insert(0, '.')
from pydt3 import DEVONthink3

dtp = DEVONthink3()
def get_api_key():
result = dtp.search("name==__openai_api_key__")
if result:
api_key = result[0].plain_text
else:
response = dtp.display_dialog("Please enter your OpenAI API key", "")
api_key = response["textReturned"]
dtp.create_record_with({
"name": "__openai_api_key__",
"type": "txt",
"plain text": api_key,
})

return api_key


def expand_content(content) -> str:
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
eg.
User: "Today I watched a famous British movie <<Movie Name>>. Its's written by <<Author>>. It's about <<Plot>>. I like it very much.
AI: {"Movie Name": "The Godfather.", "Author": "Mario Puzo", "Plot": "a mafia family"}
"'''

completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": system,},
{"role": "user", "content": content,},
{"role": "assistant", "content": "Okay, I'll gie the answer in json format.",},

]
)
print(completion.choices)
response = completion.choices[0]['message']['content']
results = json.loads(response)
print("=======", results)
for key in results:
content = re.sub(f'<<{key}>>', f'=={results[key]}==', content, count=1)
return content

def expand_current_record():
retry_count = 3
record = dtp.think_windows[0].content_record

for _ in range(retry_count):
try:
record.plain_text = expand_content(record.plain_text)
break
except json.decoder.JSONDecodeError as e:
print(e)
print("retrying...")
continue

if __name__ == '__main__':
openai.api_key = get_api_key()
expand_current_record()
5 changes: 5 additions & 0 deletions examples/chatgtp/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pydt3==0.0.1
pyobjc-core==9.1.1
pyobjc-framework-AppleScriptKit==9.1.1
pyobjc-framework-AppleScriptObjC==9.1.1
openai==0.27.6
58 changes: 58 additions & 0 deletions examples/document_analysis/word_cloud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import jieba
from wordcloud import WordCloud
import random
import matplotlib.pyplot as plt

from pydt3 import DEVONthink3

ignore_words = """function return var value if else for while break continue switch case default element object key array https component"""\
.split()

def generate_wordcloud(text, output_file='wordcloud.png'):
# 对文本进行分词
word_list = list(jieba.cut(text))
text = ''
for word in word_list:
if len(word) <= 2 or word in ignore_words:
continue
text += word + ' '

# 创建词云对象
wc = WordCloud(
background_color='white',
width=800,
height=600,
max_words=200,
max_font_size=100,
random_state=42
)

wc.generate(text)

wc.to_file(output_file)

plt.imshow(wc, interpolation='bilinear')
plt.axis('off')
plt.show()

if __name__ == '__main__':
texts = []
dtp3 = DEVONthink3()
db = dtp3.ext.db_by_name('blue-book')
contents = db.contents
print(len(contents))
sampled_records = random.sample(db.contents, min(40, len(db.contents)))
names = []
texts = []
for record in sampled_records:
if record.type == 'picture':
continue
if 'newsletter' in record.location:
continue
name = record.name
names.append(name)
texts.append(name)
texts.append(record.rich_text.splitlines()[0])

samples = texts
generate_wordcloud(' '.join(samples), 'wordcloud.png')
Binary file added images/add_tags_contextual_menu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/after_expansion.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/api_key_prompt.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/before_expansion.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/generated_tags.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 80af58d

Please sign in to comment.