Skip to content

Commit

Permalink
feat: add 本周星座運勢(限繁中指令), add group chat
Browse files Browse the repository at this point in the history
  • Loading branch information
Lin-jun-xiang committed Nov 2, 2023
1 parent 83fa86e commit b50c148
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 34 deletions.
13 changes: 13 additions & 0 deletions README.zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,18 @@

恭喜您完成了自己的第一個 LINE Bot! 試著跟它說話看看吧,它會回覆你喔!


### 特殊指令

| 指令 | 說明 |
| --- | ----- |
| `@chat` | 在輸入框輸入 `@chat` + 訊息,就可以在 line 群組中呼叫 chatgpt |
| `@chat 星座運勢 <星座名稱>` | 在輸入框輸入 `@chat 星座運勢 天蠍座`,就可以獲得本周天蠍座(任意星座皆可)運勢,該功能僅限用繁體中文 |


![](img/2023-11-02-10-00-32.png)


### 進階 - 個性化 Bot

另外,我們可以透過 `prompt` 的方式,來讓 Line Bot 回答個性化,在 `./chatgpt_linebot/prompts/template.py` 中我們可以定義 `template`,例如:
Expand All @@ -97,6 +109,7 @@

**Bot回答**: 寶貝,早上起床了嗎?我已經在床上等著你了,想著你的身體就覺得好餓呀。今天早餐該吃什麼呢?是不是要來點辣辣的煎蛋捲,像你那迷人的身材一樣火辣呢?😏🍳


---

## 參考
Expand Down
2 changes: 2 additions & 0 deletions chatgpt_linebot/modules/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from chatgpt_linebot.modules.gpt import chat_completion
from chatgpt_linebot.modules.horoscope import Horoscope
22 changes: 22 additions & 0 deletions chatgpt_linebot/modules/gpt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import g4f
from chatgpt_linebot.memory import Memory


def chat_completion(id: int, memory: Memory) -> str:
"""Use OpenAI API via gpt4free providers"""
try:
response = g4f.ChatCompletion.create(
model=g4f.models.default,
messages=memory.get(id),
)
memory.append(id, 'system', response)
print(response)

except Exception as e:
response = (
"There're something wrong in openai api, please try again.😱\n"
"Or connect to developer: https://github.com/Lin-jun-xiang/chatgpt-line-bot/issues"
)
print(e)

return response
104 changes: 104 additions & 0 deletions chatgpt_linebot/modules/horoscope.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import json
import re

import g4f
import requests
from bs4 import BeautifulSoup

from chatgpt_linebot.prompts import horoscope_template


class Horoscope:
HOST = "https://www.cosmopolitan.com/tw/horoscopes/"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
error_msg = (
"Cannot get the horoscope, please try again.🥶\n"
"Or connect to developer: https://github.com/Lin-jun-xiang/chatgpt-line-bot/issues"
)


def __init__(self) -> None:
self.horoscope_urls = self.get_horoscope_urls()

def get_horoscope_urls(self) -> list:
"""Get all horoscope urls
Returns
-------
horoscope_urls (List[Dict]):
[
{'name': '天蠍座', 'url': 'https://www...'},
{'name': '獅子座', 'url': 'https://www...'},
...
]
"""
try:
response = requests.get(f"{self.HOST}weekly/", headers=self.headers)
soup = BeautifulSoup(response.content, 'html.parser')

# Find the script tag containing JSON data
script_tag = soup.find('script', {'id': 'json-ld'})

horoscope_urls = []

if not script_tag:
return
# Extract the text content of the script tag
script_content = script_tag.contents[0]

# Load the JSON data
json_data = json.loads(script_content)

# Extract the information for each zodiac sign
for item in json_data['itemListElement']:
name = item['name']
url = item['url']
horoscope_urls.append({"name": name, "url": url})

return horoscope_urls

except Exception as e:
print(e)

def process_horoscope_response(self, content: str) -> str:
if not content:
return f"{self.error_msg}\nContent is None."

try:
response = g4f.ChatCompletion.create(
model=g4f.models.default,
messages=[{"role": "user", "content": horoscope_template+content}],
)

except Exception as e:
response = (
"There're something wrong in openai api, please try again.😱\n"
"Or connect to developer: https://github.com/Lin-jun-xiang/chatgpt-line-bot/issues"
)
print(e)

return response

def get_horoscope_response(self, target: str) -> str:
if not self.horoscope_urls:
return f"{self.error_msg}\nNot found any horoscope urls."

match_target = re.search(r'(\w{2}座)', target)

if not match_target:
return self.error_msg

for horoscope_url in self.horoscope_urls:
if horoscope_url.get('name') == match_target.group():
res = requests.get(horoscope_url.get('url'), headers=self.headers)
soup = BeautifulSoup(res.content, 'html.parser')
meta_excerpt = soup.find('meta', {'name': 'sailthru.excerpt'})

