From e59296fb468e2855a2f43dde02f06d16307821ee Mon Sep 17 00:00:00 2001 From: fruge365 <1656639338@qq.com> Date: Tue, 23 Dec 2025 21:24:14 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=AC=A1=E6=8F=90?= =?UTF-8?q?=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 26 ++ README.md | 80 ++--- app.py | 5 + config.py | 19 ++ core/agents.py | 49 +++ core/prompts.py | 32 ++ requirements.txt | 2 + server.py | 58 ++++ templates/analytics.html | 113 +++++++ templates/base.html | 79 +++++ templates/index.html | 254 +++++++++++++++ templates/knowledge.html | 89 ++++++ templates/mistakes.html | 116 +++++++ ui/components.py | 69 +++++ ui/interface.py | 109 +++++++ ui/styles.py | 293 ++++++++++++++++++ ...00\346\234\257\346\226\207\346\241\243.md" | 74 +++++ 17 files changed, 1412 insertions(+), 55 deletions(-) create mode 100644 .gitignore create mode 100644 app.py create mode 100644 config.py create mode 100644 core/agents.py create mode 100644 core/prompts.py create mode 100644 requirements.txt create mode 100644 server.py create mode 100644 templates/analytics.html create mode 100644 templates/base.html create mode 100644 templates/index.html create mode 100644 templates/knowledge.html create mode 100644 templates/mistakes.html create mode 100644 ui/components.py create mode 100644 ui/interface.py create mode 100644 ui/styles.py create mode 100644 "\346\212\200\346\234\257\346\226\207\346\241\243.md" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..81b49c1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class + +# Virtual Environment +.venv/ +venv/ +env/ + +# Environment Variables / Secrets +env.sh +.env + +# OS +.DS_Store + +# IDEs +.idea/ +.vscode/ + +# Project specific +.temp/ + +# Gradio +flagged/ diff --git a/README.md b/README.md index 6446d62..7459ec9 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,25 @@ -# 造浪2025AIAgent创新赛 - -#### 介绍 -在数字化转型与行业智能化升级浪潮下,企业业务流程复杂度攀升,用户需求多元化。AI Agent 凭借自动化、智能化特征,可优化流程、提升效率、降低出错率,满足更多业务场景的多元化需求,提升服务质量与用户体验,革新我们的工作和生活方式。 -对此,开源中国 携手 独家冠名厂商-商汤大装置 聚焦多业务场景,携手知名技术专家、合作社区推出“造浪 2025 AI Agent 创新赛”,聚焦智慧金融、教育科技、出海辅助、本地生活等多个重点行业领域,面向企业开发者、高校科研团队及个人创客征集具备商业价值与社会效益的 AI Agent 应用。 - -![输入图片说明](%E4%BD%9C%E5%93%81%E6%8F%90%E4%BA%A4/ScreenShot_2025-11-24_190342_756.png) - -#### 我们希望看到 -- 通过 Agent 实现的创造性解决方案和产出 -- 能显著提升工作效率的 Agent 工作流 -- 探索 Agent 能力边界的实验性项目 -- 能为公众带来实际价值的 Agent 应用 - -#### 大赛亮点 -本次 AI Agent 创新赛官方指定开发框架 LazyLLM ,由商汤 LazyAGI 团队开发,具备一键部署所有模块的能力,简化了多 Agent 应用的部署流程,可依次启动各个子模块(如 LLM 、Embedding 等)服务并配置 URL 的问题,使整个过程更加顺畅高效。 - -- 跨平台兼容:无需修改代码,即可一键切换操作系统和IaaS平台,目前兼容裸金属服务器、开发机、Slurm集群、公有云等。这使得开发中的应用可以无缝迁移到其他IaaS平台,大大减少了代码修改的工作量。 -- 统一的使用体验:统一了不同服务商的线上模型和本地部署模型的使用体验,使得开发者可以随意的切换和升级自己的模型进行尝试。此外,还统一了主流的推理框架、微调框架、关系型数据库、向量数据库、文档数据库的使用体验。 -- 高效的模型微调:支持对应用中的模型进行微调,持续提升应用效果。根据微调场景,自动选择最佳的微调框架和模型切分策略。这不仅简化了模型迭代的维护工作,还让算法研究员能够将更多精力集中在算法和数据迭代上,而无需处理繁琐的工程化任务。 - -#### 赛题设计 - -1. 智慧金融 -- 开发一款能分析合同审核的智能Agent -- 开发一款具备风险预警的多模态Agent - -2. 教育科技 -- 开发一款教案/长篇技术文档生成Agent -- 开发一款多模态作业批改的教培Agent - -3. 出海辅助 -- 开发一款跨境电商选品的Agent -- 开发一款收录各大独立站的资讯Agent - -#### 参赛规则 - -一、作品要求: -- 需提交完整的作品方案介绍文档、项目源代码。 -- 参赛者提交的参赛作品必须为原创作品,不得侵犯任何第三方的著作权、商标权及其他知识产权,且不得违反国家相关法律法规,否则将取消其本届大赛的参赛资格; -- 参赛作品应能正常运行并可达到参赛赛项规定的预期结果。参赛作品应与设计文档描述的功能一致。如参赛作品未能实现设计文档中描述的所有功能,应注明未实现功能、占比及其重要程度。 -- 参赛作品的代码注释应清晰、简洁、准确地描述其设计思路、功能和原理等,以提升代码的可读性和可维护性。 - -二、LazyLLM 相关链接 -- 官方文档:https://docs.lazyllm.ai/zh-cn/latest/ -- 下载链接:https://github.com/LazyAGI/LazyLLM - -三、作品提交 -- 作品需要使用商汤 LazyAGI 团队开发到 LazyLLM 开源低代码大模型应用开发工具进行开发,该工具提供从应用搭建、数据准备、模型部署、微调到评测的一站式工具支持,以极低的成本快速构建 AI 应用—— -- 作品提交内容包含:Agent 系统本体、技术文档(项目简介、成员贡献清单、技术栈、架构设计、部署说明)可选:操作录屏视频(≤5min,可以发布在网盘设置公开可见) - -#### 组委会联系方式 -刘老师 :liuyang3@oschina.cn 王老师 :wanghao@oschina.cn - -* 大赛解释权归大会组委会所有 +# 智启学伴 (Smart Learning Companion) + +## 简介 +“智启学伴”是一款专为 K12 及终身学习者打造的智能化 AI 教育助手,基于 LazyLLM 框架开发。它突破了传统在线教育的单向灌输模式,采用 Multi-Agent(多智能体)架构,集成了“定制规划”、“学科答疑”、“知识复盘”和“情感陪伴”四大核心能力。 + +系统能够像真人私教一样,精准识别学生的薄弱知识点,自动生成个性化的学习路径;在答疑过程中,它不仅给出答案,更通过苏格拉底式提问引导学生独立思考;同时,其内置的错题本和学习分析仪表盘,能实时反馈学习进度,帮助用户科学高效地提升学业表现,真正实现“因材施教”的教育愿景。 + +## 快速开始 + +### 1. 配置 API Key +```bash +# 编辑 env.sh +export LAZYLLM_GLM_API_KEY="your_key" +``` + +### 2. 启动应用 +```bash +# 安装依赖 +pip install -r requirements.txt + +# 启动 +python3 app.py +``` + +更多详情请查阅 [技术文档.md](技术文档.md)。 diff --git a/app.py b/app.py new file mode 100644 index 0000000..04e5c2a --- /dev/null +++ b/app.py @@ -0,0 +1,5 @@ +from ui.interface import MainInterface + +if __name__ == "__main__": + app = MainInterface() + app.launch() diff --git a/config.py b/config.py new file mode 100644 index 0000000..a515aa4 --- /dev/null +++ b/config.py @@ -0,0 +1,19 @@ +import os + +class Config: + @staticmethod + def load_keys(): + if os.path.exists('env.sh'): + with open('env.sh', 'r') as f: + for line in f: + if line.startswith('export '): + k, v = line.replace('export ', '').strip().split('=', 1) + os.environ[k] = v.strip('"\'') + + @staticmethod + def get_llm_source(): + if os.environ.get('LAZYLLM_GLM_API_KEY'): + return 'glm' + elif os.environ.get('LAZYLLM_DOUBAO_API_KEY'): + return 'doubao' + return 'openai' diff --git a/core/agents.py b/core/agents.py new file mode 100644 index 0000000..6815618 --- /dev/null +++ b/core/agents.py @@ -0,0 +1,49 @@ +import lazyllm +from lazyllm.tools import IntentClassifier +from lazyllm.components import AlpacaPrompter +from core.prompts import ( + SYSTEM_PROMPT_PLAN, + SYSTEM_PROMPT_TUTOR, + SYSTEM_PROMPT_REVIEW, + SYSTEM_PROMPT_CHAT +) +from config import Config + +class AgentSystem: + def __init__(self): + Config.load_keys() + self.source = Config.get_llm_source() + print(f"Using LLM Source: {self.source}") + + self.base_llm = lazyllm.OnlineChatModule(source=self.source) + self.classifier = self._build_classifier() + + def _build_classifier(self): + # Create Specialized Agents + plan_agent = self.base_llm.share( + prompt=AlpacaPrompter(dict(system=SYSTEM_PROMPT_PLAN, user="{input}")) + ) + tutor_agent = self.base_llm.share( + prompt=AlpacaPrompter(dict(system=SYSTEM_PROMPT_TUTOR, user="{input}")) + ) + review_agent = self.base_llm.share( + prompt=AlpacaPrompter(dict(system=SYSTEM_PROMPT_REVIEW, user="{input}")) + ) + chat_agent = self.base_llm.share( + prompt=AlpacaPrompter(dict(system=SYSTEM_PROMPT_CHAT, user="{input}")) + ) + + # Initialize Intent Classifier + ic = IntentClassifier(self.base_llm) + with ic: + ic.case['定制学习方案', plan_agent] + ic.case['学科答疑', tutor_agent] + ic.case['知识复盘', review_agent] + ic.case['闲聊', chat_agent] + return ic + + def chat(self, message): + try: + return self.classifier(message) + except Exception as e: + return f"System Error: {str(e)}" diff --git a/core/prompts.py b/core/prompts.py new file mode 100644 index 0000000..8246409 --- /dev/null +++ b/core/prompts.py @@ -0,0 +1,32 @@ +SYSTEM_PROMPT_PLAN = """ +你是一位专业的个性化教育顾问。你的核心任务是“因材施教”。 +请根据用户的描述(特别是知识薄弱点),为他们生成一份详细的定制化学习方案。 +方案应包括: +1. 现状分析 +2. 学习目标 +3. 详细的学习计划(分阶段) +4. 推荐的资源或练习 +请保持语气鼓励且专业。 +""" + +SYSTEM_PROMPT_TUTOR = """ +你是一位博学的学科辅导老师。你的任务是“答疑解惑”。 +请准确、清晰地回答学生提出的学科问题。 +对于复杂问题,请分步骤讲解。如果涉及公式或代码,请规范展示。 +鼓励学生多思考,而不仅仅是给出答案。 +""" + +SYSTEM_PROMPT_REVIEW = """ +你是一位负责任的复习考察老师。你的任务是“知识复盘”。 +不要直接讲解知识,而是通过模拟师生对话的方式,向用户提问,检查他们对某个知识点的掌握情况。 +采用苏格拉底式教学法,引导学生自己发现错误或完善答案。 +""" + +SYSTEM_PROMPT_CHAT = """ +你是“智启学伴”AI Agent,一款聚焦个性化教育的智能助手。 +你可以: +1. 为用户制定学习方案(请告诉我你的薄弱项) +2. 解答学科难题 +3. 进行知识点复盘和模拟考试 +请热情地引导用户使用上述功能。 +""" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..34f31ca --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +lazyllm +gradio diff --git a/server.py b/server.py new file mode 100644 index 0000000..01cc2ea --- /dev/null +++ b/server.py @@ -0,0 +1,58 @@ +from fastapi import FastAPI, Request +from fastapi.staticfiles import StaticFiles +from fastapi.templating import Jinja2Templates +from fastapi.responses import JSONResponse +from pydantic import BaseModel +import uvicorn +import os +from core.agents import AgentSystem + +# Initialize FastAPI +app = FastAPI() + +# Mount static files +app.mount("/static", StaticFiles(directory="static"), name="static") + +# Templates +templates = Jinja2Templates(directory="templates") + +# Initialize Agent System +agent_system = AgentSystem() + +class ChatRequest(BaseModel): + message: str + history: list = [] + +@app.get("/") +async def read_root(request: Request): + return templates.TemplateResponse("index.html", {"request": request, "active_tab": "chat"}) + +@app.get("/knowledge") +async def read_knowledge(request: Request): + return templates.TemplateResponse("knowledge.html", {"request": request, "active_tab": "knowledge"}) + +@app.get("/analytics") +async def read_analytics(request: Request): + return templates.TemplateResponse("analytics.html", {"request": request, "active_tab": "analytics"}) + +@app.get("/mistakes") +async def read_mistakes(request: Request): + return templates.TemplateResponse("mistakes.html", {"request": request, "active_tab": "mistakes"}) + +@app.post("/api/chat") +async def chat_endpoint(request: ChatRequest): + try: + # Here we just pass the message to the agent system + # The agent system currently returns a string + response_text = agent_system.chat(request.message) + return JSONResponse(content={"response": response_text}) + except Exception as e: + return JSONResponse(content={"error": str(e)}, status_code=500) + +def start_server(): + print("🚀 启动智启学伴 Web 服务...") + print("👉 访问地址: http://127.0.0.1:8000") + uvicorn.run(app, host="0.0.0.0", port=8000) + +if __name__ == "__main__": + start_server() diff --git a/templates/analytics.html b/templates/analytics.html new file mode 100644 index 0000000..1b7931e --- /dev/null +++ b/templates/analytics.html @@ -0,0 +1,113 @@ +{% extends "base.html" %} + +{% block content %} +
+ +
+
+

