pascal-kun / app.py
YKajima's picture
fix api call
55d40b4
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")