PodcastVox / src /agent.py
Plat
init
3a09141
raw
history blame
5.13 kB
import json
from typing import Literal
from pydantic import BaseModel
import litellm
from litellm.types.utils import ModelResponse
SAFETY_SETTINGS = [
{
"category": "HARM_CATEGORY_HARASSMENT",
"threshold": "BLOCK_NONE",
},
{
"category": "HARM_CATEGORY_HATE_SPEECH",
"threshold": "BLOCK_NONE",
},
{
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
"threshold": "BLOCK_NONE",
},
{
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
"threshold": "BLOCK_NONE",
},
]
class BloggerAgent:
instructions = [
{
"role": "user",
"content": "与えられる情報について、重要なポイントを踏まえて平易な言葉で解説・紹介する記事を書いてください",
},
]
model: str = "gemini/gemini-2.5-flash-preview-05-20"
temperature: float = 1.0
max_tokens: int = 4096
thinking_budget: int = 1024
api_key: str
def __init__(self, api_key: str):
self.api_key = api_key
async def task(self, information: str) -> str:
messages = self.instructions.copy()
messages.append({"role": "user", "content": information})
res = await litellm.acompletion(
api_key=self.api_key,
model=self.model,
messages=messages,
temperature=self.temperature,
max_completion_tokens=self.max_tokens,
thinking={"type": "enabled", "budget_tokens": self.thinking_budget},
safety_settings=SAFETY_SETTINGS,
)
assert isinstance(res, ModelResponse)
blog = res.choices[0].message.content
assert isinstance(blog, str)
return blog
class WriterAgent:
instructions = [
{
"role": "user",
"content": """与えられる情報ソースとその解説記事をもとに、コンテンツを紹介する Podcast の会話を作成してください。
Podcast では、二人の人物が交互に会話をします。
# 登場人物
- スピーカー: コンテンツ紹介をリードする人で、主にこの人物が解説を行う
- サポーター: スピーカーの説明を聞き、うなづいたり、さらに質問を投げかけることで、理解を助ける。
# 構成
1. イントロ: まず、スピーカーとサポーターが何について話すのか、挨拶を交えながら会話します。自己紹介は省略する。
2. 解説: 前提知識の確認をしながら、内容を解説していきます
3. アウトロ: 今後の展望を交えながら締めくくります
---
このような内容になるような Podcast の脚本を作成してください。
""".strip(),
},
]
model: str = "gemini/gemini-2.5-flash-preview-05-20"
temperature: float = 1.0
max_tokens: int = 4096
thinking_budget: int = 1024
api_key: str
def __init__(self, api_key: str):
self.api_key = api_key
async def task(self, information: str, blog: str) -> str:
messages = self.instructions.copy()
messages.append(
{"role": "user", "content": f"# 情報\n{information}\n\n# 解説\n{blog}"}
)
res = await litellm.acompletion(
api_key=self.api_key,
model=self.model,
messages=messages,
temperature=self.temperature,
max_completion_tokens=self.max_tokens,
thinking={"type": "enabled", "budget_tokens": self.thinking_budget},
safety_settings=SAFETY_SETTINGS,
)
assert isinstance(res, ModelResponse)
dialogue = res.choices[0].message.content
assert isinstance(dialogue, str)
return dialogue
class Dialogue(BaseModel):
role: Literal["speaker", "supporter"]
content: str
class Conversation(BaseModel):
conversation: list[Dialogue]
class StructureAgent:
instructions = [
{
"role": "user",
"content": """この会話を指定されたスキーマに従った形に変換してください。スピーカーの role は `speaker`、サポーターは `supporter` です。""".strip(),
},
]
model: str = "gemini/gemini-2.5-flash-preview-05-20"
temperature: float = 0.1
max_tokens: int = 12_288
thinking_budget: int = 0
api_key: str
def __init__(self, api_key: str):
self.api_key = api_key
async def task(self, dialogue: str) -> Conversation:
messages = self.instructions.copy()
messages.append({"role": "user", "content": dialogue})
res = await litellm.acompletion(
api_key=self.api_key,
model=self.model,
messages=messages,
temperature=self.temperature,
max_completion_tokens=self.max_tokens,
thinking={"type": "disabled"},
response_format=Conversation,
safety_settings=SAFETY_SETTINGS,
)
conversation = Conversation.model_validate(
json.loads(res.choices[0].message.content)
)
return conversation