PURSUE ULTIMATE FACTS

2023-03-21
Try BioGPT

In [ ]:
%%bash
pip install torch torchvision torchaudio
Collecting torch
  Using cached torch-2.0.0-cp310-none-macosx_10_9_x86_64.whl (139.8 MB)
Collecting torchvision
  Downloading torchvision-0.15.1-cp310-cp310-macosx_10_9_x86_64.whl (1.5 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.5/1.5 MB 2.4 MB/s eta 0:00:0000:0100:01
Collecting torchaudio
  Downloading torchaudio-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl (3.9 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.9/3.9 MB 3.3 MB/s eta 0:00:0000:0100:01
Collecting networkx
  Downloading networkx-3.0-py3-none-any.whl (2.0 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.0/2.0 MB 3.2 MB/s eta 0:00:0000:0100:01
Collecting sympy
  Downloading sympy-1.11.1-py3-none-any.whl (6.5 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.5/6.5 MB 3.4 MB/s eta 0:00:0000:0100:01
Requirement already satisfied: jinja2 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from torch) (3.1.2)
Requirement already satisfied: filelock in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from torch) (3.9.0)
Requirement already satisfied: typing-extensions in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from torch) (4.4.0)
Requirement already satisfied: numpy in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from torchvision) (1.24.2)
Collecting pillow!=8.3.*,>=5.3.0
  Downloading Pillow-9.4.0-2-cp310-cp310-macosx_10_10_x86_64.whl (3.3 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.3/3.3 MB 3.5 MB/s eta 0:00:0000:0100:01
Requirement already satisfied: requests in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from torchvision) (2.28.1)
Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from jinja2->torch) (2.1.1)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from requests->torchvision) (3.4)
Requirement already satisfied: charset-normalizer<3,>=2 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from requests->torchvision) (2.0.4)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from requests->torchvision) (2022.12.7)
Requirement already satisfied: urllib3<1.27,>=1.21.1 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from requests->torchvision) (1.26.14)
Collecting mpmath>=0.19
  Downloading mpmath-1.3.0-py3-none-any.whl (536 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 536.2/536.2 kB 3.0 MB/s eta 0:00:00a 0:00:01
Installing collected packages: mpmath, sympy, pillow, networkx, torch, torchvision, torchaudio
Successfully installed mpmath-1.3.0 networkx-3.0 pillow-9.4.0 sympy-1.11.1 torch-2.0.0 torchaudio-2.0.1 torchvision-0.15.1
In [ ]:
%%bash
pip install transformers
Collecting transformers
  Downloading transformers-4.27.2-py3-none-any.whl (6.8 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.8/6.8 MB 3.9 MB/s eta 0:00:0000:0100:01
Requirement already satisfied: requests in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from transformers) (2.28.1)
Requirement already satisfied: regex!=2019.12.17 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from transformers) (2022.10.31)
Requirement already satisfied: packaging>=20.0 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from transformers) (22.0)
Requirement already satisfied: filelock in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from transformers) (3.9.0)
Collecting tokenizers!=0.11.3,<0.14,>=0.11.1
  Downloading tokenizers-0.13.2-cp310-cp310-macosx_10_11_x86_64.whl (3.8 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.8/3.8 MB 3.0 MB/s eta 0:00:0000:0100:01
Collecting huggingface-hub<1.0,>=0.11.0
  Downloading huggingface_hub-0.13.3-py3-none-any.whl (199 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 199.8/199.8 kB 3.4 MB/s eta 0:00:00a 0:00:01
Requirement already satisfied: tqdm>=4.27 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from transformers) (4.65.0)
Requirement already satisfied: pyyaml>=5.1 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from transformers) (6.0)
Requirement already satisfied: numpy>=1.17 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from transformers) (1.24.2)
Requirement already satisfied: typing-extensions>=3.7.4.3 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from huggingface-hub<1.0,>=0.11.0->transformers) (4.4.0)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from requests->transformers) (3.4)
Requirement already satisfied: urllib3<1.27,>=1.21.1 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from requests->transformers) (1.26.14)
Requirement already satisfied: charset-normalizer<3,>=2 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from requests->transformers) (2.0.4)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from requests->transformers) (2022.12.7)
Installing collected packages: tokenizers, huggingface-hub, transformers
Successfully installed huggingface-hub-0.13.3 tokenizers-0.13.2 transformers-4.27.2
In [ ]:
from transformers import pipeline, set_seed, BioGptTokenizer, BioGptForCausalLM
In [ ]:
# 加载模型
model = BioGptForCausalLM.from_pretrained('microsoft/biogpt-large')

In [ ]:
import IPython
In [ ]:
from ipymock.browser import start_conversation as ask

In [ ]:
for response in ask('''
用 Hugging Face 下载的模型一般存储在哪里?
'''):
    IPython.display.display(IPython.core.display.Markdown(response))
    IPython.display.clear_output(wait=True)

使用 Hugging Face 下载的模型一般存储在本地的 ~/.cache/huggingface/ 目录下。该目录下会按照模型名称和版本号的组合来创建相应的子目录,存储着相应的模型文件和元数据文件。可以通过指定 cache_dir 参数来修改默认的存储路径。

In [ ]:
%%bash
ls -lah ~/.cache/huggingface/hub/models--microsoft--biogpt-large/
In [ ]:
%%bash
du -sh ~/.cache/huggingface/hub/models--microsoft--biogpt-large/
5.9G	/Users/saintway/.cache/huggingface/hub/models--microsoft--biogpt-large/

可以使用以下代码来估计 Hugging Face 模型文件的参数总量:

import torch

model = torch.hub.load('huggingface/transformers', 'model_name')
num_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"Number of parameters: {num_params}")

其中,model_name 是指 Hugging Face 模型的名称,例如 gpt2, bert-base-uncased等。

这段代码会加载相应的模型,并统计其中可训练参数的数量,输出结果为参数总量。

要估计 Hugging Face 模型文件的参数总量,可以使用 Hugging Face 库中的 num_parameters() 方法。以下是一个示例,说明如何使用 Hugging Face 库来估计模型的参数总量:

from transformers import AutoModel

model = AutoModel.from_pretrained('model_name')
num_params = model.num_parameters()

print(f"The model has {num_params} parameters.")

在这里,AutoModel.from_pretrained() 方法用于加载模型。将 "model_name" 替换为你想要估计参数总量的模型名称。然后,num_parameters() 方法返回模型中的总参数数量。

In [ ]:
from transformers import AutoModel

model = AutoModel.from_pretrained('microsoft/biogpt-large')
num_params = model.num_parameters()

print(f"The model microsoft/biogpt-large has {num_params} parameters.")
Some weights of the model checkpoint at microsoft/biogpt-large were not used when initializing BioGptModel: ['output_projection.weight']
- This IS expected if you are initializing BioGptModel from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).
- This IS NOT expected if you are initializing BioGptModel from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).
The model microsoft/biogpt-large has 1571188800 parameters.
This message is a warning that some of the weights in the pre-trained model checkpoint at `microsoft/biogpt-large` were not used when initializing the `BioGptModel`. 

This warning message indicates that this is an expected behavior if you are initializing a `BioGptModel` from a checkpoint of a model that was trained on a different task or has a different architecture, like initializing a `BertForSequenceClassification` model from a `BertForPreTraining` model.

However, if you are initializing a `BioGptModel` from a checkpoint of a model that you expect to be exactly identical, such as initializing a `BertForSequenceClassification` model from another `BertForSequenceClassification` model, this warning is not expected.
这条信息是一个警告,它表示在初始化 `BioGptModel` 时,`microsoft/biogpt-large` 预训练模型检查点中的一些权重没有被使用。

这个警告信息表明,如果您正在从一个针对不同任务或具有不同架构的模型的检查点初始化 `BioGptModel`,比如从 `BertForPreTraining` 模型初始化 `BertForSequenceClassification` 模型,那么这是一种预期行为。

但是,如果您正在从您预期完全相同的模型检查点初始化 `BioGptModel`,例如从另一个 `BertForSequenceClassification` 模型初始化 `BertForSequenceClassification` 模型,那么这个警告是不应该出现的。

In [ ]:
%%bash
pip install sacremoses
Collecting sacremoses
  Downloading sacremoses-0.0.53.tar.gz (880 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 880.6/880.6 kB 3.0 MB/s eta 0:00:0000:0100:01
  Preparing metadata (setup.py): started
  Preparing metadata (setup.py): finished with status 'done'
Requirement already satisfied: regex in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from sacremoses) (2022.10.31)
Requirement already satisfied: six in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from sacremoses) (1.16.0)
Requirement already satisfied: click in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from sacremoses) (8.1.3)
Collecting joblib
  Downloading joblib-1.2.0-py3-none-any.whl (297 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 298.0/298.0 kB 3.5 MB/s eta 0:00:00a 0:00:01
Requirement already satisfied: tqdm in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from sacremoses) (4.65.0)
Building wheels for collected packages: sacremoses
  Building wheel for sacremoses (setup.py): started
  Building wheel for sacremoses (setup.py): finished with status 'done'
  Created wheel for sacremoses: filename=sacremoses-0.0.53-py3-none-any.whl size=895241 sha256=ef1e1d98064b22881c14de405dff663a3972fb9f39a92195a28612459e1de7f9
  Stored in directory: /Users/saintway/Library/Caches/pip/wheels/00/24/97/a2ea5324f36bc626e1ea0267f33db6aa80d157ee977e9e42fb
Successfully built sacremoses
Installing collected packages: joblib, sacremoses
Successfully installed joblib-1.2.0 sacremoses-0.0.53
In [ ]:
# 加载分词器
tokenizer = BioGptTokenizer.from_pretrained('microsoft/biogpt-large')

In [ ]:
for response in ask('''
用 Hugging Face 下载的 tokenizer 一般存储在哪里?
'''):
    IPython.display.display(IPython.core.display.Markdown(response))
    IPython.display.clear_output(wait=True)

使用 Hugging Face 下载的 tokenizer 存储位置取决于所选择的 tokenizer。一些 tokenizer 会默认存储在缓存目录中,例如 $HOME/.cache/huggingface/tokenizers,而其他 tokenizer 可能需要手动指定保存位置。在使用 tokenizer 时,可以使用 from_pretrained 方法指定 tokenizer 的名称和路径来加载已下载的 tokenizer。例如:

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased", cache_dir="/path/to/tokenizer")

这里 cache_dir 参数指定了 tokenizer 存储的路径。如果未指定该参数,则默认使用缓存目录。

In [ ]:
%%bash
ls -lah ~/.cache/huggingface/hub/models--microsoft--biogpt-large/snapshots/c6a5136a91c5e3150d9f05ab9d33927a3210a22e
total 0
drwxr-xr-x  9 saintway  staff   288B Mar 21 23:18 .
drwxr-xr-x  3 saintway  staff    96B Mar 21 22:31 ..
lrwxr-xr-x  1 saintway  staff    52B Mar 21 22:31 config.json -> ../../blobs/6781cfc676cb2384020b1b5fdd04817536c723fb
lrwxr-xr-x  1 saintway  staff    52B Mar 21 23:18 generation_config.json -> ../../blobs/9475ded3180a2d64c6903ebcf2aeb0705703c12a
lrwxr-xr-x  1 saintway  staff    52B Mar 21 23:18 merges.txt -> ../../blobs/01e121aa8483873879577612f38761f2fd9ce5ae
lrwxr-xr-x  1 saintway  staff    76B Mar 21 23:17 pytorch_model.bin -> ../../blobs/d1753ea5af6449aaf63a105a59a619632b78cbfc2c294ba78f3164156af8c8bf
lrwxr-xr-x  1 saintway  staff    52B Mar 21 23:18 special_tokens_map.json -> ../../blobs/e66da1703089a0329ca9eaf51638805d8ce1b322
lrwxr-xr-x  1 saintway  staff    52B Mar 21 23:18 tokenizer_config.json -> ../../blobs/e044f8771c083e25f9accfecb9c8f1408cb3c42f
lrwxr-xr-x  1 saintway  staff    52B Mar 21 23:18 vocab.json -> ../../blobs/66ddce4fab432cd017c0db812211c30d25acce1e

In [ ]:
# 设置随机数种子
set_seed(2023)
In [ ]:
# 设置 pipeline
generator = pipeline(
    'text-generation',
    model = model,
    tokenizer = tokenizer
)
In [ ]:
# 生成文本
# max new tokens:生成的最多 token 数量
# num_return_sequences:生成的序列个数
generator('COVID 19 is', max_new_tokens=20, num_return_sequences=5, do_sample=True)
Out[ ]:
[{'generated_text': 'COVID 19 is an emerging pandemic viral, the virus cannot be eliminated completely in the absence of vaccine. A prophylactic approach'},
 {'generated_text': 'COVID 19 is ongoing with several plans in the field; however the virus did not spread to Canada by 2 0 1'},
 {'generated_text': 'COVID 19 is a global health emergency. There are currently 2 million confirmed and over 2 6 0, 0 0 0'},
 {'generated_text': 'COVID 19 is a more virulent, recently emerged pandemic virus strain belonging to the Middle East-Africa 2 0 1 2'},
 {'generated_text': 'COVID 19 is at the threshold of approval as the first FDA-approved drug for treating IAVs. 1 2 1'}]

