1.在讯飞大平台申请免费接口(申请后获取url和token)
2.创建一个数据库进行储存对话聊天记录
package com.example.myapplication.XL;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.example.myapplication.Bean.MessageBean;
import java.util.ArrayList;
import java.util.List;
/**
* ai聊天对话 数据库
*/
public class MessageDatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "chat.db";
private static final int DATABASE_VERSION = 1;
private static final String TABLE_MESSAGES = "messages";
private static final String COLUMN_ID = "id";
private static final String COLUMN_CONTENT = "content";
private static final String COLUMN_IS_USER = "is_user";
public MessageDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String createTable = "CREATE TABLE " + TABLE_MESSAGES + " (" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COLUMN_CONTENT + " TEXT, " +
COLUMN_IS_USER + " INTEGER)";
db.execSQL(createTable);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_MESSAGES);
onCreate(db);
}
// 插入消息
public void insertMessage(String content, boolean isUser) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COLUMN_CONTENT, content);
values.put(COLUMN_IS_USER, isUser ? 1 : 0);
db.insert(TABLE_MESSAGES, null, values);
db.close();
}
public List<MessageBean> getAllMessages() {
List<MessageBean> messages = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = null;
try {
cursor = db.query(TABLE_MESSAGES, null, null, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
int contentIndex = cursor.getColumnIndex(COLUMN_CONTENT);
int isUserIndex = cursor.getColumnIndex(COLUMN_IS_USER);
if (contentIndex != -1 && isUserIndex != -1) {
String content = cursor.getString(contentIndex);
boolean isUser = cursor.getInt(isUserIndex) == 1;
messages.add(new MessageBean(content, isUser));
}
}
}
} catch (Exception e) {
Log.e("DatabaseError", "Error reading from database", e);
} finally {
if (cursor != null) {
cursor.close();
}
db.close();
}
return messages;
}
}
3.使用recycleview展示出人机对话聊天(输入框\按钮等)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#EFEDED">
<RelativeLayout
android:id="@+id/r1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="20dp">
<ImageView
android:id="@+id/back"
android:layout_width="18dp"
android:layout_height="18dp"
android:src="@drawable/back" />
<TextView
android:id="@+id/titleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="智链智能"
android:textColor="#000" />
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/inputLayout"
android:layout_below="@id/r1"
android:layout_marginBottom="30dp"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
<TextView
android:id="@+id/t1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/inputLayout"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:text="正在加载中...."
android:visibility="gone"/>
<LinearLayout
android:id="@+id/inputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentBottom="true"
android:background="#FFF"
android:padding="10dp">
<EditText
android:id="@+id/editTextMessage"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@drawable/yuan"
android:backgroundTint="#EFEDED"
android:layout_weight="1"
android:hint="请输入内容"
android:paddingLeft="10dp"
android:textSize="13sp"
android:padding="10dp"/>
<Button
android:id="@+id/buttonSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/yuan"
android:backgroundTint="#DC6464"
android:layout_marginLeft="20dp"
android:text="发送"/>
</LinearLayout>
</RelativeLayout>
4.编写xml对应的java文件
package com.example.myapplication.XL;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.example.myapplication.Adapter.MessageAdapter;
import com.example.myapplication.Bean.MessageBean;
import com.example.myapplication.R;
import com.google.gson.Gson;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
// LianXiKeFuActivity: 用于实现与 AI 聊天的活动
public class LianXiKeFuActivity extends AppCompatActivity {
// UI 组件
private ImageView backButton;
private RecyclerView messageRecyclerView;
private MessageAdapter messageAdapter;
private List<MessageBean> messageList;
private EditText messageInputField;
private MessageDatabaseHelper messageDatabaseHelper;
private TextView loadingIndicator;
private Button sendButton;
// 申请 讯飞开放平台API 请求的 URL 和 认证令牌
private static final String API_URL = "https://spark-api-open.xf-yun.com/v1/chat/completions";
private static final String AUTH_TOKEN = "Bearer AxYXpMyqsxTUzJtMHdS:NbbTQZhZWAZUafwGgfl"; //这是我自己的token,不可以直接使用,请自己申请
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lian_xi_ke_fu);
// 初始化 UI 组件
initializeUIComponents();
// 设置返回按钮的点击事件
backButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish(); // 关闭当前活动
}
});
// 设置 RecyclerView
messageList = new ArrayList<>();
messageAdapter = new MessageAdapter(messageList);
messageRecyclerView.setLayoutManager(new LinearLayoutManager(this));
messageRecyclerView.setAdapter(messageAdapter);
//每次进入时 启动数据库 并且放入recycleview
//TODO 初始化数据库助手并加载消息
messageDatabaseHelper = new MessageDatabaseHelper(this);
loadMessages(); // 从数据库加载消息
// 设置发送按钮的点击事件
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String userMessage = messageInputField.getText().toString().trim();
if (!userMessage.isEmpty()) {
// 添加用户消息到列表
messageList.add(new MessageBean(userMessage, true));
messageAdapter.notifyItemInserted(messageList.size() - 1);
messageRecyclerView.scrollToPosition(messageList.size() - 1);
messageInputField.setText(""); // 清空输入框
// 将用户消息插入数据库
messageDatabaseHelper.insertMessage(userMessage, true);
// 发送聊天请求
sendChatRequest(userMessage);
}
}
});
sendGreetingMessage();
}
//TODO 从数据库加载消息 调用方法
private void loadMessages() {
List<MessageBean> messages = messageDatabaseHelper.getAllMessages();
messageList.clear(); // 清空消息列表
messageList.addAll(messages); // 添加从数据库加载的消息
messageAdapter.notifyDataSetChanged(); // 更新适配器
// 滚动到最新消息
if (!messageList.isEmpty()) {
messageRecyclerView.scrollToPosition(messageList.size() - 1);
}
}
// 初始化 UI 组件
private void initializeUIComponents() {
backButton = findViewById(R.id.back);
messageRecyclerView = findViewById(R.id.recyclerView);
loadingIndicator = findViewById(R.id.t1);
messageInputField = findViewById(R.id.editTextMessage);
sendButton = findViewById(R.id.buttonSend);
}
// 发送问候语
private void sendGreetingMessage() {
String greeting = "您好,请问有什么可以帮到您!";
messageList.add(new MessageBean(greeting, false));
messageAdapter.notifyItemInserted(messageList.size() - 1);
messageRecyclerView.scrollToPosition(messageList.size() - 1);
}
//TODO 发送聊天请求
private void sendChatRequest(String userInput) {
OkHttpClient client = new OkHttpClient(); // 创建 OkHttpClient 实例
// 构建请求参数 步骤1
Map<String, Object> requestParams = new HashMap<>();
requestParams.put("max_tokens", 4096);
requestParams.put("top_k", 4);
requestParams.put("temperature", 0.5);
requestParams.put("model", "4.0Ultra");
requestParams.put("stream", true);
Log.e("Map",requestParams.toString());
// 构建list 请求参数
List<Map<String, String>> messages = new ArrayList<>();
Map<String, String> systemMessage = new HashMap<>();
systemMessage.put("role", "system");
systemMessage.put("content","你是一位智链校园app的客服,目标任务:解决用户发送的内容,但是只能回复与该APP有关的话题,当询问与app不相关的问题时,则默认回复,不好意思,我无法回答您的问题如果您有关于智链校园app使用的疑问或帮助,请随时告诉我!,"); //TODO 这是给ai设置了固定角色要求,,如果没有要求则删除
messages.add(systemMessage);
//用户发送消息 存储到map列表
Map<String, String> userMessage = new HashMap<>();
userMessage.put("role", "user");
userMessage.put("content", userInput);
messages.add(userMessage);
requestParams.put("messages", messages);
Log.e("map",requestParams.toString());
// 将请求参数转换为 JSON 步骤2
Gson gson = new Gson();
String jsonRequestBody = gson.toJson(requestParams);
Log.e("jsonRequestBody",jsonRequestBody);
// 创建请求体
RequestBody requestBody = RequestBody.create(jsonRequestBody,MediaType.parse("application/json; charset=utf-8"));
// 创建请求
Request request = new Request.Builder()
.url(API_URL)
.addHeader("Authorization", AUTH_TOKEN) // 添加认证头
.post(requestBody) // POST 请求
.build();
loadingIndicator.setVisibility(View.VISIBLE); // 显示加载指示器
sendButton.setEnabled(false); // 禁用发送按钮
// 发送请求 步骤3
client.newCall(request).enqueue(new Callback() {
public void onFailure(Call call, IOException e) {
Log.e("Error", "Request Failed: " + e.getMessage());
runOnUiThread(() -> {
Toast.makeText(LianXiKeFuActivity.this, "请求失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
});
}
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
runOnUiThread(() -> {
loadingIndicator.setVisibility(View.GONE);
Toast.makeText(LianXiKeFuActivity.this, "无数据", Toast.LENGTH_SHORT).show();
});
return;
}
//如若成功,则获取成功后的json数据,查看他的json数据是什么样子的,,,,然后json数据是一个大的list列表,客服回复的的内容都是拆开的,所以现在我要将内容全部拼接到一块然后储存到数据库中/
String jsonResponse = response.body().string(); // 获取响应体
Log.e("json",jsonResponse);
// 处理 JSON 响应
//TODO 获取ai 回复的内容
String botResponse = processJsonResponse(jsonResponse);
// 在主线程更新 UI 插入数据库中
runOnUiThread(() -> {
if (!botResponse.isEmpty()) {
loadingIndicator.setVisibility(View.GONE);
sendButton.setEnabled(true); // 启用发送按钮
messageList.add(new MessageBean(botResponse, false)); // 添加机器人的回复
messageAdapter.notifyItemInserted(messageList.size() - 1);
messageRecyclerView.scrollToPosition(messageList.size() - 1); // 滚动到最新消息
messageDatabaseHelper.insertMessage(botResponse, false); // 插入机器人的消息到数据库
}
});
}
});
}
// 处理 JSON 响应 处理json数据然后将content拼接. 拼接
private String processJsonResponse(String jsonResponse) {
StringBuilder responseBuilder = new StringBuilder();
// 按行拆分响应
String[] responseLines = jsonResponse.split("\\n");
for (String line : responseLines) {
if (line.startsWith("data:")) {
String jsonString = line.substring(5).trim(); // 去掉前缀 "data:"
if (jsonString.equals("[DONE]")) {
break; // 结束标记
}
try {
// 解析 JSON 数据
JSONObject jsonObject = new JSONObject(jsonString);
JSONArray choicesArray = jsonObject.getJSONArray("choices");
for (int i = 0; i < choicesArray.length(); i++) {
JSONObject choice = choicesArray.getJSONObject(i);
JSONObject delta = choice.getJSONObject("delta");
String content = delta.getString("content");
// 拼接内容
responseBuilder.append(content);
}
} catch (JSONException e) {
Log.e("Error", "JSON 解析错误: " + e.getMessage());
}
}
}
Log.e("拼接的内容:",responseBuilder.toString());
return responseBuilder.toString(); // 返回拼接后的内容
}
}