|
@@ -1,21 +1,16 @@
|
|
-import { Component } from '@angular/core';
|
|
|
|
-import { IonHeader, IonToolbar, IonTitle, IonContent, IonFooter, IonItem, IonInput, IonButton, IonIcon, IonSpinner } from '@ionic/angular/standalone';
|
|
|
|
|
|
+import { Component, ViewChild } from '@angular/core';
|
|
|
|
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonFooter, IonItem, IonTextarea, IonButton, IonIcon } from '@ionic/angular/standalone';
|
|
import { FormsModule } from '@angular/forms';
|
|
import { FormsModule } from '@angular/forms';
|
|
-import { NgClass, NgFor, NgIf } from '@angular/common';
|
|
|
|
|
|
+import { NgClass, NgFor, NgIf, DatePipe } from '@angular/common';
|
|
import { addIcons } from 'ionicons';
|
|
import { addIcons } from 'ionicons';
|
|
import { send } from 'ionicons/icons';
|
|
import { send } from 'ionicons/icons';
|
|
-import { HttpClient, HttpHeaders } from '@angular/common/http';
|
|
|
|
-import Parse from 'parse';
|
|
|
|
-
|
|
|
|
-// 定义API响应类型
|
|
|
|
-interface ChatResponse {
|
|
|
|
- reply: string;
|
|
|
|
- [key: string]: any;
|
|
|
|
-}
|
|
|
|
|
|
+import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
|
|
|
|
|
|
|
|
+// 定义消息接口
|
|
interface ChatMessage {
|
|
interface ChatMessage {
|
|
content: string;
|
|
content: string;
|
|
isUser: boolean;
|
|
isUser: boolean;
|
|
|
|
+ timestamp: Date;
|
|
}
|
|
}
|
|
|
|
|
|
@Component({
|
|
@Component({
|
|
@@ -30,74 +25,96 @@ interface ChatMessage {
|
|
IonContent,
|
|
IonContent,
|
|
IonFooter,
|
|
IonFooter,
|
|
IonItem,
|
|
IonItem,
|
|
- IonInput,
|
|
|
|
|
|
+ IonTextarea,
|
|
IonButton,
|
|
IonButton,
|
|
IonIcon,
|
|
IonIcon,
|
|
- IonSpinner,
|
|
|
|
FormsModule,
|
|
FormsModule,
|
|
NgClass,
|
|
NgClass,
|
|
NgFor,
|
|
NgFor,
|
|
- NgIf
|
|
|
|
|
|
+ NgIf,
|
|
|
|
+ DatePipe,
|
|
|
|
+ MarkdownPreviewModule
|
|
],
|
|
],
|
|
})
|
|
})
|
|
export class Tab1Page {
|
|
export class Tab1Page {
|
|
|
|
+ @ViewChild(IonContent) content!: IonContent;
|
|
|
|
+
|
|
messages: ChatMessage[] = [];
|
|
messages: ChatMessage[] = [];
|
|
userInput: string = '';
|
|
userInput: string = '';
|
|
isLoading: boolean = false;
|
|
isLoading: boolean = false;
|
|
|
|
+ isComplete: boolean = false;
|
|
|
|
+ currentResponse: string = '';
|
|
|
|
|
|
- constructor(private http: HttpClient) {
|
|
|
|
|
|
+ constructor() {
|
|
addIcons({ send });
|
|
addIcons({ send });
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // 发送消息
|
|
async sendMessage() {
|
|
async sendMessage() {
|
|
if (this.userInput.trim() && !this.isLoading) {
|
|
if (this.userInput.trim() && !this.isLoading) {
|
|
this.isLoading = true;
|
|
this.isLoading = true;
|
|
|
|
+ this.isComplete = false;
|
|
|
|
+ this.currentResponse = '';
|
|
|
|
|
|
// 添加用户消息
|
|
// 添加用户消息
|
|
- this.messages.push({
|
|
|
|
|
|
+ const userMessage: ChatMessage = {
|
|
content: this.userInput,
|
|
content: this.userInput,
|
|
- isUser: true
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- // 准备AI回复占位
|
|
|
|
- this.messages.push({
|
|
|
|
- content: '',
|
|
|
|
- isUser: false
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- try {
|
|
|
|
- // 使用直接的HTTP请求
|
|
|
|
- const headers = new HttpHeaders({
|
|
|
|
- 'X-Parse-Application-Id': 'ncloudmaster',
|
|
|
|
- 'X-Parse-Session-Token': Parse.User.current()?.getSessionToken() || '',
|
|
|
|
- 'Content-Type': 'application/json'
|
|
|
|
- });
|
|
|
|
|
|
+ isUser: true,
|
|
|
|
+ timestamp: new Date()
|
|
|
|
+ };
|
|
|
|
+ this.messages.push(userMessage);
|
|
|
|
|
|
- const response = await this.http.post<ChatResponse>(
|
|
|
|
- 'https://server.fmode.cn/api/apig/chat',
|
|
|
|
- { message: this.userInput },
|
|
|
|
- { headers }
|
|
|
|
- ).toPromise();
|
|
|
|
|
|
+ // 创建 completion 实例
|
|
|
|
+ const completion = new FmodeChatCompletion([
|
|
|
|
+ { role: "system", content: "你是一个专业的教师,可以帮助用户解答各种学习问题。" },
|
|
|
|
+ { role: "user", content: this.userInput }
|
|
|
|
+ ]);
|
|
|
|
|
|
- console.log('API Response:', response);
|
|
|
|
-
|
|
|
|
- // 更新AI回复
|
|
|
|
- if (this.messages.length > 0 && response) {
|
|
|
|
- const aiMessage = this.messages[this.messages.length - 1];
|
|
|
|
- aiMessage.content = response.reply || '抱歉,我没有收到有效的回复。';
|
|
|
|
|
|
+ // 发送请求并订阅响应
|
|
|
|
+ completion.sendCompletion().subscribe({
|
|
|
|
+ next: (message: any) => {
|
|
|
|
+ this.currentResponse = message.content;
|
|
|
|
+
|
|
|
|
+ if (message?.complete) {
|
|
|
|
+ this.isComplete = true;
|
|
|
|
+ this.isLoading = false;
|
|
|
|
+
|
|
|
|
+ // 添加 AI 回复到消息列表
|
|
|
|
+ const aiMessage: ChatMessage = {
|
|
|
|
+ content: this.currentResponse,
|
|
|
|
+ isUser: false,
|
|
|
|
+ timestamp: new Date()
|
|
|
|
+ };
|
|
|
|
+ this.messages.push(aiMessage);
|
|
|
|
+
|
|
|
|
+ // 清空输入和当前响应
|
|
|
|
+ this.userInput = '';
|
|
|
|
+ this.currentResponse = '';
|
|
|
|
+
|
|
|
|
+ // 滚动到底部
|
|
|
|
+ this.scrollToBottom();
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ error: (error) => {
|
|
|
|
+ console.error('发送消息失败:', error);
|
|
|
|
+ this.isLoading = false;
|
|
|
|
+ this.messages.push({
|
|
|
|
+ content: '抱歉,发生了一些错误,请稍后再试。',
|
|
|
|
+ isUser: false,
|
|
|
|
+ timestamp: new Date()
|
|
|
|
+ });
|
|
|
|
+ this.scrollToBottom();
|
|
}
|
|
}
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- } catch (error) {
|
|
|
|
- console.error('Chat Error:', error);
|
|
|
|
-
|
|
|
|
- // 显示错误消息
|
|
|
|
- if (this.messages.length > 0) {
|
|
|
|
- this.messages[this.messages.length - 1].content = '抱歉,发生了一些错误,请稍后再试。';
|
|
|
|
- }
|
|
|
|
- } finally {
|
|
|
|
- this.isLoading = false;
|
|
|
|
- this.userInput = ''; // 清空输入框
|
|
|
|
- }
|
|
|
|
|
|
+ // 滚动到底部
|
|
|
|
+ async scrollToBottom() {
|
|
|
|
+ try {
|
|
|
|
+ await this.content.scrollToBottom(300);
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error('滚动失败:', error);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|