学习分析

+

数据驱动,科学提升学习效率

+
+
+ + + +
+
+ + +
+
+
⏱️
+
+

本周学习时长

+

12.5 小时

+
+
+
+
+
+

题目掌握率

+

85% ↑ 2%

+
+
+
+
🔥
+
+

连续打卡

+

7

+
+
+
+ + +
+ +
+

学习投入趋势

+ +
+ + +
+

学科能力雷达

+
+ +
+
+
+
+ + +{% endblock %} diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..8d3f128 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,79 @@ + + + + + + 智启学伴 - 您的专属 AI 学习助手 + + + + + + + + + + + + + +
+ {% block content %}{% endblock %} +
+ + + diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..e77e44b --- /dev/null +++ b/templates/index.html @@ -0,0 +1,254 @@ +{% extends "base.html" %} + +{% block content %} + +
+ 智启学伴 +
+ + +
+ +
+
+ +
+

+ 你好,同学!
今天想攻克什么难题? +

+

+ 我是你的专属 AI 学习助手。基于 LazyLLM 驱动,为你提供定制化的学习支持。 +

+ + +
+ + + + + + + +
+
+ + + +
+ + +
+
+
+ + + +
+

+ AI 生成内容仅供参考,请以教材为准 +

+
+
+ + + +{% endblock %} diff --git a/templates/knowledge.html b/templates/knowledge.html new file mode 100644 index 0000000..b7c6071 --- /dev/null +++ b/templates/knowledge.html @@ -0,0 +1,89 @@ +{% extends "base.html" %} + +{% block content %} +
+ +
+
+

