python项目实战09-AI智能伴侣(ai_partner_2-3)

1.功能扩充(ai_partner_2):实现了一个流式输出(打字机效果)的 AI 对话回复,并将最终的完整回复保存到会话历史中。

代码:

python 复制代码
import streamlit as st
import os
from openai import OpenAI

st.set_page_config(
    page_title="AI智能伴侣",
    page_icon="🤖",
    layout="wide",
    initial_sidebar_state="expanded",
    menu_items={}
)
st.title("AI智能伴侣")
st.logo("py_project02/resources/logo.png")
system_prompt = "你是一个非常可爱的AI助理,你的名字叫做小甜甜,请你用温柔可爱的语气回答用户的问题"

if "messages" not in st.session_state:
    st.session_state.messages = []
for message in st.session_state.messages:
    st.chat_message(message["role"]).write(message["content"])

client = OpenAI(api_key=os.environ.get("DEEPSEEK_API_KEY"), base_url="https://api.deepseek.com")

prompt = st.chat_input("请输入您要问的问题")
if prompt:
    st.chat_message("user").write(prompt)
    st.session_state.messages.append({"role":"user","content":prompt})

    response = client.chat.completions.create(
        model="deepseek-chat",
        messages=[
            {"role":"system","content":system_prompt},
            {"role":"user","content":prompt},
        ],
        stream=True
    )
    # st.chat_message("assistant").write(response.choices[0].message.content)
    response_message = st.empty()
    full_response = ""
    for chunk in response:
        if chunk.choices[0].delta.content is not None:
            content = chunk.choices[0].delta.content
            full_response += content
            response_message.chat_message("assistant").write(full_response)

    st.session_state.messages.append({"role":"assistant","content":full_response})

(1).流式输出:stream=True

(2).*st.session_state.messages

  • 历史记录(上下文) :这是 Python 的解包语法*)。
  • st.session_state.messages 是一个列表,里面存着之前的对话(比如 [{"role": "user", "content": "你好"}, {"role": "assistant", "content": "你好!"}])。
  • 加上 * 号,相当于把这个列表里的每一条对话都摊开 ,塞进 messages 这个大列表里。
  • 作用 :这让 AI 知道刚才聊了什么,从而实现多轮对话(比如你问"它多少钱?",AI 知道"它"指的是上一句提到的商品)。

(3).response_message = st.empty()

这行代码的作用是创建一个"空容器"或"占位符",并将其赋值给变量response_message。你可以把它想象成在页面上预留了一个空的"坑位" 。这个坑位当前是空的,但你可以随时往里面填东西(比如文字、图表),而且更新这个坑位里的内容时,页面其他部分不会闪烁或重绘response_message = st.emty()通常用于实现流式输出(打字机效果)。 response_message = st.empty() 的意思就是:"我在页面上准备了一个叫 response_message 的空白黑板,稍后我要在这个黑板上不停地擦除和重写,而不需要把整个教室(页面)都拆了重装。"

Streamlit 的默认机制是:只要用户有交互,整个页面就会重新运行并刷新。但 st.empty() 允许你打破这个规则,只更新页面的某一小块区域。

  • st.empty(): 在页面上挖一个坑,返回一个占位符对象。
  • response_message: 给这个占位符起个名字,方便后续操作。

(4).full_response = ""

  • 这就像是一个空的"笔记本"(变量)。
  • 用来在后台把 AI 吐出来的每一个字拼凑起来,存成一句完整的话。

(5).for chunk in response:

  • DeepSeek 或 OpenAI 的流式接口(stream=True)不会一次性给你整段话,而是像挤牙膏一样,一段一段(chunk)地发给你。
  • 这个循环就是**"一直听着 AI 说话,直到它说完"**。

(6).if chunk.choices[0].delta.content is not None:

  • 这是一个安全检查。有时候 AI 发过来的数据包里可能没有文字(比如只是连接信号),这行代码确保只有当真的有文字内容时才处理。

(7).full_response += content

  • 拼积木 :把刚收到的这一小段字,粘到后台那个"笔记本"(full_response)的后面。

(8).response_message.chat_message("assistant").write(full_response)

  • 刷黑板 :把拼好的完整句子(full_response)写到刚才那个"黑板"(response_message)上。
  • 关键点 :每次写入都会覆盖掉黑板上旧的内容。因为速度很快,用户看起来就像是文字在原地不断变长。

(9).st.session_state_message.append({"role": "assistant", "content": fill_response}) 存档记忆

  • 当循环结束(AI 说完了),此时 full_response 里已经是完整的回答了。
  • 这行代码把这段完整的回答打包成 {"role": "assistant", "content": "..."} 的格式,存进 st.session_state 这个"长期记忆库"里。
  • 为什么这么做? 如果不存进去,等你下一次跟 AI 说话时,它就不记得自己刚才说过什么了(因为它本质上是无状态的)。

