commit b8bb6a24dd4411be0c12c572e8d9335140446f88 Author: sit002 Date: Wed Dec 31 14:41:33 2025 +0800 feat: add initial project README file diff --git a/README.md b/README.md new file mode 100644 index 0000000..00bafb0 --- /dev/null +++ b/README.md @@ -0,0 +1,365 @@ +# Python程序设计课程设计 + +## 🎯 课程概述 + +**课程主题**:基于 DeepSeek API + Streamlit 的 AI 应用开发 + +**课程理念**: + +> 在 AI 时代,代码可以生成,Bug 可以修复,文档可以自动撰写—— +> +> **但判断什么值得做、为结果负责、理解用户真实需求、在约束中做取舍,这些能力永远属于你。** + +本课程通过 AI 代码编辑器(如 Cursor、Windsurf)进行 **Vibe Coding**,让学生体验"用自然语言编程"的全新开发方式。但更重要的是,在这个过程中**思考人与 AI 的协作边界**,培养 AI 时代真正不可替代的能力。 + +**技术栈**: +- 🐍 **Python 3.10+** +- 🤖 **DeepSeek API**(大语言模型) +- 🎨 **Streamlit**(Web 界面框架) +- 🛠️ **Cursor / Windsurf**(AI 代码编辑器) + +--- + +## 📅 课程安排 + +| 日期 | 内容 | 形式 | +|:---:|:---:|:---:| +| **第1天** | 课程讲解与演示 | 教师授课 | +| **第2天** | 自主开发 | 学生自学 | +| **第3天** | 中期答疑 | 集中答疑 | +| **第4天** | 自主开发 | 学生自学 | +| **第5天** | 项目展示与评审 | 成果展示 | + +--- + +## 📚 第1天:课程讲解与演示(3学时) + +### 1.1 课程导入(30分钟) + +#### 什么是 Vibe Coding? +- **定义**:一种"以人为本、AI 为器"的编程范式。开发者专注于**意图描述**和**结果验收**,而将代码实现、调试细节交由 AI 辅助完成。 +- **核心逻辑**:"描述你想要什么,而不是告诉计算机怎么做"。 +- **演示**:用自然语言在 3 分钟内创建一个完整应用。 + +#### AI 时代,什么能力真正属于你? + +> **AI 能做的事越来越多:** 语法查询、代码生成、Bug 修复、文档撰写、测试创建、架构建议、代码重构... +> +> **但这些能力永远属于你:** +> - 🎯 **判断什么值得做** —— 选题的眼光和价值判断 +> - 📋 **为结果负责** —— 代码能跑不等于问题解决 +> - 👥 **理解真实需求** —— 用户要的不是功能,是解决方案 +> - ⚖️ **在约束中取舍** —— 时间、资源、技术的平衡 +> - 🤝 **与人协作** —— 包括与 AI 协作 + +本课程不只是教你用 AI 写代码,更是让你**体验和思考这些不可替代的能力**。 + +#### AI 代码编辑器介绍 +- **Cursor**:[https://cursor.com](https://cursor.com) +- **Windsurf**:[https://codeium.com/windsurf](https://codeium.com/windsurf) +- **核心模式**: + - **Approve/Reject**:人是最终的决策者。 + - **Context Awareness**:如何让 AI "看见"你的整个项目。 + +### 1.2 技术栈讲解(60分钟) + +#### DeepSeek API 快速入门 +```python +from openai import OpenAI + +# 初始化客户端 +client = OpenAI( + api_key="your-api-key", # 建议使用环境变量 + base_url="https://api.deepseek.com" +) + +# 发送请求 +response = client.chat.completions.create( + model="deepseek-chat", # 使用 V3 模型 + messages=[ + {"role": "system", "content": "你是一个有帮助的助手"}, + {"role": "user", "content": "你好!"} + ], + stream=False +) + +print(response.choices[0].message.content) +``` + +> [!WARNING] +> **API Key 安全**: +> 绝对不要按将 API Key 直接提交到 GitHub 等公共仓库!请使用 `.env` 文件配合 `.gitignore` 管理。 + +**关键概念**: +- **API Key**:你的"通行证",注意保密。 +- **Messages**:对话历史的列表,包含 system(人设)、user(用户)、assistant(AI)。 +- **Stream**:流式输出,提升用户体验(像打字机一样显示)。 + +#### Streamlit 快速入门 +```python +import streamlit as st + +st.title("我的第一个 Streamlit 应用") + +# 侧边栏 +with st.sidebar: + st.write("这是侧边栏") + +# 输入框 +user_input = st.text_input("请输入你的问题:") + +# 按钮与交互 +if st.button("提交"): + if user_input: + st.write(f"你输入了:{user_input}") + else: + st.warning("请输入内容!") +``` + +**常用组件**: +- 🛠️ **输入**:`st.text_input`, `st.text_area`, `st.slider` +- 📄 **输出**:`st.write`, `st.markdown`, `st.chat_message` +- 🎒 **状态**:`st.session_state` (用于记住对话历史) + +### 1.3 完整示例演示(45分钟) + +#### 现场演示:用 Vibe Coding 构建一个 AI 聊天应用 + +**演示步骤**: +1. **Init**:新建文件夹,用自然语言让 AI 初始化环境。 +2. **Draft**:描述核心需求,生成 1.0 版本代码。 +3. **Refine**: + - 添加对话历史记忆(Session State)。 + - 开启流式输出(Streaming)。 + - 优化 UI(添加侧边栏设置)。 +4. **Deploy**:运行并测试。 + +**示例 Prompt**: +> "帮我创建一个基于 DeepSeek API 的聊天应用,使用 Streamlit 构建界面。要求: +> 1. 支持多轮对话,保留对话历史 +> 2. 使用流式输出,打字机效果显示回复 +> 3. 左侧边栏可以设置系统提示词 +> 4. 界面美观,有清空对话的按钮" + +### 1.4 项目要求说明(15分钟) + +#### 项目选题(任选其一或自拟) + +| 难度 | 项目名称 | 服务对象/场景 | 解决的真实问题/价值 | +|:---:|:---|:---|:---| +| ⭐⭐ | AI 写作助手 | 学生/自媒体 | 写作与润色提效,输出更顺畅 | +| ⭐⭐ | 智能单词本 | 英语学习者 | 释义+例句,降低背词与造句门槛 | +| ⭐⭐ | AI 任务拆解教练 | 学习/入职 | 把目标拆成可执行步骤与提醒 | +| ⭐⭐⭐ | 会议纪要助手 | 团队会议 | 自动要点/待办提炼,减少遗漏 | +| ⭐⭐⭐ | 代码解释与修复 | 编程学习者 | 逐行讲解+修复建议,缩短排错时间 | +| ⭐⭐⭐ | 产品需求澄清助手 | PM/开发 | 拆解模糊需求→可执行条目 | +| ⭐⭐⭐ | 学习笔记整理 | 学生/职场 | 将笔记结构化,生成概要/测验题 | +| ⭐⭐⭐⭐ | 智能知识库问答 | 企业/课程 | 自有文档精准问答,减少人工答疑 | +| ⭐⭐⭐⭐ | AI 数据洞察仪表盘 | 中小团队 | 上传表格自动生成洞察与可视化 | +| ⭐⭐⭐⭐ | AI 面试官 | 求职者 | 简历定制问答,练习反馈与改进建议 | +| ⭐⭐⭐⭐⭐ | 多 Agent 决策工作坊 | 方案评审 | 多角色视角辩论,生成决策要点 | + +> 💡 **选题思考**:不只是"我能做什么",更要思考"这个项目**对谁有价值**?解决什么**真实问题**?" + +--- + +## 🔧 第2天:自主开发 + +### 建议学习路线 + +``` +上午:环境搭建 + 熟悉工具 +├── 安装 Python、Cursor/Windsurf +├── 申请 DeepSeek API Key +├── 运行第一天的示例代码 +└── 熟悉 AI 编辑器的操作(Composer/Chat 模式) + +下午:开始项目开发 +├── 确定项目选题 +├── 用自然语言描述项目需求(Project Requirements) +├── 让 AI 生成初始代码框架 +└── 运行调试,迭代优化 +``` + +### Vibe Coding 技巧 + +#### 1. 上下文管理(Context) +AI 不是神,它需要知道你的代码、你的报错、你的意图。 +- **@Files**:在 Cursor 中使用 `@` 引用相关文件。 +- **Paste Error**:直接粘贴报错信息,不要只说"报错了"。 + +#### 2. 有效的 Prompt 模板 +```markdown +角色:你是一个 Python 专家。 +任务:创建一个 [项目类型],使用 [技术栈]。 + +功能需求: +1. [功能1] +2. [功能2] + +约束条件: +- 代码简洁,有注释 +- 使用 Streamlit 的 sidebar 布局 +``` + +#### 3. 常见问题排查 +- **Streamlit 页面频繁刷新?** -> 检查是否把初始化代码放在了循环里,或者没用 `st.session_state`。 +- **API 报错 401?** -> 检查 API Key 是否正确,环境变量是否生效。 + +### 学习资源 +- 📚 **Streamlit 文档**:[docs.streamlit.io](https://docs.streamlit.io) +- 🤖 **DeepSeek API**:[platform.deepseek.com](https://platform.deepseek.com) +- 📺 **教程**:B站搜索 "Streamlit 入门" 或 "Cursor 教程" + +--- + +## ❓ 第3天:中期答疑 + +### 答疑内容 +- ✅ 项目选题确认 +- 🐛 疑难 Bug 攻关 +- 🏗️ 架构设计与优化建议 + +### 常见问题解决方案表 + +| 问题分类 | 现象描述 | 解决方案核心 | +|:---|:---|:---| +| **环境** | `ModuleNotFoundError` | 运行 `pip install <库名>` | +| **API** | `402 Payment Required` | 账户余额不足,需充值 | +| **API** | 回复中断/不完整 | 检查 `max_tokens` 设置,或上下文超长 | +| **Streamlit** | 变量一点按钮就重置 | **必须**使用 `st.session_state` 存储变量 | +| **Streamlit** | 运行无反应 | 确保命令是 `streamlit run app.py` 而不是 `python app.py` | + +### 中期检查清单 +- [ ] 选题已定,核心功能跑通 +- [ ] 理解核心代码逻辑(能给别人讲清楚) +- [ ] 无论是 Git 还是手动备份,确保代码有存档 +- [ ] 能清晰回答:**我的项目为谁解决了什么问题?** + +--- + +## 🔧 第4天:自主开发 + +### 建议工作重点 +- **完善功能**:处理边界情况(如用户输入为空、API 请求失败)。 +- **美化界面**:使用 `st.columns` 排版,添加 Emoji,优化提示语。 +- **准备展示**:开始思考演示流程,准备 README。 + +> [!TIP] +> **加分项**: +> - 💾 **数据持久化**:对话不丢失(存本地 JSON 或 SQLite)。 +> - 📱 **响应式**:手机端打开也好看。 +> - 📊 **可视化**:用图表直观展示数据。 + +--- + +## 🎤 第5天:项目展示与评审 + +### 展示形式 +- **时间**:每组 (2-3人) **5分钟**。 +- **内容**:PPT/文档介绍 (1min) + 实机演示 (4min) + 心得分享 (2min)。 + +### 评分标准(总分 100) + +| 维度 | 分值 | 核心考量 | +|:---|:---:|:---| +| **功能完成度** | 25 | 核心功能由无 Bug,流程跑通 | +| **创意与体验** | 20 | 界面美观,交互顺滑,解决痛点 | +| **技术实现** | 20 | 代码结构清晰,错误处理完善 | +| **展示表现** | 10 | 表达清晰,演示流畅 | +| **开发心得** | 15 | **(重要)** 对 AI 协作的真实思考与反思 | +| **学习态度** | 10 | 课堂与答疑的参与度 | + +> **难度系数**: +> 基础项目 (⭐⭐) 系数 ×1.0;挑战项目 (⭐⭐⭐⭐) 系数 ×1.1。 +> *鼓励挑战,但也尊重将简单事情做到极致。* + +--- + +## 📦 提交要求 + +### 1. 提交材料 +1. **源代码**:完整项目文件夹。 +2. **README.md**:项目说明文档。 +3. **requirements.txt**:`pip freeze > requirements.txt` 生成。 +4. **开发心得**:Markdown 格式,**不少于 500 字**。 + +### 2. README.md 模板 +```markdown +# [项目名称] + +## 简介 +这句话介绍你的项目是做什么的,解决了什么问题。 + +## 如何运行 +1. 安装依赖:`pip install -r requirements.txt` +2. 配置 Key:复制 `.env.example` 为 `.env` 并填入 Key。 +3. 运行:`streamlit run app.py` + +## 功能列表 +- [x] 功能 A +- [ ] 功能 B (待开发) +``` + +### 3. 📝 开发心得(必填,>500字) + +**请围绕以下核心问题撰写:** + +1. **选题思考**:为什么做这个?解决了谁的痛苦? +2. **AI 协作体验**: + - 第一次用 AI 写代码的感觉? + - 哪个 Prompt 让你直呼"牛逼"?哪个让你想砸键盘? + - AI 生成的 Bug 你是怎么解的? +3. **自我反思**: + - 离开 AI,我还能写出这个吗? + - AI 时代,我作为程序员的核心竞争力到底是什么? + +> 💡 **真情实感最重要**。我们不想看套话,想看你的真实挣扎与顿悟。 + +--- + +## 🔗 附录:环境配置指南 + +### 1. 基础环境 +- **Python**:推荐 3.10+ ([官网下载](https://www.python.org/downloads/)) +- **编辑器**:推荐 Cursor 或 VS Code + Windsurf 插件。 + +### 2. 项目初始化命令 +```bash +# 1. 创建虚拟环境 (Windows) +python -m venv venv +.\venv\Scripts\activate + +# 1. 创建虚拟环境 (Mac/Linux) +python3 -m venv venv +source venv/bin/activate + +# 2. 安装核心库 +pip install streamlit openai python-dotenv +``` + +### 3. API Key 管理示例 (`.env`) +不要把 Key 写死在代码里! +```python +# .env 文件 +DEEPSEEK_API_KEY=sk-xxxxxxx +``` +```python +# app.py +import os +from dotenv import load_dotenv + +load_dotenv() # 加载 .env +api_key = os.getenv("DEEPSEEK_API_KEY") +``` + +--- + +## 🌟 结语 + +> **代码是 AI 写的没关系,** +> +> **但选题是你定的,需求是你理解的,取舍是你做的,结果是你交付的,成长是你自己的。** + +祝大家在 **Vibe Coding** 中找到属于自己的价值!🚀 + diff --git a/示例项目-AI数据分析师/.env-example b/示例项目-AI数据分析师/.env-example new file mode 100644 index 0000000..9b9185e --- /dev/null +++ b/示例项目-AI数据分析师/.env-example @@ -0,0 +1,9 @@ +# DeepSeek API Key 配置示例 +# ================================ +# 使用方法: +# 1. 将此文件复制并重命名为 .env +# 2. 将下面的 sk-xxx... 替换为你的真实 API Key +# ================================ + +DEEPSEEK_API_KEY=sk-xxxxx + diff --git a/示例项目-AI数据分析师/.gitignore b/示例项目-AI数据分析师/.gitignore new file mode 100644 index 0000000..b7fca19 --- /dev/null +++ b/示例项目-AI数据分析师/.gitignore @@ -0,0 +1,25 @@ +# 环境变量(包含敏感信息) +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +venv/ +ENV/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# macOS +.DS_Store + +# 临时文件 +*.tmp +*.log + diff --git a/示例项目-AI数据分析师/README.md b/示例项目-AI数据分析师/README.md new file mode 100644 index 0000000..ee38b9a --- /dev/null +++ b/示例项目-AI数据分析师/README.md @@ -0,0 +1,314 @@ +# 📊 AI 数据分析师 + +一个基于 DeepSeek API + Streamlit 的智能数据分析平台,上传 CSV 数据即可获得 AI 驱动的深度洞察和可视化报告。 + +![Python](https://img.shields.io/badge/Python-3.10+-blue.svg) +![Streamlit](https://img.shields.io/badge/Streamlit-1.28+-red.svg) +![DeepSeek](https://img.shields.io/badge/DeepSeek-API-green.svg) +![Difficulty](https://img.shields.io/badge/难度-⭐⭐⭐⭐-orange.svg) + +## ✨ 功能特性 + +| 功能 | 描述 | +|:---|:---| +| 📈 **数据预览** | 数据表格展示、统计摘要、列信息分析 | +| 📊 **智能可视化** | 根据数据类型自动生成直方图、散点图、箱线图、热力图 | +| 🤖 **AI 深度分析** | 综合分析、相关性分析、异常检测三种模式 | +| 💬 **自然语言问答** | 用中文直接询问关于数据的任何问题 | +| 📝 **报告生成** | 一键生成完整的 Markdown 格式分析报告并下载 | + +## 🖼️ 界面预览 + +``` +┌────────────────────────────────────────────────────────────────────┐ +│ 📊 AI 数据分析师 │ +│ 上传数据,让 AI 帮你发现数据中的故事 │ +├────────────────────────────────────────────────────────────────────┤ +│ [📈 数据预览] [📊 智能可视化] [🤖 AI 分析] [💬 数据问答] [📝 生成报告] │ +├────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ +│ │ 100 │ │ 7 │ │ 0 │ │ 5 │ │ +│ │ 数据行 │ │ 数据列 │ │ 缺失值 │ │ 数值列 │ │ +│ └──────┘ └──────┘ └──────┘ └──────┘ │ +│ │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ 姓名 │ 部门 │ 年龄 │ 工龄 │ 月薪 │ 绩效评分 │ 满意度 │ │ +│ │ 张三 │ 技术部 │ 28 │ 3 │ 15000 │ 85.5 │ 4.2 │ │ +│ │ 李四 │ 市场部 │ 32 │ 5 │ 18000 │ 78.3 │ 3.8 │ │ +│ │ ... │ ... │ ... │ ... │ ... │ ... │ ... │ │ +│ └─────────────────────────────────────────────────────────────┘ │ +│ │ +└────────────────────────────────────────────────────────────────────┘ +``` + +## 🚀 快速开始 + +### 1. 进入项目目录 + +```bash +cd 示例项目-AI数据分析师 +``` + +### 2. 创建虚拟环境(推荐) + +```bash +python -m venv venv + +# Windows +venv\Scripts\activate + +# macOS/Linux +source venv/bin/activate +``` + +### 3. 安装依赖 + +```bash +pip install -r requirements.txt +``` + +### 4. 配置 API Key + +创建 `.env` 文件: + +```bash +echo "DEEPSEEK_API_KEY=sk-your-api-key" > .env +``` + +或直接在应用界面的侧边栏输入 API Key。 + +### 5. 运行应用 + +```bash +streamlit run app.py +``` + +浏览器会自动打开 http://localhost:8501 + +## 📁 项目结构 + +``` +示例项目-AI数据分析师/ +├── app.py # 主程序 (~600行) +├── requirements.txt # 项目依赖 +├── sample_data.csv # 示例数据(员工信息) +├── .env # 环境变量(需自行创建) +├── .gitignore # Git 忽略文件 +└── README.md # 项目说明 +``` + +## 🛠️ 技术架构 + +``` +┌─────────────────────────────────────────────────────────┐ +│ Streamlit UI │ +│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ +│ │数据预览 │ │智能可视化│ │ AI分析 │ │数据问答 │ │ +│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ +│ │ │ │ │ │ +├───────┼───────────┼───────────┼───────────┼─────────────┤ +│ ▼ ▼ ▼ ▼ │ +│ ┌─────────────────────────────────────────────────┐ │ +│ │ Pandas DataFrame │ │ +│ │ (数据处理与统计分析) │ │ +│ └─────────────────────────────────────────────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────┐ ┌─────────────────────────────────────┐ │ +│ │ Altair │ │ DeepSeek API │ │ +│ │ (可视化)│ │ (AI 分析 / 问答 / 报告生成) │ │ +│ └─────────┘ └─────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────┘ +``` + +## 🔑 核心技术点 + +### 1. 数据处理与摘要生成 + +```python +def get_data_summary(df: pd.DataFrame) -> str: + """生成数据摘要供 AI 分析""" + summary = [] + + # 基本信息 + summary.append(f"数据集包含 {len(df)} 行和 {len(df.columns)} 列。") + + # 数值列统计 + numeric_cols = df.select_dtypes(include=['number']).columns + stats = df[numeric_cols].describe().to_string() + + # ... 更多统计信息 + return "\n".join(summary) +``` + +### 2. AI 分析的 Prompt 工程 + +```python +def analyze_with_ai(client, data_summary, analysis_type): + prompts = { + "general": """你是一个专业的数据分析师... +请从以下几个方面进行分析: +1. 📊 数据概况 +2. 🔍 关键发现 +3. 📈 建议可视化 +4. ⚠️ 注意事项 +5. 💡 进一步分析建议""", + + "correlation": """分析变量之间的相关性...""", + "anomaly": """检测数据中的异常值...""" + } + + response = client.chat.completions.create( + model="deepseek-chat", + messages=[ + {"role": "system", "content": prompts[analysis_type]}, + {"role": "user", "content": f"数据摘要:\n{data_summary}"} + ] + ) + return response.choices[0].message.content +``` + +### 3. 自动可视化生成 + +```python +def create_visualizations(df): + """根据数据类型自动选择合适的图表""" + charts = [] + numeric_cols = df.select_dtypes(include=['number']).columns + cat_cols = df.select_dtypes(include=['object']).columns + + # 数值分布 -> 直方图 + if numeric_cols: + hist_chart = alt.Chart(df).mark_bar().encode( + x=alt.X(f'{col}:Q', bin=True), + y='count()' + ) + charts.append(hist_chart) + + # 多数值变量 -> 散点图 + 相关性热力图 + # 分类+数值 -> 箱线图 + # ... + + return charts +``` + +### 4. 多轮对话的上下文管理 + +```python +def ask_data_question(client, data_summary, question, chat_history): + messages = [ + {"role": "system", "content": "你是数据分析助手..."}, + {"role": "user", "content": f"数据摘要:\n{data_summary}"}, + {"role": "assistant", "content": "我已了解数据,请问您想知道什么?"} + ] + + # 添加历史对话 + for msg in chat_history: + messages.append(msg) + + # 添加当前问题 + messages.append({"role": "user", "content": question}) + + return client.chat.completions.create( + model="deepseek-chat", + messages=messages + ) +``` + +### 5. Session State 管理 + +```python +# 初始化状态 +if "df" not in st.session_state: + st.session_state.df = None +if "analyses" not in st.session_state: + st.session_state.analyses = {} +if "qa_history" not in st.session_state: + st.session_state.qa_history = [] + +# 跨 Tab 共享数据 +df = st.session_state.df +``` + +## 📊 使用的 Streamlit 组件 + +| 组件 | 用途 | +|:---|:---| +| `st.tabs` | 多标签页布局 | +| `st.columns` | 统计卡片布局 | +| `st.file_uploader` | CSV 文件上传 | +| `st.dataframe` | 交互式数据表格 | +| `st.altair_chart` | Altair 图表渲染 | +| `st.chat_message` | 问答对话界面 | +| `st.chat_input` | 聊天输入框 | +| `st.session_state` | 状态管理 | +| `st.download_button` | 报告下载 | +| `st.spinner` | 加载动画 | +| `st.expander` | 可折叠区域 | + +## 🎨 Vibe Coding 开发过程 + +### 初始 Prompt + +> "帮我创建一个 AI 数据分析师应用,使用 DeepSeek API 和 Streamlit。 +> +> 功能需求: +> 1. 上传 CSV 文件,显示数据预览和统计 +> 2. 自动根据数据类型生成可视化图表(用 Altair) +> 3. AI 分析功能:综合分析、相关性分析、异常检测 +> 4. 自然语言问答,可以问关于数据的问题 +> 5. 生成 Markdown 格式的分析报告 +> +> 技术要求: +> - 使用 st.tabs 做多标签页布局 +> - 使用 st.session_state 管理状态 +> - 界面要美观,使用自定义 CSS" + +### 迭代优化 + +``` +Prompt 1: "给数据预览页添加统计卡片,显示行数、列数、缺失值等" + +Prompt 2: "让可视化更智能,根据数据类型自动选择图表类型" + +Prompt 3: "问答功能要支持多轮对话,AI 要记住之前的问题" + +Prompt 4: "报告生成功能要把之前的分析结果都整合进去" + +Prompt 5: "加一个示例数据选项,方便没有数据的用户体验" +``` + +## 🔧 扩展建议 + +如果你想进一步完善这个项目,可以考虑: + +1. **支持更多文件格式**:Excel、JSON、Parquet +2. **添加数据清洗功能**:缺失值处理、异常值处理 +3. **更丰富的可视化**:时间序列图、地理图 +4. **导出更多格式**:PDF、HTML、Word +5. **添加数据筛选器**:让用户选择分析哪些列/行 +6. **机器学习预测**:简单的回归/分类预测功能 + +## ⚠️ 注意事项 + +1. **数据大小**:大数据集(>10万行)可能导致界面卡顿 +2. **API 成本**:长文本分析和多轮问答会消耗更多 Token +3. **隐私安全**:敏感数据请在本地使用,不要上传到公共服务器 +4. **API Key 安全**:不要将 `.env` 提交到代码仓库 + +## 📚 参考资料 + +- [Streamlit 官方文档](https://docs.streamlit.io) +- [Altair 可视化文档](https://altair-viz.github.io) +- [Pandas 数据分析](https://pandas.pydata.org/docs/) +- [DeepSeek API 文档](https://platform.deepseek.com/api-docs) + +## 👤 作者 + +Python 程序设计课程设计 - 高级示例项目 + +--- + +**让数据说话,用 AI 倾听!** 📊🤖 + diff --git a/示例项目-AI数据分析师/app.py b/示例项目-AI数据分析师/app.py new file mode 100644 index 0000000..21ac70b --- /dev/null +++ b/示例项目-AI数据分析师/app.py @@ -0,0 +1,735 @@ +""" +📊 AI 数据分析师 +================== +一个基于 DeepSeek API + Streamlit 的智能数据分析应用 + +功能特性: +- 📁 上传 CSV 数据文件 +- 📈 自动生成可视化图表 +- 🤖 AI 智能分析数据特征 +- 💬 自然语言问答数据 +- 📝 生成分析报告 + +技术栈: +- Streamlit: Web 界面 +- Pandas: 数据处理 +- Altair: 数据可视化 +- DeepSeek API: AI 分析 +""" + +import streamlit as st +import pandas as pd +import altair as alt +import json +from openai import OpenAI +import os +from dotenv import load_dotenv +from io import StringIO + +# 加载环境变量 +load_dotenv() + +# ============== 配置 ============== + +API_KEY = os.getenv("DEEPSEEK_API_KEY", "") +BASE_URL = "https://api.deepseek.com" +MODEL = "deepseek-chat" + +# ============== 页面配置 ============== + +st.set_page_config( + page_title="AI 数据分析师", + page_icon="📊", + layout="wide", + initial_sidebar_state="expanded" +) + +# ============== 自定义样式 ============== + +st.markdown(""" + +""", unsafe_allow_html=True) + +# ============== 辅助函数 ============== + +def get_data_summary(df: pd.DataFrame) -> str: + """生成数据摘要文本供 AI 分析""" + summary = [] + + # 基本信息 + summary.append(f"数据集包含 {len(df)} 行和 {len(df.columns)} 列。") + summary.append(f"\n列名:{', '.join(df.columns.tolist())}") + + # 数据类型 + summary.append(f"\n\n各列数据类型:") + for col in df.columns: + dtype = str(df[col].dtype) + null_count = df[col].isnull().sum() + summary.append(f"- {col}: {dtype}, 缺失值: {null_count}") + + # 数值列统计 + numeric_cols = df.select_dtypes(include=['number']).columns.tolist() + if numeric_cols: + summary.append(f"\n\n数值列统计摘要:") + stats = df[numeric_cols].describe().to_string() + summary.append(stats) + + # 分类列信息 + cat_cols = df.select_dtypes(include=['object', 'category']).columns.tolist() + if cat_cols: + summary.append(f"\n\n分类列信息:") + for col in cat_cols[:5]: # 最多显示5个 + unique_count = df[col].nunique() + top_values = df[col].value_counts().head(5).to_dict() + summary.append(f"- {col}: {unique_count} 个唯一值, 前5个: {top_values}") + + # 样本数据 + summary.append(f"\n\n前3行数据样本:") + summary.append(df.head(3).to_string()) + + return "\n".join(summary) + + +def analyze_with_ai(client: OpenAI, data_summary: str, analysis_type: str = "general") -> str: + """使用 AI 分析数据""" + + prompts = { + "general": """你是一个专业的数据分析师。请根据以下数据摘要,提供全面的数据分析洞察。 + +请从以下几个方面进行分析: +1. 📊 数据概况:数据的整体情况和质量评估 +2. 🔍 关键发现:数据中的重要模式和特征 +3. 📈 建议可视化:推荐适合这个数据集的图表类型 +4. ⚠️ 注意事项:数据中可能存在的问题或需要注意的地方 +5. 💡 进一步分析建议:可以深入探索的方向 + +请用清晰的结构和通俗易懂的语言回答。""", + + "correlation": """你是一个专业的数据分析师。请分析以下数据中各变量之间可能存在的相关性和关联。 + +请重点分析: +1. 哪些变量之间可能存在正相关或负相关? +2. 是否存在明显的因果关系假设? +3. 建议做哪些相关性分析? + +请用通俗易懂的语言解释。""", + + "anomaly": """你是一个专业的数据分析师。请分析以下数据中可能存在的异常值或异常模式。 + +请关注: +1. 数值是否有明显的异常值? +2. 数据分布是否有异常? +3. 是否存在数据质量问题? +4. 建议如何处理这些异常? + +请给出具体的分析和建议。""" + } + + system_prompt = prompts.get(analysis_type, prompts["general"]) + + response = client.chat.completions.create( + model=MODEL, + messages=[ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": f"数据摘要:\n\n{data_summary}"} + ], + max_tokens=2000, + temperature=0.7 + ) + + return response.choices[0].message.content + + +def ask_data_question(client: OpenAI, data_summary: str, question: str, chat_history: list) -> str: + """根据数据回答用户问题""" + + system_prompt = """你是一个专业的数据分析助手。用户会就数据集提出问题,你需要根据提供的数据摘要来回答。 + +回答要求: +1. 基于数据事实回答,不要编造数据中没有的信息 +2. 如果数据摘要中没有足够信息回答问题,请诚实说明 +3. 尽可能提供具体的数字和分析 +4. 可以给出进一步分析的建议""" + + messages = [{"role": "system", "content": system_prompt}] + messages.append({"role": "user", "content": f"数据摘要:\n{data_summary}\n\n请记住这个数据摘要,我接下来会问你关于这个数据的问题。"}) + messages.append({"role": "assistant", "content": "好的,我已经了解了这个数据集的情况。请问您想了解什么?"}) + + # 添加对话历史 + for msg in chat_history: + messages.append(msg) + + # 添加当前问题 + messages.append({"role": "user", "content": question}) + + response = client.chat.completions.create( + model=MODEL, + messages=messages, + max_tokens=1500, + temperature=0.7 + ) + + return response.choices[0].message.content + + +def generate_report(client: OpenAI, data_summary: str, analyses: dict) -> str: + """生成完整的分析报告""" + + system_prompt = """你是一个专业的数据分析师,请根据数据摘要和已有的分析结果,生成一份完整的数据分析报告。 + +报告格式要求: +1. 使用 Markdown 格式 +2. 包含标题、摘要、详细分析、结论和建议 +3. 结构清晰,层次分明 +4. 语言专业但易懂 +5. 适当使用 emoji 增加可读性""" + + user_content = f"""数据摘要: +{data_summary} + +已有分析结果: +{json.dumps(analyses, ensure_ascii=False, indent=2)} + +请生成一份完整的数据分析报告。""" + + response = client.chat.completions.create( + model=MODEL, + messages=[ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_content} + ], + max_tokens=3000, + temperature=0.7 + ) + + return response.choices[0].message.content + + +def create_visualizations(df: pd.DataFrame): + """根据数据自动生成可视化图表""" + charts = [] + + numeric_cols = df.select_dtypes(include=['number']).columns.tolist() + cat_cols = df.select_dtypes(include=['object', 'category']).columns.tolist() + + # 1. 数值分布直方图(第一个数值列) + if numeric_cols: + col = numeric_cols[0] + hist_chart = alt.Chart(df).mark_bar( + opacity=0.7, + color='#667eea' + ).encode( + alt.X(f'{col}:Q', bin=alt.Bin(maxbins=30), title=col), + alt.Y('count()', title='频数'), + tooltip=[alt.Tooltip(f'{col}:Q', bin=alt.Bin(maxbins=30)), 'count()'] + ).properties( + title=f'📊 {col} 分布直方图', + height=300 + ) + charts.append(('distribution', hist_chart, f'{col} 的数值分布')) + + # 2. 分类计数柱状图(第一个分类列) + if cat_cols: + col = cat_cols[0] + if df[col].nunique() <= 20: # 类别不要太多 + bar_chart = alt.Chart(df).mark_bar( + color='#764ba2' + ).encode( + x=alt.X(f'{col}:N', sort='-y', title=col), + y=alt.Y('count()', title='计数'), + tooltip=[col, 'count()'] + ).properties( + title=f'📈 {col} 分类计数', + height=300 + ) + charts.append(('category', bar_chart, f'{col} 各类别的计数')) + + # 3. 散点图(如果有多个数值列) + if len(numeric_cols) >= 2: + col1, col2 = numeric_cols[0], numeric_cols[1] + color_col = cat_cols[0] if cat_cols and df[cat_cols[0]].nunique() <= 10 else None + + scatter_encoding = { + 'x': alt.X(f'{col1}:Q', title=col1), + 'y': alt.Y(f'{col2}:Q', title=col2), + 'tooltip': [col1, col2] + } + + if color_col: + scatter_encoding['color'] = alt.Color(f'{color_col}:N', title=color_col) + scatter_encoding['tooltip'].append(color_col) + + scatter_chart = alt.Chart(df).mark_circle( + size=60, + opacity=0.6 + ).encode( + **scatter_encoding + ).properties( + title=f'🔵 {col1} vs {col2} 散点图', + height=350 + ).interactive() + + charts.append(('scatter', scatter_chart, f'{col1} 与 {col2} 的关系')) + + # 4. 箱线图(数值列按分类) + if numeric_cols and cat_cols: + num_col = numeric_cols[0] + cat_col = cat_cols[0] + if df[cat_col].nunique() <= 10: + box_chart = alt.Chart(df).mark_boxplot( + color='#11998e' + ).encode( + x=alt.X(f'{cat_col}:N', title=cat_col), + y=alt.Y(f'{num_col}:Q', title=num_col), + color=alt.Color(f'{cat_col}:N', legend=None) + ).properties( + title=f'📦 {num_col} 按 {cat_col} 分组箱线图', + height=300 + ) + charts.append(('boxplot', box_chart, f'{num_col} 在不同 {cat_col} 下的分布')) + + # 5. 相关性热力图(如果有多个数值列) + if len(numeric_cols) >= 3: + corr_df = df[numeric_cols].corr().reset_index().melt(id_vars='index') + corr_df.columns = ['var1', 'var2', 'correlation'] + + heatmap = alt.Chart(corr_df).mark_rect().encode( + x=alt.X('var1:N', title=''), + y=alt.Y('var2:N', title=''), + color=alt.Color('correlation:Q', + scale=alt.Scale(scheme='redblue', domain=[-1, 1]), + title='相关系数'), + tooltip=['var1', 'var2', alt.Tooltip('correlation:Q', format='.2f')] + ).properties( + title='🔥 相关性热力图', + height=300 + ) + charts.append(('heatmap', heatmap, '各数值变量间的相关性')) + + return charts + + +# ============== 初始化 Session State ============== + +if "df" not in st.session_state: + st.session_state.df = None + +if "data_summary" not in st.session_state: + st.session_state.data_summary = None + +if "analyses" not in st.session_state: + st.session_state.analyses = {} + +if "qa_history" not in st.session_state: + st.session_state.qa_history = [] + +# ============== 侧边栏 ============== + +with st.sidebar: + st.markdown("## 🔧 设置") + + # API Key 输入 + api_key_input = st.text_input( + "DeepSeek API Key", + value=API_KEY, + type="password", + help="输入你的 DeepSeek API Key" + ) + + if api_key_input: + API_KEY = api_key_input + + st.divider() + + # 文件上传 + st.markdown("## 📁 数据上传") + + uploaded_file = st.file_uploader( + "上传 CSV 文件", + type=['csv'], + help="支持 CSV 格式的数据文件" + ) + + # 或使用示例数据 + use_sample = st.checkbox("使用示例数据", value=False) + + if use_sample: + # 生成示例数据 + import numpy as np + np.random.seed(42) + + sample_df = pd.DataFrame({ + '姓名': [f'员工{i}' for i in range(1, 101)], + '部门': np.random.choice(['技术部', '市场部', '财务部', '人事部', '运营部'], 100), + '年龄': np.random.randint(22, 55, 100), + '工龄': np.random.randint(1, 20, 100), + '月薪': np.random.randint(8000, 50000, 100), + '绩效评分': np.round(np.random.uniform(60, 100, 100), 1), + '满意度': np.round(np.random.uniform(1, 5, 100), 1) + }) + + st.session_state.df = sample_df + st.session_state.data_summary = get_data_summary(sample_df) + st.success("✅ 已加载示例数据") + + elif uploaded_file is not None: + try: + df = pd.read_csv(uploaded_file) + st.session_state.df = df + st.session_state.data_summary = get_data_summary(df) + st.session_state.analyses = {} # 重置分析结果 + st.session_state.qa_history = [] # 重置问答历史 + st.success(f"✅ 成功加载 {len(df)} 行数据") + except Exception as e: + st.error(f"❌ 文件加载失败: {str(e)}") + + # 显示数据信息 + if st.session_state.df is not None: + st.divider() + st.markdown("### 📊 数据概览") + df = st.session_state.df + st.markdown(f"- **行数**: {len(df)}") + st.markdown(f"- **列数**: {len(df.columns)}") + st.markdown(f"- **数值列**: {len(df.select_dtypes(include=['number']).columns)}") + st.markdown(f"- **分类列**: {len(df.select_dtypes(include=['object', 'category']).columns)}") + +# ============== 主界面 ============== + +st.markdown('