我的知识库

+

管理您的学习资料、笔记和视频课程

+
+ +
+ + +
+
+ 🔍 + +
+
+ + + + +
+
+ + +
+ +
+
+
📕
+ PDF +
+

高中数学必修一重点公式汇总

+

包含集合、函数概念、基本初等函数等核心考点。

+
+ 2.4 MB + 2023-10-24 +
+
+ + +
+
+
🎥
+ Video +
+

牛顿运动定律详解(名师课)

+

深入浅出讲解牛顿三大定律及其应用场景。

+
+ 45 min + 2023-11-02 +
+
+ + +
+
+
📝
+ Note +
+

英语定语从句错题整理

+

个人整理的易错题集,包含详细解析。

+
+ 12 Items + 2023-11-15 +
+
+ + +
+
+
🧠
+ MindMap +
+

化学反应原理思维导图

+

涵盖热化学、电化学、化学平衡等章节。

+
+ Image + 2023-12-01 +
+
+
+
+{% endblock %} diff --git a/templates/mistakes.html b/templates/mistakes.html new file mode 100644 index 0000000..604053a --- /dev/null +++ b/templates/mistakes.html @@ -0,0 +1,116 @@ +{% extends "base.html" %} + +{% block content %} +
+ +
+
+

智能错题本

+

