Compare commits

..

8 Commits

Author SHA1 Message Date
gcw_4spBpAfv
4e33063a98 add photo 2026-04-23 15:21:24 +08:00
gcw_4spBpAfv
1550783eef word similarity 2026-04-21 23:05:59 +08:00
gcw_4spBpAfv
e23aaaa4ba book questions 2026-04-18 19:26:25 +08:00
gcw_4spBpAfv
06c7410e23 add unity person 2026-03-17 18:44:51 +08:00
gcw_4spBpAfv
1cae048a7f llm testing 2026-03-10 19:00:32 +08:00
gcw_4spBpAfv
ec1f7d2e72 face regonition refine 2026-03-10 15:40:05 +08:00
gcw_4spBpAfv
d5767156b9 ai state machine init 2026-03-05 18:50:48 +08:00
gcw_4spBpAfv
ef2bada800 config update 2026-03-05 14:41:25 +08:00
1662 changed files with 56317 additions and 443 deletions

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "automatic"
}

View File

@@ -1,12 +1,29 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
}
def oneSentenceAsrAar = file('libs/asr-one-sentence-release.aar')
kapt {
// Room uses javac stubs under kapt; keep parameter names for :bind variables.
javacOptions {
option("-parameters")
}
}
android {
namespace 'com.digitalperson'
compileSdk 34
sourceSets {
main {
// app/note/ref → assets 中为 ref/...(与 AppConfig.RefCorpus.ASSETS_ROOT 一致)
assets.srcDirs = ['src/main/assets', 'note']
}
}
buildFeatures {
buildConfig true
}
@@ -31,7 +48,7 @@ android {
defaultConfig {
applicationId "com.digitalperson"
minSdk 21
minSdk 22
targetSdk 33
versionCode 1
versionName "1.0"
@@ -47,6 +64,9 @@ android {
buildConfigField "String", "LLM_MODEL", "\"${(project.findProperty('LLM_MODEL') ?: 'doubao-1-5-pro-32k-character-250228').toString()}\""
buildConfigField "boolean", "USE_LIVE2D", "${(project.findProperty('USE_LIVE2D') ?: 'true').toString()}"
// 腾讯云「一句话识别」Android SDK将 asr-one-sentence-release.aar 放入 app/libs/ 后为 true
buildConfigField "boolean", "HAS_TENCENT_ASR_SDK", "${oneSentenceAsrAar.exists()}"
ndk {
abiFilters "arm64-v8a"
}
@@ -91,4 +111,19 @@ dependencies {
implementation files('libs/realtime_tts-release-v2.0.16-20260128-d80cafe.aar')
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
// Room dependencies
implementation 'androidx.room:room-runtime:2.5.2'
kapt 'androidx.room:room-compiler:2.5.2'
implementation 'androidx.room:room-ktx:2.5.2'
implementation project(':tuanjieLibrary')
implementation files('../tuanjieLibrary/libs/unity-classes.jar')
// BGE tokenizer (BasicTokenizer) + SimilarityManager 批量相似度测试
implementation 'com.google.guava:guava:31.1-android'
implementation 'org.ejml:ejml-core:0.43.1'
implementation 'org.ejml:ejml-simple:0.43.1'
// 腾讯云「一句话识别」通过 OkHttp 直接实现 TC3 签名,无需 AAR SDK
}

View File

@@ -0,0 +1,4 @@
1. Open https://console.cloud.tencent.com/asr/download
2. Download the Android package for real-time speech recognition (实时语音识别).
3. Copy asr-realtime-release.aar into this folder (app/libs/).
4. Sync Gradle — BuildConfig.HAS_TENCENT_ASR_SDK will become true.

BIN
app/libs/_asr.zip Normal file

Binary file not shown.

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tencent.iot.speech" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="33" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

1
app/libs/_asr_out/R.txt Normal file
View File

@@ -0,0 +1 @@
int string app_name 0x0

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,9 @@
# SDK
-keepclasseswithmembernames class com.tencent.aai.** { # 保持 native 方法不被混淆
native <methods>;
}
-keep public class com.tencent.aai.** {*;}
-keep interface com.tencent.aai.audio.data.PcmAudioDataSource {
void start(); throws com.tencent.aai.exception.ClientException;
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">aai</string>
</resources>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tencent.cloud.qcloudasrsdk.onesentence" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="33" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

1577
app/libs/_osr_out/R.txt Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,90 @@
-optimizationpasses 5 # 指定代码的压缩级别
-allowaccessmodification #优化时允许访问并修改有修饰符的类和类的成员
-dontusemixedcaseclassnames # 是否使用大小写混合
-dontskipnonpubliclibraryclasses # 是否混淆第三方jar
-dontpreverify # 混淆时是否做预校验
-verbose # 混淆时是否记录日志
-ignorewarnings # 忽略警告,避免打包时某些警告出现
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/* # 混淆时所采用的算法
-keepattributes *Annotation*
-keepclasseswithmembernames class * { # 保持 native 方法不被混淆
native <methods>;
}
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * { # 保持枚举 enum 类不被混淆
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable { # 保持 Parcelable 不被混淆
public static final android.os.Parcelable$Creator *;
}
-keepclassmembers class **.R$* { #不混淆R文件
public static <fields>;
}
-dontwarn android.support.**
##--- End android默认 ---
##--- For:不能被混淆的 ---
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Fragment
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
##--- For:保持自定义控件类不被混淆 ---
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
##--- For:android-support-v4 ---
-dontwarn android.support.v4.**
-keep class android.support.v4.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class * extends android.support.v4.** { *; }
-keep public class * extends android.support.v4.**
-keep class * extends android.support.v4.app.** {*;}
-keep class * extends android.support.v4.view.** {*;}
##--- For:Serializable ---
-keep class * implements java.io.Serializable {*;}
-keepnames class * implements java.io.Serializable
-keepclassmembers class * implements java.io.Serializable {*;}
##--- For:Gson ---
-keepattributes *Annotation*
-keep class com.google.gson.stream.** { *; }
##--- For:Remove log ---
-assumenosideeffects class android.util.Log {
public static boolean isLoggable(java.lang.String, int);
public static int v(...);
public static int i(...);
public static int w(...);
public static int d(...);
public static int e(...);
}
##--- For:attributes(未启用) ---
#-keepattributes SourceFile,LineNumberTable # 保持反编译工具能看到代码的行数以及release包安装后出现异常信息可以知道在哪行代码出现异常建议不启用
-keepattributes *Annotation* #使用注解
-keepattributes Signature #过滤泛型 出现类型转换错误时,启用这个
#-keepattributes *Exceptions*,EnclosingMethod #没试过,未知效果

BIN
app/libs/_tts.zip Normal file

Binary file not shown.

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tencent.cloud.realtime.tts" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="33" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

0
app/libs/_tts_out/R.txt Normal file
View File

Binary file not shown.

View File

Binary file not shown.

Binary file not shown.

BIN
app/libs/classes.jar Normal file

Binary file not shown.

View File

@@ -113,7 +113,194 @@ https://www.modelscope.cn/datasets/shaoxuan/WIDER_FACE/files
8. 人脸识别模型是insightface的r18模型转成了rknn格式并且使用了 lfw 的数据集进行了校准,下载地址:
https://tianchi.aliyun.com/dataset/93864
9.
9. 本地LLM用的是 rkllm 模型,由于内存限制,只能用较小的模型,如 Qwen3-0.6B-rk3588-w8a8.rkllm。
10. 数字人交互设计说明书(优化版)
核心原则
* 尊重用户:给用户足够的反应时间,不抢话,不催促。
* 主动但不打扰:用户沉默时适度引导,但不强行交互;数字人拥有独立的内心活动,即便无人交互也保持“生命感”。
* 个性化:记住每个用户的偏好、名字、对话历史,并据此调整问候和回应。
* 动作同步Live2D人物的表情与动作与当前状态、情绪、内心活动相匹配。
* 持续内心活动:数字人即使在没有用户时也会进行“回忆”或“思考”,并通过文字展现,用户可随时打断并询问想法。
状态定义
[空闲状态]:无人,数字人无内心活动(省电模式)。
[回忆状态]:无人,数字人正在根据记忆产生内心想法,通过表情表现。
[问候状态]:检测到用户,主动打招呼。
[等待回复状态]:问候后或对话间隙,等待用户回复。
[对话状态]:正在与用户交流,根据情绪调整动作。
[主动引导状态]:用户沉默但仍在画面中,数字人主动开启新话题。
[告别状态]:用户离开画面,数字人告别。
[空闲状态]
动作 haru_g_idle (待机动作)
检测到人脸 → 等待1秒让人脸稳定
[问候状态]
动作
- 认识用户: haru_g_m22 (高兴动作)
- 不认识: haru_g_m01中性动作
AI问候根据是否认识节日时间等因素个性化
启动20秒计时器
[等待回复状态]
动作 haru_g_m17
├─ 如果用户按下了麦克风按钮 → 进入[对话状态]
│ 动作 :根据对话情绪动态调整
│ - 开心: haru_g_m22 / haru_g_m21 / haru_g_m18 / haru_g_m09 / haru_g_m08
│ - 悲伤: haru_g_m25 / haru_g_m24 / haru_g_m05 / haru_g_m16
│ - 惊讶: haru_g_m26 / haru_g_m12
│ - 愤怒: haru_g_m04 / haru_g_m11 / haru_g_m04
│ - 平静: haru_g_m15 / haru_g_m07 / haru_g_m06 / haru_g_m02 / haru_g_m01
│ AI根据内容回应持续直到用户说“再见”
│ ↓
│ (用户离开)→ 进入[告别状态]
└─ 如果20秒内无回复
检查用户是否还在画面
├─ 如果还在 → [主动引导状态]
│ 动作 haru_g_m15 / haru_g_m07 (中性动作)
│ AI开启轻松话题如“我出一道数学题考考你吧1+6等于多少
│ 等待10秒
│ ↓
│ ├─ 回复 → 进入[对话状态]
│ └─ 没回复 → 换话题我们上完厕所应该干什么呀最多重复3次
│ 动作 haru_g_m22 / haru_g_m18
│ (重复尝试)→ 再次等待10秒
3次后仍无回复→ 回到[等待回复状态]
└─ 如果已离开 → [告别状态]
动作 haru_g_idle (告别后待机)
3秒后 → 回到[空闲状态]
[空闲状态] (长时间无人)
如果持续30秒无人 → 进入[回忆状态]
动作 haru_g_m15
回顾之前的聊天记录,生成想法,不发声,把想法显示在屏幕上
如果检测到人脸 → 立即中断回忆,进入[问候状态]
[回忆状态] 被用户询问“你在想什么?”
AI说出最近的想法如“我刚才在想上次你说你喜欢蓝色...”)
进入[问候状态]或直接进入[对话状态](根据用户后续反应)
[告别状态] (用户离开后)
动作 简短告别,用语音,→ 等待3秒 → 回到[空闲状态]
11. ## 用户类型区分
1. guest 用户
- 默认用户ID当没有检测到人脸时使用
- 在 Live2DChatActivity.kt 中初始化为 private var activeUserId: String = "guest"
- 表示未通过人脸识别的临时用户
2. face_ 用户
- 通过人脸识别生成的用户ID格式为 face_<数字>
- 在 FaceDetectionPipeline.kt 中生成: lastFaceIdentityId = match.matchedId?.let { "face_$it" }
- 表示通过人脸识别的正式用户
## 转换逻辑
当系统检测到人脸时,会触发以下流程:
1. 人脸检测 FaceDetectionPipeline 检测到人脸
2. 身份识别 FaceRecognizer 尝试识别用户身份
3. ID生成 :如果是新用户,生成新的 face_<数字> ID
4. 回调更新 :通过 onPresenceChanged 回调将 faceIdentityId 传递给 Live2DChatActivity
5. ID切换 Live2DChatActivity 中的 interactionController.onFacePresenceChanged 会调用 handler.onRememberUser(faceIdentityId, recognized)
6. 更新活跃用户 onRememberUser 方法会将 activeUserId 更新为 faceIdentityId
因此,当检测到人脸时, guest 用户会自动切换为 face_ 用户。
face_profiles 和 user_memory 表之间的关联是通过 ID转换 实现的,没有专门的关联表:
## 关联机制
1. ID转换规则
- face_profiles 表中的 id 字段(数字)→ 转换为 face_<id> 格式
- 例如: id=1 → face_1
- 这个转换在 FaceDetectionPipeline.kt 中实现: lastFaceIdentityId = match.matchedId?.let { "face_$it" }
2. 关联流程
- 系统检测到人脸后,从 face_profiles 表中查找匹配的记录,获取 id
- 将 id 转换为 face_<id> 格式的用户ID
- 这个用户ID被用作 user_memory 表中的 userId 字段
- 通过这个 userId ,两个表就建立了关联
12. 使用 adb shell 直接操作sqlite数据库
1. 进入设备 shell
adb shell
2. 找到应用数据库
# 进入应用数据目录
run-as com.digitalperson
# 进入数据库目录
cd databases
# 查看数据库文件
ls -la
3. 使用 sqlite3 命令查看数据库
bash
# 打开数据库
sqlite3 your_database.db # digital_human.db face_feature.db
# 在 sqlite3 提示符下执行命令:
.tables # 查看所有表
.schema table_name # 查看表结构
SELECT * FROM table_name; # 查询数据
.headers on # 显示列名
.mode column # 列模式显示
.quit # 退出
13. Unity 集成时遇到的问题:
1. 问题描述NDK的版本不对导致编译错误
解决方法:
- 在 build.gradle 中指定 NDK 版本
ndkVersion "23.1.7779620"
2. 问题描述Unity 编译时提示 NDK 路径错误
解决方法:
- 在 build.gradle 中指定 NDK 路径
ndkPath "D:/software/2022.3.62t5/Editor/Data/PlaybackEngines/AndroidPlayer/NDK"
3. 问题描述Build file 'D:\code\digital_person\tuanjieLibrary\build.gradle'
Could not get unknown property 'tuanjieStreamingAssets' for object of type com.android.build.gradle.internal.dsl.LibraryAndroidResourcesImpl$AgpDecorated.
解决方法:
- 在项目的顶层的 gradle.properties 中添加 tuanjieStreamingAssets 配置
tuanjieStreamingAssets=.unity3d, google-services-desktop.json, google-services.json, GoogleService-Info.plist
4. 问题描述:重新从 Tuanjie 导出 tuanjieLibrary 后报错:
Build was configured to prefer settings repositories over project repositories but repository 'maven' was added by build file 'tuanjieLibrary\build.gradle'
原因tuanjieLibrary/build.gradle 里的 repositories {} 块与根目录 settings.gradle 中的
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 冲突。
解决方法:
- 直接删除 tuanjieLibrary/build.gradle 中的整个 repositories {} 块。
- 所需的 Aliyun 镜像已在 settings.gradle 的 dependencyResolutionManagement.repositories 中统一声明,无需重复。
5. 问题描述Build file 'D:\code\digital_person\tuanjieLibrary\build.gradle' line: 6
Error resolving plugin [id: 'com.android.application', version: '7.4.2', apply: false]
> The request for this plugin could not be satisfied because the plugin is already on the classpath with a different version (8.2.2).
解决方法:
直接修改项目的 build.gradle 文件,将插件版本改为一致的 8.2.2
6. 问题描述Build file 'D:\code\digital_person\tuanjieLibrary\build.gradle' line: 16
A problem occurred evaluating project ':tuanjieLibrary'.
> Build was configured to prefer settings repositories over project repositories but repository 'maven' was added by build file 'tuanjieLibrary\build.gradle'
解决方法见问题4删除 tuanjieLibrary/build.gradle 中的 repositories {} 块。
7. 问题描述:重新从 Tuanjie 导出后,:tuanjieLibrary 模块无法被 :app 解析:
Could not resolve project :tuanjieLibrary.
> No matching configuration of project :tuanjieLibrary was found. None of the consumable configurations have attributes.
原因Tuanjie 重新导出后tuanjieLibrary/build.gradle 被还原为只含 apply false 的"根项目"构建文件,
没有 apply plugin: 'com.android.library'Gradle 无法识别该模块为 Android 库。
解决方法:
- 将 tuanjieLibrary/build.gradle 替换为完整的 Android library 模块构建文件apply plugin: 'com.android.library'
参考 launcher/build.gradle 的配置compileSdkVersion、ndkVersion、ndkPath、aaptOptions、buildTypes 等),
并在 dependencies 中添加 implementation files('libs/unity-classes.jar')。
- 注意:每次从 Tuanjie 重新导出后都需要重新替换该文件。

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More