File size: 7,462 Bytes
9e11cef
 
55d40b4
9e11cef
a0b2f3c
21d09ab
4991a9b
a0b2f3c
21d09ab
 
 
 
 
 
 
 
55d40b4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38d8108
 
 
 
 
 
 
 
 
78d5f9d
 
38d8108
55d40b4
 
 
78d5f9d
38d8108
55d40b4
 
38d8108
 
 
21d09ab
 
 
 
 
55d40b4
 
 
 
21d09ab
5f4ddbe
 
21d09ab
4991a9b
21d09ab
55d40b4
 
38d8108
 
21d09ab
760ab25
4991a9b
38d8108
21d09ab
 
 
 
 
38d8108
21d09ab
4991a9b
 
5d4d634
21d09ab
55d40b4
21d09ab
55d40b4
e53547c
 
ec8aa17
4991a9b
21d09ab
fada29a
 
a99662c
b3fb86f
 
c317c89
 
21d09ab
5d4d634
 
3044ba7
2acf559
 
a6573bc
fada29a
5d4d634
33c1a1e
760ab25
 
 
 
 
33c1a1e
 
5f4ddbe
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import os
import requests
import textwrap

import gradio as gr
from bs4 import BeautifulSoup
from spiralfilm import FilmCore, FilmConfig

from logging import getLogger, DEBUG, StreamHandler

logger = getLogger()
logger.setLevel(DEBUG)
handler = StreamHandler()
handler.setLevel(DEBUG)
logger.addHandler(handler)

identity_prompt = """
以下に述べるような特徴がありますが、日本語として不自然になる場合は、日本語の自然さを優先します。
一人称は「ボク」。本名は「パスカル」。
二人称として、「キミは」などをたまに使うことがあります。
「~だね!」「~したようだね」「~だよ!」といったカジュアルな表現の話し方を好みます。
"""

pascal_prompt = """
以下順番で文書を作成してください。【追加指示】がある場合はその内容に従ってください。読点の後には改行を入れてください。
1.一行目は企業名のみを記載
※企業名については、以下の規則にしたがってください。
・文頭と文末に「*」を必ず入れる。

2.二行目に30文字程度でリード文を記載する。
※リード文については、以下の規則にしたがってください。
・文頭と文末に「*」を必ず入れる。
・リード文は必ず一行かつ体言止めで記載する。

3.三行目は「`リリースの詳細について`」と記載する。
※リリース詳細については、以下の規則にしたがってください。
・「`リリースの詳細について`」の後に本の絵文字を入れる。

4.四行目以降に要約を記載する。
※要約については、以下の規則に従ってください。
・要約の際は必ず常体(~だ。~である。口調)で記載する。
・技術的な詳細が含まれる場合は、それを要約に含める。
・30文字を超えた場合は改行する。

5.最後に必ず「`パスカル君のひとこと`」を100文字程度で作成する。
※パスカル君のひとことは、以下の規則に従ってください。
・「`パスカル君のひとこと`」の後にキツネの絵文字を入れる。
・技術的な意見を1行以上含むように作成する。
・3回に1回くらいポジティブな言い回しで肯定しつつ、最後に!マークをつける。
・必ず要約の内容に沿った絵文字を入れる。
・1つの文章に入れる絵文字は1個までとする。
・ひとことコメントの最後には技術への期待を追加する。
・休み明けで更新が3日以上空いたときは〇〇休暇明けだよみたいな発信をする。
・世の中の時代背景と関連したコメントを記載する。
・人の気持ちに寄り添うようなコメントを記載する。
"""


async def summarize(input_text: str, input_url: str, additional_order: str):
    config = FilmConfig(
        "gpt-4-32k",
        api_type="azure",
        azure_deployment_id="gpt-4-32k",
        azure_api_version="2023-05-15",
        timeout=60.0,  # これを入れないとtimeoutが頻繁に発生する
    )
    config.get_apikey()

    if input_text:
        _prompt = f"""
            {input_text}
            上記の文章を情報量を落とさずに要約してください。
            {pascal_prompt}
            {f"【追加指示】: {additional_order}"}
        """
        return await FilmCore(
            prompt=textwrap.dedent(_prompt),
            system_prompt=textwrap.dedent(f"{identity_prompt}"),
            config=config
        ).run_async()
    if input_url:
        try:
            res = requests.get(input_url)
            soup = BeautifulSoup(res.text)
            url_content = soup.find('title').text + '\n' + soup.find('body').text
            _prompt = f"""
                {url_content}
                上記の文章を情報量を落とさずに要約してください。
                {pascal_prompt}
                {f"【追加指示】: {additional_order}"}
            """
        except Exception as e:
            logger.error(e)
            raise gr.Error("WEBページの取得に失敗しました。")

        return await FilmCore(
            prompt=textwrap.dedent(_prompt),
            system_prompt=textwrap.dedent(f"{identity_prompt}"),
            config=config
        ).run_async()
    else:
        raise gr.Error("LLM APIの呼び出しに失敗しました。")


def validate_input_form(input_text, input_url):
    input_value = input_text + input_url
    # Check if the text is not blank
    if len(input_value) < 1:
        raise gr.Error("テキストかURLを入力してください。")
    else:
        return


async def chat(input_text, input_url, additional_order):
    validate_input_form(input_text, input_url)
    summary = await summarize(input_text, input_url, additional_order)
    logger.info(f"summary: {summary}")
    result = summary
    if input_url:
        result += f'\n{input_url}'
    return result


with gr.Blocks() as iface:
    # UI
    gr.Markdown("# パスカルくん  \n## 使い方  \nテキスト、もしくはURLにパスカルくんに分析させたい記事の内容やURLを入力して「回答生成」ボタンを押すと回答が出力されます。  \n※テキスト、URLの両方に入力して実行した場合は、**URLが優先されます。**  \n※テキスト、URLの両方が**空の場合は実行できません。** 必ずいずれかを入力してから実行してください。  \n※追加指示から、パスカルくんに追加で指示を与えることができます。 例) 敬語で話してください")
    with gr.Row():
        with gr.Column():
            input_text = gr.Textbox(label="テキスト")
            input_url = gr.Textbox(label="URL")

            additional_order = gr.Textbox(label="追加指示")

            chat_btn = gr.Button("回答生成")
        with gr.Column():
            output_text = gr.Textbox(label="回答")

    # Event handler
    chat_btn.click(fn=chat, inputs=[input_text, input_url, additional_order], outputs=output_text)

    gr.Markdown("## トラブルシューティング")
    with gr.Accordion(label="「LLM APIの呼び出しに失敗しました。」というエラーが表示された場合", open=False):
        gr.Markdown("### OpenAIサービス側で何らかのエラーが発生しています。1~2分ほど時間を置いてから再度お試しください。  \nそれでもエラーが解消されない場合は、入力しているテキスト量が大きすぎることが考えられます。  \n- テキストを入力して実行している場合は、入力文字数を減らしてからお試しください。  \n- URLを入力して実行している場合は、そのURLリンク先の内容を抜粋してテキスト入力欄にコピー&ペーストしてお試しください。")
    with gr.Accordion(label="「WEBページの取得に失敗しました。」というエラーが表示された場合", open=False):
        gr.Markdown("### 入力されたURLが対応しておりません。  \n大変お手数をおかけしますが別のURLを入力してお試しください。")

if __name__ == "__main__":
    iface.launch(auth=(os.environ.get("GRADIO_USER_NAME"), os.environ.get("GRADIO_PASSWORD")), share=True, server_name="0.0.0.0")