Compare commits

..

10 Commits

Author SHA1 Message Date
gcw_4spBpAfv
ccb4e02545 note 2026-05-15 16:36:20 +08:00
gcw_4spBpAfv
b29dfd8b47 update 2026-05-15 16:33:22 +08:00
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 56395 additions and 444 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 { plugins {
id 'com.android.application' id 'com.android.application'
id 'org.jetbrains.kotlin.android' 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 { android {
namespace 'com.digitalperson' namespace 'com.digitalperson'
compileSdk 34 compileSdk 34
sourceSets {
main {
// app/note/ref → assets 中为 ref/...(与 AppConfig.RefCorpus.ASSETS_ROOT 一致)
assets.srcDirs = ['src/main/assets', 'note']
}
}
buildFeatures { buildFeatures {
buildConfig true buildConfig true
} }
@@ -31,7 +48,7 @@ android {
defaultConfig { defaultConfig {
applicationId "com.digitalperson" applicationId "com.digitalperson"
minSdk 21 minSdk 22
targetSdk 33 targetSdk 33
versionCode 1 versionCode 1
versionName "1.0" 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 "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()}" 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 { ndk {
abiFilters "arm64-v8a" abiFilters "arm64-v8a"
} }
@@ -91,4 +111,19 @@ dependencies {
implementation files('libs/realtime_tts-release-v2.0.16-20260128-d80cafe.aar') implementation files('libs/realtime_tts-release-v2.0.16-20260128-d80cafe.aar')
implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.code.gson:gson:2.8.9'
implementation 'com.squareup.okhttp3:okhttp:4.9.3' 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,255 @@ https://www.modelscope.cn/datasets/shaoxuan/WIDER_FACE/files
8. 人脸识别模型是insightface的r18模型转成了rknn格式并且使用了 lfw 的数据集进行了校准,下载地址: 8. 人脸识别模型是insightface的r18模型转成了rknn格式并且使用了 lfw 的数据集进行了校准,下载地址:
https://tianchi.aliyun.com/dataset/93864 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 重新导出后都需要重新替换该文件。
14. 从 Unity 导出 Android 项目IL2CPP推荐步骤
下面按 Unity 2021/2022+ 通用流程写(菜单名可能略有差异,但逻辑一致)。
1. 切到 Android 平台
File → Build Settings…
左侧选中 Android
若未切换过,点 Switch Platform等切换完成
2. Player SettingsAndroid
Build Settings 窗口里点 Player Settings…或 Edit → Project Settings → Player
选中 Android 图标(或 Android 标签页)
在 Other Settings 里检查并设置:
Scripting Backend选 IL2CPP
Target Architectures勾选 ARM64你现在 app 的 abiFilters 也是 arm64-v8a要一致
Minimum API Level与你们 Android 工程要求一致(你工程 minSdk 22Unity 不要设得更高除非你有意为之)
可选但常见Publishing Settings / Keystore导出后若要直接装真机后面 Build 时可用 debug发版再配正式签名。
3. 选择导出方式
在 Build Settings
Export Project ✅ 勾选(你们要集成到现有 Android Studio 工程,必须勾)
Development Build调试可开发版关
4. Export 输出目录
点 Export不要只点“生成文件夹”就关掉选一个空目录或新版本目录例如
D:\unity_export\MyProject_Android_IL2CPP_20260424\
等 Unity 完整跑完(控制台无失败)。
5. 在导出结果里确认 libil2cpp.so
在导出根目录里找 unityLibrary或你们模块名
unityLibrary\src\main\jniLibs\arm64-v8a\libil2cpp.so
同目录通常还有 libmain.so、libunity.so 等
若这里仍然没有,再回到 Player Settings → Android → Scripting Backend 逐项核对(尤其是是否被 Override 成 Mono
6. 集成到你们 digital_person 工程
原则:同一轮 Export 的 jniLibs/arm64-v8a 整包拷贝到你们 tuanjieLibrary/src/main/jniLibs/arm64-v8a/(或你们实际使用的 Unity module不要“只替换较新文件”也不要混两次导出的 so。
15. Unity导出安卓工程目录之后找不到 libil2cpp.so可以通过先不export先编译出apk得到这个so然后复制到对应的目录下
power shell 命令
# 源文件路径
$source = "C:\Users\42087\My project\Library\Bee\Android\Prj\IL2CPP\Gradle\tuanjieLibrary\build\intermediates\stripped_native_libs\release\out\lib\arm64-v8a\libil2cpp.so"
# 目标路径(你的导出工程)
$targetDir = "D:\code\digital_person\tuanjieLibrary\src\main\jniLibs\arm64-v8a"
# 创建目标目录(如果不存在)
New-Item -ItemType Directory -Force -Path $targetDir
# 复制文件
Copy-Item -Path $source -Destination $targetDir -Force
# 验证复制成功
Get-ChildItem -Path $targetDir\libil2cpp.so | Select-Object Name, Length
16. 有些Unity导出的问题可以参考https://blog.csdn.net/weixin_45774916/article/details/144171875

Binary file not shown.

Binary file not shown.

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