|
|
|
|
@ -15,17 +15,11 @@ import androidx.work.WorkerParameters;
|
|
|
|
|
import com.google.firebase.auth.FirebaseAuth;
|
|
|
|
|
import com.google.firebase.firestore.FirebaseFirestore;
|
|
|
|
|
import com.google.firebase.firestore.QueryDocumentSnapshot;
|
|
|
|
|
import com.google.gson.JsonObject;
|
|
|
|
|
|
|
|
|
|
import net.micode.notes.data.Notes;
|
|
|
|
|
import net.micode.notes.data.Notes.NoteColumns;
|
|
|
|
|
import net.micode.notes.model.CloudNote;
|
|
|
|
|
import net.micode.notes.tool.AiNotificationHelper;
|
|
|
|
|
import net.micode.notes.tool.SyncMapper;
|
|
|
|
|
import net.micode.notes.tool.ai.AiDataSyncHelper;
|
|
|
|
|
import net.micode.notes.tool.ai.CozeClient;
|
|
|
|
|
import net.micode.notes.tool.ai.CozeRequest;
|
|
|
|
|
import net.micode.notes.tool.ai.CozeResponse;
|
|
|
|
|
|
|
|
|
|
import java.util.UUID;
|
|
|
|
|
import java.util.concurrent.CountDownLatch;
|
|
|
|
|
@ -37,7 +31,6 @@ public class SyncWorker extends Worker {
|
|
|
|
|
public static final int MODE_ALL = 0; // 默认:全量同步
|
|
|
|
|
public static final int MODE_PUSH = 1; // 仅上传
|
|
|
|
|
public static final int MODE_PULL = 2; // 仅拉取
|
|
|
|
|
public static final int MODE_REMINDER = 3;
|
|
|
|
|
|
|
|
|
|
public SyncWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
|
|
|
|
super(context, workerParams);
|
|
|
|
|
@ -63,7 +56,6 @@ public class SyncWorker extends Worker {
|
|
|
|
|
// --- PUSH 逻辑 (保持同步执行即可,因为它本身不依赖回调返回数据给UI) ---
|
|
|
|
|
if (mode == MODE_PUSH || mode == MODE_ALL) {
|
|
|
|
|
performPush(db, uid);
|
|
|
|
|
syncToCozeAgent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- PULL 逻辑 (异步变同步) ---
|
|
|
|
|
@ -80,12 +72,6 @@ public class SyncWorker extends Worker {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. 在 doWork() 中增加判断
|
|
|
|
|
if (mode == MODE_REMINDER) {
|
|
|
|
|
String title = getInputData().getString("reminder_title");
|
|
|
|
|
requestAiReminderReply(title);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return isSuccess[0] ? Result.success() : Result.failure();
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
@ -94,161 +80,6 @@ public class SyncWorker extends Worker {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. 实现提醒请求逻辑
|
|
|
|
|
private void requestAiReminderReply(String agendaTitle) {
|
|
|
|
|
try {
|
|
|
|
|
// 1. 构造请求参数
|
|
|
|
|
com.google.gson.JsonObject json = new com.google.gson.JsonObject();
|
|
|
|
|
json.addProperty("intent", "reminder");
|
|
|
|
|
json.addProperty("payload", "日程即将开始:" + agendaTitle);
|
|
|
|
|
json.addProperty("current_time", AiDataSyncHelper.getCurrentTime());
|
|
|
|
|
|
|
|
|
|
// 2. 发起对话
|
|
|
|
|
CozeRequest request = new CozeRequest(CozeClient.BOT_ID, "user_demo", json.toString());
|
|
|
|
|
retrofit2.Response<CozeResponse> response = CozeClient.getInstance()
|
|
|
|
|
.chat(CozeClient.getAuthToken(), request).execute();
|
|
|
|
|
|
|
|
|
|
// 声明变量,用于存放最终结果
|
|
|
|
|
String finalAnswer = null;
|
|
|
|
|
|
|
|
|
|
if (response.isSuccessful() && response.body() != null && response.body().data != null) {
|
|
|
|
|
String chatId = response.body().data.id;
|
|
|
|
|
String convId = response.body().data.conversation_id;
|
|
|
|
|
|
|
|
|
|
// 3. 轮询状态直到完成
|
|
|
|
|
String status = "";
|
|
|
|
|
int retries = 0;
|
|
|
|
|
while (!"completed".equals(status) && retries < 15) {
|
|
|
|
|
Thread.sleep(2000);
|
|
|
|
|
retrofit2.Response<CozeResponse> pollResp = CozeClient.getInstance()
|
|
|
|
|
.retrieveChat(CozeClient.getAuthToken(), chatId, convId).execute();
|
|
|
|
|
|
|
|
|
|
if (pollResp.isSuccessful() && pollResp.body() != null && pollResp.body().data != null) {
|
|
|
|
|
status = pollResp.body().data.status;
|
|
|
|
|
}
|
|
|
|
|
retries++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. [核心修复点]:状态完成后,请求消息列表并解析出 content
|
|
|
|
|
if ("completed".equals(status)) {
|
|
|
|
|
retrofit2.Response<com.google.gson.JsonObject> msgListResp = CozeClient.getInstance()
|
|
|
|
|
.getMessageList(CozeClient.getAuthToken(), chatId, convId).execute();
|
|
|
|
|
|
|
|
|
|
if (msgListResp.isSuccessful() && msgListResp.body() != null) {
|
|
|
|
|
com.google.gson.JsonArray messages = msgListResp.body().getAsJsonArray("data");
|
|
|
|
|
|
|
|
|
|
// 遍历寻找 AI 的回答内容
|
|
|
|
|
for (com.google.gson.JsonElement el : messages) {
|
|
|
|
|
com.google.gson.JsonObject m = el.getAsJsonObject();
|
|
|
|
|
if ("assistant".equals(m.get("role").getAsString()) &&
|
|
|
|
|
"answer".equals(m.get("type").getAsString())) {
|
|
|
|
|
finalAnswer = m.get("content").getAsString();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 5. 统一处理最终结果
|
|
|
|
|
if (finalAnswer != null && !finalAnswer.isEmpty()) {
|
|
|
|
|
saveReminderToLocal(finalAnswer);
|
|
|
|
|
AiNotificationHelper.sendAiNotification(getApplicationContext(), finalAnswer);
|
|
|
|
|
Log.d("AiReminder", "Successfully got AI reminder: " + finalAnswer);
|
|
|
|
|
} else {
|
|
|
|
|
Log.w("AiReminder", "AI returned empty answer for reminder.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e("AiReminder", "Error in requestAiReminderReply", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void saveReminderToLocal(String content) {
|
|
|
|
|
android.content.ContentValues values = new android.content.ContentValues();
|
|
|
|
|
values.put(Notes.ChatColumns.SENDER_TYPE, 1); // AI
|
|
|
|
|
values.put(Notes.ChatColumns.MSG_TYPE, 1); // [重要] 设为提醒卡片类型
|
|
|
|
|
values.put(Notes.ChatColumns.CONTENT, content);
|
|
|
|
|
values.put(Notes.ChatColumns.CREATED_AT, System.currentTimeMillis());
|
|
|
|
|
getApplicationContext().getContentResolver().insert(
|
|
|
|
|
android.net.Uri.parse("content://micode_notes/chat_messages"), values);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 在 SyncWorker 类中添加
|
|
|
|
|
private void syncToCozeAgent() {
|
|
|
|
|
try {
|
|
|
|
|
com.google.gson.JsonObject payloadJson = new com.google.gson.JsonObject();
|
|
|
|
|
payloadJson.addProperty("intent", "sync");
|
|
|
|
|
payloadJson.addProperty("payload", AiDataSyncHelper.getSyncPayload(getApplicationContext()));
|
|
|
|
|
payloadJson.addProperty("current_time", AiDataSyncHelper.getCurrentTime());
|
|
|
|
|
|
|
|
|
|
CozeRequest request = new CozeRequest(CozeClient.BOT_ID, "user_demo", payloadJson.toString());
|
|
|
|
|
|
|
|
|
|
// 1. 发起对话
|
|
|
|
|
retrofit2.Response<CozeResponse> response = CozeClient.getInstance()
|
|
|
|
|
.chat(CozeClient.getAuthToken(), request).execute();
|
|
|
|
|
|
|
|
|
|
if (response.isSuccessful() && response.body() != null && response.body().data != null) {
|
|
|
|
|
String chatId = response.body().data.id;
|
|
|
|
|
String convId = response.body().data.conversation_id; // [关键] 获取会话ID
|
|
|
|
|
|
|
|
|
|
String status = "";
|
|
|
|
|
int retries = 0;
|
|
|
|
|
while (!"completed".equals(status) && retries < 15) {
|
|
|
|
|
Thread.sleep(2000);
|
|
|
|
|
// [关键] 传入两个 ID 轮询
|
|
|
|
|
retrofit2.Response<CozeResponse> pollResp = CozeClient.getInstance()
|
|
|
|
|
.retrieveChat(CozeClient.getAuthToken(), chatId, convId).execute();
|
|
|
|
|
|
|
|
|
|
if (pollResp.isSuccessful() && pollResp.body() != null && pollResp.body().data != null) {
|
|
|
|
|
status = pollResp.body().data.status;
|
|
|
|
|
}
|
|
|
|
|
retries++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. 完成后抓取真正的“Answer”
|
|
|
|
|
if ("completed".equals(status)) {
|
|
|
|
|
retrofit2.Response<com.google.gson.JsonObject> msgListResp = CozeClient.getInstance()
|
|
|
|
|
.getMessageList(CozeClient.getAuthToken(), chatId, convId).execute();
|
|
|
|
|
|
|
|
|
|
if (msgListResp.isSuccessful() && msgListResp.body() != null) {
|
|
|
|
|
com.google.gson.JsonArray messages = msgListResp.body().getAsJsonArray("data");
|
|
|
|
|
String finalAnswer = null;
|
|
|
|
|
|
|
|
|
|
// 遍历寻找 role=assistant 且 type=answer 的内容
|
|
|
|
|
for (com.google.gson.JsonElement el : messages) {
|
|
|
|
|
com.google.gson.JsonObject m = el.getAsJsonObject();
|
|
|
|
|
if ("assistant".equals(m.get("role").getAsString()) &&
|
|
|
|
|
"answer".equals(m.get("type").getAsString())) {
|
|
|
|
|
finalAnswer = m.get("content").getAsString();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (finalAnswer != null && !finalAnswer.isEmpty()) {
|
|
|
|
|
// 插入本地数据库并弹通知
|
|
|
|
|
saveChatMessageToLocal(finalAnswer);
|
|
|
|
|
AiNotificationHelper.sendAiNotification(getApplicationContext(), finalAnswer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Log.e("CozeSync", "Sync Failed", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 辅助方法:将 AI 消息存入本地 chat_messages 表
|
|
|
|
|
private void saveChatMessageToLocal(String content) {
|
|
|
|
|
android.content.ContentValues values = new android.content.ContentValues();
|
|
|
|
|
values.put(net.micode.notes.data.Notes.ChatColumns.SENDER_TYPE, 1); // AI
|
|
|
|
|
values.put(net.micode.notes.data.Notes.ChatColumns.MSG_TYPE, 0); // 文本
|
|
|
|
|
values.put(net.micode.notes.data.Notes.ChatColumns.CONTENT, content);
|
|
|
|
|
values.put(net.micode.notes.data.Notes.ChatColumns.CREATED_AT, System.currentTimeMillis());
|
|
|
|
|
getApplicationContext().getContentResolver().insert(
|
|
|
|
|
android.net.Uri.parse("content://micode_notes/chat_messages"), values);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* [上行逻辑]:查询本地所有 sync_state = 1 的记录并上传
|
|
|
|
|
*/
|
|
|
|
|
|