Compare commits
4 Commits
gitea
...
0050bfff09
| Author | SHA1 | Date | |
|---|---|---|---|
|
0050bfff09
|
|||
|
e4192bb47c
|
|||
|
c9479bd7f4
|
|||
|
6432f339b4
|
32
.gitea/workflows/build.yaml
Normal file
32
.gitea/workflows/build.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Build and Push Docker Image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- gitea
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to Docker Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: docker.gardel.top
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Build and Push Docker Image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
tags: docker.gardel.top/gardel/mofox:dev
|
||||
build-args: |
|
||||
BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
||||
VCS_REF=${{ github.sha }}
|
||||
149
.github/workflows/docker-image.yml
vendored
149
.github/workflows/docker-image.yml
vendored
@@ -1,149 +0,0 @@
|
||||
name: Docker Build and Push
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- dev
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
- "v*"
|
||||
- "*.*.*"
|
||||
- "*.*.*-*"
|
||||
workflow_dispatch: # 允许手动触发工作流
|
||||
|
||||
# Workflow's jobs
|
||||
jobs:
|
||||
build-amd64:
|
||||
name: Build AMD64 Image
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
buildkitd-flags: --debug
|
||||
|
||||
# Log in docker hub
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
# Generate metadata for Docker images
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ secrets.DOCKERHUB_USERNAME }}/mofox
|
||||
|
||||
# Build and push AMD64 image by digest
|
||||
- name: Build and push AMD64
|
||||
id: build
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
file: ./Dockerfile
|
||||
cache-from: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/mofox:amd64-buildcache
|
||||
cache-to: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/mofox:amd64-buildcache,mode=max
|
||||
outputs: type=image,name=${{ secrets.DOCKERHUB_USERNAME }}/mofox,push-by-digest=true,name-canonical=true,push=true
|
||||
build-args: |
|
||||
BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
||||
VCS_REF=${{ github.sha }}
|
||||
|
||||
build-arm64:
|
||||
name: Build ARM64 Image
|
||||
runs-on: ubuntu-24.04-arm
|
||||
outputs:
|
||||
digest: ${{ steps.build.outputs.digest }}
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
buildkitd-flags: --debug
|
||||
|
||||
# Log in docker hub
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
# Generate metadata for Docker images
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ secrets.DOCKERHUB_USERNAME }}/mofox
|
||||
|
||||
# Build and push ARM64 image by digest
|
||||
- name: Build and push ARM64
|
||||
id: build
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/arm64/v8
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
file: ./Dockerfile
|
||||
cache-from: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/mofox:arm64-buildcache
|
||||
cache-to: type=registry,ref=${{ secrets.DOCKERHUB_USERNAME }}/mofox:arm64-buildcache,mode=max
|
||||
outputs: type=image,name=${{ secrets.DOCKERHUB_USERNAME }}/mofox,push-by-digest=true,name-canonical=true,push=true
|
||||
build-args: |
|
||||
BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
||||
VCS_REF=${{ github.sha }}
|
||||
|
||||
create-manifest:
|
||||
name: Create Multi-Arch Manifest
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- build-amd64
|
||||
- build-arm64
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
# Log in docker hub
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
# Generate metadata for Docker images
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ secrets.DOCKERHUB_USERNAME }}/mofox
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=tag
|
||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=sha,prefix=${{ github.ref_name }}-,enable=${{ github.ref_type == 'branch' }}
|
||||
|
||||
- name: Create and Push Manifest
|
||||
run: |
|
||||
# 为每个标签创建多架构镜像
|
||||
for tag in $(echo "${{ steps.meta.outputs.tags }}" | tr '\n' ' '); do
|
||||
echo "Creating manifest for $tag"
|
||||
docker buildx imagetools create -t $tag \
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/mofox@${{ needs.build-amd64.outputs.digest }} \
|
||||
${{ secrets.DOCKERHUB_USERNAME }}/mofox@${{ needs.build-arm64.outputs.digest }}
|
||||
done
|
||||
@@ -4,6 +4,7 @@ import binascii
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
import json_repair
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
@@ -1023,6 +1024,15 @@ class EmojiManager:
|
||||
- 必须是表情包,非普通截图。
|
||||
- 图中文字不超过5个。
|
||||
请确保你的最终输出是严格的JSON对象,不要添加任何额外解释或文本。
|
||||
输出格式:
|
||||
```json
|
||||
{{
|
||||
"detailed_description": "",
|
||||
"keywords": [],
|
||||
"refined_sentence": "",
|
||||
"is_compliant": true
|
||||
}}
|
||||
```
|
||||
"""
|
||||
|
||||
image_data_for_vlm, image_format_for_vlm = image_base64, image_format
|
||||
@@ -1042,16 +1052,14 @@ class EmojiManager:
|
||||
if not vlm_response_str:
|
||||
continue
|
||||
|
||||
match = re.search(r"\{.*\}", vlm_response_str, re.DOTALL)
|
||||
if match:
|
||||
vlm_response_json = json.loads(match.group(0))
|
||||
description = vlm_response_json.get("detailed_description", "")
|
||||
emotions = vlm_response_json.get("keywords", [])
|
||||
refined_description = vlm_response_json.get("refined_sentence", "")
|
||||
is_compliant = vlm_response_json.get("is_compliant", False)
|
||||
if description and emotions and refined_description:
|
||||
logger.info("[VLM分析] 成功解析VLM返回的JSON数据。")
|
||||
break
|
||||
vlm_response_json = self._parse_json_response(vlm_response_str)
|
||||
description = vlm_response_json.get("detailed_description", "")
|
||||
emotions = vlm_response_json.get("keywords", [])
|
||||
refined_description = vlm_response_json.get("refined_sentence", "")
|
||||
is_compliant = vlm_response_json.get("is_compliant", False)
|
||||
if description and emotions and refined_description:
|
||||
logger.info("[VLM分析] 成功解析VLM返回的JSON数据。")
|
||||
break
|
||||
logger.warning("[VLM分析] VLM返回的JSON数据不完整或格式错误,准备重试。")
|
||||
except (json.JSONDecodeError, AttributeError) as e:
|
||||
logger.error(f"VLM JSON解析失败 (第 {i+1}/3 次): {e}")
|
||||
@@ -1122,7 +1130,7 @@ class EmojiManager:
|
||||
if emoji_base64 is None: # 再次检查读取
|
||||
logger.error(f"[注册失败] 无法读取图片以生成描述: {filename}")
|
||||
return False
|
||||
|
||||
|
||||
# 等待描述生成完成
|
||||
description, emotions = await self.build_emoji_description(emoji_base64)
|
||||
|
||||
@@ -1135,7 +1143,7 @@ class EmojiManager:
|
||||
except Exception as e:
|
||||
logger.error(f"[错误] 删除描述生成失败文件时出错: {e!s}")
|
||||
return False
|
||||
|
||||
|
||||
new_emoji.description = description
|
||||
new_emoji.emotion = emotions
|
||||
except Exception as build_desc_error:
|
||||
@@ -1196,6 +1204,29 @@ class EmojiManager:
|
||||
logger.error(f"[错误] 删除异常处理文件时出错: {remove_error}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def _parse_json_response(cls, response: str) -> dict[str, Any] | None:
|
||||
"""解析 LLM 的 JSON 响应"""
|
||||
try:
|
||||
# 尝试提取 JSON 代码块
|
||||
json_match = re.search(r"```json\s*(.*?)\s*```", response, re.DOTALL)
|
||||
if json_match:
|
||||
json_str = json_match.group(1)
|
||||
else:
|
||||
# 尝试直接解析
|
||||
json_str = response.strip()
|
||||
|
||||
# 移除可能的注释
|
||||
json_str = re.sub(r"//.*", "", json_str)
|
||||
json_str = re.sub(r"/\*.*?\*/", "", json_str, flags=re.DOTALL)
|
||||
|
||||
data = json_repair.loads(json_str)
|
||||
return data
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
logger.warning(f"JSON 解析失败: {e}, 响应: {response[:200]}")
|
||||
return None
|
||||
|
||||
|
||||
emoji_manager = None
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import asyncio
|
||||
import json
|
||||
import re
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
import json_repair
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
@@ -187,8 +187,8 @@ class ShortTermMemoryManager:
|
||||
"importance": 0.7,
|
||||
"attributes": {{
|
||||
"time": "时间信息",
|
||||
"attribute1": "其他属性1"
|
||||
"attribute2": "其他属性2"
|
||||
"attribute1": "其他属性1",
|
||||
"attribute2": "其他属性2",
|
||||
...
|
||||
}}
|
||||
}}
|
||||
@@ -327,7 +327,7 @@ class ShortTermMemoryManager:
|
||||
# 创建决策对象
|
||||
# 将 LLM 返回的大写操作名转换为小写(适配枚举定义)
|
||||
operation_str = data.get("operation", "CREATE_NEW").lower()
|
||||
|
||||
|
||||
decision = ShortTermDecision(
|
||||
operation=ShortTermOperation(operation_str),
|
||||
target_memory_id=data.get("target_memory_id"),
|
||||
@@ -531,7 +531,7 @@ class ShortTermMemoryManager:
|
||||
json_str = re.sub(r"//.*", "", json_str)
|
||||
json_str = re.sub(r"/\*.*?\*/", "", json_str, flags=re.DOTALL)
|
||||
|
||||
data = json.loads(json_str)
|
||||
data = json_repair.loads(json_str)
|
||||
return data
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
@@ -597,35 +597,35 @@ class ShortTermMemoryManager:
|
||||
# 1. 正常筛选:重要性达标的记忆
|
||||
candidates = [mem for mem in self.memories if mem.importance >= self.transfer_importance_threshold]
|
||||
candidate_ids = {mem.id for mem in candidates}
|
||||
|
||||
|
||||
# 2. 检查低重要性记忆是否积压
|
||||
# 剩余的都是低重要性记忆
|
||||
low_importance_memories = [mem for mem in self.memories if mem.id not in candidate_ids]
|
||||
|
||||
|
||||
# 如果低重要性记忆数量超过了上限(说明积压严重)
|
||||
# 我们需要清理掉一部分,而不是转移它们
|
||||
if len(low_importance_memories) > self.max_memories:
|
||||
# 目标保留数量(降至上限的 90%)
|
||||
target_keep_count = int(self.max_memories * 0.9)
|
||||
num_to_remove = len(low_importance_memories) - target_keep_count
|
||||
|
||||
|
||||
if num_to_remove > 0:
|
||||
# 按创建时间排序,删除最早的
|
||||
low_importance_memories.sort(key=lambda x: x.created_at)
|
||||
to_remove = low_importance_memories[:num_to_remove]
|
||||
|
||||
|
||||
for mem in to_remove:
|
||||
if mem in self.memories:
|
||||
self.memories.remove(mem)
|
||||
|
||||
|
||||
logger.info(
|
||||
f"短期记忆清理: 移除了 {len(to_remove)} 条低重要性记忆 "
|
||||
f"(保留 {len(self.memories)} 条)"
|
||||
)
|
||||
|
||||
|
||||
# 触发保存
|
||||
asyncio.create_task(self._save_to_disk())
|
||||
|
||||
|
||||
return candidates
|
||||
|
||||
async def clear_transferred_memories(self, memory_ids: list[str]) -> None:
|
||||
|
||||
Reference in New Issue
Block a user