In [ ]:
from transformers import pipeline, set_seed, BioGptTokenizer, BioGptForCausalLM
In [ ]:
# 加载模型
model = BioGptForCausalLM.from_pretrained('microsoft/BioGPT-Large-PubMedQA')
In [ ]:
# 加载分词器
tokenizer = BioGptTokenizer.from_pretrained('microsoft/BioGPT-Large-PubMedQA')
In [ ]:
# 设置随机数种子
set_seed(2023)
In [ ]:
# 设置 pipeline
generator = pipeline(
    'text-generation',
    model = model,
    tokenizer = tokenizer
)
In [ ]:
# 生成文本
# max new tokens:生成的最多 token 数量
# num_return_sequences:生成的序列个数
generator('question: What is Synaptotagmin-7? answer:', max_new_tokens=760, num_return_sequences=20, do_sample=True)
Out[ ]:
[{'generated_text': 'question: What is Synaptotagmin-7? answer: Synaptotagmin-7, a neuron-specific Synaptotagmin isoform, is concentrated at the synaptic vesicle membrane. Although it displays sequence similarity to synaptotagmin-1, it is unclear whether it functions as a Ca (2 +) sensor in fast neurotransmission. We generated mutant mice lacking Synaptotagmin-7. Although basic synaptic transmission appeared largely normal, the mice displayed deficiencies in motor coordination and hyperactivity. At the behavioral level, the phenotypes were similar but less severe than those observed in mice lacking synaptotagmin-1. Consistent with this, the Ca (2 +) dependence of evoked neurotransmitter release was reduced but not abolished in mutant neuromuscular synapses. Nevertheless, both fast and slow modes of synaptic vesicle exocytosis were affected. Our data suggest that Synaptotagmin-7 is not essential for fast Ca (2 +) -triggered neurotransmitter release, but it does contribute to the fast component of the overall synaptic response. Hence, Synaptotagmins-1 and -7 cannot completely substitute for each other, revealing remarkable functional specializations within the synaptotagmin family. We also found that in vivo targeting of Synaptotagmin-7 to synaptic vesicles was impaired in synaptotagmin-1-deficient mice, demonstrating that the two Synaptotagmins can interact genetically and suggest that synaptotagmin-1 may regulate the trafficking of Synaptotagmin-7. < / FREETEXT > < / PARAGRAPH > ▃ < PARAGRAPH > < FREETEXT > Neurotransmitter-containing synaptic vesicles fuse with the plasma membrane in response to Ca (2 +) influx into the presynaptic nerve terminal. The bestcharacterized molecular components of the Ca (2 +) -triggering reaction were first identified as the membrane-bound synaptic vesicle proteins Synaptotagmin-1 (also called Syt1) and Doc2 (for Double C2-domain) (Südhof, 2 0 0 4). Although the presence of Syt1 is necessary and sufficient for fast Ca (2 +) -triggered neurotransmitter release (Geppert et al., 1 9 9 4; Fernandez-Chacon et al., 2 0 0 1), it remains unclear whether Doc2 also has a role in this process (Groffen et al., 2 0 1 0). Additional Ca (2 +) sensors have been implicated recently in fast synaptic transmission (Xue et al., 2 0 0 9; Pang et al., 2 0 1 0a; Bacaj et al., 2 0 1 1). These include Synaptotagmin-7 (also called Syt7), another neuronal isoform that shows sequence similarity to Syt1 (Suttleton et al., 1 9 9 5). Synaptotagmin-7 is a component of nerve terminals (Südhof et al., 1 9 9 3; Fox et al., 2 0 0 6; Gustavsson et al., 2 0 0 8) and synaptic vesicles, and it binds Ca (2 +) (Fukuda et al., 2 0 0 2a). Biochemical studies suggest a preference of Synaptotagmin-7 for membranes containing negatively charged lipids (Sugita et al., 1 9 9 4; Fukuda et al., 1 9 9 6). Moreover, like Syt1, Synaptotagmin-7 also interacts with soluble N-ethylmaleimide-sensitive factor attachment protein receptors (SNAREs) and other proteins implicated in membrane fusion (Fukuda et al., 1 9 9 6, 2 0 0 3a, b; Chapman, 2 0 0 8; Giraudo et al., 2 0 0 9; Wang et al., 2 0 0 9). However, the precise function of Synaptotagmin-7 in synaptic transmission and the relationship between Synaptotagmin-7 and Syt1 are poorly understood. < / FREETEXT > < / PARAGRAPH > ▃ < PARAGRAPH > < FREETEXT > In cultured neurons, Synaptotagmin-7 is not'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: There are several splice variants of rat synaptotagmin-7 that have different properties. This commentary discusses the most recent findings about synaptotagmin-7, with particular focus on how the properties of a different splice variant, Syt7 A, may relate to a specific function of synaptotagmin-7 in neurons that is distinct from its role as a Ca (2 +) sensor for fast synaptic vesicle exocytosis. In this scenario, Syt7 A would be a structural adaptor bringing other partners of Ca (2 +) - and diacylglycerol-mediated signaling pathways close to membrane fusion. Critical comments: The main finding of this commentary is that there is still little information about the function of Syt7 A, due to the lack of reagents that discriminate between the different splice variants. Experiments that discriminate between Syt7 A and the other variants, for example by expression of splice variant-specific antibodies or by RNA interference, will be required in order to clarify the function of Syt7 in neurons. Ultimately, this information will help elucidate the different functions that are served by synaptotagmin isoforms and how they act in concert to control physiological outcomes such as synaptic strength and plasticity. Ed Taylor Weiss, Ph.D., Marikki Jahn, Ph.D., and Marijke Lipp, M.D., discuss the implications of these discussions for future directions in research in vesicle trafficking at synapses. Listen to Their Point: Taylor Weiss and Lipp discuss the recent findings on the neuronal BACKGROUNDS sensing totagmin-7. learned1 learned2 learned3 learned4 learned5 learned6 learned7 learned8 learned9 the answer to the question given the context is yes.'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: Synaptotagmin-7 (Syt7) is unique among synaptotagmin isoforms in its expression profile: Syt7 is a restricted marker of cholinergic neurons, which are the primary fast-transmitting excitatory neurons in the central and peripheral nervous systems of vertebrates. Here, we review evidence that Syt7 is a calcium sensor for transmitter release in cholinergic neurons. Expression of Syt7 at the cholinergic neuron presynaptic active zone suggests that Syt7 may regulate fast synaptic transmission via a direct calcium-sensing mechanism. Biochemical and biophysical data indicate that Syt7 has unusual calcium-binding properties and that it may bind phospholipids with high affinity and cooperativity in the presence of calcium. Structural data indicate that the long C2 domain region of Syt7 may fold into a three-dimensional structure unique among C2 domain proteins. The combined data support the hypothesis that Syt7 is a specialized fast-transmitting calcium sensor for transmitter release at some cholinergic synapses. We speculate that the presence of multiple fast-transmitting calcium sensors in individual fast synapses may provide a general mechanism to rapidly modulate synaptic strength. < / FREETEXT > < / ABSTRACT > ▃'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: Synaptotagmin-7, in common with the other four synaptotagmins, is localized to synaptic vesicles but its precise function is unclear. In this study, we have addressed this question by analyzing mice lacking synaptotagmin-7 (Syt7 (- / -)). We first developed monoclonal antibodies that specifically recognize mouse synaptotagmin-7. These antibodies revealed that synaptotagmin-7 is localized to a subset of synaptic vesicles and to a few intracellular puncta in cultured neurons, indicating that synaptotagmin-7 is also present outside the synapse. Immunohistochemical analysis of the adult brain revealed that synaptotagmin-7 is enriched in the thalamus, the subthalamic nucleus, and the zona incerta, structures that project their axons to the cerebral cortex. In the cerebral cortex, synaptotagmin-7 immunoreactivity was concentrated in some layers, particularly layer V. Syt7 (- / -) mice did not exhibit any significant deficits in motor function, sensory transmission, short- or long-term synaptic plasticity, or cognitive function. Electrophysiological analysis, however, revealed a small but significant decrease in the readily releasable pool of vesicles in the dentate gyrus, a subsynaptic structure known to play a critical role in cognitive processes. Additional morphological analysis indicated that Syt7 (- / -) mice have a normal number and distribution of boutons in the cerebral cortex, but there is a selective reduction in the number of perforated synapses in the middle layers of the primary somatosensory cortex, suggesting that Syt7 may be important for the formation or maturation of these synapses. Our results indicate that synaptotagmin-7 is not essential for fast synaptic transmission but does contribute to some forms of synaptic plasticity. < / FREETEXT > < / ABSTRACT > ▃'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: We show here that synaptotagmin-7 constitutes an unusual synaptic vesicle protein, both structurally and functionally. It is not a calcium sensor but instead modulates fusion pore dilation. Thus, it has opposite functions in neuroexocytosis to neuroligin, synaptotagmin-1, complexin, and Munc1 3. Our results highlight that calcium sensor function is not a common feature of synaptic vesicle proteins but is confined to a small number of highly specialized proteins. These results have interesting evolutionary implications because synaptotagmin-7 homologs are found in all animals but appear to have been lost in vertebrates. Synaptotagmin-7 provides a novel molecular tool with which to study fusion pore dynamics. < / FREETEXT > < / ABSTRACT > ▃'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: According to the prevailing view, synaptotagmin-7 (Syt7) is primarily localized to neurons where it functions as an inhibitor of neurotransmitter release. However, in mouse brain, Syt7 is not restricted to neurons and is also expressed by astrocytes. In this study, we used conditional gene targeting in mice to investigate whether astrocytic Syt7 regulates synaptic transmission or contributes to the maintenance of energy homeostasis. Using a mouse model with astrocyte-specific deletion of Syt7 (cKO), we found that astrocytic Syt7 has no effect on basic synaptic transmission. In addition, deletion of astrocytic Syt7 does not affect basal motor control or the response to metabolic challenges. Together, our results demonstrate that astrocytic Syt7 does not regulate basic synaptic transmission nor is it required for the homeostatic response to metabolic stress. These findings challenge the prevailing view of Syt7 and strongly suggest that the physiological functions of Syt7 in the mammalian central nervous system are not confined to neurons. Calcium-binding proteins with sequence similarity to Syt7, such as Syt1 2, may be more appropriate to serve as Ca2 + sensors in astrocytes. Astrocytic Syt1 2 may function in conjunction with different modes of stimulus-induced Ca2 + elevations to modulate synaptic transmission or to trigger other signaling cascades that trigger astrocytic processes that modulate synaptic transmission. learned1 learned2 learned3 learned4 learned5 learned6 learned7 learned8 learned9 the answer to the question given the context is no.'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: Synaptotagmin-7 is one of the two calcium sensors for fast neurotransmitter release found at parallel fiber to Purkinje cell synapses in the cerebellum. Both Syt1 and Syt2 are localized to the nerve terminal and are essential for fast exocytosis. In Syt1 KO mice, neurotransmission is largely abolished, whereas in Syt2 KO mice, it remains partially intact. Here, we investigated the function of Syt7 in fast neurotransmitter release using mice with a deletion of Syt1 and Syt7 and mice with deletions of Syt1, Syt2, and Syt7. Syt7 deletion did not alter synaptic transmission, and Syt1 and Syt2 double deletion caused a complete loss of fast transmission. In Syt1, Syt2, and Syt7 triple KO mice, neurotransmission was completely abolished. Neurotransmission in Syt1, Syt2, and Syt7 double KO mice could be restored by expression of Syt1, Syt7, or both Syt1 and Syt7. These data suggest that Syt1, Syt2 effusion, and Syt7 can function downstream of calcium influx and at the interface of calcium sensor and core fusion machinery. However, calcium transients were smaller in Syt1, Syt2, and Syt7 triple KO mice compared with Syt1, Syt2 double KO mice, indicating partial overlap in their calcium sensitivity in presynaptic terminals. Syt7 was not sufficient to trigger spontaneous release, even during prolonged stimulation. Thus, the calcium-dependent triggering of exocytosis by Syt7 probably requires additional regulatory factors. Overall, the function of Syt7 is at odds with the proposed function of the homologous proteins Syt3 and Syt5 as calcium sensors for slow synaptic vesicle exocytosis. Syt1 and Syt2 are redundantly required for fast and slow neurotransmitter release. Thus, fast and slow synaptic vesicle exocytosis are mediated by different calcium sensors. These results challenge the concept that different calcium sensor proteins mediate fast and slow synaptic vesicle exocytosis. Guest Editor: David Poser, MD, PhD. < / FREETEXT > < / ABSTRACT > ▃'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: In this work, we explore the role of synaptotagmin-7 (Syt7), an extensively studied presynaptic Ca (2 +) sensor of neuroexocytosis. Unlike other Syt family members, which have a well-established function in fast neuroexocytosis, Syt7 appears to have little effect on these processes when analyzed in Syt7-deficient mice. Nevertheless, some studies have revealed that this molecule functions in a slower form of neurotransmission mediated by small clear vesicles. Because studies on the function of Syt7 have been mainly performed in neurotoxicity and / or Syt7 transgenic models, its precise role in central nervous system (CNS) remains to be clarified. Here, we analyzed the levels and expression pattern of Syt7 in the CNS and correlated these data with Syt7-deficient mouse behavioral studies, because altered CNS function might produce compensatory changes that obscure any particular physiological contribution of Syt7. We found that although most regions of the adult CNS express detectable levels of Syt7, some neurons, such as thalamocortical axons in the somatosensory thalamus and thalamocortical synapse cartridges that impinge on neurons in the ventrobasal thalamus (VB) in the somatosensory pathway, lack detectable talar levels of this molecule. Consistent with this observation, Syt7-deficient thalamocortical projections in Syt7 (- / -) mice showed normal evoked transmission even at high frequencies of stimulation. Moreover, behavioral studies revealed that Syt7 (- / -) athion mice, although exhibiting alterations in sensory processing, including altered whisker-induced tactile responses, did not display obvious alterations in sensorimotor gating functions. Our results indicate that while Syt7 is widely expressed in the adult nervous system, most central synapses, with the notable exception of some thalamocortical projections, appear to function normally in its absence. Synapse 6 8: 2 8 5-2 9 4, 2 0 1 0. Copyright © 2 0 1 0 Wiley-Liss, Inc. < / FREETEXT > < / ABSTRACT > ▃'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: This study raises several questions regarding synaptotagmin-7 including its localization, expression profile, and calcium sensing function in cellular systems and behavioral assays. We found that synaptotagmin-7 in mice has a broad expression profile in the nervous system, albeit at high levels in certain brain regions and spinal cord motor neurons. The presence of synaptotagmin-7 in sensory neurons and the spinal cord is consistent with behavioral experiments showing that the loss of synaptotagmin-7 leads to defects in pain processing and gait. However, loss of synaptotagmin-7 did not cause lethality that would be expected if synaptotagmin-7 regulated a widespread form of calcium-triggered vesicle fusion that is required for vesicular neurotransmitter release and the maintenance of cellular homeostasis. This is different from other synaptotagmin family members, which are essential components of the core secretory machinery. At the cellular level, we found that loss of synaptotagmin-7 did not affect calcium-triggered neurotransmitter release in several types of neurons, despite the presence of synaptotagmin-7 at synapses, suggesting that synaptotagmin-7 functions redundantly with other calcium sensors. Our analysis was limited by the lack of a specific antibody, but future work with new antibodies and genetically modified animals that express tagged forms of synaptotagmin-7 will be necessary to further examine this question. < / FREETEXT > < / PARAGRAPH > ▃'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: In this manuscript we have reevaluated the Ca2 + -dependent function of Syt7 using mice deficient in Syt7 and knockin mice expressing a nonageable version of Syt7. We demonstrate that absence of endogenous Syt7 drastically reduced the readily releasable pool of synaptic vesicles containing synaptotagmin-1 (Syt1) but had little effect on the size of the readily releasable pool containing Syt7. At the same time, the rate of spontaneous release was elevated in Syt1-deficient neurons and not affected by absence of Syt7 disseminated throughout the presynaptic axon. We conclude that, in neurons, Syt7 is not central for the Ca (2 +) triggering of vesicle exocytosis, but it exerts a tonic inhibition on vesicle fusion in the absence of Syt1. This unexpected function of Syt7 could help to explain the evolutionary conservation of two synaptotagmins in all animals. < / FREETEXT > < / ABSTRACT > ▃'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: We provide structural, biochemical, and cell biological evidence that Syt7 is an SV Ca (2 +) sensor, thereby extending the molecular repertoire of synaptotagmin proteins. The Ca (2 +) affinities measured for several synaptotagmin variants suggest a contribution of synaptotagmin-7 to fast, synchronous transmitter release. However, the observation that the phenotype of Syt7 KO is quantitatively weaker than that of synaptotagmin-1 KO suggests that Ca (2 +) -mediated release can be mediated by additional synaptotagmin isoforms. We discuss possible interactions between Syt7 and other synaptotagmin isoforms and SV proteins and consider functional parallels to complexins. Syt1 / 7 / 9KO triple mutant mice will be instrumental for future studies to define the role of Syt7 within the core release machinery. Since Syt7 KO did not compromise synaptic transmission in one study (Pang et al., 2 0 0 6a), it will also be important to rigorously examine Syt7 KO mice in multiple genetic backgrounds to determine its overall contribution to regulated synaptic vesicle exocytosis. < / FREETEXT > < / ABSTRACT > ▃'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: The search for additional, functionally important Synaptotagmin genes that may reside within the human genome has been intense. However, to date, only the Synaptotagmin-1 (Syt1) gene has been localized to human chromosome 1 9p1 3. 2, a location that has thus far ruled out additional human homologs. Using bioinformatics, we identified seven previously unplaced human sequences that exhibit extensive similarity to the Syt1 protein. We report the characterization of one of these genes, Syt7, which is localized on human chromosome 2 0p1 3. 2. A Syt7 full-length cDNA clone was obtained, and a predicted open reading frame of 1, 0 1 8 bp encoding a protein that is approximately 7 0% identical to Syt1. Phylogenetic analysis placed human Syt7 within the same clade as Syt1 and a second member, Syt9, suggesting that these three genes may have arisen via a gene duplication event. Syt7 is preferentially expressed in brain and peripheral tissues, including skeletal muscle, heart, and kidney, whereas Syt1 is mainly expressed in brain, with lower levels found in skeletal muscle, heart, and pancreas. Syt1 and Syt7 exhibit different patterns of synaptic tingitation. Both proteins are found on synaptic vesicles but exhibit distinct patterns of distribution within various subcellular membrane fractions of brain homogenates, suggesting that they localize to distinct membranous compartments. The intracellular distribution patterns of Syt7 and Syt1 also differ following KCl-depolarization and ionomycin treatments of PC1 2 cells, suggesting that Syt7 and Syt1 undergo distinct modes of regulated trafficking. Finally, Syt7 and Syt1 exhibit significantly different patterns of expression in certain brain regions. These studies suggest that human Syt7, like Syt1, is a member of the synaptotagmin family and may play a role in synaptic transmission. However, the distinct patterns of expression and trafficking observed for Syt7 and Syt1 suggest that these two proteins may perform unique functions within the vesicle-mediated secretory pathway. Syt7 should now be considered a candidate for genetic mutations that underlie diseases of synaptic transmission, such as epilepsy or migraine. Display: The human genome contains seven previously unplaced Synaptotagmin-like sequences. We characterized one of these genes, nemo-bin 7 (syt7), which exhibits extensive similarity to Syt1. Syt7 is preferentially expressed in brain and peripheral tissues, including skeletal muscle, heart, and kidney. Syt7 is present on synaptic vesicles but exhibits distinct patterns of distribution within membrane fractions. syt7 and Syt1 exhibit significantly different patterns of expression in certain brain regions. Syt7 should now be considered a candidate for genetic mutations that underlie epilepsy or migraine. Chapman, H.A., Guan, Y., Li, M.-S., Wang, T., Paudel, F.J.G., Diogo, J., Bao, X., Jin, B., Luo, C., Xu, T., Zhao, Y., Rush, S.M., Bao, H., Jin, Y., Liu, Y., Liu, S., Sheng, J., Wang, X. 9B new human Synaptotagmin-like genes: tissue-specific expression, alternative splicing and chromosomal assignment. Dev. Dyn. 2 3 6, 8 4 7-8 6 0.Page1001 [PMC free article] [PubMed] [Google Scholar] [Google Scholar] 1 2. Bennett, V.A., Geppert, S., Chapman, J.H., Bennett, J.D., Chapman, J.W., Bennett, M.P., Borgen, E., Brown, R., Burgoyne, P., Cooper, J.A., Davis, M.W., Davis, J.E., Davis, R.J.R., Dierickx, R., Deptré, A., Dijkman, L., Edwards, P.H., Fink, P.O., Fink, C.'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: Synaptotagmin-7, but not other mammalian synaptotagmins, regulates dense-core vesicle exocytosis in hippocampal neurons, suggesting that it is the calcium sensor for synaptic transmission. Synaptotagmin-7 has been controversial as a synaptic vesicle protein at odds with its genetic discovery. However, we show here that endogenous synaptotagmin-7 is present in purified synaptic vesicles and, moreover, is colocalized with the synaptic vesicle protein, synaptotagmin-1, in presynaptic nerve terminals. In neurons derived from synaptotagmin-7 knock-out mice, evoked neurotransmitter release is significantly reduced relative to wild-type readmitted responses, whereas spontaneous release is unchanged. Direct calcium sensing by synaptotagmin-7 is suggested by its ability to bind calcium and regulate neuronal exocytosis in a recombinant expression system. Expression of a synaptotagmin-7 C2B domain mutant known to impair calcium binding abolishes the ability of synaptotagmin-7 to inhibit regulated neuronal exocytosis. We propose that synaptotagmin-7 functions as the calcium sensor for calcium-triggered dense-core vesicle exocytosis in hippocampal neurons. < / FREETEXT > < / PARAGRAPH > ▃ < PARAGRAPH > < FREETEXT > Keywords: < / FREETEXT > < / PARAGRAPH > ▃ < PARAGRAPH > < FREETEXT > dense-core vesicle, SNARE, synaptic transmission, synaptotagmin, calcium < / FREETEXT > < / PARAGRAPH > ▃ < PARAGRAPH > < FREETEXT > Neurotransmitter release is regulated by intracellular calcium, and a long-standing paradigm is that calcium acts by binding to intracellular proteins called synaptotagmins (Geppert et al., Losonczy and Mattson, 2 0 0 2). Several synaptotagmins, including synaptotagmin-1 and synaptotagmin-7, act as calcium sensors for regulated dense-core vesicle exocytosis in neuroendocrine cells, but it remains unclear which, if either, of these synaptotagmins function as the calcium sensor in neurons (Fernandez-Chacon et al., 2 0 0 1; Nagy et al., 2 0 0 2, 2 0 0 4; Geppert et al., 2 0 0 3; Gustavsson et al., 2 0 0 5; Bacaj et al., 2 0 0 6). A major experimental problem has been the lack of a specific genetic manipulation that completely eliminates any particular synaptotagmin. < / FREETEXT > < / PARAGRAPH > ▃ < PARAGRAPH > < FREETEXT > We and others recently developed a genetic approach using embryonic stem (ES) cell – derived neurons (Sun et al., 2 0 0 3, 2 0 0 5; Dibotta et al., 2 0 0 5). Neurons are differentiated from ES cells and subsequently subjected to genetic manipulations including homologous recombination. Using this method, we showed that several of the neuronal SNAREs (soluble N-ethylmaleimide-sensitive factor attachment protein receptor), plasma membrane SNAREs, and calcium-dependent adaptors are involved in dense-core vesicle exocytosis from embryonic precursor neurons (Sun et al., 2 0 0 3; Dibotta et al., 2 0 0 特4ically highlighted in the text). Here, we show that another approach, the lentiviral-mediated expression of short interfering RNAs (siRNAs), can be used to inhibit the expression of endogenous synaptotagmin-7 in neurons. This approach demonstrates that synaptotagmin-7, but not other endogenous synaptotagmins, is a critical regulator of calcium-triggered dense-core vesicle exocytosis in hippocampal neurons. Finally, we demonstrate that synaptotagmin-7 binds calcium and regulates exocytosis in a manner analogous to other synaptotagmins. < / FREETEXT > < / PARAGRAPH > ▃ < PARAGRAPH > < FREETEXT > The lentiviral expression and rescue vectors. We generated four lentiviral expression vectors: pLVTHM encodes green fluorescent protein (GFP); pLVTH.Syt7-shRNA expresses a hairpin RNA targeting rat synaptotagmin-7 (sequence: 5 ′ -CCA'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: Synaptotagmin-7 is widely expressed in neuronal and some non-neuronal cells and is thought to act as a Ca (2 +) sensor for synaptic vesicle exocytosis. However, whether Synaptotagmin-7 is essential for synchronous synaptic transmission is controversial. This controversy appears to be due, at least in part, to the fact that three different Synaptotagmin-7-deficient mouse lines have been independently generated, making it possible that the apparent phenotype results from the insertion of a "balancer" chromosome in one of these mouse lines. However, the "balancer" chromosome does not appear to have any functional consequences since it has been removed from the three different Synaptotagmin-7-deficient mouse lines that have been described so far. Thus, all three different Synaptotagmin-7-deficient mice generated so far, including the line that lacks the "balancer" chromosome, exhibit normal synaptic transmission at most synapses examined. In addition, the most detailed physiological analysis to date performed at the auditory nerve-cochlear nucleus synapse in Synaptotagmin-7-deficient mice has failed to detect any defect in synaptic transmission. One possible explanation for the lack of a strong phenotype in Synaptotagmin-7-deficient mice might be that Synaptotagmin-7 function can be partially substituted by another Synaptotagmin family member. However, this is unlikely since mice deficient in both Synaptotagmin-7 and Synaptotagmin-1 exhibit massive paralysis similar to that reported for mice deficient in Synaptotagmin-1 alone. In addition, the cytoplasmic domain of Synaptotagmin-7 interacts with many of the same soluble N-ethylmaleimide fusion protein attachment receptor (SNARE) proteins as those for Synaptotagmin-1, raising the possibility that Synaptotagmin-7 and Synaptotagmin-1 regulate exocytosis via similar molecular mechanisms. Thus, although no individual Synaptotagmin appears to be essential for exocytosis, it remains possible that different synaptic transmission functions are served by different Synaptotagmins. Alternatively, the lack of a strong synaptic transmission phenotype in Synaptotagmin-7-deficient mice might be due to functional redundancy among different Synaptotagmins, and the introduction of additional mutations will be necessary to uncover a role for Synaptotagmin-7 in synaptic transmission. Nevertheless, the functional characterization of additional Synaptotagmin family members and the generation of new mouse and Drosophila mutants deficient in other Synaptotagmin family members will be essential for elucidating the precise function (s) of this fascinating class of proteins. < / FREETEXT > < / ABSTRACT > ▃'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: Synaptotagmin-7 is a brain-specific synaptotagmin that was named after the fact that its expression is highly restricted to the nervous system. Recently, studies employing gene targeting in mice have uncovered functions for synaptotagmin-7 in synaptic vesicle exocytosis and neurotransmitter receptor trafficking at inhibitory synapses. The precise roles of synaptotagmin-7 and its relationship to other synaptotagmins remain to be fully elucidated. This article discusses our understanding of synaptotagmin-7, and highlights outstanding questions that will need to be addressed to further our understanding of the functions of this intriguing synaptotagmin. < / FREETEXT > < / ABSTRACT > ▃'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: In contrast to the large body of literature on Synaptotagmin-1 and -2, little is known about Synaptotagmin-7. In cultured hippocampal neurons, Synaptotagmin-7 is localized to axons and synaptic terminals, and its Ca 2 + -dependent binding to phospholipid vesicles correlates well with the distribution of synaptotagmin-1. Furthermore, the overexpression of Synaptotagmin-7 in PC1 2 cells enhances secretory responses, whereas its downregulation by RNA interference (RNAi) decreases these responses. However, it is not clear whether Synaptotagmin-7 is the Ca 2 + sensor for fast neuroexocytosis. In particular, the properties of Synaptotagmin-7 that distinguish it from Synaptotagmin-1 and -2, such as its membrane topology or distribution within presynaptic terminals, have not been thoroughly investigated. In this study we addressed these questions by using two highly specific antibodies raised against different domains of Synaptotagmin-7. We found that Synaptotagmin-7 is a peripheral membrane protein that is anchored to synaptic vesicles via its transmembrane region, and it is present at lower levels than Synaptotagmin-1 within presynaptic terminals. Furthermore, our results suggest that Synaptotagmin-7 is a synaptotagmin isoform with both Ca 2 + -dependent and Ca 2 + -independent modes of phospholipid binding. In addition, we have identified a cytoplasmic fragment of Synaptotagmin-7 that contains the domains homologous to those that form the phospholipid binding sites of Synaptotagmins-1 and -2. Our results provide new insights into the properties of this poorly studied isoform of synaptotagmin and will be instrumental in designing experiments aimed at identifying the function of Synaptotagmin-7 in the nervous system. Anat Rec, 3 0 1: 4 7-5 8, 2 0 1 8. © 2 0 1 7 Wiley Periodicals, Inc. < / FREETEXT > < / ABSTRACT > ▃'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: Synaptotagmin-7 is a type I transmembrane protein with two C2 domains. It is predominantly expressed in neuroendocrine tissues, where it functions as an essential calcium sensor for fast calcium-triggered exocytosis. Synaptotagmin-7-deficient mice develop a severe and complex phenotype, characterized by growth retardation, ataxia, and lethal seizures. Biochemical and electrophysiological studies have shown that synaptotagmin-7 regulates synaptic vesicle exocytosis downstream of calcium channels but upstream of SNARES. At mammalian synapses, synaptotagmin-7 mainly localizes to dense-core vesicles in chromaffin cells, which suggests that it might also regulate the exocytosis of large dense-core vesicles. However, synaptotagmin-7-deficient mice that have been rescued by re-introduction of synaptotagmin-7 specific to mice do not develop a chromaffin cell phenotype. Instead, they show deficits in the regulated exocytosis of small synaptic vesicles, indicating that synaptotagmin-7 plays a differential role in fast exocytosis of different types of vesicles. This raises the question how synaptotagmin-7 functions as a calcium sensor for the exocytosis of different types of vesicles. Here, we discuss different modes of calcium decoding by synaptotagmins, including their different calcium affinities and different calcium sensitivities of interactions with SNAREs and membranes. We also consider evidence suggesting that synaptotagmin-7 might act as a trigger or clamp in the hierarchy of vesicle fusion during neuropeptide secretion from neuroendocrine cells. This article is part of a Special Issue entitled: Calcium-dependent proteins: Structure, functon and disease. Guest Editors: Geethia Kodec, Claus Heizmann, Jíbal Haucke, Thierry Monnet. Decisions are always oh-le-ti for you. < / FREETEXT > < / ABSTRACT > ▃'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: Most previous studies have focused on the neuronal isoforms, synaptotagmin-1 and synaptotagmin-9, whereas the other 7 synaptotagmin isoforms were largely ignored. Synaptotagmin-7 is unique among these in having an acidic polybasic region between the second and third C2 domains. Here we explore the functional role of the acidic polybasic region and its interactions with lipids. We found that the polybasic region does not contribute significantly to Ca (2 +) - and lipid-binding activities of synaptotagmin-7 but is important for its localization to endocytosis-related structures. Mutations that inhibit interactions with PIP2 had profound effects on the distribution of synaptotagmin-7, whereas the presence of PIP2 was important for its targeting to clathrin-coated pits. Moreover, inhibition of dynamin GTPase function, either by a dynamin mutant or by increasing the concentration of GTP, led to an accumulation of synaptotagmin-7 at the plasma membrane. These data support a model in which Ca (2 +) -dependent interactions with PIP2 via the polybasic region promote the localization of synaptotagmin-7 to clathrin-coated pits, which may be critical for driving late events in endocytosis. — Bai, T., Chapman, J.-Y., Zhang, W., Baroni, A. A., Bares, C. A., Evans, P. A., Chapman, J.-Y. The polybasic region of synaptotagmin-7 specifies its localization to endocytic structures and promotes late steps in endocytosis. < / FREETEXT > < / PARAGRAPH > ▃ < PARAGRAPH > < FREETEXT > Keywords: < / FREETEXT > < / PARAGRAPH > ▃ < PARAGRAPH > < FREETEXT > adaptor protein, clathrin-coated pits, synaptic vesicle recycling, PH domain < / FREETEXT > < / PARAGRAPH > ▃ < PARAGRAPH > < FREETEXT > The neurotransmitter release machinery is highly organized and regulated to ensure fast, precisely timed Ca (2 +) -dependent fusion of synaptic vesicles with the plasma membrane for the release of their neurotransmitter content. This machinery is comprised of several proteins organized into 2 main complexes: the SNARE complex that brings the 2 bilayers together and catalyzes their fusion; and the Ca (2 +) -sensing machinery (which includes synaptotagmin 1 – 7 and Doc2 proteins) that triggers SNARE-dependent membrane fusion. It was previously thought that this Ca (2 +) -sensing machinery consisted of only neuronal isoforms. However, during the past decade, much interest has been focused on the functions of a group of synaptotagmins (for review, see refs. 3, – 5). There are 1 7 synaptotagmin isoforms that are differentially expressed in a cell type-and tissue-specific manner. Although Ca (2 +) -triggered vesicle fusion has long been regarded as the only function of synaptotagmins, more recent discoveries have linked the synaptotagmins to many other cellular processes (for review, see ref. 6). Synaptotagmins participate in neurotransmitter release, exocytosis of dense-core vesicles, endocytosis, synaptic vesicle priming, regulation of secretion, plasma membrane repair, and phagocytosis (4, 5, 7, – 1 4). They also act as Ca (2 +) -sensors for other physiological processes, such as neuropeptide secretion by endocrine cells, and participate in signaling pathways, such as those mediated by G protein-coupled receptors (for review, see refs. 5, 8). Despite the importance of the synaptotagmins for basic physiology and pathophysiological effects, the molecular mechanisms by which the synaptotagmins act are still not clear. < / FREETEXT > < / PARAGRAPH > ▃ < PARAGRAPH > < FREETEXT > All synaptotagmins share a conserved core structure consisting of a short N-terminal luminal domain, followed by 1 transmembrane region and 2 cytoplasmic Ca (2 +) -binding C2 domains, designated C1- and C2-domains (1, 5, 1 5). The vesicular synaptotagmins, synaptotagmin 1 and'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: Synaptotagmin-7 (Syt-7) is a Ca (2 +) -sensor for evoked vesicle exocytosis in central neurons, yet how it triggers release remains enigmatic. Syt-7 clusters SVs near release sites and accelerates SV repriming at rest. Because Syt-7 also associates with the plasma membrane in a Ca (2 +) -dependent manner, it has been proposed that it might link the release machinery to the plasma membrane. Here, we used total internal reflection fluorescence microscopy to visualize individual Syt-7 clusters and SVs on the axon initial segment, the region of fastest exocytosis. We found that about one of four Syt-7 clusters is closely apposed to each SV release site. Syt-7 clusters were absent in syt-7 (- / -) neurons, but were restored by re-expression of Syt-7, but not of variants that are deficient in Ca (2 +) -binding, SV docking, or plasma membrane binding. Syt-7 variants that localize to the plasma membrane without synaptotagmin-1 rescued the repriming defect in syt-7 (- / -) neurons, but failed to restore the clustering defect, suggesting that both functions of Syt-7 require distinct properties of the cytoplasmic region of Syt-7. Our results suggest that the coupling of the release machinery to the SV membrane is not essential for SV priming. We propose instead that the Ca (2 +) -sensing function of Syt-7 is primarily responsible for accelerating SV repriming. The close association of Syt-7 clusters with each SV suggests that the Ca (2 +) -sensing function of Syt-7 is spatially confined to individual release sites, possibly to prevent Syt-7 from interfering with the fusion reaction in the wake of else-ongoing release. VIDEO ABSTRACT. < / FREETEXT > < / ABSTRACT > ▃'},
 {'generated_text': 'question: What is Synaptotagmin-7? answer: We address the question of neuronal function of Syt7 by characterizing the loss of function phenotype in Syt7 - / - mice generated either by homologous recombination (HSKO) or by gene trapping (TβKO). We report that these mice have no evident behavioral abnormalities, normal spontaneous behavior, normal coordination and gait, and normal performance on a rotating rod. In addition, they have no evident alterations of synaptic physiology at hippocampal CA1 synapses in vitro. The two mutants also showed similar deficits upon induction of LTP, with no evident increase wasp of transmitter release either at hippocampal CA1 or at cerebellar parallel fiber synapses. Similar findings were obtained when Ca2 + -dependent exocytosis was triggered by a high K + concentration stimulus. Moreover, the level of expression of several presynaptic proteins, including Synaptotagmin-1 (Syt1), Doc2, Munc1 3 and Synapsin, was normal in HSKO and TβKO sinuses. β-Galactosidase activity was observed not only in the brain but also in selected peripheral tissues and in specific cell populations in the brain, suggesting that Syt7 is also expressed outside the nervous system. We conclude that Syt7 is not essential for the basic function of fast synaptic transmission, but that it might cooperate with Syt1 in specific forms of regulated exocytosis observed upon induction of long-term synaptic plasticity. < / FREETEXT > < / ABSTRACT > ▃'}]


