feat: add account sync entry and cleanup legacy runtime
This commit is contained in:
@@ -147,6 +147,32 @@ class StoryForgeRepository(private val context: Context) {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
suspend fun createContentSourceSyncJob(
|
||||||
|
platform: String,
|
||||||
|
handle: String,
|
||||||
|
sourceUrl: String,
|
||||||
|
title: String,
|
||||||
|
knowledgeBaseId: String,
|
||||||
|
assistantId: String,
|
||||||
|
analysisModelProfileId: String,
|
||||||
|
maxItems: Int,
|
||||||
|
skipExisting: Boolean,
|
||||||
|
autoTriggerAnalysis: Boolean
|
||||||
|
): JobDto = api().createContentSourceSyncJob(
|
||||||
|
ContentSourceSyncRequest(
|
||||||
|
knowledge_base_id = knowledgeBaseId,
|
||||||
|
assistant_id = assistantId,
|
||||||
|
platform = platform,
|
||||||
|
handle = handle,
|
||||||
|
source_url = sourceUrl,
|
||||||
|
title = title,
|
||||||
|
analysis_model_profile_id = analysisModelProfileId,
|
||||||
|
max_items = maxItems,
|
||||||
|
skip_existing = skipExisting,
|
||||||
|
auto_trigger_analysis = autoTriggerAnalysis
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
suspend fun uploadVideo(
|
suspend fun uploadVideo(
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
title: String,
|
title: String,
|
||||||
|
|||||||
@@ -293,6 +293,7 @@ private fun ExploreTab(state: StoryForgeUiState, vm: StoryForgeViewModel, onPick
|
|||||||
SectionCard(title = "素材入口", subtitle = "视频链接、上传视频、输入文字都会转成文本并做风格分析") {
|
SectionCard(title = "素材入口", subtitle = "视频链接、上传视频、输入文字都会转成文本并做风格分析") {
|
||||||
ChoiceRow(
|
ChoiceRow(
|
||||||
options = listOf(
|
options = listOf(
|
||||||
|
"账号同步" to (state.exploreInputMode == ExploreInputMode.ContentSource),
|
||||||
"视频链接" to (state.exploreInputMode == ExploreInputMode.VideoLink),
|
"视频链接" to (state.exploreInputMode == ExploreInputMode.VideoLink),
|
||||||
"上传视频" to (state.exploreInputMode == ExploreInputMode.UploadVideo),
|
"上传视频" to (state.exploreInputMode == ExploreInputMode.UploadVideo),
|
||||||
"输入文字" to (state.exploreInputMode == ExploreInputMode.Text)
|
"输入文字" to (state.exploreInputMode == ExploreInputMode.Text)
|
||||||
@@ -300,6 +301,7 @@ private fun ExploreTab(state: StoryForgeUiState, vm: StoryForgeViewModel, onPick
|
|||||||
onSelect = { label ->
|
onSelect = { label ->
|
||||||
vm.setExploreInputMode(
|
vm.setExploreInputMode(
|
||||||
when (label) {
|
when (label) {
|
||||||
|
"账号同步" -> ExploreInputMode.ContentSource
|
||||||
"视频链接" -> ExploreInputMode.VideoLink
|
"视频链接" -> ExploreInputMode.VideoLink
|
||||||
"上传视频" -> ExploreInputMode.UploadVideo
|
"上传视频" -> ExploreInputMode.UploadVideo
|
||||||
else -> ExploreInputMode.Text
|
else -> ExploreInputMode.Text
|
||||||
@@ -319,6 +321,93 @@ private fun ExploreTab(state: StoryForgeUiState, vm: StoryForgeViewModel, onPick
|
|||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
when (state.exploreInputMode) {
|
when (state.exploreInputMode) {
|
||||||
|
ExploreInputMode.ContentSource -> {
|
||||||
|
Text(
|
||||||
|
text = "适合导入抖音、B 站、小红书创作者账号主页。抖音 public 页面抓不到时,也可以把分享页链接和账号标识手工填进来。",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
|
ChoiceRow(
|
||||||
|
options = listOf(
|
||||||
|
"抖音" to (state.accountSyncPlatform == "抖音"),
|
||||||
|
"B站" to (state.accountSyncPlatform == "bilibili"),
|
||||||
|
"小红书" to (state.accountSyncPlatform == "小红书")
|
||||||
|
),
|
||||||
|
onSelect = { label ->
|
||||||
|
vm.updateAccountSyncPlatform(
|
||||||
|
when (label) {
|
||||||
|
"B站" -> "bilibili"
|
||||||
|
else -> label
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
|
OutlinedTextField(
|
||||||
|
value = state.accountSyncUrl,
|
||||||
|
onValueChange = vm::updateAccountSyncUrl,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
label = { Text("账号主页或分享页链接") },
|
||||||
|
minLines = 2
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
|
OutlinedTextField(
|
||||||
|
value = state.accountSyncHandle,
|
||||||
|
onValueChange = vm::updateAccountSyncHandle,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
label = { Text("账号标识(可选)") },
|
||||||
|
singleLine = true
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
|
OutlinedTextField(
|
||||||
|
value = state.accountSyncTitle,
|
||||||
|
onValueChange = vm::updateAccountSyncTitle,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
label = { Text("任务标题(可选)") },
|
||||||
|
singleLine = true
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
|
OutlinedTextField(
|
||||||
|
value = state.accountSyncMaxItems,
|
||||||
|
onValueChange = vm::updateAccountSyncMaxItems,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
label = { Text("最多拉取视频数(1-20)") },
|
||||||
|
singleLine = true
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
Text("跳过已存在视频", style = MaterialTheme.typography.bodySmall)
|
||||||
|
Switch(
|
||||||
|
checked = state.accountSyncSkipExisting,
|
||||||
|
onCheckedChange = vm::setAccountSyncSkipExisting
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
Text("自动触发分析", style = MaterialTheme.typography.bodySmall)
|
||||||
|
Switch(
|
||||||
|
checked = state.accountSyncAutoTriggerAnalysis,
|
||||||
|
onCheckedChange = vm::setAccountSyncAutoTriggerAnalysis
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
Button(onClick = vm::submitContentSourceSync, enabled = !state.busy) {
|
||||||
|
Text("同步账号内容")
|
||||||
|
}
|
||||||
|
}
|
||||||
ExploreInputMode.VideoLink -> {
|
ExploreInputMode.VideoLink -> {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = state.videoUrl,
|
value = state.videoUrl,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ enum class StoryForgeAuthMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum class ExploreInputMode {
|
enum class ExploreInputMode {
|
||||||
|
ContentSource,
|
||||||
VideoLink,
|
VideoLink,
|
||||||
UploadVideo,
|
UploadVideo,
|
||||||
Text
|
Text
|
||||||
@@ -72,6 +73,13 @@ data class StoryForgeUiState(
|
|||||||
val createKnowledgeBaseName: String = "",
|
val createKnowledgeBaseName: String = "",
|
||||||
val createKnowledgeBaseDescription: String = "",
|
val createKnowledgeBaseDescription: String = "",
|
||||||
val exploreInputMode: ExploreInputMode = ExploreInputMode.VideoLink,
|
val exploreInputMode: ExploreInputMode = ExploreInputMode.VideoLink,
|
||||||
|
val accountSyncPlatform: String = "抖音",
|
||||||
|
val accountSyncHandle: String = "",
|
||||||
|
val accountSyncUrl: String = "",
|
||||||
|
val accountSyncTitle: String = "",
|
||||||
|
val accountSyncMaxItems: String = "5",
|
||||||
|
val accountSyncSkipExisting: Boolean = true,
|
||||||
|
val accountSyncAutoTriggerAnalysis: Boolean = true,
|
||||||
val videoUrl: String = "",
|
val videoUrl: String = "",
|
||||||
val videoTitle: String = "",
|
val videoTitle: String = "",
|
||||||
val textTitle: String = "",
|
val textTitle: String = "",
|
||||||
@@ -155,6 +163,35 @@ class StoryForgeViewModel(application: Application) : AndroidViewModel(applicati
|
|||||||
_state.value = _state.value.copy(videoUrl = value)
|
_state.value = _state.value.copy(videoUrl = value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateAccountSyncPlatform(value: String) {
|
||||||
|
_state.value = _state.value.copy(accountSyncPlatform = value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateAccountSyncHandle(value: String) {
|
||||||
|
_state.value = _state.value.copy(accountSyncHandle = value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateAccountSyncUrl(value: String) {
|
||||||
|
_state.value = _state.value.copy(accountSyncUrl = value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateAccountSyncTitle(value: String) {
|
||||||
|
_state.value = _state.value.copy(accountSyncTitle = value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateAccountSyncMaxItems(value: String) {
|
||||||
|
val digits = value.filter { it.isDigit() }
|
||||||
|
_state.value = _state.value.copy(accountSyncMaxItems = digits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setAccountSyncSkipExisting(value: Boolean) {
|
||||||
|
_state.value = _state.value.copy(accountSyncSkipExisting = value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setAccountSyncAutoTriggerAnalysis(value: Boolean) {
|
||||||
|
_state.value = _state.value.copy(accountSyncAutoTriggerAnalysis = value)
|
||||||
|
}
|
||||||
|
|
||||||
fun updateVideoTitle(value: String) {
|
fun updateVideoTitle(value: String) {
|
||||||
_state.value = _state.value.copy(videoTitle = value)
|
_state.value = _state.value.copy(videoTitle = value)
|
||||||
}
|
}
|
||||||
@@ -463,6 +500,43 @@ class StoryForgeViewModel(application: Application) : AndroidViewModel(applicati
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun submitContentSourceSync() {
|
||||||
|
val current = state.value
|
||||||
|
if (current.accountSyncUrl.isBlank()) {
|
||||||
|
setError("请先输入账号主页链接")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val knowledgeBaseId = selectedKnowledgeBaseIdOrFallback()
|
||||||
|
if (knowledgeBaseId.isBlank()) {
|
||||||
|
setError("请先选择知识库")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val maxItems = current.accountSyncMaxItems.toIntOrNull()?.coerceIn(1, 20) ?: 5
|
||||||
|
runBusy(message = "正在创建账号同步任务...", task = {
|
||||||
|
repository.createContentSourceSyncJob(
|
||||||
|
platform = current.accountSyncPlatform.trim(),
|
||||||
|
handle = current.accountSyncHandle.trim(),
|
||||||
|
sourceUrl = current.accountSyncUrl.trim(),
|
||||||
|
title = current.accountSyncTitle.trim(),
|
||||||
|
knowledgeBaseId = knowledgeBaseId,
|
||||||
|
assistantId = current.selectedAssistantId,
|
||||||
|
analysisModelProfileId = preferredModelId(),
|
||||||
|
maxItems = maxItems,
|
||||||
|
skipExisting = current.accountSyncSkipExisting,
|
||||||
|
autoTriggerAnalysis = current.accountSyncAutoTriggerAnalysis
|
||||||
|
)
|
||||||
|
}) { job ->
|
||||||
|
appendTimeline("账号同步任务已创建: ${job.title}")
|
||||||
|
_state.value = state.value.copy(
|
||||||
|
accountSyncHandle = "",
|
||||||
|
accountSyncUrl = "",
|
||||||
|
accountSyncTitle = "",
|
||||||
|
accountSyncMaxItems = maxItems.toString()
|
||||||
|
)
|
||||||
|
afterJobCreated(job)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun submitText() {
|
fun submitText() {
|
||||||
val current = state.value
|
val current = state.value
|
||||||
if (current.textTitle.isBlank() || current.textContent.isBlank()) {
|
if (current.textTitle.isBlank() || current.textContent.isBlank()) {
|
||||||
|
|||||||
65
deploy/cleanup_legacy_fastgpt_runtime.sh
Executable file
65
deploy/cleanup_legacy_fastgpt_runtime.sh
Executable file
@@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
LEGACY_CONTAINERS=(
|
||||||
|
storyforge-fastgpt-plugin
|
||||||
|
storyforge-sandbox
|
||||||
|
storyforge-pg
|
||||||
|
storyforge-minio
|
||||||
|
storyforge-redis
|
||||||
|
storyforge-mongo
|
||||||
|
)
|
||||||
|
|
||||||
|
LEGACY_NETWORK="storyforge-net"
|
||||||
|
COLLECTOR_HEALTH_URL="${COLLECTOR_HEALTH_URL:-http://127.0.0.1:8081/healthz}"
|
||||||
|
N8N_HEALTH_URL="${N8N_HEALTH_URL:-http://127.0.0.1:5670/healthz}"
|
||||||
|
APPLY="${APPLY:-0}"
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '[cleanup] %s\n' "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_url() {
|
||||||
|
local url="$1"
|
||||||
|
curl -fsS "$url" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
log "preflight: verifying StoryForge collector and n8n"
|
||||||
|
check_url "$COLLECTOR_HEALTH_URL"
|
||||||
|
check_url "$N8N_HEALTH_URL"
|
||||||
|
|
||||||
|
log "legacy containers:"
|
||||||
|
for container in "${LEGACY_CONTAINERS[@]}"; do
|
||||||
|
if docker ps -a --format '{{.Names}}' | grep -Fxq "$container"; then
|
||||||
|
status="$(docker inspect --format '{{.State.Status}}' "$container")"
|
||||||
|
printf ' - %s (%s)\n' "$container" "$status"
|
||||||
|
else
|
||||||
|
printf ' - %s (missing)\n' "$container"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$APPLY" != "1" ]]; then
|
||||||
|
log "dry run complete. Re-run with APPLY=1 to stop and remove legacy containers."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
for container in "${LEGACY_CONTAINERS[@]}"; do
|
||||||
|
if docker ps -a --format '{{.Names}}' | grep -Fxq "$container"; then
|
||||||
|
log "removing $container"
|
||||||
|
docker rm -f "$container" >/dev/null
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if docker network inspect "$LEGACY_NETWORK" >/dev/null 2>&1; then
|
||||||
|
if [[ "$(docker network inspect "$LEGACY_NETWORK" --format '{{len .Containers}}')" == "0" ]]; then
|
||||||
|
log "removing empty network $LEGACY_NETWORK"
|
||||||
|
docker network rm "$LEGACY_NETWORK" >/dev/null
|
||||||
|
else
|
||||||
|
log "network $LEGACY_NETWORK still has attached containers; leaving it in place"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "post-check: verifying StoryForge collector and n8n"
|
||||||
|
check_url "$COLLECTOR_HEALTH_URL"
|
||||||
|
check_url "$N8N_HEALTH_URL"
|
||||||
|
log "legacy FastGPT runtime cleanup completed"
|
||||||
@@ -163,6 +163,7 @@
|
|||||||
## 当前已完成迁移面
|
## 当前已完成迁移面
|
||||||
|
|
||||||
- FastGPT 运行时依赖已从 `collector-service` 主代码中剥离
|
- FastGPT 运行时依赖已从 `collector-service` 主代码中剥离
|
||||||
|
- 旧 FastGPT 运行残留容器 `storyforge-fastgpt-plugin / sandbox / pg / minio / redis / mongo` 已于 2026-03-20 实际下线并清理
|
||||||
- 数据库已支持 `project/content_source/job_events`
|
- 数据库已支持 `project/content_source/job_events`
|
||||||
- `collector-service` 已增加:
|
- `collector-service` 已增加:
|
||||||
- `n8n` 触发
|
- `n8n` 触发
|
||||||
@@ -173,10 +174,11 @@
|
|||||||
- `n8n` 工作流导出文件已纳入仓库
|
- `n8n` 工作流导出文件已纳入仓库
|
||||||
- `collector-service` 的 live 运行态已回归到 `StoryForge-gitea` 自身源码构建,不再依赖 `/Users/kris/code/Fastgpt/collector-service/app` 的临时 bind mount
|
- `collector-service` 的 live 运行态已回归到 `StoryForge-gitea` 自身源码构建,不再依赖 `/Users/kris/code/Fastgpt/collector-service/app` 的临时 bind mount
|
||||||
- `collector-service` 现已在 live `8081` 提供 `/v2/douyin/*` 接口,并保留原有 `real-cut / ai-video / content-source-sync` 路由
|
- `collector-service` 现已在 live `8081` 提供 `/v2/douyin/*` 接口,并保留原有 `real-cut / ai-video / content-source-sync` 路由
|
||||||
|
- Android Explore 页已补上“账号同步”入口,可直接创建内容源账号同步任务,并支持平台、主页链接、账号标识、最大抓取条数、跳过已存在、自动触发分析等参数
|
||||||
|
|
||||||
## 当前主要风险
|
## 当前主要风险
|
||||||
|
|
||||||
1. 小红书账号级内容源还未做真实平台验证
|
1. 小红书账号级内容源还未做真实平台验证
|
||||||
2. `douyin` public 直抓仍受反爬限制,生产落地还需要补 cookie 或人工页面采集协作链
|
2. `douyin` public 直抓仍受反爬限制,生产落地还需要补 cookie 或人工页面采集协作链
|
||||||
3. `huobao-drama-upstream` 已完成代码迁移并可编译,但 fresh smoke 受外部图片/视频凭证 `403 invalid user` 阻塞
|
3. `huobao-drama-upstream` 已完成代码迁移并可编译,但 fresh smoke 受外部图片/视频凭证 `403 invalid user` 阻塞
|
||||||
4. `douyin` 新接口已上线 live,但还需要补一轮真实账号级回归,确认手工 payload 和相似账号分析都稳定
|
4. Android 端完整编译目前仍被既有 `MainViewModel` 缺失依赖阻塞,本轮新增账号同步入口未触发新的 Kotlin 编译错误,但无法在现有工作区拿到全量 APK 构建通过结论
|
||||||
|
|||||||
@@ -226,3 +226,18 @@ docker compose up -d --build
|
|||||||
- 抖音 public 页面直抓会命中反爬挑战;生产接入仍需要 cookie 或人工页面采集协助
|
- 抖音 public 页面直抓会命中反爬挑战;生产接入仍需要 cookie 或人工页面采集协助
|
||||||
- 小红书账号级内容源还未做真实平台验证
|
- 小红书账号级内容源还未做真实平台验证
|
||||||
- `huobao-drama-upstream` 代码已迁移完成,但 fresh 生成仍受外部图片/视频凭证 `403 invalid user` 阻塞
|
- `huobao-drama-upstream` 代码已迁移完成,但 fresh 生成仍受外部图片/视频凭证 `403 invalid user` 阻塞
|
||||||
|
|
||||||
|
## 10. 旧 FastGPT 残留清理
|
||||||
|
|
||||||
|
- 旧 FastGPT runtime 容器已在 2026-03-20 实际清理完成:
|
||||||
|
- `storyforge-fastgpt-plugin`
|
||||||
|
- `storyforge-sandbox`
|
||||||
|
- `storyforge-pg`
|
||||||
|
- `storyforge-minio`
|
||||||
|
- `storyforge-redis`
|
||||||
|
- `storyforge-mongo`
|
||||||
|
- 清理脚本已纳入仓库:
|
||||||
|
- `/Users/kris/code/StoryForge-gitea/deploy/cleanup_legacy_fastgpt_runtime.sh`
|
||||||
|
- 脚本会在清理前后校验:
|
||||||
|
- `http://127.0.0.1:8081/healthz`
|
||||||
|
- `http://127.0.0.1:5670/healthz`
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
- `user -> project -> assistant / knowledge base / job / content source` 数据模型
|
- `user -> project -> assistant / knowledge base / job / content source` 数据模型
|
||||||
- 文本 / 视频链接 / 上传视频 三类分析任务创建
|
- 文本 / 视频链接 / 上传视频 三类分析任务创建
|
||||||
- 内容源账号同步任务创建与子任务派发
|
- 内容源账号同步任务创建与子任务派发
|
||||||
|
- Android Explore 页已补上内容源账号同步入口
|
||||||
- `n8n` 工作流导入、激活与触发接口
|
- `n8n` 工作流导入、激活与触发接口
|
||||||
- 本地下载器调用
|
- 本地下载器调用
|
||||||
- 本地 `ffmpeg` / `whisper` 风格入口封装
|
- 本地 `ffmpeg` / `whisper` 风格入口封装
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
- `douyin` 手工 payload 导入与账号分析链路已跑通
|
- `douyin` 手工 payload 导入与账号分析链路已跑通
|
||||||
- 本机 `huobao-drama` API 调度、首尾帧生成、视频生成与结果回写接口
|
- 本机 `huobao-drama` API 调度、首尾帧生成、视频生成与结果回写接口
|
||||||
- FastGPT 运行时依赖删除
|
- FastGPT 运行时依赖删除
|
||||||
|
- 旧 FastGPT 运行残留容器已实际下线
|
||||||
|
|
||||||
## 已验证的真实任务
|
## 已验证的真实任务
|
||||||
|
|
||||||
@@ -47,6 +49,7 @@
|
|||||||
- `douyin` public 主页直抓会命中 `public_profile_anti_bot_challenge`;当前已验证手工 payload 导入、分析、相似账号搜索和对标关系可作为可用兜底路径
|
- `douyin` public 主页直抓会命中 `public_profile_anti_bot_challenge`;当前已验证手工 payload 导入、分析、相似账号搜索和对标关系可作为可用兜底路径
|
||||||
- `huobao-upstream` 已能全量编译;并且旧改版隔离实例也已重放确认,当前 fresh 生成被外部图片/视频凭证统一返回 `403 invalid user`
|
- `huobao-upstream` 已能全量编译;并且旧改版隔离实例也已重放确认,当前 fresh 生成被外部图片/视频凭证统一返回 `403 invalid user`
|
||||||
- `huobao-upstream` 已新增 `HUOBAO_TEXT_* / HUOBAO_IMAGE_* / HUOBAO_VIDEO_*` 运行时覆盖能力,后续补新 key 可直接接管数据库配置
|
- `huobao-upstream` 已新增 `HUOBAO_TEXT_* / HUOBAO_IMAGE_* / HUOBAO_VIDEO_*` 运行时覆盖能力,后续补新 key 可直接接管数据库配置
|
||||||
|
- Android 整体 `compileDebugKotlin` 目前仍被工作区既有 `MainViewModel` 缺失依赖阻塞,暂时无法给出 APK 级构建通过结论
|
||||||
|
|
||||||
## 下一步优先级
|
## 下一步优先级
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user