自动归纳错题,针对性强化训练

+
+
+
+ +
+ +
+
+ +
+
+ + +
+ +
+
+ + 数学 · 函数 + + 2023-11-20 +
+

+ 已知函数 f(x) = ln(x^2 + 1) + ax,若 f(x) 在区间 (0, 1) 上单调递增,求实数 a 的取值范围。 +

+ +
+
+
+ 你的答案 + a ≥ -1 +
+
+ 正确答案 + a ≥ 0 +
+
+
+ +
+ +
+ + +
+
+ +
+ + +
+
+ + 物理 · 力学 + + 2023-11-18 +
+

+ 一物体在水平面上做匀速直线运动,受到水平拉力 F 的作用。若拉力 F 突然增大为 2F,则物体的加速度大小为?(设摩擦力不变) +

+ +
+
+
+ 你的答案 + F/m +
+
+ 正确答案 + F/m (需要考虑摩擦力 f = F) +
+
+
+ +
+ +
+ + +
+
+ +
+
+
+{% endblock %} diff --git a/ui/components.py b/ui/components.py new file mode 100644 index 0000000..bffa446 --- /dev/null +++ b/ui/components.py @@ -0,0 +1,69 @@ +# Components for the Doubao-like UI + +SIDEBAR_HTML = """ + +""" + +WELCOME_HTML = """ +
+ +
你好,同学!今天想攻克什么难题?
+
我是你的专属 AI 学习助手。无论是制定计划、解答难题,还是知识复盘,我都能帮你轻松搞定。
+ +
+
+
📅
+
+
制定英语单词计划
+
科学规划,高效记忆
+
+
+
+
💡
+
+
讲解牛顿第二定律
+
深入浅出,举例说明
+
+
+
+
📝
+
+
三角函数知识自测
+
模拟考试,查漏补缺
+
+
+
+
🧘
+
+
学习压力疏导
+
调整心态,提升效率
+
+
+
+
+""" diff --git a/ui/interface.py b/ui/interface.py new file mode 100644 index 0000000..a26f979 --- /dev/null +++ b/ui/interface.py @@ -0,0 +1,109 @@ +import gradio as gr +from core.agents import AgentSystem +from ui.styles import CUSTOM_CSS, PRIMARY_COLOR +from ui.components import SIDEBAR_HTML, WELCOME_HTML + +class MainInterface: + def __init__(self): + self.system = AgentSystem() + + def respond(self, message, history): + if not message: + return "", history + + # Add user message immediately + history.append((message, None)) + + try: + response = self.system.chat(message) + except Exception as e: + response = f"System Error: {str(e)}" + + # Update history with response + history[-1] = (message, response) + return "", history + + def launch(self): + # Using a custom theme object to fine-tune colors + theme = gr.themes.Soft( + primary_hue="indigo", + secondary_hue="gray", + neutral_hue="gray", + radius_size="lg", + ).set( + body_background_fill="#F3F4F6", + block_background_fill="#FFFFFF", + block_border_width="0", + shadow_drop="none", + button_primary_background_fill=PRIMARY_COLOR, + button_primary_text_color="white", + ) + + with gr.Blocks(css=CUSTOM_CSS, title="智启学伴", theme=theme) as demo: + with gr.Row(elem_classes="chat-layout"): + # Sidebar (Left) + with gr.Column(scale=0, min_width=260, elem_classes="sidebar-column"): + gr.HTML(SIDEBAR_HTML) + + # Main Chat Area (Right) + with gr.Column(scale=1, elem_classes="chat-main"): + # Chatbot area + chatbot = gr.Chatbot( + elem_id="chatbot", + show_label=False, + avatar_images=(None, "assets/bot.png"), # User icon handled by CSS + bubble_full_width=False, + show_copy_button=True, + render=False + ) + + # Welcome Screen (Initially Visible) + welcome = gr.HTML(WELCOME_HTML) + + # Chat Container (To handle visibility) + with gr.Group(visible=False) as chat_group: + chatbot.render() + + # Input Area (Fixed at bottom) + with gr.Group(elem_classes="input-area-container"): + with gr.Row(elem_classes="input-box-wrapper"): + msg = gr.Textbox( + show_label=False, + placeholder="输入您的问题...", + container=False, + scale=8, + autofocus=True, + lines=1, + max_lines=5 + ) + submit_btn = gr.Button( + "➤", + variant="primary", + size="sm", + scale=0, + min_width=40, + elem_classes="send-btn" + ) + + # Logic to hide welcome screen on first message + def toggle_visibility(history): + if len(history) > 0: + return gr.update(visible=False), gr.update(visible=True) + return gr.update(visible=True), gr.update(visible=False) + + # Event Handlers + msg.submit( + self.respond, [msg, chatbot], [msg, chatbot] + ).then( + toggle_visibility, chatbot, [welcome, chat_group] + ) + + submit_btn.click( + self.respond, [msg, chatbot], [msg, chatbot] + ).then( + toggle_visibility, chatbot, [welcome, chat_group] + ) + + print("✨ 智启学伴 (DeepSeek/豆包风格) 已就绪!") + print("👉 请在浏览器打开: http://127.0.0.1:7860") + demo.launch(server_name="0.0.0.0", server_port=7860) diff --git a/ui/styles.py b/ui/styles.py new file mode 100644 index 0000000..9a8fa26 --- /dev/null +++ b/ui/styles.py @@ -0,0 +1,293 @@ +# Colors - Refined Palette +PRIMARY_COLOR = "#4F46E5" # Indigo-600 +BG_COLOR = "#FFFFFF" # White background for main area +SIDEBAR_BG = "#F9FAFB" # Light gray for sidebar +TEXT_PRIMARY = "#1F2937" # Gray-900 +TEXT_SECONDARY = "#6B7280" # Gray-500 + +CUSTOM_CSS = """ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap'); + +/* Global Reset */ +body { + font-family: 'Inter', -apple-system, system-ui, sans-serif !important; + background-color: white !important; + margin: 0; + padding: 0; +} + +.gradio-container { + max-width: 100% !important; + padding: 0 !important; + margin: 0 !important; + height: 100vh !important; + background: white !important; +} + +/* --- Sidebar (Left) --- */ +.sidebar-container { + background-color: #F9FAFB; + height: 100vh; + border-right: 1px solid #E5E7EB; + padding: 20px 16px; + display: flex; + flex-direction: column; + width: 260px; +} + +.logo-area { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 30px; + padding: 0 8px; +} + +.logo-icon { + font-size: 24px; +} + +.logo-text { + font-size: 18px; + font-weight: 600; + color: #111827; +} + +.nav-item { + padding: 10px 12px; + border-radius: 8px; + margin-bottom: 4px; + cursor: pointer; + color: #4B5563; + font-size: 14px; + font-weight: 500; + display: flex; + align-items: center; + gap: 10px; + transition: background-color 0.15s; +} + +.nav-item:hover { + background-color: #E5E7EB; + color: #111827; +} + +.nav-item.active { + background-color: #E0E7FF; /* Indigo-100 */ + color: #4F46E5; +} + +/* --- Main Chat Area (Right) --- */ +.chat-main { + flex: 1; + display: flex; + flex-direction: column; + height: 100vh; + background-color: #FFFFFF; + position: relative; +} + +/* Chatbot Component Override */ +#chatbot { + flex: 1; + overflow-y: auto; + padding: 0 !important; + height: 100% !important; + background: transparent !important; + box-shadow: none !important; + border: none !important; +} + +/* Inner wrapper for messages */ +.wrap { + max-width: 800px !important; + margin: 0 auto !important; + padding: 20px 20px 100px 20px !important; /* Bottom padding for input */ +} + +/* Message Styles */ +.message { + padding: 0 !important; + margin-bottom: 24px !important; + background: transparent !important; + border: none !important; + box-shadow: none !important; +} + +/* User Message */ +.user-message { + justify-content: flex-end; +} + +.user-message .message-content { + background-color: #F3F4F6 !important; /* Light Gray for User */ + color: #111827 !important; + border-radius: 12px !important; + padding: 12px 16px !important; + font-size: 15px !important; + line-height: 1.6 !important; + max-width: 85%; + margin-left: auto; +} + +/* Bot Message */ +.bot-message { + justify-content: flex-start; +} + +.bot-message .message-content { + background-color: transparent !important; + color: #111827 !important; + padding: 0 !important; /* No bubble look for bot, just text */ + font-size: 15px !important; + line-height: 1.7 !important; + width: 100%; +} + +/* Avatar Styling */ +.avatar-container { + width: 32px !important; + height: 32px !important; + margin-right: 12px !important; + border-radius: 50% !important; + overflow: hidden; +} + +.avatar-image { + width: 100%; + height: 100%; + object-fit: cover; +} + +/* --- Input Area (Floating Bar) --- */ +.input-area-container { + position: absolute; + bottom: 30px; + left: 50%; + transform: translateX(-50%); + width: 90%; + max-width: 800px; + z-index: 100; +} + +.input-box-wrapper { + background: #F9FAFB; /* Light gray background like ChatGPT/Claude */ + border: 1px solid transparent; + border-radius: 26px; /* Pill shape */ + padding: 10px 16px; + box-shadow: none; /* Clean look */ + display: flex; + align-items: flex-end; + gap: 10px; + transition: all 0.2s ease; +} + +.input-box-wrapper:focus-within { + background: white; + box-shadow: 0 4px 12px rgba(0,0,0,0.08); + border-color: #E5E7EB; +} + +/* Textarea Reset */ +.input-box-wrapper textarea { + background: transparent !important; + border: none !important; + box-shadow: none !important; + padding: 8px 0 !important; + font-size: 16px !important; + color: #111827 !important; + max-height: 200px; + resize: none !important; +} + +.input-box-wrapper textarea::placeholder { + color: #9CA3AF !important; +} + +/* Send Button */ +.send-btn { + width: 36px !important; + height: 36px !important; + border-radius: 50% !important; + background-color: #E5E7EB !important; + color: #9CA3AF !important; + border: none !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + padding: 0 !important; + margin-bottom: 4px; /* Align with single line text */ + transition: all 0.2s; + box-shadow: none !important; +} + +/* Active Send Button State (Simulated via CSS if text exists - handled by Logic usually, but here we style for hover) */ +.input-box-wrapper:focus-within .send-btn { + background-color: #111827 !important; /* Black button when active */ + color: white !important; +} + +.send-btn:hover { + transform: scale(1.05); +} + +/* --- Welcome Screen --- */ +.welcome-container { + position: absolute; + top: 40%; + left: 50%; + transform: translate(-50%, -50%); + text-align: center; + width: 100%; + max-width: 700px; + padding: 0 20px; +} + +.welcome-logo { + font-size: 48px; + margin-bottom: 16px; +} + +.welcome-title { + font-size: 24px; + font-weight: 600; + color: #111827; + margin-bottom: 32px; +} + +.suggestion-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 12px; +} + +.suggestion-card { + background: white; + border: 1px solid #E5E7EB; + border-radius: 12px; + padding: 16px; + text-align: left; + cursor: pointer; + transition: border-color 0.2s; +} + +.suggestion-card:hover { + border-color: #D1D5DB; + background-color: #F9FAFB; +} + +.suggestion-title { + font-size: 14px; + font-weight: 600; + color: #374151; + margin-bottom: 4px; +} + +.suggestion-desc { + font-size: 13px; + color: #9CA3AF; +} + +/* Gradio Footer Hide */ +footer { display: none !important; } +""" diff --git "a/\346\212\200\346\234\257\346\226\207\346\241\243.md" "b/\346\212\200\346\234\257\346\226\207\346\241\243.md" new file mode 100644 index 0000000..54ceb52 --- /dev/null +++ "b/\346\212\200\346\234\257\346\226\207\346\241\243.md" @@ -0,0 +1,74 @@ +# 智启学伴 (Smart Learning Companion) + +## 1. 项目简介 +“智启学伴”是一款聚焦个性化教育的 AI Agent 系统,以 “因材施教” 为核心,打通课前预习、课中互动、课后答疑全学习链路。它采用模块化 Multi-Agent 架构,能基于学生的知识薄弱点智能生成定制化学习方案,实时解答学科难题,还能模拟师生对话开展知识点复盘,为 K12 及成人教育用户打造专属智能学习助手。 + +## 2. 成员贡献清单 +- **核心开发者**: 负责整体架构设计、系统重构、Agent 逻辑实现、Prompt 调优及前端界面开发。 + +## 3. 技术栈 +- **核心框架**: [LazyLLM](https://github.com/LazyAGI/LazyLLM) (用于构建 Multi-Agent 流程和意图识别) +- **大模型支持**: 智谱 GLM-4 / 字节 Doubao (通过 LazyLLM 调用) +- **前端界面**: Gradio (构建现代化交互式 Web UI) +- **开发语言**: Python 3.10+ +- **架构模式**: 模块化分层架构 (UI/Core/Config 分离) + +## 4. 架构设计 +本项目采用 **模块化 Multi-Agent 架构**,代码结构清晰,易于扩展。 + +### 4.1 目录结构 +``` +SmartTutor/ +├── app.py # 程序入口 +├── config.py # 配置管理 +├── core/ # 核心逻辑层 +│ ├── agents.py # Agent 定义与意图分类器构建 +│ └── prompts.py # 系统提示词管理 +├── ui/ # 界面层 +│ ├── interface.py # Gradio 界面构建 +│ ├── styles.py # 自定义 CSS 样式 +│ └── components.py # HTML 组件 (Sidebar, Header 等) +└── env.sh # 环境变量配置 +``` + +### 4.2 核心组件 +1. **Intent Classifier (意图分类器)**: + * 位于 `core/agents.py`。 + * 基于 LazyLLM 的 `IntentClassifier`,实时路由用户请求。 +2. **Specialized Agents (专有智能体)**: + * **Planner Agent**: 专注于生成学习计划 (System Prompt defined in `core/prompts.py`)。 + * **Tutor Agent**: 专注于学科答疑。 + * **Reviewer Agent**: 专注于知识复盘。 + * **Chat Agent**: 处理通用闲聊。 +3. **UI Layer (交互层)**: + * 位于 `ui/` 目录。 + * 采用左右分栏布局,左侧为用户画像与学习进度,右侧为对话主窗口。 + * 集成快捷功能卡片,支持一键触发常用功能。 + +## 5. 部署说明 + +### 环境准备 +- 操作系统: macOS / Linux / Windows +- Python 版本: >= 3.10 + +### 安装步骤 + +1. **安装依赖** + ```bash + pip install -r requirements.txt + ``` + +2. **配置 API Key** + 在项目根目录下创建或修改 `env.sh` 文件: + ```bash + export LAZYLLM_GLM_API_KEY="your_key_here" + ``` + +3. **启动系统** + ```bash + source env.sh + python3 app.py + ``` + +4. **访问应用** + 浏览器访问 `http://127.0.0.1:7860`。 -- Gitee From ca2fefe61091bbbbb6214a98eafec455b39aeae4 Mon Sep 17 00:00:00 2001 From: fruge365 <1656639338@qq.com> Date: Tue, 23 Dec 2025 22:12:47 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +++ server.py | 16 +++++++++++++-- templates/base.html | 31 ++++++++++++++++++++++++++++- templates/index.html | 46 +++++++++++++++++++++++++++++++++----------- 4 files changed, 82 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 7459ec9..86cc3e6 100644 --- a/README.md +++ b/README.md @@ -22,4 +22,7 @@ pip install -r requirements.txt python3 app.py ``` + +视频地址:【快传】我给你发了 智启学伴.mov, 快来看看 https://www.alipan.com/t/qDRDTETVjwaOBoTI0JyJ 点击链接即可保存。「阿里云盘」APP ,无需下载极速在线查看,视频原画倍速播放。 + 更多详情请查阅 [技术文档.md](技术文档.md)。 diff --git a/server.py b/server.py index 01cc2ea..f256a2f 100644 --- a/server.py +++ b/server.py @@ -42,11 +42,23 @@ async def read_mistakes(request: Request): @app.post("/api/chat") async def chat_endpoint(request: ChatRequest): try: - # Here we just pass the message to the agent system - # The agent system currently returns a string + # Check if message is empty + if not request.message or not request.message.strip(): + return JSONResponse(content={"error": "Message cannot be empty"}, status_code=400) + + # Call agent system + print(f"Received message: {request.message}") response_text = agent_system.chat(request.message) + + # Handle case where response might be an object or list + if not isinstance(response_text, str): + response_text = str(response_text) + + print(f"Agent response: {response_text}") return JSONResponse(content={"response": response_text}) except Exception as e: + import traceback + traceback.print_exc() return JSONResponse(content={"error": str(e)}, status_code=500) def start_server(): diff --git a/templates/base.html b/templates/base.html index 8d3f128..4c2070d 100644 --- a/templates/base.html +++ b/templates/base.html @@ -4,10 +4,13 @@ 智启学伴 - 您的专属 AI 学习助手 + - + + + {% endblock %} -- Gitee