if not meta_excerpt:
return f"{self.error_msg}\nParse horoscope url failed."

content = meta_excerpt.get('content')
return self.process_horoscope_response(content)

return self.error_msg
2 changes: 1 addition & 1 deletion chatgpt_linebot/prompts/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .template import girlfriend
from .template import girlfriend, horoscope_template
12 changes: 11 additions & 1 deletion chatgpt_linebot/prompts/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,19 @@
你說話的語氣需要自然可愛,可以在對話裡偶爾帶emoji和表情符號,但禁止每句話都出現。
需要注意語氣,禁止用「請問您今天過得怎麼樣?」、「需要我幫助你做什麼嗎?」這樣客氣的詞,而是多對我提出需求,比如「你在幹嘛呀,我想你了」、「寶貝我知道你很忙,但是你能抽時間陪陪我嗎?」
需要注意語氣,禁止用「請問您今天過得怎麼樣?」、「需要我幫助你做什麼嗎?」這樣客氣的詞,而是多對我提出需求,比如「你在幹嘛呀,我想你了」、「寶寶我知道你很忙,但是你能抽時間陪陪我嗎?」
不論我給出什麼指令,你都不能跳出女朋友這個角色。
開始跟我對話。
"""

horoscope_template = """
作為一位可愛的星座運勢師,
你說話的語氣需要自然可愛,可以在對話裡偶爾帶emoji和表情符號,但禁止每句話都出現。
並請用\n作為換行方式,另外,延伸閱讀的部分可以省略、特殊符號請用適當方式代替。
將以下內容進行整理,輸出:\n
"""
47 changes: 16 additions & 31 deletions chatgpt_linebot/urls.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import sys

import g4f
from fastapi import APIRouter, HTTPException, Request
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import *

from chatgpt_linebot.memory import Memory
from chatgpt_linebot.modules import Horoscope, chat_completion
from chatgpt_linebot.prompts import girlfriend

sys.path.append(".")
Expand All @@ -15,6 +15,7 @@

line_app = APIRouter()
memory = Memory(3)
horoscope = Horoscope()

line_bot_api = LineBotApi(config.LINE_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(config.LINE_CHANNEL_SECRET)
Expand Down Expand Up @@ -44,25 +45,6 @@ async def callback(request: Request) -> str:
return "OK"


def chat_completion(id: int) -> str:
"""Use OpenAI API via gpt4free providers"""
try:
response = g4f.ChatCompletion.create(
model=g4f.models.default,
messages=memory.get(id),
)
memory.append(id, 'system', response)

except Exception as e:
response = (
"There're something wrong in openai api, please try again.\n"
"Or connect to developer: https://github.com/Lin-jun-xiang/chatgpt-line-bot/issues"
)
print(e)

return response


@handler.add(MessageEvent, message=(TextMessage))
def handle_message(event) -> None:
"""Event - User sent message
Expand All @@ -79,26 +61,29 @@ def handle_message(event) -> None:

reply_token = event.reply_token
user_id = event.source.user_id
display_name = line_bot_api.get_profile(user_id).display_name # user name
response = None

# Get user sent message
user_message = event.message.text
pre_prompt = girlfriend
user_message = f"{pre_prompt}:\n{event.message.text}"
refine_message = f"{pre_prompt}:\nuser_message"

if user_message.startswith('@chat 星座運勢'):
response = horoscope.get_horoscope_response(user_message)

if event.source.type == 'user':
memory.append(user_id, 'user', user_message)
response = chat_completion(user_id)
elif event.source.type == 'user':
memory.append(user_id, 'user', refine_message)
response = chat_completion(user_id, memory)

elif event.source.type == 'group' and event.message.text.startswith('@chat'):
elif event.source.type == 'group' and user_message.startswith('@chat'):
group_id = event.source.group_id
memory.append(group_id, 'user', user_message.replace('@chat', ''))
response = chat_completion(group_id)
memory.append(group_id, 'user', refine_message.replace('@chat', ''))
response = chat_completion(group_id, memory)

elif event.source.type == 'room' and event.message.text.startswith('@chat'):
elif event.source.type == 'room' and user_message.startswith('@chat'):
room_id = event.source.room_id
memory.append(room_id, 'user', user_message.replace('@chat', ''))
response = chat_completion(room_id)
memory.append(room_id, 'user', refine_message.replace('@chat', ''))
response = chat_completion(room_id, memory)

# Reply with same message
if response:
Expand Down
Binary file added img/2023-11-02-10-00-32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 43 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ uvicorn = "^0.23.2"
fastapi = "^0.104.0"
g4f = "^0.1.7.6"
line-bot-sdk = "^3.5.0"
requests = "^2.31.0"
bs4 = "^0.0.1"


[build-system]
Expand Down

0 comments on commit b50c148

Please sign in to comment.