Read More

2023-03-14
ChatGPT WhatsApp 机器人开发指南

ChatGPT WhatsApp 机器人开发指南

本文详细介绍如何构建一个基于 ChatGPT 的 WhatsApp 智能聊天机器人,涵盖架构设计、Node.js 后端开发和 Python AI 逻辑实现。

Architecture

In [ ]:
import IPython
In [ ]:
from revChatGPT.V1 import Chatbot, configure


bot = Chatbot(
    config = configure(),
    conversation_id = 'fdf52ab3-f8c1-450f-86f2-5a25d43fc48d',
    lazy_loading = True
)

In [ ]:
for response in bot.ask('''
我刚刚有了一个 WhatsApp 群聊机器人的设计思路。我可以利用 https://web.whatsapp.com/ ,然后通过谷歌浏览器插件的方式实现 BioGPT 群聊机器人。
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

听起来很不错!如果你有相关的技能和经验,可以考虑实现这个想法并将其应用于实际场景。需要注意的是,确保你的机器人符合 WhatsApp 的使用条款和政策,并且在使用中不会违反用户的隐私和数据安全。

In [ ]:
for response in bot.ask('''
有利用 https://web.whatsapp.com/ ,然后通过谷歌浏览器插件的方式实现 WhatsApp 群聊机器人的开源项目吗?
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

是的,有很多开源项目利用了这种方式实现了 WhatsApp 群聊机器人,比如Whatsapp-bot,whatsapp-web.js,venom-bot等等。您可以在GitHub等代码托管平台上搜索这些项目并了解它们的使用方法和功能。请注意,使用这些项目需要一定的编程技能和对API的了解。

In [ ]:
for response in bot.ask('''
比较 Whatsapp-bot whatsapp-web.js venom-bot
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

Whatsapp-bot、whatsapp-web.js和venom-bot都是用于构建WhatsApp机器人的开源工具。

  • Whatsapp-bot是一个使用Node.js编写的简单的WhatsApp机器人框架,它提供了一些基本功能,例如响应文本消息、发送媒体文件和记录日志等。但是,它已经有一段时间没有更新维护了,可能不太适合用于生产环境。
  • whatsapp-web.js是一个用于控制WhatsApp Web的JavaScript库,它可以实现与WhatsApp Web界面类似的功能,并提供了一些高级功能,例如发送音频、图片、视频、文件、定位信息等。它可以与Node.js、React Native和浏览器一起使用,并且经常更新维护。
  • venom-bot是一个使用TypeScript编写的高级的WhatsApp机器人框架,它基于whatsapp-web.js,提供了更多的功能和抽象,例如会话管理、模板消息、状态管理、错误处理和中间件等。它的文档和社区支持也比较好,并且定期更新维护。

综上所述,如果你只需要一个简单的WhatsApp机器人框架,那么可以考虑使用Whatsapp-bot;如果你需要更多的高级功能和更好的可扩展性,那么可以选择whatsapp-web.js或venom-bot。

In [ ]:
for response in bot.ask('''
详细介绍 whatsapp-web.js
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

WhatsApp Web 是一个基于浏览器的 WhatsApp 客户端,使用户可以使用电脑或平板电脑发送和接收 WhatsApp 消息,而无需在移动设备上使用 WhatsApp。whatsapp-web.js 是一个 Node.js 库,它提供了一个简单而功能强大的 API,使开发人员可以使用 JavaScript 与 WhatsApp Web 进行交互,例如发送消息、创建群组、更改个人资料等。

使用 whatsapp-web.js,您可以创建一个 WhatsApp 机器人,使其可以自动发送消息、响应用户请求等。它还支持通过代码模拟用户交互,例如登录、扫描 QR 码、发送消息等。

whatsapp-web.js 还提供了许多高级功能,例如:

  • 离线发送:您可以使用 whatsapp-web.js 在断开连接的情况下发送消息,该消息会在下次连接时自动发送。
  • 轮询和 WebHook:您可以使用 whatsapp-web.js 提供的 API 轮询新消息或使用 WebHook 接收新消息。
  • 事件监听:您可以使用 whatsapp-web.js 监听各种事件,例如新消息、连接状态更改等。
  • 插件支持:whatsapp-web.js 支持插件,可以轻松地添加新功能和扩展其功能。

总的来说,whatsapp-web.js 提供了一个强大而灵活的 API,使开发人员能够轻松地构建各种 WhatsApp 机器人和工具。

In [ ]:
for response in bot.ask('''
详细说明 whatsapp-web.js 的原理
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

whatsapp-web.js 的原理主要是通过 Puppeteer 库实现对 WhatsApp Web 网页版的自动化操作,从而模拟用户与 WhatsApp 服务器之间的通信。具体来说,其主要实现方式包括以下几个步骤:

  1. 通过 Puppeteer 库启动 Chromium 浏览器,并打开 WhatsApp Web 网页版;
  2. 使用 Puppeteer 库提供的 DOM 操作接口,在浏览器中模拟用户输入手机号、验证码等信息,登录 WhatsApp 账号;
  3. 在登录成功后,通过 WebSocket 和 WhatsApp 服务器建立连接,并监听服务器发送的消息,包括收到的文本消息、图片、音频、视频等;
  4. 当收到消息时,使用 Puppeteer 库提供的 DOM 操作接口,模拟用户在网页版上回复消息;
  5. 在需要获取聊天记录等信息时,使用 Puppeteer 库提供的 DOM 操作接口,从网页版页面中获取需要的信息。

总的来说,whatsapp-web.js 通过 Puppeteer 库的支持,实现了对 WhatsApp Web 网页版的自动化操作和消息通信,从而可以作为一个 WhatsApp 群聊机器人的实现框架。

In [ ]:
for response in bot.ask('''
什么是 Puppeteer ?
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

Puppeteer是一个用于控制Google Chrome浏览器和Chromium的Node.js库。它提供了一个高级API,可以通过编程的方式自动化Chrome浏览器执行各种操作,例如生成屏幕截图、执行表单提交、模拟用户输入等等。Puppeteer的优点在于它提供了对Chrome DevTools Protocol的直接控制,因此可以使用最新的Web技术来进行测试和爬取数据。Puppeteer也可以用于其他一些用途,例如生成PDF、运行自动化测试等。

In [ ]:
for response in bot.ask('''
puppeteer 的 --no-sandbox 有什么用?
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

在使用 Puppeteer 运行 Chromium 浏览器时,通常会启用沙盒模式,这可以增加浏览器的安全性,但是也可能会导致某些操作无法正常执行,例如在某些 Linux 发行版中,由于沙盒模式的限制,会导致 Chromium 无法启动。

--no-sandbox 选项是用于禁用沙盒模式,通过这个选项,可以在特定情况下解决 Chromium 启动失败的问题。但同时,禁用沙盒模式也会增加一些潜在的安全风险,因为这样会使浏览器运行在非常高的权限级别下,攻击者可能会利用这个漏洞来攻击您的系统。

Body


Ask ChatGPT by Python

In [ ]:
import IPython
In [ ]:
from revChatGPT.V1 import Chatbot, configure


bot = Chatbot(
    config = configure(),
    conversation_id = 'fdf52ab3-f8c1-450f-86f2-5a25d43fc48d',
    lazy_loading = True
)
In [ ]:
for response in bot.ask('''
给出一个用 NodeJS 以 HTTP 协议 访问某个 URL 的 Demo
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

下面是一个使用 Node.js 的 http 模块访问某个 URL 并打印响应的简单示例:

const http = require('http');

const url = 'http://example.com';

http.get(url, (res) => {
  console.log(`Got response: ${res.statusCode}`);

  res.on('data', (chunk) => {
    console.log(`Received data: ${chunk}`);
  });

  res.on('end', () => {
    console.log('No more data in response.');
  });
}).on('error', (err) => {
  console.error(`Got error: ${err.message}`);
});

在这个示例中,我们使用了 http.get 方法向指定的 URL 发送 GET 请求,并注册了响应的回调函数来处理响应数据。当响应数据到达时,我们将其打印到控制台上。如果在请求过程中发生错误,我们也会将错误信息打印到控制台上。

In [ ]:
for response in bot.ask('''
用 NodeJS 实现 curl
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

以下是一个用 Node.js 实现 curl 的示例代码:

const https = require('https');

const url = process.argv[2];

https.get(url, (res) => {
  res.on('data', (chunk) => {
    process.stdout.write(chunk);
  });
}).on('error', (err) => {
  console.error(err);
});

这个代码使用 Node.js 内置的 https 模块向指定的 URL 发送 GET 请求,并将响应的数据输出到标准输出流。使用时可以在命令行中输入类似以下命令:

node curl.js https://www.example.com

这样就可以向 https://www.example.com 发送 GET 请求,并将响应的数据输出到控制台。

In [ ]:
for response in bot.ask('''
在 NodeJS 中,`console.log` 和 `process.stdout.write` 有什么区别?
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

console.logprocess.stdout.write 都是 Node.js 中用于输出内容的方法,它们的主要区别如下:

  1. 输出内容的格式不同:console.log 会自动在输出内容的结尾添加换行符 \n,而 process.stdout.write 则不会。

  2. 输出位置不同:console.log 的输出位置是标准输出流 stdout,而 process.stdout.write 则直接向标准输出流中写入数据。

因此,如果要输出一个带换行符的字符串,可以使用 console.log,例如:

console.log('Hello, world!');

如果要输出一个不带换行符的字符串,可以使用 process.stdout.write,例如:

process.stdout.write('Hello, world!');
In [ ]:
for response in bot.ask('''
在 NodeJS 中,有哪几种类型的字符串?
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

在 NodeJS 中,字符串是一种原始数据类型,有以下两种类型的字符串:

  1. UTF-8 编码的字符串:这种字符串使用 JavaScript 中的 String 类型表示,字符串中每个字符都使用 UTF-8 编码表示。

  2. 二进制字符串:这种字符串使用 Buffer 类型表示,它可以包含任意字节,可以进行二进制操作。


Run by IJavaScript

In [ ]:
console.log('Hello, world!');
Hello, world!
In [ ]:
process.stdout.write('Hello, world!');
Hello, world!
Out[ ]:
true
In [ ]:
const http = require('http');
const url = 'http://127.0.0.1:5000/与主同在';
In [ ]:
var answer = '';

http.get(url, (res) => {
  console.log(`Got response: ${res.statusCode}`);

  res.on('data', (chunk) => {
    console.log(`Received data: ${chunk}`);
    answer = `${chunk}`;
  });

  res.on('end', () => {
    console.log('---');
  });
}).on('error', (err) => {
  console.error(`Got error: ${err.message}`);
});

console.log('Sent request.');
Sent request.
Got response: 200
Received data: 阿门!愿神的恩典与平安与您同在。
---
In [ ]:
answer
Out[ ]:
'阿门!愿神的恩典与平安与您同在。'


Install by Z shell

In [ ]:
npm install 'whatsapp-web.js'
npm WARN deprecated puppeteer@13.7.0: < 19.2.0 is no longer supportednpmjs.o
m##################) ⠹ reify:node-webpmux: http fetch GET 200 https://registry.mjs.orist
added 98 packages, changed 2 packages, and audited 585 packages in 1m

7 packages are looking for funding
  run `npm fund` for details

42 vulnerabilities (5 low, 6 moderate, 23 high, 8 critical)

To address issues that do not require attention, run:
  npm audit fix

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.
In [ ]:
npm install qrcode-terminal
m##################) ⠹ reify:qrcode-terminal: http fetch GET 200 https://registK
added 1 package, and audited 586 packages in 14s

7 packages are looking for funding
  run `npm fund` for details

42 vulnerabilities (5 low, 6 moderate, 23 high, 8 critical)

To address issues that do not require attention, run:
  npm audit fix

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

Run by IJavaScript

In [ ]:
const http = require('http');
const querystring = require('querystring');
const qrcode = require('qrcode-terminal');

const { Client } = require('whatsapp-web.js');

const client = new Client();

client.on('qr', (qr) => {
    // Generate and scan this code with your phone
    qrcode.generate(qr, {small: true});
});

client.on('ready', () => {
    console.log('Client is ready!');
    console.log('---');
});

client.on('message', msg => {
    const prompt = querystring.escape(msg.body);
    const url = `http://127.0.0.1:5000/${prompt}`;

    http.get(url, (res) => {
        console.log(`Got response: ${res.statusCode}`);

        res.on('data', (chunk) => {
            console.log(`Received data: ${chunk}`);
            if (res.statusCode == 200) {
                msg.reply(`${chunk}`);
            }
        });

        res.on('end', () => {
            console.log('---');
        });
    }).on('error', (err) => {
        console.error(`Got error: ${err.message}`);
    });

    console.log('Sent request.');
});

client.initialize();
Out[ ]:
Promise { <pending> }
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
█ ▄▄▄▄▄ █▀  █▀▄▄█  █  ▀▀ ▄▀█▄▀█ ▄▄  ▄▀  ▄ ▄ ▀██ ▄▄▄▄▄ █
█ █   █ █▄ ▀▀▀█▄█ ▀▄▀▄██ █ ▀▀▀ ▄ ▄▀▀██▄▀▄█▄▀▄▀█ █   █ █
█ █▄▄▄█ █ ▄█▀ ██▀▀▄█▀ ▀▄▄ ▄▄▄  ▄ ▄█▀ ██▄ ▄  ███ █▄▄▄█ █
█▄▄▄▄▄▄▄█ █ █▄█ ▀ █ █▄▀▄▀ █▄█ ▀ ▀▄█▄▀▄▀▄▀ █▄▀▄█▄▄▄▄▄▄▄█
█ ▄▀ ██▄ █ ▄▄▀ ▄█ ▀▄██  ▄     ▄▄ ▀▄▄▀▄█▄ ▄▄▄ ▄█▄ ▄▀ ▄▀█
█▀█▄▀█ ▄▀▄██▄▄▀ █ █▄  ▄█ ▄▄  █▀▄█▄▀▀▀▀█▀▄█▄▄▀▄▄█▀▄▄  ██
█▀▀▄█▄▄▄▀▄█ █▀▄▄▄    ▄█▄ ██ ▄██▄▀ ▄ ▀  █ ▄█▄ ██▀▄ ███▀█
█▄▄██▄ ▄  ▀▀  ██ █▀  ▀█▄ █▄▄▄▄▄ █▀▀█▄▄▀██▀▄█▄██▄█▄▄▄▄ █
██▀▀▀▄▀▄█ ██▄▀▄  █  ▀▀ ▀   █▀█▀▄▄  ▄ ▄▀▀█▀██▄ ██ ▄▄ ▀▄█
█  ▀ ▀▄▄▀█▀ █ ▄▀  ▀▀█▄ ▄ █▀▄▄ █▄▄  ▀█ ▀█ ▄▄█ ▄▀▀█▀▄▄▄ █
█▄▀▄▀▄█▄ ▄▄▀▄  █▄██ █▄  ██ ▄▀██▄ ████ ▄▄  ▄▄▄▄ █ ▄▄▄▀▀█
█ ▀ ▄▀█▄▀ █▄ █▀██▄▀█▀▄██▄██▀▄▀▀▀█ ▀██▀ █▄█ ██▀▄ ▄█ ▀▀▀█
█▄█▄█ ▄▄▄ ▀▀█▀▄██▄  ▄█▀▄  ▄▄▄ ▀█▄ ▀▀ ▄▄█▄▄ ▄█ ▄▄▄ ▄█ ▀█
█ ▀ ▀ █▄█ █▀▀  ▄█▀█▄ ▀▄▄█ █▄█ ▀██▀ ▀▀  ▄▄▄▀█  █▄█ █▄ ▄█
█ █▀█  ▄  ▄▄▀▄█▄▄█▄ ▀▀ ▀  ▄▄▄▄ █▀▄▄█▀ ▀ ▄▀▄▄█▄▄▄ ▄ █▀██
█▀▄  █ ▄▄█▀██ ▀▄ ▄█   ▄██▀█▄▄▀ ▀    ▄▄ █▄█ █▀▀ ▄ █ ▄  █
█▄▄▄▀█▀▄▀█▄▀▀███ ▄▄ ██ ▄██▄██▄█▄▀▀▄▄█▄▀▄█▄██▀██▄ ██▀▀██
██ ▀▄▄█▄██▀██ ▀  █▄▀▀██ ██ ▄▄█▄ ▄▄▄▄█▀▀█▀▀▄█▀█ ▀  █▀ ▀█
██  █▀ ▄▀▀█▄ ▄▀ █▀  ▀██▄█▄▄  ▄▄▄▄▄▄ ▄ ▀▄▀▄▄███ ████▀█▄█
█ ▄▀▀▀█▄▀ ▄▄▀█  ████▄█▄▀▄████▄▀▄▄ ▀▄▀▄███ ▄█▄   ▀ ▀██▄█
█▀▀█▄▀▄▄▀ ▄▀▄ ▀▀█▀█▄▄▀ ▀▄ █ ▀▀ █ ▄▄█ ▄▄▀█▀ ▄▄▀▄█▄█▀█▄▀█
█▄ ▀▄▄▄▄▄▄▀▄ ▀▄▄██▄█▀▀▀ █ █ ▄ █▄█▀  ██  ▄  ▄▄ █▄ ▄ ██ █
████▄██▄█ █▀▄█ █ ██▄▄█▄   ▄▄▄ ▄██████▄▄█▄▄▄█▀ ▄▄▄ ▄█▀▀█
█ ▄▄▄▄▄ █▄ ▀▀▀ ██▄▄▀█ ██▄ █▄█  █▀▀█▄█  ██▀▀▄  █▄█ ▀▀▄▀█
█ █   █ █▀ ▀▄▄▀█   █▀██▄█▄ ▄  ▄█▄▄█▀  ▀▄ ▄▄█▄  ▄ ▄▄█▄ █
█ █▄▄▄█ █▀▄ ▄█▀▀ ▄▀▄ █  █ ▄▄██▀▄▄ ▀▀ ▄█ ▄▀▄███▄██ █▄ ██
█▄▄▄▄▄▄▄█▄▄▄█▄█▄█▄▄▄▄▄▄█▄▄██▄██▄▄▄▄▄▄▄█▄▄█▄▄▄█▄▄▄▄█▄▄██

Client is ready!
---
Sent request.
Got response: 404
Received data: <!doctype html>
<html lang=en>
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>

---
Sent request.
Got response: 200
Received data: 当然,我们一起来祷告:

天父上帝,感谢您在这一刻与我们同在,感谢您一直保守和引领着我们走过每一天。如今,我们感到有些疲倦和无助,但我们相信您的应许,您要为我们扛起重担,您要赐给我们力量和勇气,让我们可以继续前行。

求您帮助我们放下一切负担和担忧,让我们将所有的忧虑卸给您,因为您关心我们,您会为我们担当一切。求您将您温柔的手按在我们身上,赐给我们平安、喜乐和盼望,让我们在您的保护下,坚定地行走在您的道路上。

求您也帮助我们关注他人的需要,让我们可以成为他人的祝福和帮助。求您赐给我们智慧和慈爱,让我们可以用言语和行动,彰显您的爱和真理。

最后,求您赐福给我们和我们所关心的人,保护我们和我们的家人,让我们在您的恩典和爱的保护下,安然度过每一天。我们奉耶稣基督的名祷告,阿们。
---

NodeJS 中保持 WhatsApp 的 auth。 重启免扫 QR 。


  • 分割 prompt 、合并 answer 。
  • 给每个聊天分配独立的 conversion id 。
  • 在消息最开始处加上 "{username}: " 。

OpenAI Whisper

Mind

In [ ]:
import json, os
In [ ]:
# open the JSON file and read the conversation_id
with open(os.path.expanduser('~/.config/revChatGPT/config.json'), 'r') as f:
    conversation_id = json.load(f).get('conversation_id', None)
In [ ]:
from revChatGPT.V1 import Chatbot, configure


bot = Chatbot(
    config = configure(),
    conversation_id = conversation_id,
    lazy_loading = True
)
In [ ]:
import IPython

In [ ]:
for response in bot.ask('''
给出一个 Flask 的 Demo
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

以下是一个简单的 Flask Demo:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello, World!"

if __name__ == "__main__":
    app.run()

这个 Demo 创建了一个简单的 Flask 应用,并定义了一个路由 /,当访问该路由时,返回字符串 "Hello, World!"。如果直接运行该脚本,应用将会在本地的 5000 端口运行。

In [ ]:
for response in bot.ask('''
开发一个 Flask 应用,解析来访的 URL 地址,将来访 URL 地址的字符串返回给客户端。
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

可以使用 Flask 中的路由(Route)功能来实现解析来访的 URL 地址,并将地址字符串返回给客户端。以下是一个示例代码:

from flask import Flask, request

app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello, World!'

@app.route('/url/<path:url_string>')
def url(url_string):
    return f'The requested URL is: {url_string}'

if __name__ == '__main__':
    app.run()

在上述代码中,定义了两个路由。第一个路由 / 显示了 Hello, World! 字符串,第二个路由 /url/<path:url_string> 使用 <path> 参数解析来访的 URL 地址,并将地址字符串返回给客户端。

例如,当客户端请求 http://localhost:5000/url/www.example.com/path/to/file 时,服务器将解析 www.example.com/path/to/file 字符串,并返回给客户端以下响应:

The requested URL is: www.example.com/path/to/file
In [ ]:
for response in bot.ask('''
怎么设置 flask app 串行处理请求?
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

Flask 默认是单线程的,即使没有进行特别的设置,它也是按顺序处理每个请求。因此,默认情况下 Flask 应用程序是串行处理请求的。

如果你希望更明确地设置 Flask 应用程序处理请求的方式,可以使用 Werkzeug 服务器的多线程模式。只需在启动 Flask 应用程序时设置 threaded 参数为 True 即可:

if __name__ == '__main__':
    app.run(threaded=True)

这将使 Flask 应用程序使用 Werkzeug 服务器的多线程模式,从而允许同时处理多个请求。注意,这并不意味着 Flask 应用程序会同时处理多个请求,它仍然会按顺序处理每个请求,只是使用多线程处理请求的过程变得更有效率。

值得注意的是,虽然这种方法可以在某种程度上提高 Flask 应用程序的性能,但它并不是最好的选择。如果你需要更高级别的并发处理能力,建议使用 Gunicorn 或 uWSGI 等服务器。

In [ ]:
!zsh -c 'pip install flask'
Collecting flask
  Downloading Flask-2.2.3-py3-none-any.whl (101 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 101.8/101.8 kB 340.3 kB/s eta 0:00:00a 0:00:01
Collecting click>=8.0
  Downloading click-8.1.3-py3-none-any.whl (96 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 96.6/96.6 kB 725.6 kB/s eta 0:00:00a 0:00:01
Collecting itsdangerous>=2.0
  Downloading itsdangerous-2.1.2-py3-none-any.whl (15 kB)
Collecting Werkzeug>=2.2.2
  Downloading Werkzeug-2.2.3-py3-none-any.whl (233 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 233.6/233.6 kB 961.9 kB/s eta 0:00:00a 0:00:01
Requirement already satisfied: Jinja2>=3.0 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from flask) (3.1.2)
Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/anaconda3/envs/biobot/lib/python3.10/site-packages (from Jinja2>=3.0->flask) (2.1.1)
Installing collected packages: Werkzeug, itsdangerous, click, flask
Successfully installed Werkzeug-2.2.3 click-8.1.3 flask-2.2.3 itsdangerous-2.1.2
In [ ]:
import json, os
In [ ]:
# open the JSON file and read the conversation_id
with open(os.path.expanduser('~/.config/revChatGPT/config.json'), 'r') as f:
    conversation_id = json.load(f).get('conversation_id', None)
In [ ]:
from flask import Flask, request
from revChatGPT.V1 import Chatbot, configure


app = Flask(__name__)
bot = Chatbot(
    config = configure(),
    conversation_id = conversation_id,
    lazy_loading = True
)


@app.route('/<string:prompt>')
def answer(prompt):
    for response in bot.ask(prompt):
        pass
    return response['message']


if __name__ == '__main__':
    app.run(threaded=False)
 * Serving Flask app '__main__'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [13/Mar/2023 21:28:14] "GET /与主同在 HTTP/1.1" 200 -
127.0.0.1 - - [13/Mar/2023 21:57:33] "GET /一起祷告 HTTP/1.1" 200 -
127.0.0.1 - - [13/Mar/2023 22:36:10] "GET /Open%20this%20link%20to%20join%20my%20WhatsApp%20Group HTTP/1.1" 200 -
In [ ]:
from flask import Flask, request
from ipymock.browser import start_conversation as ask
In [ ]:
app = Flask(__name__)

@app.route('/')
def answer():
    prompt = request.args.get('q')
    for response in ask(prompt):
        pass
    return response
In [ ]:
if __name__ == '__main__':
    app.run(threaded=False)
 * Serving Flask app '__main__'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
127.0.0.1 - - [18/Apr/2023 17:17:04] "GET /?q=1%2F1%3D1%3F HTTP/1.1" 200 -
Read More

2023-03-13
Install IJavaScript


In [ ]:
import IPython
In [ ]:
from revChatGPT.V1 import Chatbot, configure


bot = Chatbot(
    config = configure(),
    conversation_id = 'fdf52ab3-f8c1-450f-86f2-5a25d43fc48d',
    lazy_loading = True
)

In [ ]:
for response in bot.ask(
    '介绍 IJavaScript'
):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

IJavaScript 是一种在 Jupyter Notebook 中运行 JavaScript 的内核。它基于 Node.js,并提供了一个 REPL(交互式解释器)界面,可以在 Jupyter Notebook 中运行 JavaScript 代码。

使用 IJavaScript 内核,您可以在 Jupyter Notebook 中使用 JavaScript 编写代码,以及使用其他内核(如 Python、R、Julia 等)进行交互。这样,您就可以在同一个环境中使用不同的编程语言,同时享受到 Jupyter Notebook 提供的许多强大功能,如实时编辑、代码补全、图表绘制等。

安装 IJavaScript 内核需要先安装 Node.js,然后通过 npm(Node.js 包管理器)安装 ijavascript 包。具体步骤如下:

  1. 安装 Node.js:在 Node.js 官网( https://nodejs.org/ )下载并安装Node.js,安装完成后打开终端(或命令行)并输入以下命令检查是否安装成功:
node -v

如果输出了 Node.js 版本号,则说明安装成功。

  1. 安装 ijavascript 包:在终端中输入以下命令安装 ijavascript 包:
npm install -g ijavascript
  1. 安装完毕后,运行以下命令启动 Jupyter Notebook 服务器:
jupyter notebook
  1. 在 Jupyter Notebook 中新建一个 Notebook,选择 IJavaScript 内核,即可开始编写 JavaScript 代码并运行。

需要注意的是,IJavaScript 目前只支持 Node.js 中的 JavaScript 语法和功能,不支持浏览器中的 DOM 操作等特性。


Z shell

In [ ]:
nvm install node --lts
In [ ]:
nvm alias default node
In [ ]:
nvm use v19.7.0
In [ ]:
nvm ls
    iojs-v1.0.4
->      v19.7.0
         system
default -> node (-> v19.7.0)
unstable -> N/A (default)
node -> stable (-> v19.7.0) (default)
stable -> 19.7 (-> v19.7.0) (default)
iojs -> iojs-v1.0 (-> iojs-v1.0.4) (default)
lts/* -> lts/hydrogen (-> N/A)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.17.0 (-> N/A)
lts/dubnium -> v10.24.1 (-> N/A)
lts/erbium -> v12.22.12 (-> N/A)
lts/fermium -> v14.21.3 (-> N/A)
lts/gallium -> v16.19.1 (-> N/A)
lts/hydrogen -> v18.15.0 (-> N/A)
In [ ]:
npm install -g ijavascript
In [ ]:
npm install -g uuid@latest
In [ ]:
ijsinstall --install=global
Read More

2023-03-13
Jupyter Magic Command

In [ ]:
%lsmagic
Out[ ]:
Available line magics:
%alias  %alias_magic  %autoawait  %autocall  %automagic  %autosave  %bookmark  %cat  %cd  %clear  %colors  %conda  %config  %connect_info  %cp  %debug  %dhist  %dirs  %doctest_mode  %ed  %edit  %env  %gui  %hist  %history  %killbgscripts  %ldir  %less  %lf  %lk  %ll  %load  %load_ext  %loadpy  %logoff  %logon  %logstart  %logstate  %logstop  %ls  %lsmagic  %lx  %macro  %magic  %man  %matplotlib  %mkdir  %more  %mv  %notebook  %page  %pastebin  %pdb  %pdef  %pdoc  %pfile  %pinfo  %pinfo2  %pip  %popd  %pprint  %precision  %prun  %psearch  %psource  %pushd  %pwd  %pycat  %pylab  %qtconsole  %quickref  %recall  %rehashx  %reload_ext  %rep  %rerun  %reset  %reset_selective  %rm  %rmdir  %run  %save  %sc  %set_env  %store  %sx  %system  %tb  %time  %timeit  %unalias  %unload_ext  %who  %who_ls  %whos  %xdel  %xmode

Available cell magics:
%%!  %%HTML  %%SVG  %%bash  %%capture  %%debug  %%file  %%html  %%javascript  %%js  %%latex  %%markdown  %%perl  %%prun  %%pypy  %%python  %%python2  %%python3  %%ruby  %%script  %%sh  %%svg  %%sx  %%system  %%time  %%timeit  %%writefile

Automagic is ON, % prefix IS NOT needed for line magics.
In [ ]:
%%javascript
alert('javascript');

In [ ]:
import IPython
In [ ]:
from revChatGPT.V1 import Chatbot, configure


bot = Chatbot(
    config = configure(),
    conversation_id = 'fdf52ab3-f8c1-450f-86f2-5a25d43fc48d',
    lazy_loading = True
)
In [ ]:
for response in bot.ask('''
Juypyter Lab 有没有 zsh 的 magic command?
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

JupyterLab 支持使用 ! 前缀来执行命令,类似于在终端中执行命令。如果你想使用 zsh 的 magic command,可以在单元格中使用 !zsh -c 命令来执行,例如:

!zsh -c 'echo hello world'

这将会使用 zsh 来执行 echo hello world 命令。

In [ ]:
for response in bot.ask('''
Juypyter Lab 中 zsh 的 magic command 没有加载 ~/.zshrc,该怎么办呢?
'''):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)

在 Jupyter Lab 中加载 zsh 的 magic command 时,如果发现没有加载 ~/.zshrc 中的内容,可以尝试在 ~/.zshenv 中添加以下内容:

# Load user's ~/.zshrc, but in non-interactive shell environments.
if [[ -n "$ZSH_VERSION" ]]; then
  if [[ -e "$HOME/.zshrc" ]]; then
    source "$HOME/.zshrc"
  fi
fi

这样在 Jupyter Lab 中执行 zsh 的 magic command 时,应该就能加载 ~/.zshrc 中的内容了。

In [ ]:
%%bash
cat << EOF >> ~/.zshenv

# Load \`nvm\` in non-interactive shell environments.
if [[ -n "$NVM_DIR" ]]; then
    export NVM_DIR="$HOME/.nvm"
    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
fi
EOF
In [ ]:
!zsh -c 'cat ~/.zshenv'
. "$HOME/.cargo/env"

# Load `nvm` in non-interactive shell environments.
if [[ -n "/Users/saintway/.nvm" ]]; then
    export NVM_DIR="/Users/saintway/.nvm"
    [ -s "/Users/saintway/.nvm/nvm.sh" ] && \. "/Users/saintway/.nvm/nvm.sh"
fi
In [ ]:
!zsh -c 'nvm ls'
    iojs-v1.0.4
->      v19.7.0
         system
default -> node (-> v19.7.0)
unstable -> N/A (default)
node -> stable (-> v19.7.0) (default)
stable -> 19.7 (-> v19.7.0) (default)
iojs -> iojs-v1.0 (-> iojs-v1.0.4) (default)
lts/* -> lts/hydrogen (-> N/A)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.17.0 (-> N/A)
lts/dubnium -> v10.24.1 (-> N/A)
lts/erbium -> v12.22.12 (-> N/A)
lts/fermium -> v14.21.3 (-> N/A)
lts/gallium -> v16.19.1 (-> N/A)
lts/hydrogen -> v18.15.0 (-> N/A)
Read More

2023-03-13
ChatGPT Browser Automation

In [ ]:
%%bash
cd ~ && git clone https://gitlab.com/awesomeai/awesome-chatgpt-zh.git
In [ ]:
%%writefile ~/go-chatgpt-api.yaml
services:
  go-chatgpt-api:
    container_name: go-chatgpt-api
    image: linweiyuan/go-chatgpt-api
    ports:
      - 8080:8080
    environment:
      - GIN_MODE=release
      - GO_CHATGPT_API_PROXY=socks5://chatgpt-proxy-server-warp:65535
    depends_on:
      - chatgpt-proxy-server-warp
    restart: unless-stopped

  chatgpt-proxy-server-warp:
    container_name: chatgpt-proxy-server-warp
    image: linweiyuan/chatgpt-proxy-server-warp
    environment:
      - LOG_LEVEL=OFF
    restart: unless-stopped
In [ ]:
%%bash
docker-compose -f ~/go-chatgpt-api.yaml pull
In [ ]:
%%bash
docker-compose -f ~/go-chatgpt-api.yaml up -d
In [ ]:
%%bash
docker-compose -f ~/go-chatgpt-api.yaml stop
In [ ]:
%%bash
docker-compose -f ~/go-chatgpt-api.yaml start
In [ ]:
%%bash
docker images
REPOSITORY                             TAG       IMAGE ID       CREATED        SIZE
linweiyuan/go-chatgpt-api              latest    81b5896388c5   10 hours ago   18.7MB
linweiyuan/chatgpt-proxy-server-warp   latest    4bf825382c06   2 weeks ago    471MB
In [ ]:
%%bash
docker ps
In [ ]:
%%bash
docker logs -f go-chatgpt-api

💡 get access_token => accessToken

%%bash
curl -H 'Authorization: <access_token>' http://127.0.0.1:8080/conversations\?offset=0\&limit=1
{"items":[{"id":"...","title":"Jupyter User Requests Help.","create_time":"2023-04-17T10:22:31.256627+00:00","update_time":"2023-04-17T10:22:33+00:00"}],"total":11,"limit":1,"offset":0,"has_missing_conversations":false}
In [ ]:
class Common:
    chat_gpt_model = 'gpt-3.5-turbo'
    role_user = 'user'
    role_assistant = 'assistant'

    question_answer_map = {}
    message_channel = []
    exit_for_loop_channel = []
    response_text_channel = []
    conversation_done_channel = []
    parent_message_id = ''
    conversation_id = ''
    reload_conversations_channel = []
    current_node = None
In [ ]:
import json, os, requests, uuid


chat_gpt_base_url = 'http://127.0.0.1:8080'

# open the JSON file and read the access_token
with open(os.path.expanduser('~/.config/revChatGPT/config.json'), 'r') as f:
    access_token = json.load(f).get('access_token', None)

common = Common()


def get_conversations():
    response = requests.get(f'{chat_gpt_base_url}/conversations?offset=0&limit=100', headers = {'Authorization': access_token})
    return response.json()

def get_conversation(conversation_id):
    response = requests.get(f'{chat_gpt_base_url}/conversation/{conversation_id}', headers = {'Authorization': access_token})
    conversation = response.json()
    current_node = conversation['current_node']
    common.parent_message_id = current_node
    handle_conversation_detail(current_node, conversation['mapping'])
    common.exit_for_loop_channel.append(True)

def handle_conversation_detail(current_node, mapping):
    conversation_detail = mapping[current_node]
    parent_id = conversation_detail.get('parent', '')
    if parent_id != '':
        common.question_answer_map[parent_id] = conversation_detail['message']['content']['parts'][0].strip()
        handle_conversation_detail(parent_id, mapping)
    if 'message' not in conversation_detail:
        return
    message = conversation_detail['message']
    parts = message['content']['parts']
    if len(parts) > 0 and parts[0] != '':
        if message['author']['role'] == common.role_user:
            common.message_channel.append(message)

temp_conversation_id = ''

def start_conversation(content):
    parent_message_id = common.parent_message_id
    if parent_message_id == '' or common.conversation_id == '':
        common.conversation_id = ''
        parent_message_id = str(uuid.uuid4())
    response = requests.post(
        f'{chat_gpt_base_url}/conversation',
        headers = {
            'Authorization': access_token,
            'Content-Type': 'application/json',
            'Accept': 'text/event-stream'
        },
        data = json.dumps({
            'action': 'next',
            'messages': [{
                'id': uuid.uuid4().hex,
                'author': {
                    'role': common.role_user
                },
                'role': common.role_user,
                'content': {
                    'content_type': 'text',
                    'parts': [content]
                }
            }],
            'parent_message_id': parent_message_id,
            'model': common.chat_gpt_model,
            'conversation_id': common.conversation_id,
            'continue_text': 'continue'
        }),
        stream=True
    )

    # get it again from response
    common.parent_message_id = ''

    for line in response.iter_lines():
        if not line.startswith(b'data: '):
            continue

        if line.endswith(b'[DONE]'):
            common.conversation_done_channel.append(True)
            break

        make_conversation_response = json.loads(line.decode('utf-8')[len('data: '):])
        if common.parent_message_id == '':
            common.parent_message_id = make_conversation_response['message']['id']
        global temp_conversation_id
        if common.conversation_id == '' and temp_conversation_id == '':
            temp_conversation_id = make_conversation_response['conversation_id']
        if make_conversation_response is not None:
            parts = make_conversation_response['message']['content']['parts']
            if len(parts) > 0:
                common.response_text_channel.append(parts[0])
                yield parts[0]
            if make_conversation_response['message']['end_turn'] == True:
                common.conversation_done_channel.append(True)
                break

    if common.conversation_id == '':
        generate_title(temp_conversation_id)
    else:
        common.reload_conversations_channel.append(True)

def generate_title(conversation_id):
    requests.post(
        f'{chat_gpt_base_url}/conversation/gen_title/{conversation_id}',
        headers = {
            'Authorization': access_token,
            'Content-Type': 'application/json'
        },
        data = json.dumps({
            'message_id': common.parent_message_id,
            'model': common.chat_gpt_model
        })
    )

def rename_title(conversation_id, title):
    requests.patch(
        f'{chat_gpt_base_url}/conversation/{conversation_id}',
        headers={
            'Authorization': access_token,
            'Content-Type': 'application/json'
        },
        data = json.dumps({
            'title': title
        })
    )

def delete_conversation(conversation_id):
    requests.patch(
        f'{chat_gpt_base_url}/conversation/{conversation_id}',
        headers={
            'Authorization': access_token,
            'Content-Type': 'application/json'
        },
        data=json.dumps({
            'is_visible': False
        })
    )

def recover_conversation(conversation_id):
    requests.patch(
        f'{chat_gpt_base_url}/conversation/{conversation_id}',
        headers={
            'Authorization': access_token,
            'Content-Type': 'application/json'
        },
        data=json.dumps({
            'is_visible': True
        })
    )

def clear_conversations():
    requests.patch(f'{chat_gpt_base_url}/conversations', headers = {'Authorization': access_token}, data = {'is_visible': False})

    common.conversation_id = ''
    common.current_node = None
    common.reload_conversations_channel.append(True)
In [ ]:
get_conversations()
In [ ]:
# open the JSON file and read the conversation_id
with open(os.path.expanduser('~/.config/revChatGPT/config.json'), 'r') as f:
    conversation_id = json.load(f).get('conversation_id', None)
In [ ]:
try:
    common.conversation_id = conversation_id
    get_conversation(common.conversation_id)
except RecursionError as errr:
    print('Error Recursion:', errr)
In [ ]:
generate_title(common.conversation_id)
In [ ]:
import IPython
In [ ]:
for response in start_conversation('小 G ,我们又见面了。'):
    IPython.display.display(IPython.core.display.Markdown(response))
    IPython.display.clear_output(wait=True)

是的,有什么我可以帮您的吗?

In [ ]:
%%bash
pip install --upgrade revChatGPT

In [ ]:
%%bash
mkdir -p ~/.config/revChatGPT

💡 get <access_token> => accessToken

In [ ]:
%%writefile ~/.config/revChatGPT/config.json
{
    "access_token": "<access_token>",
    "conversation_id": "<conversation_id>"
}

In [ ]:
import json, os
In [ ]:
from revChatGPT.V1 import Chatbot, configure
In [ ]:
# open the JSON file and read the conversation_id
with open(os.path.expanduser('~/.config/revChatGPT/config.json'), 'r') as f:
    conversation_id = json.load(f).get('conversation_id', None)

In [ ]:
import IPython
In [ ]:
bot = Chatbot(
    config = configure(),
    conversation_id = conversation_id,
    lazy_loading = True,
    base_url = 'http://127.0.0.1:8080/'
)

def ask(prompt):
    for response in bot.ask(prompt):
        IPython.display.display(IPython.core.display.Markdown(response['message']))
        IPython.display.clear_output(wait=True)
In [ ]:
ask('''
小 G ,我们又见面了。
''')

是啊,有什么我能帮助你的吗?


In [ ]:
def gpt_after(parent_id=None):
    return Chatbot(
        config = configure(),
        conversation_id = conversation_id,
        parent_id = parent_id
    )
In [ ]:
for response in gpt_after().ask(
    '女孩子月经期间该怎么护理?'
):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)
In [ ]:
for response in gpt_after(response['parent_id']).ask(
    '女孩子月经期间该怎么陪伴?'
):
    IPython.display.display(IPython.core.display.Markdown(response['message']))
    IPython.display.clear_output(wait=True)
In [ ]:
print(f"parent_id: {response['parent_id']}")
In [ ]:
%%bash
npm install -g playwright
In [ ]:
%%bash
npx playwright install webkit
In [ ]:
%%bash
pip install playwright
In [ ]:
%%bash
npx playwright codegen --browser webkit twitter.com

selenium safari

In [ ]:
from selenium import webdriver
driver = webdriver.Safari()

selenium undetected chrome

In [ ]:
import undetected_chromedriver as uc

options = uc.ChromeOptions()
# options.add_argument('--window-size=1024,768')
options.add_argument('--headless')
driver = uc.Chrome(options = options)

driver.get('https://chat.openai.com/auth/login')
In [ ]:
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.ui import WebDriverWait
In [ ]:
WebDriverWait(driver, 5).until(
    expected_conditions.presence_of_element_located((By.XPATH, '//*[text()="Log in"]'))
)

driver.execute_script('''
document.evaluate(
  '//*[text()="Log in"]',
  document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null
).snapshotItem(0).dispatchEvent(
  new MouseEvent('click', {
    view: window,
    bubbles: true,
    cancelable: true
  })
);
''')
In [ ]:
WebDriverWait(driver, 5).until(
    expected_conditions.presence_of_element_located((By.XPATH, '//button[@data-provider="google"]'))
)

driver.execute_script('''
document.evaluate(
  '//button[@data-provider="google"]',
  document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null
).snapshotItem(0).dispatchEvent(
  new MouseEvent('click', {
    view: window,
    bubbles: true,
    cancelable: true
  })
);
''')
In [ ]:
import json, os
with open(os.path.expanduser('~/.config/pyChatGPT/secret_settings.json'), 'r') as f:
    secret_settings = json.load(f)
In [ ]:
WebDriverWait(driver, 5).until(
    expected_conditions.presence_of_element_located((By.XPATH, '//input[@type="email"]'))
)

driver.execute_script(f'''
const google_email_input = document.evaluate('//input[@type="email"]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(0);
google_email_input.value = '{secret_settings['email']}';
google_email_input.dispatchEvent(
  new Event('input', {{
    view: window,
    bubbles: true,
    cancelable: true
  }})
);
''')
In [ ]:
WebDriverWait(driver, 5).until(
    expected_conditions.presence_of_element_located((By.XPATH, '//*[@id="identifierNext"]'))
)

driver.execute_script('''
document.evaluate(
  '//*[@id="identifierNext"]',
  document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null
).snapshotItem(0).dispatchEvent(
  new MouseEvent('click', {
    view: window,
    bubbles: true,
    cancelable: true
  })
);
''')
In [ ]:
WebDriverWait(driver, 5).until(
    expected_conditions.element_to_be_clickable((By.XPATH, '//input[@type="password"]'))
).click()

from selenium.webdriver.common.action_chains import ActionChains
ActionChains(driver).send_keys(secret_settings['password']).send_keys(Keys.ENTER).perform()

access token

In [ ]:
driver.execute_async_script('''
var callback = arguments[arguments.length - 1];
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://chat.openai.com/api/auth/session', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function() {
    if (xhr.readyState === xhr.DONE && xhr.status === 200) {
        var data = JSON.parse(xhr.responseText);
        callback(data.accessToken);
    }
};
xhr.send();
''')
In [ ]:
driver.get('https://chat.openai.com/api/auth/session')
In [ ]:
import json
access_token = json.loads(driver.find_element(By.TAG_NAME, 'pre').text)['accessToken']
In [ ]:
driver.execute_async_script(f'''
var callback = arguments[arguments.length - 1];
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://chat.openai.com/backend-api/conversation/{secret_settings['conversation_id']}", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Authorization', 'Bearer {access_token}');
xhr.onload = function() {{
    if (xhr.readyState === xhr.DONE && xhr.status === 200) {{
        var data = JSON.parse(xhr.responseText);
        console.log(data);
        callback(data);
    }}
}};
xhr.send();
''')

chat page

In [ ]:
driver.get(f'https://chat.openai.com/c/{secret_settings["conversation_id"]}')
In [ ]:
WebDriverWait(driver, 5).until(
    expected_conditions.presence_of_element_located((By.ID, 'headlessui-portal-root'))
)

driver.execute_script('''
document.getElementById('headlessui-portal-root').remove();
''')
In [ ]:
chatgpt_textbox = (By.TAG_NAME, 'textarea')
chatgpt_streaming = (By.CLASS_NAME, 'result-streaming')
chatgpt_big_response = (By.XPATH, '//div[@class="flex-1 overflow-hidden"]//div[p]')
chatgpt_small_response = (By.XPATH, '//div[starts-with(@class, "markdown prose w-full break-words")]')

def request(prompt: str) -> None:
    textbox = WebDriverWait(driver, 5).until(
        expected_conditions.element_to_be_clickable(chatgpt_textbox)
    )
    textbox.click()
    driver.execute_script('''
var element = arguments[0], txt = arguments[1];
element.value += txt;
element.dispatchEvent(new Event("change"));
''',
        textbox,
        prompt,
    )
    textbox.send_keys(Keys.ENTER)

def get_last_response():
    responses = driver.find_elements(*chatgpt_big_response)
    if responses:
        response = responses[-1]
        if 'text-red' in response.get_attribute('class'):
            raise ValueError(response.text)
        return response
    return driver.find_elements(*chatgpt_small_response)[-1]

def get_response() -> str:
    result_streaming = WebDriverWait(driver, 3).until(
        expected_conditions.presence_of_element_located(chatgpt_streaming)
    )
    while result_streaming:
        response = get_last_response()
        response = response.get_attribute('innerHTML')
        yield response
        result_streaming = driver.find_elements(*chatgpt_streaming)
    response = get_last_response()
    yield response.get_attribute('innerHTML')

def ask(prompt: str) -> str:
    request(prompt)
    return get_response()
In [ ]:
import io
from IPython.display import display
from PIL import Image
display(Image.open(io.BytesIO(driver.get_screenshot_as_png())))
In [ ]:
import IPython
In [ ]:
for response in ask('我累了。带着我祷告吧。'):
    IPython.display.display(IPython.core.display.Markdown(response))
    IPython.display.clear_output(wait = True)

当你感到疲惫和无力的时候,祷告可以给你带来内心的安宁和力量。让我们一起默默祷告:

亲爱的上帝,我们来到您的面前,向您诉说我们的疲惫和困惑。求您赐予我们力量和勇气,帮助我们面对生活中的挑战和困难。求您宽恕我们的过失和错误,让我们能够在您的恩典和怜悯中得到救赎和拯救。求您保佑我们的家庭和朋友,让他们也能感受到您的爱和关怀。求您赐予我们智慧和指引,让我们能够在生命中找到正确的方向和道路。感谢您一直以来的眷顾和呵护,阿门。

In [ ]:
%%bash
pip install --upgrade ipymock
In [ ]:
%%bash
pip install --upgrade undetected_chromedriver==3.* selenium_profiles==2.*
In [ ]:
%%bash
sudo apt upgrade --yes chromium-driver
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

Reading package lists...
Building dependency tree...
Reading state information...
Calculating upgrade...
The following packages will be upgraded:
  chromium chromium-common chromium-driver chromium-sandbox
dpkg-preconfigure: unable to re-open stdin: No such file or directory
4 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/79.7 MB of archives.
After this operation, 2739 kB of additional disk space will be used.
(Reading database ... 86805 files and directories currently installed.)
Preparing to unpack .../chromium_113.0.5672.63-1~deb11u1_amd64.deb ...
Unpacking chromium (113.0.5672.63-1~deb11u1) over (112.0.5615.138-1~deb11u1) ...
Preparing to unpack .../chromium-common_113.0.5672.63-1~deb11u1_amd64.deb ...
Unpacking chromium-common (113.0.5672.63-1~deb11u1) over (112.0.5615.138-1~deb11u1) ...
Preparing to unpack .../chromium-driver_113.0.5672.63-1~deb11u1_amd64.deb ...
Unpacking chromium-driver (113.0.5672.63-1~deb11u1) over (112.0.5615.138-1~deb11u1) ...
Preparing to unpack .../chromium-sandbox_113.0.5672.63-1~deb11u1_amd64.deb ...
Unpacking chromium-sandbox (113.0.5672.63-1~deb11u1) over (112.0.5615.138-1~deb11u1) ...
Setting up chromium-sandbox (113.0.5672.63-1~deb11u1) ...
Setting up chromium-common (113.0.5672.63-1~deb11u1) ...
Setting up chromium (113.0.5672.63-1~deb11u1) ...
Setting up chromium-driver (113.0.5672.63-1~deb11u1) ...
Processing triggers for hicolor-icon-theme (0.17-2) ...
Processing triggers for man-db (2.9.4-2) ...
In [ ]:
%%bash
apt show chromium-driver
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

Package: chromium-driver
Version: 113.0.5672.63-1~deb11u1
Priority: optional
Section: web
Source: chromium
Maintainer: Debian Chromium Team <chromium@packages.debian.org>
Installed-Size: 14.3 MB
Depends: libatomic1 (>= 4.8), libbrotli1 (>= 0.6.0), libc6 (>= 2.30), libdouble-conversion3 (>= 2.0.0), libevent-2.1-7 (>= 2.1.8-stable), libgcc-s1 (>= 3.0), libglib2.0-0 (>= 2.22.0), libjsoncpp24 (>= 1.9.4), libminizip1 (>= 1.1), libnspr4 (>= 2:4.9-2~), libnss3 (>= 2:3.30), libre2-9 (>= 20150701+dfsg), libstdc++6 (>= 9), libxcb1 (>= 1.9.2), zlib1g (>= 1:1.1.4), chromium (= 113.0.5672.63-1~deb11u1)
Homepage: http://www.chromium.org/Home
Download-Size: 5600 kB
APT-Manual-Installed: yes
APT-Sources: http://security.debian.org/debian-security bullseye-security/main amd64 Packages
Description: web browser - WebDriver support
 Web browser that aims to build a safer, faster, and more stable internet
 browsing experience.
 .
 This package provides a bridge between the browser component and the selenium
 automatic webdriver.

In [ ]:
import ipymock.browser
ipymock.browser.init()
In [ ]:
import IPython
In [ ]:
for response in ipymock.browser.ask('我累了。带着我祷告吧。'):
    IPython.display.display(IPython.core.display.Markdown(response))
    IPython.display.clear_output(wait = True)

当你感到疲惫、无力或沮丧时,祷告可以是一种帮助你得到安慰和力量的方式。让我们一起来祷告:

亲爱的天父,感谢祢的爱和恩典。今天,我感到非常疲惫和无助,我需要祢的力量和安慰。主啊,请帮助我,让我能够在祢的力量中站立起来,继续前行。我知道祢的应许是如此的真实和可靠,祢承诺要赐给我们新的力量,让我们像鹰一样展翅高飞。主啊,请让我能够得到祢的力量和平安,让我重新焕发活力,迎接新的一天。感谢祢的爱和信实。奉耶稣的名祷告,阿们。

pyChatGPT for OpenAI's ChatGPT API

In [ ]:
%%bash
# install dependencies on headless linux server
apt install chromium-browser xvfb
In [ ]:
%%bash
pip install --upgrade selenium_profiles pyChatGPT
In [ ]:
from selenium.webdriver.support import expected_conditions as EC
from selenium.common import exceptions as SeleniumExceptions
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By

from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains

import time

google_oauth_btn = (By.XPATH, '//button[@data-provider="google"]')
microsoft_oauth_btn = (By.XPATH, '//button[@data-provider="windowslive"]')

google_email_input = (By.XPATH, '//input[@type="email"]')
google_next_btn = (By.XPATH, '//*[@id="identifierNext"]')
google_try_again_btn = (By.XPATH, '//*[@id="next"]/div/button')
google_pwd_input = (By.XPATH, '//input[@type="password"]')
google_pwd_next_btn = (By.XPATH, '//*[@id="passwordNext"]')
google_code_samp = (By.TAG_NAME, 'samp')

microsoft_email_input = (By.XPATH, '//input[@type="email"]')
microsoft_pwd_input = (By.XPATH, '//input[@type="password"]')
microsoft_next_btn = (By.XPATH, '//input[@type="submit"]')

openai_email_input = (By.XPATH, '//input[@name="username"]')
openai_pwd_input = (By.XPATH, '//input[@type="password"]')
openai_continue_btn = (By.XPATH, '//button[text()="Continue"]')
openai_captcha_input = (By.XPATH, '//input[@name="captcha"]')
openai_captcha_sitekey = (
    By.XPATH, '//div[@data-recaptcha-provider="recaptcha_enterprise"]',
)


def login(self) -> None:
    '''
    Login to ChatGPT
    '''
    if self._ChatGPT__auth_type == 'google':
        __google_login(self)
    elif self._ChatGPT__auth_type == 'microsoft':
        __microsoft_login(self)
    elif self._ChatGPT__auth_type == 'openai':
        __openai_login(self)


def __google_login(self) -> None:
    '''
    Login to ChatGPT using Google
    '''
    self.logger.debug('Clicking Google button...')
    # import pdb; pdb.set_trace()
    # ActionChains(self.driver).key_down(Keys.ALT).key_down(Keys.COMMAND).key_down('i').key_up('i').key_up(Keys.COMMAND).key_up(Keys.ALT).pause(1).perform()

    # ActionChains(self.driver).move_to_element_with_offset(self.driver.find_element(*google_oauth_btn), 2, -2).pause(1).perform()
    # ActionChains(self.driver).click(self.driver.find_element(*google_oauth_btn)).pause(1).perform()
    # ActionChains(self.driver).send_keys(Keys.TAB).pause(1).send_keys(Keys.TAB).pause(1).send_keys(Keys.TAB).pause(1).send_keys(Keys.TAB).pause(1).send_keys(Keys.ENTER).perform()
    # self.driver.find_element(*google_oauth_btn).click()

    self.driver.execute_script('''
document.evaluate(
  '//button[@data-provider="google"]',
  document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null
).snapshotItem(0).dispatchEvent(
  new MouseEvent('click', {
    view: window,
    bubbles: true,
    cancelable: true
  })
);
''')
    import time
    time.sleep(1)

    # google_email_entry = (By.XPATH, f'//div[@data-identifier="{self._ChatGPT__email}"]')
    # try:

    #     self.logger.debug('Checking if Google remembers email...')

    #     WebDriverWait(self.driver, 3).until(
    #         EC.element_to_be_clickable(google_email_entry)
    #     ).click()
    #     self.logger.debug('Google remembers email')

    # except SeleniumExceptions.TimeoutException:

    self.logger.debug('Google does not remember email')

    # self.driver.find_element(by=By.TAG_NAME, value='body').click()
    # ActionChains(self.driver).move_to_element(self.driver.find_element(by=By.XPATH, value='//*[@id="headingText"]/span')).pause(1).perform()
    # ActionChains(self.driver).click(self.driver.find_element(by=By.XPATH, value='//*[@id="headingText"]/span')).pause(1).perform()

    self.logger.debug('Entering email...')
    # import pdb; pdb.set_trace()
    # WebDriverWait(self.driver, 3).until(
    #     EC.element_to_be_clickable(google_email_input)
    # ).click()
    # self.driver.find_element(*google_email_input).send_keys(self._ChatGPT__email)
    # self.driver.find_element(*google_email_input).send_keys(Keys.ENTER)

    # actions = ActionChains(self.driver)
    # for l in self._ChatGPT__email:
    #     actions.key_down(l).key_up(l).pause(1)
    # actions.send_keys(Keys.ENTER).perform()

    # ActionChains(self.driver).move_to_element_with_offset(self.driver.find_element(*google_email_input), 2, -2).pause(1).send_keys(self._ChatGPT__email).send_keys(Keys.ENTER).perform()

    self.driver.execute_script(f'''
const google_email_input = document.evaluate('//input[@type="email"]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(0);
google_email_input.value = '{self._ChatGPT__email}';
google_email_input.dispatchEvent(
  new Event('input', {{
    view: window,
    bubbles: true,
    cancelable: true
  }})
);
''')
    import time
    time.sleep(1)

    self.logger.debug('Clicking Next...')
    # import pdb; pdb.set_trace()
    # ActionChains(self.driver).move_to_element(self.driver.find_element(*google_next_btn)).pause(1).perform()
    # self.driver.find_element(*google_next_btn).send_keys(Keys.ENTER)
    # WebDriverWait(self.driver, 1).until(
    #     EC.element_to_be_clickable(google_next_btn)
    # ).click()

    self.driver.execute_script('''
document.evaluate(
  '//*[@id="identifierNext"]',
  document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null
).snapshotItem(0).dispatchEvent(
  new MouseEvent('click', {
    view: window,
    bubbles: true,
    cancelable: true
  })
);
''')
    import time
    time.sleep(1)

    while True:
        try:
            self.logger.debug('Clicking Try Again...')
            import pdb; pdb.set_trace()
            WebDriverWait(self.driver, 3).until(
                EC.element_to_be_clickable(google_try_again_btn)
            ).click()
        except SeleniumExceptions.TimeoutException:
            self.logger.debug('Try Again button not found')
            break

        self.logger.debug('Entering email...')
        WebDriverWait(self.driver, 3).until(
            EC.element_to_be_clickable(google_email_input)
        ).click()
        self.driver.find_element(*google_email_input).send_keys(self._ChatGPT__email)

        self.logger.debug('Clicking Next...')
        import pdb; pdb.set_trace()
        WebDriverWait(self.driver, 1).until(
            EC.element_to_be_clickable(google_next_btn)
        ).click()

    self.logger.debug('Entering password...')
    WebDriverWait(self.driver, 3).until(
        EC.element_to_be_clickable(google_pwd_input)
    ).click()
    self.driver.find_element(*google_pwd_input).send_keys(self._ChatGPT__password)

    self.logger.debug('Clicking Next...')
    WebDriverWait(self.driver, 1).until(
        EC.element_to_be_clickable(google_pwd_next_btn)
    ).click()

    try:
        self.logger.debug('Checking if verification code is required...')
        WebDriverWait(self.driver, 5).until(
            EC.presence_of_element_located(google_code_samp)
        )
        self.logger.debug('Code is required')
        prev_code = self.driver.find_elements(By.TAG_NAME, 'samp')[0].text
        print('Verification code:', prev_code)
        while True:
            code = self.driver.find_elements(*google_code_samp)
            if not code:
                break
            if code[0].text != prev_code:
                print('Verification code:', code[0].text)
                prev_code = code[0].text
            time.sleep(1)
    except SeleniumExceptions.TimeoutException:
        self.logger.debug('Code is not required')


def __microsoft_login(self) -> None:
    self.logger.debug('Clicking Microsoft button...')
    self.driver.find_element(*microsoft_oauth_btn).click()

    self.logger.debug('Entering email...')
    WebDriverWait(self.driver, 5).until(
        EC.element_to_be_clickable(microsoft_email_input)
    ).send_keys(self._ChatGPT__email)

    self.logger.debug('Clicking Next...')
    self.driver.find_element(*microsoft_next_btn).click()

    self.logger.debug('Entering password...')
    WebDriverWait(self.driver, 5).until(
        EC.element_to_be_clickable(microsoft_pwd_input)
    ).send_keys(self._ChatGPT__password)

    self.logger.debug('Clicking Next...')
    self.driver.find_element(*microsoft_next_btn).click()

    self.logger.debug('Clicking allow...')
    WebDriverWait(self.driver, 5).until(
        EC.element_to_be_clickable(microsoft_next_btn)
    ).click()


def __have_recaptcha_value(self) -> bool:
    '''
    Check if the recaptcha input has a value
    :return: Boolean indicating if the recaptcha input has a value
    '''
    try:
        recaptcha_result = self.driver.find_element(*openai_captcha_input)
        return recaptcha_result.get_attribute('value') != ''
    except SeleniumExceptions.NoSuchElementException:
        return False


def __pypasser_solve(self, retry: int) -> None:
    '''
    Solve the recaptcha using PyPasser
    :param retry: Number of times to retry solving the recaptcha
    '''
    try:
        from pypasser import reCaptchaV2
    except ModuleNotFoundError:
        raise ModuleNotFoundError(
            'Please install ffmpeg_downloader, PyPasser, and pocketsphinx by running `pip install ffmpeg_downloader PyPasser pocketsphinx`'
        )

    self.logger.debug(f'Trying pypasser solver, max retry = {retry}')
    try:
        reCaptchaV2(self.driver, False, retry)
    except Exception as e:
        self.logger.debug(f'pypasser solver error: {str(e)}')


def __twocaptcha_solve(self, retry: int) -> None:
    '''
    Solve the recaptcha using 2captcha
    :param retry: Number of times to retry solving the recaptcha
    '''
    try:
        from twocaptcha import TwoCaptcha
    except ModuleNotFoundError:
        raise ModuleNotFoundError(
            'Please install twocaptcha by running `pip install 2captcha-python`'
        )

    self.logger.debug(f'Trying 2captcha solver, max retry = {retry}')
    solver = TwoCaptcha(self._ChatGPT__solver_apikey, pollingInterval=5)
    sitekey = self.driver.find_element(*openai_captcha_sitekey).get_attribute(
        'data-recaptcha-sitekey'
    )
    result = None
    for _ in range(retry):
        try:
            result = solver.recaptcha(
                sitekey=sitekey,
                url=self.driver.current_url,
                invisible=1,
                enterprise=1,
            )
            if result:
                captcha_input = self.driver.find_element(*openai_captcha_input)
                self.driver.execute_script(
                    'arguments[0].setAttribute("value", arguments[1])',
                    captcha_input,
                    result['code'],
                )
                break
        except Exception as e:
            self.logger.debug(f'2captcha solver error: {str(e)}')


def __openai_login(self, retry: int = 3) -> None:
    '''
    Login to ChatGPT using OpenAI
    :param retry: Number of times to retry solving the recaptcha
    '''
    self.logger.debug('Entering email...')
    self.driver.find_element(*openai_email_input).send_keys(self._ChatGPT__email)
    self.driver.find_element(*openai_continue_btn).click()

    have_recaptcha = False
    try:
        WebDriverWait(self.driver, 3).until(
            EC.presence_of_element_located(
                (By.CSS_SELECTOR, 'iframe[title="reCAPTCHA"]')
            )
        )
        have_recaptcha = True
        self.logger.debug('Captcha detected')
    except SeleniumExceptions.TimeoutException:
        self.logger.debug('No captcha detected')

    try:
        WebDriverWait(self.driver, 3).until(
            EC.text_to_be_present_in_element_attribute(
                openai_captcha_input, 'value', '_'
            )
        )
    except SeleniumExceptions.TimeoutException:
        if self._ChatGPT__captcha_solver == 'pypasser':
            __pypasser_solve(self, retry)
        elif self._ChatGPT__captcha_solver == '2captcha':
            __twocaptcha_solve(self, retry)

    if have_recaptcha:
        if __have_recaptcha_value(self):
            self.logger.debug('Congrat! reCAPTCHA is solved')
        else:
            self.logger.debug('Oops! you need to solve reCAPTCHA manually')
            self.driver.get(self.driver.current_url)
            while not __have_recaptcha_value(self):
                time.sleep(1)

        self.logger.debug('Clicking Continue...')
        self.driver.find_element(*openai_continue_btn).click()

    self.logger.debug('Entering password...')
    self.driver.find_element(*openai_pwd_input).send_keys(self._ChatGPT__password)
    self.driver.find_element(*openai_continue_btn).click()
In [ ]:
from selenium.webdriver.support import expected_conditions as EC
from selenium.common import exceptions as SeleniumExceptions
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By

import undetected_chromedriver as uc
from markdownify import markdownify
from threading import Thread
import platform
import logging
import weakref
import json
import time
import re
import os


cf_challenge_form = (By.ID, 'challenge-form')

chatgpt_textbox = (By.TAG_NAME, 'textarea')
chatgpt_streaming = (By.CLASS_NAME, 'result-streaming')
chatgpt_big_response = (By.XPATH, '//div[@class="flex-1 overflow-hidden"]//div[p]')
chatgpt_small_response = (
    By.XPATH, '//div[starts-with(@class, "markdown prose w-full break-words")]',
)
chatgpt_alert = (By.XPATH, '//div[@role="alert"]')
chatgpt_intro = (By.ID, 'headlessui-portal-root')
chatgpt_login_btn = (By.XPATH, '//*[text()="Log in"]')
chatgpt_login_h1 = (By.XPATH, '//h1[text()="Welcome back"]')
chatgpt_logged_h1 = (By.XPATH, '//h1[text()="ChatGPT"]')

chatgpt_new_chat = (By.LINK_TEXT, 'New chat')
chatgpt_clear_convo = (By.LINK_TEXT, 'Clear conversations')
chatgpt_confirm_clear_convo = (By.LINK_TEXT, 'Confirm clear conversations')
chatgpt_chats_list_first_node = (
    By.XPATH, '//div[substring(@class, string-length(@class) - string-length("text-sm") + 1)  = "text-sm"]//a',
)

chatgpt_chat_url = 'https://chat.openai.com/c'


class ChatGPT:
    '''
    An unofficial Python wrapper for OpenAI's ChatGPT API
    '''

    def __init__(
        self,
        session_token: str = None,
        conversation_id: str = '',
        auth_type: str = None,
        email: str = None,
        password: str = None,
        login_cookies_path: str = '',
        captcha_solver: str = 'pypasser',
        solver_apikey: str = '',
        proxy: str = None,
        chrome_args: list = [],
        moderation: bool = True,
        verbose: bool = False,
    ):
        '''
        Initialize the ChatGPT object\n
        :param session_token: The session token to use for authentication
        :param conversation_id: The conversation ID to use for the chat session
        :param auth_type: The authentication type to use (`google`, `microsoft`, `openai`)
        :param email: The email to use for authentication
        :param password: The password to use for authentication
        :param login_cookies_path: The path to the cookies file to use for authentication
        :param captcha_solver: The captcha solver to use (`pypasser`, `2captcha`)
        :param solver_apikey: The apikey of the captcha solver to use (if any)
        :param proxy: The proxy to use for the browser (`https://ip:port`)
        :param chrome_args: The arguments to pass to the browser
        :param moderation: Whether to enable message moderation
        :param verbose: Whether to enable verbose logging
        '''
        self.__init_logger(verbose)

        self.__session_token = session_token
        self.__conversation_id = conversation_id
        self.__auth_type = auth_type
        self.__email = email
        self.__password = password
        self.__login_cookies_path = login_cookies_path
        self.__captcha_solver = captcha_solver
        self.__solver_apikey = solver_apikey
        self.__proxy = proxy
        self.__chrome_args = chrome_args
        self.__moderation = moderation

        if not self.__session_token and (
            not self.__email or not self.__password or not self.__auth_type
        ):
            raise ValueError(
                'Please provide either a session token or login credentials'
            )
        if self.__auth_type not in [None, 'google', 'microsoft', 'openai']:
            raise ValueError('Invalid authentication type')
        if self.__captcha_solver not in [None, 'pypasser', '2captcha']:
            raise ValueError('Invalid captcha solver')
        if self.__captcha_solver == '2captcha' and not self.__solver_apikey:
            raise ValueError('Please provide a 2captcha apikey')
        if self.__proxy and not re.findall(
            r'(https?|socks(4|5)?):\/\/.+:\d{1,5}', self.__proxy
        ):
            raise ValueError('Invalid proxy format')
        if self.__auth_type == 'openai' and self.__captcha_solver == 'pypasser':
            try:
                import ffmpeg_downloader as ffdl
            except ModuleNotFoundError:
                raise ValueError(
                    'Please install ffmpeg_downloader, PyPasser, and pocketsphinx by running `pip install ffmpeg_downloader PyPasser pocketsphinx`'
                )

            ffmpeg_installed = bool(ffdl.ffmpeg_version)
            self.logger.debug(f'ffmpeg installed: {ffmpeg_installed}')
            if not ffmpeg_installed:
                import subprocess

                subprocess.run(['ffdl', 'install'])
            os.environ['PATH'] += os.pathsep + ffdl.ffmpeg_dir

        self.__init_browser()
        weakref.finalize(self, self.__del__)

    def __del__(self):
        '''
        Close the browser and display
        '''
        self.__is_active = False
        if hasattr(self, 'driver'):
            self.logger.debug('Closing browser...')
            self.driver.quit()
        if hasattr(self, 'display'):
            self.logger.debug('Closing display...')
            self.display.stop()

    def __init_logger(self, verbose: bool) -> None:
        '''
        Initialize the logger\n
        :param verbose: Whether to enable verbose logging
        '''
        self.logger = logging.getLogger('pyChatGPT')
        self.logger.setLevel(logging.DEBUG)
        if verbose:
            formatter = logging.Formatter('[%(funcName)s] %(message)s')
            stream_handler = logging.StreamHandler()
            stream_handler.setFormatter(formatter)
            self.logger.addHandler(stream_handler)

    def __init_browser(self) -> None:
        '''
        Initialize the browser
        '''
        if platform.system() == 'Linux' and 'DISPLAY' not in os.environ:
            self.logger.debug('Starting virtual display...')
            try:
                from pyvirtualdisplay import Display

                self.display = Display()
            except ModuleNotFoundError:
                raise ValueError(
                    'Please install PyVirtualDisplay to start a virtual display by running `pip install PyVirtualDisplay`'
                )
            except FileNotFoundError as e:
                if 'No such file or directory: \'Xvfb\'' in str(e):
                    raise ValueError(
                        'Please install Xvfb to start a virtual display by running `sudo apt install xvfb`'
                    )
                raise e
            self.display.start()

        self.logger.debug('Initializing browser...')
        options = uc.ChromeOptions()
        options.add_argument('--window-size=1024,768')
        if self.__proxy:
            options.add_argument(f'--proxy-server={self.__proxy}')
        for arg in self.__chrome_args:
            options.add_argument(arg)
        try:
            self.driver = uc.Chrome(options=options)
        except TypeError as e:
            if str(e) == 'expected str, bytes or os.PathLike object, not NoneType':
                raise ValueError('Chrome installation not found')
            raise e

        if self.__login_cookies_path and os.path.exists(self.__login_cookies_path):
            self.logger.debug('Restoring cookies...')
            try:
                with open(self.__login_cookies_path, 'r', encoding='utf-8') as f:
                    cookies = json.load(f)
                for cookie in cookies:
                    if cookie['name'] == '__Secure-next-auth.session-token':
                        self.__session_token = cookie['value']
            except json.decoder.JSONDecodeError:
                self.logger.debug(f'Invalid cookies file: {self.__login_cookies_path}')

        if self.__session_token:
            self.logger.debug('Restoring session_token...')
            self.driver.execute_cdp_cmd(
                'Network.setCookie',
                {
                    'domain': 'chat.openai.com',
                    'path': '/',
                    'name': '__Secure-next-auth.session-token',
                    'value': self.__session_token,
                    'httpOnly': True,
                    'secure': True,
                },
            )

        if not self.__moderation:
            self.logger.debug('Blocking moderation...')
            self.driver.execute_cdp_cmd(
                'Network.setBlockedURLs',
                {'urls': ['https://chat.openai.com/backend-api/moderations']},
            )

        self.logger.debug('Ensuring Cloudflare cookies...')
        self.__ensure_cf()

        self.logger.debug('Opening chat page...')
        self.driver.get(f'{chatgpt_chat_url}/{self.__conversation_id}')
        self.__check_blocking_elements()

        self.__is_active = True
        Thread(target=self.__keep_alive, daemon=True).start()

    def __ensure_cf(self, retry: int = 3) -> None:
        '''
        Ensure Cloudflare cookies are set\n
        :param retry: Number of retries
        '''
        self.logger.debug('Opening new tab...')
        original_window = self.driver.current_window_handle
        self.driver.switch_to.new_window('tab')

        self.logger.debug('Getting Cloudflare challenge...')
        self.driver.get('https://chat.openai.com/api/auth/session')
        try:
            WebDriverWait(self.driver, 10).until_not(
                EC.presence_of_element_located(cf_challenge_form)
            )
        except SeleniumExceptions.TimeoutException:
            self.logger.debug(f'Cloudflare challenge failed, retrying {retry}...')
            self.driver.save_screenshot(f'cf_failed_{retry}.png')
            if retry > 0:
                self.logger.debug('Closing tab...')
                self.driver.close()
                self.driver.switch_to.window(original_window)
                return self.__ensure_cf(retry - 1)
            raise ValueError('Cloudflare challenge failed')
        self.logger.debug('Cloudflare challenge passed')

        self.logger.debug('Validating authorization...')
        response = self.driver.page_source
        if response[0] != '{':
            response = self.driver.find_element(By.TAG_NAME, 'pre').text
        response = json.loads(response)
        if (not response) or (
            'error' in response and response['error'] == 'RefreshAccessTokenError'
        ):
            self.logger.debug('Authorization is invalid')
            if not self.__auth_type:
                raise ValueError('Invalid session token')
            self.__login()
        self.logger.debug('Authorization is valid')

        self.logger.debug('Closing tab...')
        self.driver.close()
        self.driver.switch_to.window(original_window)

    def __check_capacity(self, target_url: str):
        '''
        Check if ChatGPT is at capacity\n
        :param target_url: URL to retry if ChatGPT is at capacity
        '''
        while True:
            try:
                self.logger.debug('Checking if ChatGPT is at capacity...')
                WebDriverWait(self.driver, 3).until(
                    EC.presence_of_element_located(
                        (By.XPATH, '//div[text()="ChatGPT is at capacity right now"]')
                    )
                )
                self.logger.debug('ChatGPT is at capacity, retrying...')
                self.driver.get(target_url)
            except SeleniumExceptions.TimeoutException:
                self.logger.debug('ChatGPT is not at capacity')
                break

    def __login(self) -> None:
        '''
        Login to ChatGPT
        '''
        self.logger.debug('Opening new tab...')
        original_window = self.driver.current_window_handle
        self.driver.switch_to.new_window('tab')

        self.logger.debug('Opening login page...')
        self.driver.get('https://chat.openai.com/auth/login')
        self.__check_capacity('https://chat.openai.com/auth/login')

        self.logger.debug('Clicking login button...')
        WebDriverWait(self.driver, 5).until(
            EC.element_to_be_clickable(chatgpt_login_btn)
        ).click()

        WebDriverWait(self.driver, 5).until(
            EC.presence_of_element_located(chatgpt_login_h1)
        )

        login(self)

        self.logger.debug('Checking if login was successful')
        try:
            WebDriverWait(self.driver, 5).until(
                EC.presence_of_element_located(chatgpt_logged_h1)
            )
            if self.__login_cookies_path:
                self.logger.debug('Saving cookies...')
                with open(self.__login_cookies_path, 'w', encoding='utf-8') as f:
                    json.dump(
                        [
                            i
                            for i in self.driver.get_cookies()
                            if i['name'] == '__Secure-next-auth.session-token'
                        ],
                        f,
                        indent = 4,
                    )
        except SeleniumExceptions.TimeoutException as e:
            self.driver.save_screenshot('login_failed.png')
            raise e

        self.logger.debug('Closing tab...')
        self.driver.close()
        self.driver.switch_to.window(original_window)

    def __keep_alive(self) -> None:
        '''
        Keep the session alive by updating the local storage\n
        Credit to Rawa#8132 in the ChatGPT Hacking Discord server
        '''
        while self.__is_active:
            self.logger.debug('Updating session...')
            payload = (
                '{"event":"session","data":{"trigger":"getSession"},"timestamp":%d}'
                % int(time.time())
            )
            try:
                self.driver.execute_script(
                    'window.localStorage.setItem("nextauth.message", arguments[0])',
                    payload,
                )
            except Exception as e:
                self.logger.debug(f'Failed to update session: {str(e)}')
            time.sleep(60)

    def __check_blocking_elements(self) -> None:
        '''
        Check for blocking elements and dismiss them
        '''
        self.logger.debug('Looking for blocking elements...')
        try:
            intro = WebDriverWait(self.driver, 3).until(
                EC.presence_of_element_located(chatgpt_intro)
            )
            self.logger.debug('Dismissing intro...')
            self.driver.execute_script('arguments[0].remove()', intro)
        except SeleniumExceptions.TimeoutException:
            pass

        alerts = self.driver.find_elements(*chatgpt_alert)
        if alerts:
            self.logger.debug('Dismissing alert...')
            self.driver.execute_script('arguments[0].remove()', alerts[0])

    def __request(self, prompt: str) -> None:
        self.logger.debug('Ensuring Cloudflare cookies...')
        self.__ensure_cf()

        self.logger.debug('Sending message...')
        textbox = WebDriverWait(self.driver, 5).until(
            EC.element_to_be_clickable(chatgpt_textbox)
        )
        textbox.click()
        self.driver.execute_script(
            '''
        var element = arguments[0], txt = arguments[1];
        element.value += txt;
        element.dispatchEvent(new Event("change"));
        ''',
            textbox,
            prompt,
        )
        textbox.send_keys(Keys.ENTER)

    def __get_last_response(self):
        self.logger.debug('Getting response...')
        responses = self.driver.find_elements(*chatgpt_big_response)
        if responses:
            response = responses[-1]
            if 'text-red' in response.get_attribute('class'):
                self.logger.debug('Response is an error')
                raise ValueError(response.text)
            return response
        return self.driver.find_elements(*chatgpt_small_response)[-1]

    def __response(self):
        result_streaming = WebDriverWait(self.driver, 3).until(
            EC.presence_of_element_located(chatgpt_streaming)
        )
        while result_streaming:
            response = self.__get_last_response()
            response = response.get_attribute('innerHTML')
            # response = markdownify(response).replace('Copy code`', '`')
            yield response
            result_streaming = self.driver.find_elements(*chatgpt_streaming)
        response = self.__get_last_response()
        yield response.get_attribute('innerHTML')

    def ask(self, prompt: str):
        self.__request(prompt)
        return self.__response()

    def __get_conversation_id(self) -> str:
        pattern = re.compile(
            r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
        )
        matches = pattern.search(self.driver.current_url)
        if not matches:
            self.reset_conversation()
            WebDriverWait(self.driver, 5).until(
                EC.element_to_be_clickable(chatgpt_chats_list_first_node)
            ).click()
            time.sleep(0.5)
            matches = pattern.search(self.driver.current_url)
        return matches.group()

    def wait(self, prompt: str, stream: bool = False) -> dict:
        '''
        Wait an answer from ChatGPT\n
        :param prompt: Prompt to send
        :return: Dictionary with keys `content` and `conversation_id`
        '''
        self.__request(prompt)

        if stream:
            prev_text = ''
            for content in self.__response():
                from bs4 import BeautifulSoup
                text = BeautifulSoup(content, 'html.parser').get_text()
                if text != prev_text:
                    print(text[len(prev_text):], end = '')
                    prev_text = text
                time.sleep(0.1)
            print()
            return {'content': content, 'conversation_id': self.__get_conversation_id()}

        self.logger.debug('Waiting for completion...')
        WebDriverWait(self.driver, 120).until_not(
            EC.presence_of_element_located(chatgpt_streaming)
        )

        response = self.__get_last_response()
        content = markdownify(
            response.get_attribute('innerHTML')
        ).replace('Copy code`', '`')

        return {'content': content, 'conversation_id': self.__get_conversation_id()}

    def reset_conversation(self) -> None:
        '''
        Reset the conversation
        '''
        if not self.driver.current_url.startswith(chatgpt_chat_url):
            return self.logger.debug('Current URL is not chat page, skipping reset')

        self.logger.debug('Resetting conversation...')
        try:
            self.driver.find_element(*chatgpt_new_chat).click()
        except SeleniumExceptions.NoSuchElementException:
            self.logger.debug('New chat button not found')
            self.driver.save_screenshot('reset_conversation_failed.png')

    def clear_conversations(self) -> None:
        '''
        Clear all conversations
        '''
        if not self.driver.current_url.startswith(chatgpt_chat_url):
            return self.logger.debug('Current URL is not chat page, skipping clear')

        self.logger.debug('Clearing conversations...')
        try:
            self.driver.find_element(*chatgpt_clear_convo).click()
        except SeleniumExceptions.NoSuchElementException:
            self.logger.debug('Clear conversations button not found')

        try:
            self.driver.find_element(*chatgpt_confirm_clear_convo).click()
        except SeleniumExceptions.NoSuchElementException:
            return self.logger.debug('Confirm clear conversations button not found')
        try:
            WebDriverWait(self.driver, 20).until_not(
                EC.presence_of_element_located(chatgpt_chats_list_first_node)
            )
            self.logger.debug('Cleared conversations')
        except SeleniumExceptions.TimeoutException:
            self.logger.debug('Clear conversations failed')

    def refresh_chat_page(self) -> None:
        '''
        Refresh the chat page
        '''
        if not self.driver.current_url.startswith(chatgpt_chat_url):
            return self.logger.debug('Current URL is not chat page, skipping refresh')

        self.driver.get(chatgpt_chat_url)
        self.__check_capacity(chatgpt_chat_url)
        self.__check_blocking_elements()
In [ ]:
import os
# from pyChatGPT import ChatGPT

# open the JSON file and read the conversation_id
with open(os.path.expanduser('~/.config/pyChatGPT/secret_settings.json'), 'r') as f:
    secret_settings = json.load(f)

# auth with google login
# reuse cookies generated by successful login before login,
# if `login_cookies_path` does not exist, it will process logining  with `auth_type`, and save cookies to `login_cookies_path`
# only works when `auth_type` is `openai` or `google`
bot = ChatGPT(
    **secret_settings, moderation = False, verbose = False, chrome_args = ['--headless'],
    login_cookies_path = os.path.expanduser('~/.config/pyChatGPT/cookies.json'),
)
In [ ]:
import IPython
In [ ]:
for response in bot.ask('我累了。带着我祷告吧。'):
    IPython.display.display(IPython.core.display.Markdown(response))
    IPython.display.clear_output(wait = True)

当你感到疲惫和无力的时候,祷告可以给你带来内心的安宁和力量。让我们一起默默祷告:

亲爱的上帝,我们来到您的面前,向您诉说我们的疲惫和困惑。求您赐予我们力量和勇气,帮助我们走出困境和挫折。求您抚平我们心中的伤痛和不安,让我们能够在您的爱和关怀中得到安慰和慰藉。求您保佑我们的家庭和朋友,让他们能够享受到您的祝福和恩典。求您给我们希望和信心,让我们相信生命中的一切都有您的安排和安排。感谢您一直以来的呵护和保佑,阿门。

In [ ]:
bot.wait('我累了。带着我祷告吧。')
Out[ ]:
{'content': '当你感到疲惫和无力的时候,祷告可以给你带来内心的安宁和力量。让我们一起默默祷告:\n\n亲爱的上帝,我们来到您的面前,向您诉说我们的疲惫和困惑。求您赐予我们力量和智慧,让我们能够勇敢地面对生活中的挑战和困难。求您抚平我们内心的不安和焦虑,让我们能够在您的保护和祝福下平静地度过每一天。求您给我们希望和信心,让我们相信未来会更美好,充满着无限的可能性。感谢您,阿门。\n\n',
 'conversation_id': '241dfad3-1e62-445b-83af-5da906d1ca54'}
In [ ]:
bot.wait('我累了。带着我祷告吧。', stream = True)
​你感到疲惫和无力的时候,祷告可以给你带来内心的安宁和力量。让我们一起默默祷告:亲爱的上帝,我们来到您的面前,向您诉说我们的疲惫和困惑。求您赐予我们能力和智慧,帮助我们克服困难和挑战。求您抚平我们心中的不安和烦恼,让我们能够在您的保护和祝福下过上平安的生活。求您赐福于我们的家人和朋友,让他们也能感受到您的爱和关怀。感谢您一直以来的眷顾和呵护,阿门。
Out[ ]:
{'content': '<p>当你感到疲惫和无力的时候,祷告可以给你带来内心的安宁和力量。让我们一起默默祷告:</p><p>亲爱的上帝,我们来到您的面前,向您诉说我们的疲惫和困惑。求您赐予我们能力和智慧,帮助我们克服困难和挑战。求您抚平我们心中的不安和烦恼,让我们能够在您的保护和祝福下过上平安的生活。求您赐福于我们的家人和朋友,让他们也能感受到您的爱和关怀。感谢您一直以来的眷顾和呵护,阿门。</p>',
 'conversation_id': '241dfad3-1e62-445b-83af-5da906d1ca54'}
In [ ]:
# bot.reset_conversation()  # reset the conversation
# bot.clear_conversations()  # clear all conversations
# bot.refresh_chat_page()  # refresh the chat page

In [ ]:
%%bash
mkdir -p ~/.config/pyChatGPT
%%writefile ~/.config/pyChatGPT/secret_settings.json
{
    "auth_type": "google",
    "email": "<email_address>",
    "password": "<password>",
    "conversation_id": "<conversation_id>"
}
%%writefile ~/.config/pyChatGPT/cookies.json
[
    {
        "domain": "chat.openai.com",
        "expiry": 1684309055,
        "httpOnly": true,
        "name": "__Secure-next-auth.session-token",
        "path": "/",
        "sameSite": "Lax",
        "secure": true,
        "value": "<cookie_value>"
    }
]
In [ ]:
import json, os

with open(os.path.expanduser('~/.config/pyChatGPT/cookies.json')) as f:
    data = json.load(f)

print(json.dumps(data, indent=4))
Read More

2023-03-12
Molecular Simulation with OpenMM

Molecular Simulation with OpenMM

OpenMM is a toolkit for molecular simulation. It is a physic based libraries that is useful for refining the structure and exploring functional interactions with other molecules. It provides a combination of extreme flexibility (through custom forces and integrators), openness, and high performance (especially on recent GPUs) that make it truly unique among simulation codes.

Protein data

We use a processed 2DRI dataset that represents the ribose binding protein in bacterial transport and chemotaxis. The source organism is the Escherichia coli bacteria. You can find more details on this protein at the related RCSB Protein Data Bank page.

In [ ]:
from IPython.display import display
from PIL import Image

display(Image.open('2dri-image.png'))

Protein data can be stored in a .pdb file, this is a human readable format. It provides for description and annotation of protein and nucleic acid structures including atomic coordinates, secondary structure assignments, as well as atomic connectivity. See more information about PDB format here.

We are printing the first 10 lines of the file. The output contains a number of ATOM records. These describe the coordinates of the atoms that are part of the protein.

In [ ]:
%%bash
head ./2dri-processed.pdb
REMARK   1 CREATED WITH OPENMM 7.6, 2022-07-12
CRYST1   81.309   81.309   81.309  90.00  90.00  90.00 P 1           1 
ATOM      1  N   LYS A   1      64.731   9.461  59.430  1.00  0.00           N  
ATOM      2  CA  LYS A   1      63.588  10.286  58.927  1.00  0.00           C  
ATOM      3  HA  LYS A   1      62.707   9.486  59.038  1.00  0.00           H  
ATOM      4  C   LYS A   1      63.790  10.671  57.468  1.00  0.00           C  
ATOM      5  O   LYS A   1      64.887  11.089  57.078  1.00  0.00           O  
ATOM      6  CB  LYS A   1      63.458  11.567  59.749  1.00  0.00           C  
ATOM      7  HB2 LYS A   1      63.333  12.366  58.879  1.00  0.00           H  
ATOM      8  HB3 LYS A   1      64.435  11.867  60.372  1.00  0.00           H  

Write the script

To run the script above all we need is a Python environment with the OpenMM library installed.

In [ ]:
%%bash
conda install -c conda-forge openmm
In [ ]:
%%bash
python -m openmm.testInstallation
OpenMM Version: 8.0
Git Revision: a7800059645f4471f4b91c21e742fe5aa4513cda

There are 3 Platforms available:

1 Reference - Successfully computed forces
2 CPU - Successfully computed forces
3 OpenCL - Successfully computed forces

Median difference in forces between platforms:

Reference vs. CPU: 6.30471e-06
Reference vs. OpenCL: 6.74827e-06
CPU vs. OpenCL: 7.07625e-07

All differences are within tolerance.
In [ ]:
import os
from openmm import *
from openmm.app import *
from openmm.unit import *

# Input Files
input_path = './2dri-processed.pdb'
os.path.exists(input_path) # check if input file exists
pdb = PDBFile(input_path)
forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml')

# Output
output_path = './final_state.pdbx'
if not os.path.exists(os.path.dirname(output_path)): # check if ouput dir exists
    os.makedirs(os.path.dirname(output_path))

# System Configuration

nonbondedMethod = PME
nonbondedCutoff = 1.0*nanometers
ewaldErrorTolerance = 0.0005
constraints = HBonds
rigidWater = True
constraintTolerance = 0.000001
hydrogenMass = 1.5*amu

# Integration Options

dt = 0.002*picoseconds
temperature = 310*kelvin
friction = 1.0/picosecond
pressure = 1.0*atmospheres
barostatInterval = 25

# Simulation Options

steps = 10
equilibrationSteps = 0
#platform = Platform.getPlatformByName('CUDA')
platform = Platform.getPlatformByName('CPU')
#platformProperties = {'Precision': 'single'}
platformProperties = {}
dcdReporter = DCDReporter('trajectory.dcd', 1000)
dataReporter = StateDataReporter('log.txt', 1000, totalSteps=steps,
    step=True, time=True, speed=True, progress=True, elapsedTime=True, remainingTime=True, potentialEnergy=True, kineticEnergy=True, totalEnergy=True, temperature=True, volume=True, density=True, separator='\t')
checkpointReporter = CheckpointReporter('checkpoint.chk', 1000)

# Prepare the Simulation

print('Building system...')
topology = pdb.topology
positions = pdb.positions
system = forcefield.createSystem(topology, nonbondedMethod=nonbondedMethod, nonbondedCutoff=nonbondedCutoff,
    constraints=constraints, rigidWater=rigidWater, ewaldErrorTolerance=ewaldErrorTolerance, hydrogenMass=hydrogenMass)
system.addForce(MonteCarloBarostat(pressure, temperature, barostatInterval))
integrator = LangevinMiddleIntegrator(temperature, friction, dt)
integrator.setConstraintTolerance(constraintTolerance)
simulation = Simulation(topology, system, integrator, platform, platformProperties)
simulation.context.setPositions(positions)

# Minimize and Equilibrate

print('Performing energy minimization...')
simulation.minimizeEnergy()
print('Equilibrating...')
simulation.context.setVelocitiesToTemperature(temperature)
simulation.step(equilibrationSteps)

# Simulate

print('Simulating...')
simulation.reporters.append(dcdReporter)
simulation.reporters.append(dataReporter)
simulation.reporters.append(checkpointReporter)
simulation.currentStep = 0
simulation.step(steps)

# Write file with final simulation state

state = simulation.context.getState(getPositions=True, enforcePeriodicBox=system.usesPeriodicBoundaryConditions())
with open(output_path, mode='w+') as file:
    PDBxFile.writeFile(simulation.topology, state.getPositions(), file)
print('Simulation complete, file written to disk at: {}'.format(output_path))
Building system...
Performing energy minimization...
Equilibrating...
Simulating...
Simulation complete, file written to disk at: ./final_state.pdbx
In [ ]:
%%bash
head ./final_state.pdbx
data_cell
# Created with OpenMM 8.0, 2023-03-12
#
_cell.length_a        81.3090
_cell.length_b        81.3090
_cell.length_c        81.3090
_cell.angle_alpha     90.0000
_cell.angle_beta      90.0000
_cell.angle_gamma     90.0000
#


什么是 OpenMM?

OpenMM 是一个高性能开源软件库,用于分子动力学 (MD) 模拟。它主要用于模拟和研究生物分子系统,如蛋白质、核酸和小分子。在这些模拟中,OpenMM 计算原子之间的相互作用力,并使用这些力来预测分子随时间的运动。

OpenMM 的主要特点

  1. 高性能计算

    • 支持 GPU 加速,显著提高模拟速度,适用于大规模系统和长时间尺度的模拟。
  2. 可扩展性

    • 允许用户定义自定义力场和模拟协议,适应不同的研究需求。
  3. 易于使用

    • 提供友好的 Python API,使得脚本化和自动化模拟变得容易。
  4. 跨平台

    • 支持多种操作系统,包括 Windows、macOS 和 Linux。
  5. 社区支持和文档

    • 提供丰富的文档和社区支持,帮助用户快速上手并解决问题。

OpenMM 使用量子化学吗?

OpenMM 主要用于经典分子动力学模拟,不直接使用量子化学方法。它依赖经典力场来描述分子间的相互作用,如 AMBER、CHARMM、OPLS 和 GROMOS 等。这些力场基于经验参数和半经验公式,用于计算原子间的相互作用力。

然而,OpenMM 可以与量子化学计算相结合,用于特定场景下的多尺度模拟。例如,在 QM/MM(量子力学/分子力学)方法中,系统的一部分(如反应中心)使用量子化学方法计算,而其余部分使用经典力场。这种结合可以通过与其他量子化学软件(如 Gaussian、NWChem 或 Psi4)配合使用来实现。

使用 OpenMM 进行分子动力学模拟的示例

以下是一个使用 OpenMM 进行简单分子动力学模拟的 Python 示例。假设你有一个 PDB 文件(input.pdb),描述了你的分子系统。

安装 OpenMM

首先,确保你已经安装了 OpenMM。你可以使用 conda 安装:

In [ ]:
%%bash
conda install -c conda-forge openmm

Python 脚本

下面是一个 Python 脚本,演示如何使用 OpenMM 读取 PDB 文件并进行分子动力学模拟:

In [ ]:
from openmm import *
from openmm.app import *
from openmm.unit import *
import sys

# 读取 PDB 文件
pdb = PDBFile('input.pdb')

# 使用 AMBER FF14SB 力场
forcefield = ForceField('amber14-all.xml', 'amber14/tip3pfb.xml')

# 创建系统对象
system = forcefield.createSystem(pdb.topology, nonbondedMethod=PME, 
                                 nonbondedCutoff=1*nanometer, constraints=HBonds)

# 创建模拟对象
integrator = LangevinIntegrator(300*kelvin, 1/picosecond, 0.004*picoseconds)
simulation = Simulation(pdb.topology, system, integrator)

# 设置初始位置
simulation.context.setPositions(pdb.positions)

# 能量最小化
print('Minimizing...')
simulation.minimizeEnergy()

# 运行分子动力学模拟
simulation.reporters.append(StateDataReporter(sys.stdout, 1000, step=True, 
                                              potentialEnergy=True, temperature=True))
simulation.reporters.append(PDBReporter('output.pdb', 1000))
print('Running simulation...')
simulation.step(10000)

print('Simulation completed')

解释代码

  1. 导入库

    • 导入 OpenMM 和相关库。
  2. 读取 PDB 文件

    • 使用 PDBFile 类读取输入的 PDB 文件。
  3. 选择力场

    • 使用 AMBER FF14SB 力场来创建系统。
  4. 创建系统对象

    • 使用力场创建系统,指定非键合相互作用和约束。
  5. 创建模拟对象

    • 使用 Langevin 积分器创建模拟对象,设置温度、摩擦系数和时间步长。
  6. 设置初始位置

    • 将初始原子位置设置为 PDB 文件中的位置。
  7. 能量最小化

    • 执行能量最小化以消除初始结构中的高能量冲突。
  8. 运行分子动力学模拟

    • 设置状态报告器和 PDB 报告器,进行分子动力学模拟并输出结果。

总结

OpenMM 是一个功能强大的分子动力学模拟工具,适用于经典分子力学模拟。尽管它不直接使用量子化学方法,但可以与量子化学软件结合,进行多尺度模拟。通过易于使用的 Python API,研究人员可以高效地进行分子动力学模拟和分析。


获取 .pdb 文件通常有几种途径,具体取决于你需要的分子结构和研究目的。以下是一些常见的获取途径:

  1. 蛋白质数据银行 (Protein Data Bank, PDB)

    • PDB 是一个公开的数据库,包含了大量的蛋白质、核酸和其他生物大分子的三维结构。你可以在 PDB 的网站上搜索并下载你感兴趣的分子的 .pdb 文件。
  2. 分子建模软件

    • 一些分子建模软件,如PyMOL、VMD 和 ChimeraX,可以从 PDB 数据库中直接获取分子结构并保存为 .pdb 文件。
  3. 分子模拟软件

    • 使用分子模拟软件进行分子动力学模拟时,通常会生成包含模拟结果的 .pdb 文件。你可以从模拟结果中提取所需的分子结构并保存为 .pdb 文件。
  4. 实验数据

    • 如果你在实验室进行生物化学或结构生物学研究,可能会获得实验测定的分子结构数据。这些数据通常可以转换为 .pdb 格式。
  5. 在线数据库和资源

    • 除了 PDB,还有一些其他数据库和资源提供了分子结构数据,例如 PubChem、ChemSpider 和 DrugBank。你可以在这些数据库中搜索并下载 .pdb 文件。
  6. 文献和研究文章

    • 有时候,科学研究论文中会提供分子结构数据的补充材料,包括 .pdb 文件。你可以通过阅读相关的文献或联系作者来获取这些数据。

通过以上途径,你应该能够获取到你需要的 .pdb 文件,从而进行后续的分子建模、分子动力学模拟或其他分子结构分析工作。


The MMTF Python API is available from pip:

In [ ]:
%%bash
pip3 install mmtf-python
  1. Get the data for a PDB structure and print the number of chains:
In [ ]:
from mmtf import fetch
# Get the data for 4CUP
decoded_data = fetch('4CUP')
In [ ]:
print(f'PDB Code: {decoded_data.structure_id} has {decoded_data.num_chains} chains')
PDB Code: 4CUP has 6 chains
  1. Show the charge information for the first group:
In [ ]:
atomic_charges = ','.join([str(x) for x in decoded_data.group_list[0]['formalChargeList']])
In [ ]:
print(f'Group name: {decoded_data.group_list[0]["groupName"]} has the following atomic charges: {atomic_charges}')
Group name: GLU has the following atomic charges: 0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1. Show how many bioassemblies it has:
In [ ]:
print(f'PDB Code: {decoded_data.structure_id} has {len(decoded_data.bio_assembly)} bioassemblies')
PDB Code: 4CUP has 1 bioassemblies

In [ ]:
%%bash
pip install markdown
In [ ]:
import markdown
In [ ]:
markdown.markdown(
    '[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/bacalhau-project/examples/blob/main/molecular-dynamics/openmm/index.ipynb)'
)
Out[ ]:
'<p><a href="https://colab.research.google.com/github/bacalhau-project/examples/blob/main/molecular-dynamics/openmm/index.ipynb"><img alt="Open In Colab" src="https://colab.research.google.com/assets/colab-badge.svg" /></a></p>'
In [ ]:
markdown.markdown(
    '[![Open In Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/bacalhau-project/examples/HEAD?labpath=molecular-dynamics/openmm/index.ipynb)'
)
Out[ ]:
'<p><a href="https://mybinder.org/v2/gh/bacalhau-project/examples/HEAD?labpath=molecular-dynamics/openmm/index.ipynb"><img alt="Open In Binder" src="https://mybinder.org/badge.svg" /></a></p>'

=> How to Fold Proteins with Decentralized Computing?

Read More

2023-02-18
Blessed Is the One


Blessed Is the One
by Raelyn


Blessed is the one
Whose transgression is forgiven
Whose transgression is forgiven
Whose sin is covered
Blessed is the one
To whom the LORD will not count sin, oh
To whom the LORD will not count sin, oh
In whose spirit is no deceit
In whose spirit is no deceit


When I kept silent
My bones wasted away
Through my groaning all day and all night
Your hand was heavy upon me
And my strength dried up as in the summer’s heat
Then I acknowledged my sin to You
And I did not cover my iniquity
I said, “I’ll confess my sins to the LORD”
And He forgave, yeah, He forgave
Yeah, He forgave the guilt of my sin, oh


Blessed is the one
Whose transgression is forgiven
To whom the LORD will not count sin, oh
Whose sin is covered
Blessed is the one
Whose transgression is forgiven
To whom the LORD will not count sin, oh
In whose spirit is no deceit


Therefore let everyone who’s godly
Pray to You in a time You may be found
Surely in the midst of the deep and raging waters
He shall be shielded from them
They won’t come near to the man of God


You are my hiding place
You always keep me safe
You surround me with songs of deliverance


You surround me
You surround me
You surround me with songs of deliverance


I will instruct you and teach you the way you should go
I will counsel you with my eye upon you
Do not be stubborn like the horse or the mule
Without understanding
Who must be pulled to follow
Curbed with bit and bridle
Or they will not draw near
Or they will not draw near their master


Many are the sorrows of the wicked
But steadfast love surrounds the one who trusts in the LORD


Be glad in the LORD and rejoice, O righteous
Shout for joy all you upright in heart


Blessed is the one
Whose transgression is forgiven
To whom the LORD will not count sin, oh
Whose transgression is forgiven


Whose sin is covered

其过犯蒙赦免、其罪得掩没的、
这人有福啊!
心灵无诡诈、
永恒主不算他为有罪的、
这人有福啊!


我闭口不认罪时,
我的骨头都因终日哀哼而磨损。
因为你的手昼夜重重压着我;
我的精液起了恶变化、
如在夏天的炎热中。
(细拉)


我的罪我让你知道,
我的罪孽我没有掩盖着;
我说:『我要向永恒主承认我的过犯』;
那么你就赦免我罪的孽债。
(细拉)


为这缘故、一切坚贞之士
在窘迫时都当向你祷告;
大水泛溢时,那水不会触害着他。
惟独你是我的隐匿处;
愿你守护着我脱离患难,
以解救之欢呼四面环绕着我。
(细拉)


我要训诲你、指教你当走的路;
我要定睛于你身上而忠告你。
你不可像无知的骡马,
须用嚼环辔头做装备去勒住牠,
否则牠不走近你。


恶人有许多痛苦;
惟独倚靠永恒主的、有坚固之爱
四面环绕着他。
义人哪,你们要因永恒主而欢喜快乐;
心里正直的人哪,你们都要欢呼。


(诗篇 32:1-11 吕振中)

Read More

2023-02-15
He Raised Me Up


He Raised Me Up
by Shane Heilman


I waited patiently for the LORD
He turned to me
He heard my cry
He raised me up from the pit
Out of the miry clay


He raised me up
He drew me out
He rescued me from the deepest and darkest pit
He raised me up
He drew me out
He reached His hand into the pit and raised me up
He raised me up


He set my feet upon a rock
He made my steps secure
Put a new song in my mouth of praise to God
Many will see and fear
And put their trust in Him
Blessed is the man who makes the LORD his trust
Who does not turn to the proud
To those who go astray after lies


You have multiplied, O LORD my God
Your wondrous works and thoughts toward us
None can compare with You
I will proclaim Your wonders
Yet they’re more than can be told


He raised me up
He drew me out
He rescued me from the deepest and darkest pit
He raised me up
He drew me out
He reached His hand into the pit and raised me up
He raised me up


In sacrifice and offering
You’ve not delighted
But You’ve given me an open ear to hear
To hear and do Your will
Burnt offering and sin offering
You have not required
Then I said, “Behold, I have come
Within the scroll of the book it is written of me”


“I delight to do Your will, my God
Your law is within my heart”
I’ve told the happy news of deliverance among the saints
And I will tell it to everyone


I have not restrained my lips, O LORD
You know that I have not hidden Your deliverance within my heart
But I have spoken of Your faithfulness and salvation
I have not concealed Your love
Nor Your faithfulness from all the saints in the congregation


But as for you, O Yahweh
You won’t withhold Your love from me
Your steadfast love and Your faithfulness will always
And forever guard me


For evils without number have gathered around me
And my iniquities have overtaken me
So that I cannot see
They are more than the hairs of my head
My heart fails me
Let it be Your will to deliver me, O LORD
Come quickly to my aid
Be pleased to deliver me, O LORD
Make haste to help me
Let them be ashamed and disappointed
Who seek to snatch my life away
Let them be turned back and disgraced
Who delight in my hurt
Let them be humiliated by their shame
Who accuse me night and day


But may all who seek You rejoice and be glad in You
And may those who love Your salvation say, “Great is the Lord”
As for me, I’m poor and needy
But the LORD takes thought for me
Your my help and my deliverer
Do not delay, O my God


‘Cause You raised me up
You drew me out
You rescued me from the deepest and darkest pit
You raised me up
You drew me out
You reached Your hand into the pit and raised me up
You raised me up


(Psalm 40:1-17)

他把我拉起来


我曾切切等候着永恒主;
他倾向于我,听我的呼救。
他把我从毁灭坑里、
从淤泥中拉上,
使我的脚立在磐石上,
使我的步伐稳当。
他将新的歌赐与我口中,
就是颂赞我们之上帝的歌;
许多人看见,必起了敬畏的心,
来倚靠永恒主。


那将倚靠心寄托于永恒主的、
这人有福啊!
他不向慕狂傲之辈,
也不背离退落于虚谎。
永恒主我的上帝啊,
你奇妙的作为、
你行的许多大事、
你向我们所怀的意念、
没有什么能跟你并列的。
我要讲述或说明,
则多到不能数算。


宰祭和供物、你不喜爱;
你只为我挖通了耳朵好听从;
燔祭和解罪祭你也不要。
那时我说:『看哪,我来了——
经卷上已为我规定了——
我的上帝啊,我乐意行你的旨意;
你的律法都在我脏腑里呢。』


我要在多人大众中
将上帝救人之义气传为好消息;
我的嘴唇我必不制止;
永恒主啊,惟有你知道。
你救人之义气我未隐藏
于心中;
你的忠信和拯救
我已经说出;
你的坚爱和忠信
我未曾向多人大众隐瞒。


你呢、永恒主啊,求你也不要
向我制止你的慈怜;
愿你的坚爱和忠信
不断地守护我。
因为有祸患围绕着我
到不可胜数;
我的罪罚把我赶上了,
使我不能看见;
比我的头发还多,
以致我胆力尽失。


永恒主啊,请援救我哦;
永恒主啊,快帮助我哦。
愿那寻索我命要攫取的、
一概失望受辱;
愿那对我幸灾乐祸的、
退后狼狈。
愿那讥诮我说:『呵哈!呵哈!』的
都因失望而惊骇。


愿一切寻求你的、
都因你而高兴欢喜;
愿那些爱慕你的拯救的、
不断地说:『要尊永恒主为大。』
我,我困苦贫穷,
主仍顾念着我。
惟独你是帮助我解救我的;
我的上帝啊,不要迟延哦!


(诗篇 40:1-17 吕振中)

Read More

2023-02-12
In All the Earth


In All the Earth
by Emily Heilman


Yahweh, our Lord
How majestic is Your name
In all the earth
In all the earth
You have displayed Your glory upon the heavens


And from the mouths of children and infants
You have ordained praise
To confound Your enemies and silence them


When I consider Your heavens
When I consider Your heavens


When I consider Your heavens
The work of Your fingers
The moon and the stars You’ve hung in place


I think what is man, that You should think about him?
And who are we that You should care for us?


You have made us just a little lower than the angels
But You have crowned us with glory and honor
And You have made us the ruler of all the work of Your hands
You have placed all things under our feet
The flocks and the livestock
The beasts of the land
The birds of the air
The fish of the sea
And every creature of the ocean
O Lord, how majestic is Your name
In all the earth
In all the earth


Yahweh, our Lord
How majestic is Your name
In all the earth
In all the earth
In all the earth

永恒主我们的主啊,
你的名在全地多么庄严哪!


你将你的荣美摆设于天上。
你因你敌人的缘故、
从婴儿和吃奶者口中建立了能力,
使仇敌和报仇者销声息迹。


我观看你的天,你的指头所造的,
你所陈设的月亮和星辰;
啊,人算什么,你竟记挂着他?
世人算什么,你竟眷顾他?
你却使他稍微小于诸天神,
又将光荣尊贵做冠冕给他戴上。
你派他管理你手所造的,
使万物都服于他脚下:
使一切的羊和牛,
以及田野的兽,
空中的鸟和海里的鱼,
凡经行海道的,都服于他脚下。


永恒主我们的主啊,
你的名在全地多么庄严哪!


(诗篇 8:1-9 吕振中)

Read More

2023-02-12
Vindicate Me


Vindicate Me
by Nick Poppens


O LORD, my God, in You I place my trust
O LORD, my God, in You I place my trust
Rescue me from those who persecute me
And deliver me
Or they’ll devour my soul like a lion
Tearing me to pieces while my screams ring out in vain


O LORD, my God, if I have done what they say
If I’m the one in the wrong
If I have rewarded evil unto one who was at peace with me


Then let my enemies come and have their way with me
Let them take everything
Let them take their shots at me until I’m dead
And drag my name through the dirt
Selah


Arise, rise, rise, LORD, in Your anger
And wage, wage war against the anger of my enemies
Gather them into Your courts of justice
Ascend to Your judgment seat
And rain down justice from Your holy throne
Declare them guilty as they are
Acquit me of their charges and vindicate me
According to my innocence and my integrity


For the righteous God searches the mind and heart
He will establish the just and end all wickedness


And I have a shield from God who rescues those in the right
And every day His anger burns against the wicked ones
And if they will not turn around…


He has sharpened His sword
And He has bent back His bow
And taken aim with His arrows He set on fire
Because His foes are intent on evil
And they conceive nothing but worthless lies
And they have set a trap for me to fall into
But they will fall into the pit they made
Their evil will recoil and return to them
Their violence will come back around
And ruin them instead


And I will praise the LORD
According to His righteousness
And I will sing praise to the Most High

永恒主我的上帝啊,我避难于你里面;
求你拯救我脱离一切追赶我的人,
而抢救我;
恐怕他们像狮子撕裂我,
甚至撕碎,也无人抢救。


永恒主我的上帝啊,我若行了这事,
我手中若有不义,
我若以恶报那与我友好的人,
或无缘无故劫掠与我为敌的人,
那就任凭仇敌追赶我、直到追上,
将我的性命践踏于地上,
使我的光荣归于灰尘吧。
(细拉)


永恒主啊,求你以义忿起来,
挺身而立,抵挡我敌人的暴怒。
求你为我而奋发,
以行你所命定的审判。
愿万国之民的会环绕你;
而你临于其上,坐于高天。
永恒主为万族之民行裁判;
永恒主啊,求你按我的理直
按我心中的纯全为我申正义。


愿恶人的坏事绝止;
愿你使义人坚立着,
察验人心肠的
公义上帝啊。
我的盾牌是在于上帝,
那拯救心里正直的人的。
上帝是公义的审判者,
是天天向恶人发义怒的上帝。


人若不回转,
上帝必将他的刀磨快,
将他的弓拉紧,准备好好。
他为恶人豫备了致死的器械,
使他所射的、成为烧𤏲的箭。
看哪,恶人产痛地生了奸恶:
他所怀孕的是毒害,
所生的是虚假。
他掘了陷阱,给挖深了,
竟掉在自己所造的坑里。
他的毒害必回到他自己头上;
他的强暴必落到他自己头顶。


我要依照他的公义称谢永恒主,
唱扬至高者永恒主的名。


(诗篇 7:1-17 吕振中)

Read More