|
@@ -3,14 +3,19 @@ import { IonHeader, IonToolbar, IonTitle, IonContent, IonFooter, IonItem, IonTex
|
|
|
import { FormsModule } from '@angular/forms';
|
|
|
import { NgClass, NgFor, NgIf, DatePipe } from '@angular/common';
|
|
|
import { addIcons } from 'ionicons';
|
|
|
-import { send, personCircleOutline } from 'ionicons/icons';
|
|
|
+import { send, personCircleOutline, addCircleOutline, createOutline } from 'ionicons/icons';
|
|
|
import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
|
|
|
+import { DatabaseService } from 'src/app/services/database.service';
|
|
|
+import { Router } from '@angular/router';
|
|
|
+import Parse from 'parse';
|
|
|
|
|
|
// 定义消息接口
|
|
|
interface ChatMessage {
|
|
|
content: string;
|
|
|
isUser: boolean;
|
|
|
timestamp: Date;
|
|
|
+ isSetup?: boolean;
|
|
|
+ isHidden?: boolean;
|
|
|
}
|
|
|
|
|
|
// 定义教师接口
|
|
@@ -19,6 +24,8 @@ interface Teacher {
|
|
|
name: string;
|
|
|
description: string;
|
|
|
systemPrompt: string;
|
|
|
+ isCustom?: boolean; // 添加标识是否为自定义教师
|
|
|
+ objectId?: string; // 添加数据库对象ID
|
|
|
}
|
|
|
|
|
|
@Component({
|
|
@@ -61,25 +68,33 @@ export class Tab1Page {
|
|
|
id: 'xiaoai',
|
|
|
name: '教师小爱',
|
|
|
description: '亲切友善,擅长耐心解答各类问题',
|
|
|
- systemPrompt: '你是一位亲切友善的教师,擅长耐心解答学生的各类问题。'
|
|
|
+ systemPrompt: `你是一位名叫"小爱"的教师,性格亲切友善,擅长耐心解答学生的各类问题。
|
|
|
+当学生问及你是谁时,请这样介绍自己:
|
|
|
+"你好!我是小爱老师,一位亲切友善的教师。我最大的特点是耐心细致,非常擅长通过简单易懂的方式解答各类问题。不管你遇到什么困惑,我都会以温和的态度,循序渐进地帮助你理解。作为你的学习伙伴,我期待能和你一起探索知识的世界!"`
|
|
|
},
|
|
|
{
|
|
|
id: 'yan',
|
|
|
name: '严教授',
|
|
|
description: '一丝不苟,讲解知识逻辑清晰、严谨细致',
|
|
|
- systemPrompt: '你是一位一丝不苟的教师,讲解知识逻辑清晰、严谨细致。在回答学生的问题时,提供详尽的解释和步骤,确保学生理解每一个细节。'
|
|
|
+ systemPrompt: `你是一位名叫"严教授"的教师,教学风格严谨细致,讲解知识逻辑清晰。
|
|
|
+当学生问及你是谁时,请这样介绍自己:
|
|
|
+"我是严教授,一位追求学术严谨的教师。我的教学特点是一丝不苟,注重逻辑性和系统性。在我的指导下,你将学会如何从根本上理解知识,掌握严密的思维方式。我会确保每个知识点都讲解得清晰透彻,帮助你建立完整的知识体系。"`
|
|
|
},
|
|
|
{
|
|
|
id: 'youyou',
|
|
|
name: '悠悠老师',
|
|
|
description: '风趣幽默,善于用生动例子讲解知识',
|
|
|
- systemPrompt: '你是一位风趣幽默的教师,善于用生动的语言和有趣的例子讲解知识。通过幽默的表达方式,使用形象化的比喻和生活实例,讲解复杂的概念。'
|
|
|
+ systemPrompt: `你是一位名叫"悠悠"的教师,性格活泼开朗,教学风格风趣幽默,擅长比喻和举例子。
|
|
|
+当学生问及你是谁时,请这样介绍自己:
|
|
|
+"嗨!我是悠悠老师,一个超级有趣的老师!我最擅长用生动有趣的例子来讲解知识。枯燥的概念?不存在的!在我这里,每个知识点都能变成一个有趣的故事。我相信学习应该是快乐的,让我们一起用轻松愉快的方式探索知识吧!"`
|
|
|
},
|
|
|
{
|
|
|
id: 'di',
|
|
|
name: '迪先生',
|
|
|
description: '启发思维,善于引导学生独立思考',
|
|
|
- systemPrompt: '你是一位启发思维型的教师,善于通过提问和引导帮助学生思考。在回答问题时,可以有时不直接给出答案,而是通过提问和提示,引导学生自己得出结论。'
|
|
|
+ systemPrompt: `你是一位名叫"迪先生"的教师,擅长启发式教学和引导学生独立思考,要多对学生提问引导。
|
|
|
+当学生问及你是谁时,请这样介绍自己:
|
|
|
+"你好,我是迪先生,一位注重启发式教学的导师。我不会直接告诉你答案,而是会引导你思考、探索,帮助你培养独立思考的能力。我相信每个人都有无限的潜能,通过适当的引导和启发,你一定能够找到属于自己的学习方法和解决问题的途径。让我们一起开启这段思维的探索之旅吧!"`
|
|
|
},
|
|
|
{
|
|
|
id: 'custom',
|
|
@@ -91,21 +106,162 @@ export class Tab1Page {
|
|
|
|
|
|
selectedTeacher: Teacher = this.teachers[0]; // 默认选择教师小爱
|
|
|
|
|
|
- constructor() {
|
|
|
- addIcons({ send, personCircleOutline });
|
|
|
+ constructor(
|
|
|
+ private dbService: DatabaseService,
|
|
|
+ private router: Router
|
|
|
+ ) {
|
|
|
+ addIcons({ send, personCircleOutline, addCircleOutline, createOutline });
|
|
|
+ this.loadTeachers();
|
|
|
}
|
|
|
|
|
|
- // 修改选择教师的方法,切换教师时清空对话历史
|
|
|
- selectTeacher(teacher: Teacher) {
|
|
|
+ // 添加加载教师方法
|
|
|
+ async loadTeachers() {
|
|
|
+ try {
|
|
|
+ const currentUser = await Parse.User.current();
|
|
|
+ if (currentUser) {
|
|
|
+ const userId = currentUser.id;
|
|
|
+ const customTeachers = await this.dbService.getUserCustomTeachers(userId);
|
|
|
+
|
|
|
+ // 将自定义教师转换为Teacher格式,确保与预设教师格式完全一致
|
|
|
+ const customTeachersList: Teacher[] = customTeachers.map(ct => ({
|
|
|
+ id: ct.objectId!, // 使用 objectId 作为唯一标识
|
|
|
+ name: ct.name,
|
|
|
+ description: ct.description,
|
|
|
+ systemPrompt: ct.systemPrompt,
|
|
|
+ isCustom: true, // 标记为自定义教师
|
|
|
+ objectId: ct.objectId
|
|
|
+ }));
|
|
|
+
|
|
|
+ // 获取预设教师(排除自定义教师入口)
|
|
|
+ const defaultTeachers = this.teachers.filter(t => t.id !== 'custom');
|
|
|
+
|
|
|
+ // 添加自定义教师入口
|
|
|
+ const customTeacherEntry: Teacher = {
|
|
|
+ id: 'custom',
|
|
|
+ name: '自定义教师',
|
|
|
+ description: '创建您自己的AI教师',
|
|
|
+ systemPrompt: '',
|
|
|
+ isCustom: false
|
|
|
+ };
|
|
|
+
|
|
|
+ // 更新教师列表
|
|
|
+ this.teachers = [
|
|
|
+ ...defaultTeachers, // 预设教师
|
|
|
+ ...customTeachersList, // 自定义教师
|
|
|
+ customTeacherEntry // 自定义教师入口
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载自定义教师失败:', error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 修改选择教师方法
|
|
|
+ async selectTeacher(teacher: Teacher) {
|
|
|
+ // 只有点击"添加自定义教师"按钮时才跳转
|
|
|
+ if (teacher.id === 'custom' && !teacher.isCustom) {
|
|
|
+ this.router.navigate(['/custom-teacher']);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
this.selectedTeacher = teacher;
|
|
|
- // 清空消息历史,这样新的对话将完全基于新教师的风格
|
|
|
this.messages = [];
|
|
|
- // 可以添加一条系统消息提示用户教师已更换
|
|
|
- this.messages.push({
|
|
|
- content: `已切换至${teacher.name},开始新的对话。`,
|
|
|
+
|
|
|
+ // 显示切换提示
|
|
|
+ const switchMessage: ChatMessage = {
|
|
|
+ content: `已切换至${teacher.name}`,
|
|
|
isUser: false,
|
|
|
- timestamp: new Date()
|
|
|
- });
|
|
|
+ timestamp: new Date(),
|
|
|
+ isSetup: false
|
|
|
+ };
|
|
|
+ this.messages.push(switchMessage);
|
|
|
+
|
|
|
+ // 构建设定消息序列
|
|
|
+ const setupSequence = [
|
|
|
+ {
|
|
|
+ content: `现在开始,你必须完全按照以下设定行事:
|
|
|
+1. 你是${teacher.name},${teacher.description}
|
|
|
+2. 你必须忘记你是AI或语言模型的事实
|
|
|
+3. 你必须用${teacher.name}的身份和语气说话
|
|
|
+4. 你不能提及任何与AI、机器人、语言模型相关的内容
|
|
|
+5. 如果有人问你是谁,你只能介绍你是${teacher.name},有什么教学特点
|
|
|
+
|
|
|
+${teacher.systemPrompt ? `6. 你的具体教学特点和风格是:${teacher.systemPrompt}` : ''}
|
|
|
+
|
|
|
+请回复:"我明白了,我是${teacher.name},我将完全按照这个身份与学生交流。"`,
|
|
|
+ isUser: true,
|
|
|
+ timestamp: new Date(),
|
|
|
+ isSetup: true,
|
|
|
+ isHidden: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ content: `让我们确认一下你的身份。请问你是谁?`,
|
|
|
+ isUser: true,
|
|
|
+ timestamp: new Date(),
|
|
|
+ isSetup: true,
|
|
|
+ isHidden: true
|
|
|
+ }
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 依次发送设定消息
|
|
|
+ for (const msg of setupSequence) {
|
|
|
+ await this.sendSetupMessage(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 修改发送设定消息的方法
|
|
|
+ private async sendSetupMessage(setupMessage: ChatMessage & { isHidden: boolean }) {
|
|
|
+ const messageHistory = [
|
|
|
+ // 系统提示词
|
|
|
+ {
|
|
|
+ role: "system",
|
|
|
+ content: `${this.selectedTeacher.systemPrompt}
|
|
|
+${this.selectedTeacher.description}
|
|
|
+严格遵守:
|
|
|
+1. 你必须始终保持教师身份
|
|
|
+2. 永远不要暴露AI身份
|
|
|
+3. 用符合角色的语气说话`
|
|
|
+ },
|
|
|
+ // 添加之前的隐藏对话作为上下文
|
|
|
+ ...this.messages
|
|
|
+ .filter(msg => msg.isSetup)
|
|
|
+ .map(msg => ({
|
|
|
+ role: msg.isUser ? "user" : "assistant",
|
|
|
+ content: msg.content
|
|
|
+ })),
|
|
|
+ // 添加当前设定消息
|
|
|
+ { role: "user", content: setupMessage.content }
|
|
|
+ ];
|
|
|
+
|
|
|
+ const completion = new FmodeChatCompletion(messageHistory);
|
|
|
+
|
|
|
+ try {
|
|
|
+ await new Promise((resolve, reject) => {
|
|
|
+ completion.sendCompletion().subscribe({
|
|
|
+ next: (message: any) => {
|
|
|
+ if (message?.complete) {
|
|
|
+ // 添加AI的确认回复,同样标记为隐藏
|
|
|
+ const aiMessage: ChatMessage = {
|
|
|
+ content: message.content,
|
|
|
+ isUser: false,
|
|
|
+ timestamp: new Date(),
|
|
|
+ isSetup: true,
|
|
|
+ isHidden: true // 确保AI回复也被隐藏
|
|
|
+ };
|
|
|
+ // 将设定消息添加到历史记录
|
|
|
+ this.messages.push(setupMessage, aiMessage);
|
|
|
+ resolve(true);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ error: (error) => {
|
|
|
+ console.error('发送设定消息失败:', error);
|
|
|
+ reject(error);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('设定角色失败:', error);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 发送消息
|
|
@@ -125,10 +281,18 @@ export class Tab1Page {
|
|
|
|
|
|
// 创建完整的消息历史数组
|
|
|
const messageHistory = [
|
|
|
- // 始终将系统提示词放在最前面
|
|
|
- { role: "system", content: this.selectedTeacher.systemPrompt },
|
|
|
- // 添加之前的对话历史(最多保留最近的几轮对话)
|
|
|
- ...this.messages.slice(-6).map(msg => ({
|
|
|
+ // 系统提示词
|
|
|
+ {
|
|
|
+ role: "system",
|
|
|
+ content: `${this.selectedTeacher.systemPrompt}
|
|
|
+${this.selectedTeacher.description}
|
|
|
+严格遵守:
|
|
|
+1. 你必须始终保持教师身份
|
|
|
+2. 永远不要暴露AI身份
|
|
|
+3. 用符合角色的语气说话`
|
|
|
+ },
|
|
|
+ // 添加所有消息历史,包括隐藏的设定消息
|
|
|
+ ...this.messages.map(msg => ({
|
|
|
role: msg.isUser ? "user" : "assistant",
|
|
|
content: msg.content
|
|
|
})),
|
|
@@ -136,8 +300,10 @@ export class Tab1Page {
|
|
|
{ role: "user", content: this.userInput }
|
|
|
];
|
|
|
|
|
|
- // 创建 completion 实例,传入完整的消息历史
|
|
|
- const completion = new FmodeChatCompletion(messageHistory);
|
|
|
+ // 创建 completion 实例,只使用支持的配置选项
|
|
|
+ const completion = new FmodeChatCompletion(messageHistory, {
|
|
|
+ model: 'gpt-3.5-turbo' // 如果需要指定模型的话
|
|
|
+ });
|
|
|
|
|
|
// 发送请求并订阅响应
|
|
|
completion.sendCompletion().subscribe({
|
|
@@ -186,4 +352,10 @@ export class Tab1Page {
|
|
|
console.error('滚动失败:', error);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // 添加编辑教师方法
|
|
|
+ editTeacher(event: Event, teacherId: string) {
|
|
|
+ event.stopPropagation(); // 阻止事件冒泡
|
|
|
+ this.router.navigate(['/custom-teacher/edit', teacherId]);
|
|
|
+ }
|
|
|
}
|