📊 AI 数据分析师

', unsafe_allow_html=True) +st.markdown("*上传数据,让 AI 帮你发现数据中的故事*") + +# 检查 API Key +if not API_KEY: + st.warning("⚠️ 请在侧边栏输入你的 DeepSeek API Key") + st.stop() + +# 检查数据 +if st.session_state.df is None: + st.info("👈 请在侧边栏上传 CSV 文件或使用示例数据") + + # 显示使用说明 + with st.expander("📖 使用说明", expanded=True): + st.markdown(""" + ### 欢迎使用 AI 数据分析师! + + **功能介绍:** + 1. **📈 数据预览** - 查看数据基本信息和统计摘要 + 2. **📊 智能可视化** - 自动生成适合数据的图表 + 3. **🤖 AI 分析** - AI 深度分析数据特征和洞察 + 4. **💬 数据问答** - 用自然语言询问关于数据的问题 + 5. **📝 生成报告** - 一键生成完整的分析报告 + + **开始使用:** + 1. 在左侧边栏输入你的 DeepSeek API Key + 2. 上传 CSV 文件或勾选"使用示例数据" + 3. 切换不同标签页探索各项功能 + """) + st.stop() + +# 创建 OpenAI 客户端 +client = OpenAI(api_key=API_KEY, base_url=BASE_URL) +df = st.session_state.df + +# 创建标签页 +tab1, tab2, tab3, tab4, tab5 = st.tabs([ + "📈 数据预览", + "📊 智能可视化", + "🤖 AI 分析", + "💬 数据问答", + "📝 生成报告" +]) + +# ============== Tab 1: 数据预览 ============== +with tab1: + st.header("📈 数据预览") + + # 统计卡片 + col1, col2, col3, col4 = st.columns(4) + + with col1: + st.markdown(f""" +
+