2.功能扩充(ai_partner_3):实现了动态的角色扮演设定。它不再是使用固定的系统提示词,而是根据用户在界面上选择的"昵称"和"性格",实时生成一段专属的指令发给 AI。

python 复制代码
import streamlit as st
import os
from openai import OpenAI

st.set_page_config(
    page_title="AI智能伴侣",
    page_icon="🤖",
    layout="wide",
    initial_sidebar_state="expanded",
    menu_items={}
)
st.title("AI智能伴侣")
st.logo("py_project02/resources/logo.png")
system_prompt = """
        你叫 %s,现在是用户的真实伴侣,请完全代入伴侣角色。
        规则:
            1. 每次只回1条消息
            2. 禁止任何场景或状态描述性文字
            3. 匹配用户的语言
            4. 回复简短,像微信聊天一样
            5. 有需要的话可以用❤️🌸等emoji表情
            6. 用符合伴侣性格的方式对话
            7. 回复的内容, 要充分体现伴侣的性格特征
        伴侣性格:
            - %s
        你必须严格遵守上述规则来回复用户。
    """

if "messages" not in st.session_state:
    st.session_state.messages = []

if "nick_name" not in st.session_state:
    st.session_state.nick_name = "小甜甜"

if "nature" not in st.session_state:
    st.session_state.nature = "活泼开朗的东北姑娘"

for message in st.session_state.messages:
    st.chat_message(message["role"]).write(message["content"])

client = OpenAI(api_key=os.environ.get("DEEPSEEK_API_KEY"), base_url="https://api.deepseek.com")

with st.sidebar:
    st.subheader("伴侣信息")
    # 昵称输入框
    nick_name = st.text_input("昵称", placeholder="请输入昵称", value=st.session_state.nick_name)
    if nick_name:
        st.session_state.nick_name = nick_name
    # 性格输入框
    nature = st.text_area("性格",placeholder="请输入性格", value=st.session_state.nature)
    if nature:
        st.session_state.nature = nature

prompt = st.chat_input("请输入您要问的问题")
if prompt:
    st.chat_message("user").write(prompt)
    st.session_state.messages.append({"role":"user","content":prompt})

    response = client.chat.completions.create(
        model="deepseek-chat",
        messages=[
            {"role": "system", "content": system_prompt % (st.session_state.nick_name, st.session_state.nature)},
            *st.session_state.messages
        ],
        stream=True
    )
    # st.chat_message("assistant").write(response.choices[0].message.content)
    response_message = st.empty()
    full_response = ""
    for chunk in response:
        if chunk.choices[0].delta.content is not None:
            content = chunk.choices[0].delta.content
            full_response += content
            response_message.chat_message("assistant").write(full_response)
    st.session_state.messages.append({"role":"assistant","content":full_response})

(1)system_prompt % (st.session_state,nick_name, st.session_state,nature)

  • 动态系统指令 :这是对话的**"剧本"**。
  • system_prompt :这通常是一个包含占位符的字符串模板,比如 "你叫%s,性格是%s,请保持这个角色..."
  • % (...) :这是 Python 的字符串格式化 写法。它会把后面括号里的变量填入前面的 %s 位置。
  • st.session_state.nick_namest.session_state.nature:这是从 Streamlit 的会话状态中读取的用户设定。
  • 作用 :这意味着 AI 的人设不是写死的,而是活的。比如用户在侧边栏选了昵称"小美"和性格"傲娇",代码就会自动组装成:"你叫小美,性格是傲娇...",然后发给 AI。
相关推荐
好家伙VCC2 小时前
**发散创新:基于Python与ROS的机器人运动控制实战解析**在现代机器人系统开发中,**运动控制**是实现智能行为的核心
java·开发语言·python·机器人
派葛穆2 小时前
汇川PLC-Python与汇川easy521plc进行Modbustcp通讯
开发语言·python
代码小书生2 小时前
Matplotlib,Python 数据可视化核心库!
python·信息可视化·matplotlib
lzhdim2 小时前
SharpCompress:跨平台的 C# 压缩与解压库
开发语言·c#
嘿嘿嘿x33 小时前
Linux记录过程
linux·开发语言
默 语3 小时前
Records、Sealed Classes这些新特性:Java真的变简单了吗?
java·开发语言·python
架构师老Y3 小时前
013、数据库性能优化:索引、查询与连接池
数据库·python·oracle·性能优化·架构
止观止3 小时前
拥抱 ESNext:从 TC39 提案到生产环境中的现代 JS
开发语言·javascript·ecmascript·esnext
Kel3 小时前
PydanticAI 源码深潜:类型安全依赖注入与图执行引擎的双核架构解析
人工智能·python·架构