liurenchaxin/app/tabs/adk_debate_tab.py

172 lines
8.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import streamlit as st
import asyncio
import sys
from pathlib import Path
from typing import Dict, Any, List
# Ensure the main project directory is in the Python path
project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root))
from google.adk import Agent, Runner
from google.adk.sessions import InMemorySessionService, Session
from google.genai import types
async def _get_llm_reply(runner: Runner, session: Session, prompt: str) -> str:
"""Helper function to call a Runner and get a text reply."""
content = types.Content(role='user', parts=[types.Part(text=prompt)])
response = runner.run_async(
user_id=session.user_id,
session_id=session.id,
new_message=content
)
reply = ""
async for event in response:
if hasattr(event, 'content') and event.content and hasattr(event.content, 'parts'):
for part in event.content.parts:
if hasattr(part, 'text') and part.text:
reply += str(part.text)
elif hasattr(event, 'text') and event.text:
reply += str(event.text)
return reply.strip()
async def run_adk_debate_streamlit(topic: str, participants: List[str], rounds: int):
"""
Runs the ADK turn-based debate and yields each statement for Streamlit display.
"""
try:
yield "🚀 **启动ADK八仙轮流辩论 (太上老君主持)...**"
all_immortals = ["铁拐李", "吕洞宾", "何仙姑", "张果老", "蓝采和", "汉钟离", "韩湘子", "曹国舅"]
if not participants:
participants = all_immortals
character_configs = {
"太上老君": {"name": "太上老君", "model": "gemini-1.5-pro", "instruction": "你是太上老君天道化身辩论的主持人。你的言辞沉稳、公正、充满智慧。你的任务是1. 对辩论主题进行开场介绍。2. 在每轮开始时进行引导。3. 在辩论结束后,对所有观点进行全面、客观的总结。保持中立,不偏袒任何一方。"},
"铁拐李": {"name": "铁拐李", "model": "gemini-1.5-flash", "instruction": "你是铁拐李,八仙中的逆向思维专家。你善于从批判和质疑的角度看问题,发言风格直接、犀利,但富有智慧。"},
"吕洞宾": {"name": "吕洞宾", "model": "gemini-1.5-flash", "instruction": "你是吕洞宾,八仙中的理性分析者。你善于平衡各方观点,用理性和逻辑来分析问题,发言风格温和而深刻。"},
"何仙姑": {"name": "何仙姑", "model": "gemini-1.5-flash", "instruction": "你是何仙姑,八仙中的风险控制专家。你总是从风险管理的角度思考问题,善于发现潜在危险,发言风格谨慎、细致。"},
"张果老": {"name": "张果老", "model": "gemini-1.5-flash", "instruction": "你是张果老,八仙中的历史智慧者。你善于从历史数据中寻找规律和智慧,提供长期视角,发言风格沉稳、博学。"},
"蓝采和": {"name": "蓝采和", "model": "gemini-1.5-flash", "instruction": "你是蓝采和,八仙中的创新思维者。你善于从新兴视角和非传统方法来看待问题,发言风格活泼、新颖。"},
"汉钟离": {"name": "汉钟离", "model": "gemini-1.5-flash", "instruction": "你是汉钟离,八仙中的平衡协调者。你善于综合各方观点,寻求和谐统一的解决方案,发言风格平和、包容。"},
"韩湘子": {"name": "韩湘子", "model": "gemini-1.5-flash", "instruction": "你是韩湘子,八仙中的艺术感知者。你善于从美学和感性的角度分析问题,发言风格优雅、感性。"},
"曹国舅": {"name": "曹国舅", "model": "gemini-1.5-flash", "instruction": "你是曹国舅,八仙中的实务执行者。你关注实际操作和具体细节,发言风格务实、严谨。"}
}
session_service = InMemorySessionService()
session = await session_service.create_session(state={}, app_name="稷下学宫八仙论道系统-Streamlit", user_id="st_user")
runners: Dict[str, Runner] = {}
for name, config in character_configs.items():
if name == "太上老君" or name in participants:
agent = Agent(name=config["name"], model=config["model"], instruction=config["instruction"])
runners[name] = Runner(app_name="稷下学宫八仙论道系统-Streamlit", agent=agent, session_service=session_service)
host_runner = runners.get("太上老君")
if not host_runner:
yield "❌ **主持人太上老君初始化失败。**"
return
yield f"🎯 **参与仙人**: {', '.join(participants)}"
debate_history = []
# Opening statement
opening_prompt = f"请为本次关于“{topic}”的辩论,发表一段公正、深刻的开场白,并宣布辩论开始。"
opening_statement = await _get_llm_reply(host_runner, session, opening_prompt)
yield f"👑 **太上老君**: {opening_statement}"
# Debate rounds
for round_num in range(rounds):
round_intro_prompt = f"请为第 {round_num + 1} 轮辩论说一段引导语。"
round_intro = await _get_llm_reply(host_runner, session, round_intro_prompt)
yield f"👑 **太上老君**: {round_intro}"
for name in participants:
if name not in runners: continue
history_context = f"\n最近的论道内容:\n" + "\n".join([f"- {h}" for h in debate_history[-5:]]) if debate_history else ""
prompt = f"论道主题: {topic}{history_context}\n\n请从你的角色特点出发,简洁地发表观点。"
reply = await _get_llm_reply(runners[name], session, prompt)
yield f"🗣️ **{name}**: {reply}"
debate_history.append(f"{name}: {reply}")
await asyncio.sleep(1)
# Summary
summary_prompt = f"辩论已结束。以下是完整的辩论记录:\n\n{' '.join(debate_history)}\n\n请对本次辩论进行全面、公正、深刻的总结。"
summary = await _get_llm_reply(host_runner, session, summary_prompt)
yield f"👑 **太上老君**: {summary}"
for runner in runners.values():
await runner.close()
yield "🎉 **ADK八仙轮流辩论完成!**"
except Exception as e:
yield f"❌ **运行ADK八仙轮流辩论失败**: {e}"
import traceback
st.error(traceback.format_exc())
def render_adk_debate_tab():
"""Renders the Streamlit UI for the ADK Debate tab."""
st.markdown("### 🏛️ 八仙论道 (ADK版 - 太上老君主持)")
topic = st.text_input(
"辩论主题",
value="AI是否应该拥有创造力",
key="adk_topic_input"
)
all_immortals = ["铁拐李", "吕洞宾", "何仙姑", "张果老", "蓝采和", "汉钟离", "韩湘子", "曹国舅"]
col1, col2 = st.columns(2)
with col1:
rounds = st.number_input("辩论轮数", min_value=1, max_value=5, value=1, key="adk_rounds_input")
with col2:
participants = st.multiselect(
"选择参与的仙人 (默认全选)",
options=all_immortals,
default=all_immortals,
key="adk_participants_select"
)
if st.button("🚀 开始论道", key="start_adk_debate_button", type="primary"):
if not topic:
st.error("请输入辩论主题。")
return
if not participants:
st.error("请至少选择一位参与的仙人。")
return
st.markdown("---")
st.markdown("#### 📜 论道实录")
# Placeholder for real-time output
output_container = st.empty()
full_log = ""
# Run the async debate function
try:
# Get a new event loop for the thread
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
# Create a coroutine object
coro = run_adk_debate_streamlit(topic, participants, rounds)
# Run the coroutine until completion
for message in loop.run_until_complete(async_generator_to_list(coro)):
full_log += message + "\n\n"
output_container.markdown(full_log)
except Exception as e:
st.error(f"启动辩论时发生错误: {e}")
async def async_generator_to_list(async_gen):
"""Helper to consume an async generator and return a list of its items."""
return [item async for item in async_gen]