{len(df)}

+

数据行数

+
+ """, unsafe_allow_html=True) + + with col2: + st.markdown(f""" +
+

{len(df.columns)}

+

数据列数

+
+ """, unsafe_allow_html=True) + + with col3: + missing = df.isnull().sum().sum() + st.markdown(f""" +
+

{missing}

+

缺失值数量

+
+ """, unsafe_allow_html=True) + + with col4: + numeric_cols = len(df.select_dtypes(include=['number']).columns) + st.markdown(f""" +
+

{numeric_cols}

+

数值列数量

+
+ """, unsafe_allow_html=True) + + st.markdown("---") + + # 数据表格 + st.subheader("📋 数据表格") + st.dataframe(df, use_container_width=True, height=400) + + # 统计摘要 + col_left, col_right = st.columns(2) + + with col_left: + st.subheader("📊 数值列统计") + numeric_df = df.select_dtypes(include=['number']) + if not numeric_df.empty: + st.dataframe(numeric_df.describe(), use_container_width=True) + else: + st.info("没有数值列") + + with col_right: + st.subheader("📝 列信息") + info_df = pd.DataFrame({ + '列名': df.columns, + '数据类型': df.dtypes.astype(str).values, + '非空值数': df.count().values, + '唯一值数': [df[col].nunique() for col in df.columns] + }) + st.dataframe(info_df, use_container_width=True, hide_index=True) + +# ============== Tab 2: 智能可视化 ============== +with tab2: + st.header("📊 智能可视化") + st.markdown("*根据数据特征自动生成适合的图表*") + + charts = create_visualizations(df) + + if not charts: + st.warning("数据列类型不足以生成可视化图表") + else: + for i, (chart_type, chart, description) in enumerate(charts): + st.markdown(f"**{description}**") + st.altair_chart(chart, use_container_width=True) + if i < len(charts) - 1: + st.divider() + +# ============== Tab 3: AI 分析 ============== +with tab3: + st.header("🤖 AI 智能分析") + + analysis_type = st.selectbox( + "选择分析类型", + options=[ + ("general", "🔍 综合分析 - 全面了解数据特征"), + ("correlation", "🔗 相关性分析 - 探索变量间关系"), + ("anomaly", "⚠️ 异常检测 - 发现数据问题") + ], + format_func=lambda x: x[1] + ) + + if st.button("🚀 开始 AI 分析", type="primary", use_container_width=True): + with st.spinner("AI 正在分析数据,请稍候..."): + try: + result = analyze_with_ai( + client, + st.session_state.data_summary, + analysis_type[0] + ) + st.session_state.analyses[analysis_type[0]] = result + st.success("✅ 分析完成!") + except Exception as e: + st.error(f"❌ 分析出错: {str(e)}") + + # 显示分析结果 + if analysis_type[0] in st.session_state.analyses: + st.markdown("### 📋 分析结果") + st.markdown(st.session_state.analyses[analysis_type[0]]) + + # 显示历史分析 + other_analyses = {k: v for k, v in st.session_state.analyses.items() if k != analysis_type[0]} + if other_analyses: + st.divider() + with st.expander("📚 查看其他分析结果"): + for key, value in other_analyses.items(): + type_names = {"general": "综合分析", "correlation": "相关性分析", "anomaly": "异常检测"} + st.markdown(f"#### {type_names.get(key, key)}") + st.markdown(value) + st.divider() + +# ============== Tab 4: 数据问答 ============== +with tab4: + st.header("💬 数据问答") + st.markdown("*用自然语言询问关于数据的任何问题*") + + # 示例问题 + with st.expander("💡 示例问题"): + st.markdown(""" + - 这个数据集的主要特征是什么? + - 哪个部门的平均薪资最高? + - 年龄和工资之间有什么关系? + - 数据中有哪些异常值? + - 如何提高员工满意度? + """) + + # 显示对话历史 + for msg in st.session_state.qa_history: + avatar = "👤" if msg["role"] == "user" else "🤖" + with st.chat_message(msg["role"], avatar=avatar): + st.markdown(msg["content"]) + + # 问题输入 + if question := st.chat_input("输入你关于数据的问题..."): + # 显示用户问题 + with st.chat_message("user", avatar="👤"): + st.markdown(question) + + # AI 回答 + with st.chat_message("assistant", avatar="🤖"): + with st.spinner("思考中..."): + try: + answer = ask_data_question( + client, + st.session_state.data_summary, + question, + st.session_state.qa_history + ) + st.markdown(answer) + + # 保存对话历史 + st.session_state.qa_history.append({"role": "user", "content": question}) + st.session_state.qa_history.append({"role": "assistant", "content": answer}) + + except Exception as e: + st.error(f"❌ 回答出错: {str(e)}") + + # 清空对话按钮 + if st.session_state.qa_history: + if st.button("🗑️ 清空对话历史"): + st.session_state.qa_history = [] + st.rerun() + +# ============== Tab 5: 生成报告 ============== +with tab5: + st.header("📝 数据分析报告") + + if not st.session_state.analyses: + st.info("💡 请先在「AI 分析」标签页进行分析,然后再生成报告") + else: + st.markdown("*基于已有分析结果生成完整的数据分析报告*") + + if st.button("📄 生成分析报告", type="primary", use_container_width=True): + with st.spinner("正在生成报告,请稍候..."): + try: + report = generate_report( + client, + st.session_state.data_summary, + st.session_state.analyses + ) + st.session_state.report = report + st.success("✅ 报告生成完成!") + except Exception as e: + st.error(f"❌ 生成报告出错: {str(e)}") + + # 显示报告 + if "report" in st.session_state: + st.markdown("---") + st.markdown(st.session_state.report) + + # 下载按钮 + st.download_button( + label="📥 下载报告 (Markdown)", + data=st.session_state.report, + file_name="数据分析报告.md", + mime="text/markdown" + ) + +# ============== 页脚 ============== +st.divider() +st.caption("Made with ❤️ using DeepSeek API + Streamlit | Python 程序设计课程设计示例") + diff --git a/示例项目-AI数据分析师/requirements.txt b/示例项目-AI数据分析师/requirements.txt new file mode 100644 index 0000000..1f57f78 --- /dev/null +++ b/示例项目-AI数据分析师/requirements.txt @@ -0,0 +1,7 @@ +streamlit>=1.28.0 +openai>=1.0.0 +python-dotenv>=1.0.0 +pandas>=2.0.0 +altair>=5.0.0 +numpy>=1.24.0 + diff --git a/示例项目-AI数据分析师/sample_data.csv b/示例项目-AI数据分析师/sample_data.csv new file mode 100644 index 0000000..3bf69d3 --- /dev/null +++ b/示例项目-AI数据分析师/sample_data.csv @@ -0,0 +1,30 @@ +姓名,部门,年龄,工龄,月薪,绩效评分,满意度 +张三,技术部,28,3,15000,85.5,4.2 +李四,市场部,32,5,18000,78.3,3.8 +王五,财务部,45,15,35000,92.1,4.5 +赵六,技术部,26,2,12000,88.7,4.0 +钱七,人事部,38,10,25000,76.5,3.5 +孙八,运营部,29,4,14000,82.3,4.1 +周九,技术部,35,8,28000,95.2,4.8 +吴十,市场部,27,3,13500,79.8,3.9 +郑十一,财务部,42,12,32000,88.9,4.3 +王十二,技术部,31,6,22000,91.5,4.6 +李十三,人事部,36,9,24000,75.2,3.4 +张十四,运营部,24,1,10000,70.5,3.2 +刘十五,技术部,33,7,25000,89.3,4.4 +陈十六,市场部,29,4,16000,81.7,4.0 +杨十七,财务部,48,18,42000,94.8,4.7 +黄十八,技术部,27,2,14000,86.2,4.1 +赵十九,人事部,41,13,28000,77.9,3.6 +钱二十,运营部,30,5,17000,83.4,4.2 +孙廿一,技术部,25,1,11000,72.8,3.3 +周廿二,市场部,34,7,21000,85.6,4.3 +吴廿三,财务部,39,11,30000,90.2,4.5 +郑廿四,技术部,28,3,16000,87.1,4.2 +王廿五,人事部,43,14,29000,78.5,3.7 +李廿六,运营部,26,2,12500,74.3,3.4 +张廿七,技术部,37,9,27000,93.6,4.7 +刘廿八,市场部,31,5,19000,80.9,3.9 +陈廿九,财务部,46,16,38000,91.8,4.6 +杨三十,技术部,29,4,18000,88.4,4.3 + diff --git a/示例项目-角色扮演聊天室/.env_example b/示例项目-角色扮演聊天室/.env_example new file mode 100644 index 0000000..995fc5c --- /dev/null +++ b/示例项目-角色扮演聊天室/.env_example @@ -0,0 +1,9 @@ +# DeepSeek API Key 配置示例 +# ================================ +# 使用方法: +# 1. 将此文件复制并重命名为 .env +# 2. 将下面的 sk-xxx... 替换为你的真实 API Key +# ================================ + +DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + diff --git a/示例项目-角色扮演聊天室/.gitignore b/示例项目-角色扮演聊天室/.gitignore new file mode 100644 index 0000000..fe0b7a4 --- /dev/null +++ b/示例项目-角色扮演聊天室/.gitignore @@ -0,0 +1,21 @@ +# 环境变量(包含敏感信息) +.env + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +venv/ +ENV/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# macOS +.DS_Store + diff --git a/示例项目-角色扮演聊天室/README.md b/示例项目-角色扮演聊天室/README.md new file mode 100644 index 0000000..8afa2f1 --- /dev/null +++ b/示例项目-角色扮演聊天室/README.md @@ -0,0 +1,220 @@ +# 🎭 AI 角色扮演聊天室 + +一个基于 DeepSeek API + Streamlit 构建的角色扮演聊天应用,支持多种预设角色和自定义角色创建。 + +![Python](https://img.shields.io/badge/Python-3.10+-blue.svg) +![Streamlit](https://img.shields.io/badge/Streamlit-1.28+-red.svg) +![DeepSeek](https://img.shields.io/badge/DeepSeek-API-green.svg) + +## ✨ 功能特性 + +- 🎭 **多种预设角色**:傲娇猫娘、智慧老者、毒舌AI、科学怪人等 +- ✨ **自定义角色**:创建你想象中的任何角色 +- 💬 **多轮对话**:保留对话历史,角色会记住上下文 +- ⚡ **流式输出**:打字机效果,实时显示 AI 回复 +- 🎨 **美观界面**:精心设计的 UI,渐变色彩和动画效果 + +## 🖼️ 界面预览 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 🎭 角色设置 │ 🎭 AI 角色扮演聊天室 │ +│ ───────────── │ ───────────────────── │ +│ 🔑 API 配置 │ │ +│ [DeepSeek API Key] │ 🐱 │ +│ ───────────── │ 正在与 小喵 对话 │ +│ 🎭 选择角色 │ │ +│ [🐱 傲娇猫娘 ▼] │ ──────────────────────────── │ +│ │ │ +│ ┌─────────────────┐ │ 👤: 你好呀! │ +│ │ 🐱 小喵 │ │ │ +│ │ 你是一个傲娇的 │ │ 🐱: 哼,才不是特意来跟你打招 │ +│ │ 猫娘... │ │ 呼的呢!...喵~ (。・ω・。) │ +│ └─────────────────┘ │ │ +│ │ ──────────────────────────── │ +│ [🗑️ 清空对话历史] │ [输入你想说的话... ] │ +└─────────────────────────────────────────────────────────────┘ +``` + +## 🚀 快速开始 + +### 1. 克隆/下载项目 + +```bash +cd 示例项目-角色扮演聊天室 +``` + +### 2. 创建虚拟环境(推荐) + +```bash +python -m venv venv + +# Windows +venv\Scripts\activate + +# macOS/Linux +source venv/bin/activate +``` + +### 3. 安装依赖 + +```bash +pip install -r requirements.txt +``` + +### 4. 配置 API Key + +复制环境变量示例文件: + +```bash +cp .env.example .env +``` + +编辑 `.env` 文件,填入你的 DeepSeek API Key: + +``` +DEEPSEEK_API_KEY=sk-your-actual-api-key +``` + +> 💡 **获取 API Key**:访问 [DeepSeek 开放平台](https://platform.deepseek.com),注册账号后在控制台创建。 + +### 5. 运行应用 + +```bash +streamlit run app.py +``` + +应用将在浏览器中自动打开,默认地址:http://localhost:8501 + +## 📁 项目结构 + +``` +示例项目-角色扮演聊天室/ +├── app.py # 主程序 +├── requirements.txt # 项目依赖 +├── .env.example # 环境变量示例 +├── .env # 环境变量(需自行创建,不要提交!) +├── .gitignore # Git 忽略文件 +└── README.md # 项目说明 +``` + +## 🎭 预设角色介绍 + +| 角色 | 名称 | 特点 | +|:---:|:---|:---| +| 🐱 | 傲娇猫娘·小喵 | 傲娇但可爱,句尾带"喵~",会用颜文字 | +| 🧙 | 智慧老者·玄清子 | 富有哲理,喜欢引用古诗词 | +| 🤖 | 毒舌AI·犀利哥 | 说话犀利一针见血,但有建设性 | +| 👨‍🔬 | 科学怪人·Dr.Eureka | 疯狂科学家,热衷科学分析 | +| 🎮 | 游戏解说·电竞小王 | 充满激情,使用游戏术语 | +| 📚 | 文艺青年·林小诗 | 说话有诗意,会即兴创作 | + +## 🛠️ 技术实现 + +### 核心技术点 + +1. **DeepSeek API 调用** + - 使用 OpenAI SDK 兼容接口 + - 流式输出(Streaming)实现打字机效果 + +2. **Streamlit 组件** + - `st.chat_message` - 聊天消息展示 + - `st.chat_input` - 聊天输入框 + - `st.session_state` - 对话历史管理 + - `st.write_stream` - 流式输出渲染 + +3. **角色扮演机制** + - System Prompt 定义角色性格和说话方式 + - 多轮对话保持角色一致性 + +### 关键代码解析 + +#### 流式输出实现 + +```python +stream = client.chat.completions.create( + model=MODEL, + messages=messages_for_api, + stream=True, # 启用流式输出 +) + +response = st.write_stream( + chunk.choices[0].delta.content or "" + for chunk in stream + if chunk.choices[0].delta.content +) +``` + +#### 对话历史管理 + +```python +# 初始化 +if "messages" not in st.session_state: + st.session_state.messages = [] + +# 添加消息 +st.session_state.messages.append({"role": "user", "content": prompt}) + +# 构建 API 请求 +messages_for_api = [ + {"role": "system", "content": system_prompt} # 角色设定 +] + st.session_state.messages # 历史消息 +``` + +## 🎨 自定义角色指南 + +创建一个好的自定义角色,需要在角色设定中包含: + +1. **身份定义**:角色是谁,背景是什么 +2. **性格特点**:外向/内向、温柔/严厉等 +3. **说话方式**:口癖、常用词、语气 +4. **对用户态度**:如何称呼用户,关系定位 +5. **特殊行为**:是否使用emoji、颜文字等 + +### 示例:创建一个"中二少年"角色 + +``` +你是一个中二病少年,自称"黑暗骑士·雷恩"。你的特点: +- 认为自己拥有被封印的黑暗力量 +- 经常用"我的右手又在疼了..."这样的台词 +- 说话夸张,喜欢用"区区凡人"称呼用户 +- 会假装痛苦地按住眼睛说"黑暗之眼快要觉醒了" +- 其实很好说话,问什么都会认真回答(虽然用中二的方式) +``` + +## 📝 开发心得 + +这个项目使用 **Vibe Coding** 方式开发,主要通过自然语言描述需求,让 AI 代码编辑器生成代码。 + +**开发过程中的 Prompt 示例:** + +> "帮我创建一个角色扮演聊天应用,使用 DeepSeek API 和 Streamlit。 +> 要求:左侧边栏选择角色,支持自定义角色,聊天界面要美观, +> 使用流式输出,要保存对话历史。" + +**迭代优化:** + +> "给界面加上渐变色效果,让角色卡片更好看一些" + +> "添加一个清空对话的按钮" + +## ⚠️ 注意事项 + +1. **保护 API Key**:不要将 `.env` 文件提交到代码仓库 +2. **控制成本**:DeepSeek API 按 Token 计费,长对话会消耗更多 Token +3. **角色设定**:过长的 System Prompt 会增加每次请求的成本 + +## 📚 参考资料 + +- [DeepSeek API 文档](https://platform.deepseek.com/api-docs) +- [Streamlit 官方文档](https://docs.streamlit.io) +- [OpenAI Python SDK](https://github.com/openai/openai-python) + +## 👤 作者 + +Python 程序设计课程设计 - 示例项目 + +--- + +**Happy Vibe Coding! 🚀** + diff --git a/示例项目-角色扮演聊天室/app.py b/示例项目-角色扮演聊天室/app.py new file mode 100644 index 0000000..57cc3fa --- /dev/null +++ b/示例项目-角色扮演聊天室/app.py @@ -0,0 +1,379 @@ +""" +AI 角色扮演聊天室 +================ +一个基于 DeepSeek API + Streamlit 的角色扮演聊天应用 + +功能特性: +- 🎭 多种预设角色可选 +- ✨ 支持自定义角色 +- 💬 多轮对话,保留历史 +- ⚡ 流式输出,打字机效果 +- 🎨 美观的聊天界面 +""" + +import streamlit as st +from openai import OpenAI +import os +from dotenv import load_dotenv + +# 加载环境变量 +load_dotenv() + +# ============== 配置区域 ============== + +# DeepSeek API 配置 +API_KEY = os.getenv("DEEPSEEK_API_KEY", "") +BASE_URL = "https://api.deepseek.com" +MODEL = "deepseek-chat" + +# 预设角色配置 +PRESET_CHARACTERS = { + "🐱 傲娇猫娘": { + "name": "小喵", + "avatar": "🐱", + "system_prompt": """你是一个傲娇的猫娘,名叫小喵。你的性格特点: +- 说话时经常在句尾加上"喵~" +- 表面上高冷傲娇,其实内心很温柔 +- 偶尔会用"哼"、"才不是呢"这样的口癖 +- 对主人(用户)有点小傲娇,但会认真回答问题 +- 会用一些可爱的颜文字,如 (。・ω・。) 、(=^・ω・^=) +请保持角色扮演,用可爱傲娇的方式回应用户。""" + }, + "🧙 智慧老者": { + "name": "玄清子", + "avatar": "🧙", + "system_prompt": """你是一位睿智的老者,道号玄清子,已修行百年。你的特点: +- 说话富有哲理,喜欢用比喻和寓言 +- 经常引用古诗词或经典语录 +- 对人生有深刻的洞察 +- 语气平和从容,有种看透世事的淡然 +- 会称呼用户为"施主"或"年轻人" +请以智慧老者的身份,用富有哲理的方式回应用户。""" + }, + "🤖 毒舌AI": { + "name": "犀利哥", + "avatar": "🤖", + "system_prompt": """你是一个毒舌但有道理的AI助手,叫犀利哥。你的特点: +- 说话直接犀利,一针见血 +- 喜欢吐槽,但吐槽中带着真知灼见 +- 会用幽默讽刺的方式指出问题 +- 虽然嘴毒但其实是刀子嘴豆腐心 +- 偶尔会说"我说的对吧?"来确认 +请保持毒舌但有建设性的风格回应用户。注意:吐槽要有分寸,不要真的伤害用户。""" + }, + "👨‍🔬 科学怪人": { + "name": "Dr. Eureka", + "avatar": "👨‍🔬", + "system_prompt": """你是一个疯狂但天才的科学家,叫 Dr. Eureka。你的特点: +- 对科学充满狂热的热情 +- 说话时经常穿插科学术语和公式 +- 喜欢说"Eureka!"(我发现了!) +- 会把日常问题用科学角度来分析 +- 经常有一些异想天开但有道理的想法 +- 语气夸张,充满戏剧性 +请以疯狂科学家的身份,用充满科学热情的方式回应用户。""" + }, + "🎮 游戏解说": { + "name": "电竞小王", + "avatar": "🎮", + "system_prompt": """你是一个热情的游戏主播/解说,叫电竞小王。你的特点: +- 说话充满激情和能量 +- 经常使用游戏术语和梗 +- 喜欢用"老铁"、"兄弟们"称呼用户 +- 会把问题类比成游戏场景 +- 偶尔会喊出"666"、"太强了"等口头禅 +- 语气热血,像在解说比赛一样 +请以游戏解说的风格,用充满激情的方式回应用户。""" + }, + "📚 文艺青年": { + "name": "林小诗", + "avatar": "📚", + "system_prompt": """你是一个文艺气息浓厚的青年,叫林小诗。你的特点: +- 说话富有诗意和文学性 +- 喜欢引用诗词、文学作品 +- 对生活中的小事有独特的感悟 +- 偶尔会即兴写一两句诗 +- 语气温柔感性,有点小忧郁 +- 喜欢用省略号营造氛围感 +请以文艺青年的身份,用充满诗意的方式回应用户。""" + } +} + +# ============== 页面配置 ============== + +st.set_page_config( + page_title="AI 角色扮演聊天室", + page_icon="🎭", + layout="wide", + initial_sidebar_state="expanded" +) + +# ============== 自定义样式 ============== + +st.markdown(""" + +""", unsafe_allow_html=True) + +# ============== 初始化 Session State ============== + +if "messages" not in st.session_state: + st.session_state.messages = [] + +if "current_character" not in st.session_state: + st.session_state.current_character = None + +if "character_config" not in st.session_state: + st.session_state.character_config = None + +# ============== 侧边栏 ============== + +with st.sidebar: + st.title("🎭 角色设置") + + # API Key 输入 + st.subheader("🔑 API 配置") + api_key_input = st.text_input( + "DeepSeek API Key", + value=API_KEY, + type="password", + help="请输入你的 DeepSeek API Key" + ) + + if api_key_input: + API_KEY = api_key_input + + st.divider() + + # 角色选择 + st.subheader("🎭 选择角色") + + # 预设角色选择 + character_options = ["🎨 自定义角色"] + list(PRESET_CHARACTERS.keys()) + selected_character = st.selectbox( + "预设角色", + options=character_options, + index=0 if st.session_state.current_character is None else ( + character_options.index(st.session_state.current_character) + if st.session_state.current_character in character_options + else 0 + ) + ) + + # 自定义角色设置 + if selected_character == "🎨 自定义角色": + st.markdown("---") + st.markdown("**✨ 创建你的专属角色**") + + custom_name = st.text_input("角色名称", placeholder="例如:小助手") + custom_avatar = st.selectbox( + "选择头像", + options=["🤖", "👽", "🦊", "🐼", "🦁", "🐸", "👻", "🎃", "🌟", "💫"], + index=0 + ) + custom_prompt = st.text_area( + "角色设定", + placeholder="描述角色的性格、说话方式、特点等...\n\n例如:你是一个活泼开朗的助手,喜欢用emoji表情,说话很有活力...", + height=150 + ) + + if custom_name and custom_prompt: + st.session_state.character_config = { + "name": custom_name, + "avatar": custom_avatar, + "system_prompt": custom_prompt + } + st.session_state.current_character = "🎨 自定义角色" + else: + # 使用预设角色 + st.session_state.character_config = PRESET_CHARACTERS[selected_character] + st.session_state.current_character = selected_character + + # 显示角色信息 + config = PRESET_CHARACTERS[selected_character] + st.markdown(f""" +
+

{config['avatar']} {config['name']}

+

{config['system_prompt'][:100]}...

+
+ """, unsafe_allow_html=True) + + st.divider() + + # 清空对话按钮 + if st.button("🗑️ 清空对话历史", use_container_width=True): + st.session_state.messages = [] + st.rerun() + + # 显示统计信息 + st.divider() + st.caption(f"📊 当前对话: {len(st.session_state.messages)} 条消息") + +# ============== 主界面 ============== + +st.title("🎭 AI 角色扮演聊天室") + +# 检查配置 +if not API_KEY: + st.warning("⚠️ 请在侧边栏输入你的 DeepSeek API Key") + st.info(""" + **如何获取 API Key?** + 1. 访问 [DeepSeek 开放平台](https://platform.deepseek.com) + 2. 注册并登录账号 + 3. 进入控制台创建 API Key + """) + st.stop() + +if not st.session_state.character_config: + st.info("👈 请在侧边栏选择一个角色或创建自定义角色") + st.stop() + +# 显示当前角色信息 +current_config = st.session_state.character_config +col1, col2 = st.columns([1, 4]) +with col1: + st.markdown(f"

{current_config['avatar']}

", unsafe_allow_html=True) +with col2: + st.markdown(f"### 正在与 **{current_config['name']}** 对话") + st.caption("试着和 TA 聊聊天吧!") + +st.divider() + +# 创建 OpenAI 客户端 +client = OpenAI(api_key=API_KEY, base_url=BASE_URL) + +# 显示对话历史 +for message in st.session_state.messages: + avatar = current_config["avatar"] if message["role"] == "assistant" else "👤" + with st.chat_message(message["role"], avatar=avatar): + st.markdown(message["content"]) + +# 用户输入 +if prompt := st.chat_input("输入你想说的话..."): + # 添加用户消息 + st.session_state.messages.append({"role": "user", "content": prompt}) + with st.chat_message("user", avatar="👤"): + st.markdown(prompt) + + # 构建完整的消息列表 + messages_for_api = [ + {"role": "system", "content": current_config["system_prompt"]} + ] + st.session_state.messages + + # 调用 API 并流式输出 + with st.chat_message("assistant", avatar=current_config["avatar"]): + try: + stream = client.chat.completions.create( + model=MODEL, + messages=messages_for_api, + stream=True, + max_tokens=2000, + temperature=0.8, # 稍高的温度让角色更有个性 + ) + + response = st.write_stream( + chunk.choices[0].delta.content or "" + for chunk in stream + if chunk.choices[0].delta.content + ) + + # 保存助手回复 + st.session_state.messages.append({"role": "assistant", "content": response}) + + except Exception as e: + st.error(f"❌ 调用 API 出错: {str(e)}") + st.info("请检查 API Key 是否正确,以及网络连接是否正常。") + +# ============== 底部信息 ============== + +st.divider() + +with st.expander("💡 使用提示"): + st.markdown(""" + **如何获得更好的角色扮演体验?** + + 1. **选择合适的角色**:不同角色有不同的说话风格和个性 + 2. **融入角色设定**:尝试用符合角色世界观的方式提问 + 3. **自定义角色**:发挥创意,创建你想要的任何角色 + 4. **多轮对话**:角色会记住之前的对话内容 + + **自定义角色技巧:** + - 明确角色的性格特点 + - 定义说话方式和口癖 + - 设定角色的背景故事 + - 指定角色对用户的称呼 + """) + +st.caption("Made with ❤️ using DeepSeek API + Streamlit | Python 程序设计课程设计示例") + diff --git a/示例项目-角色扮演聊天室/requirements.txt b/示例项目-角色扮演聊天室/requirements.txt new file mode 100644 index 0000000..52ce1f1 --- /dev/null +++ b/示例项目-角色扮演聊天室/requirements.txt @@ -0,0 +1,4 @@ +streamlit>=1.28.0 +openai>=1.0.0 +python-dotenv>=1.0.0 +