Skip to content

feat(storage): add auto language detection for semantic summary generation#1076

Open
likzn wants to merge 2 commits intovolcengine:mainfrom
likzn:feature/semantic-processor-language-test
Open

feat(storage): add auto language detection for semantic summary generation#1076
likzn wants to merge 2 commits intovolcengine:mainfrom
likzn:feature/semantic-processor-language-test

Conversation

@likzn
Copy link
Copy Markdown

@likzn likzn commented Mar 29, 2026

Summary

实现多语言摘要生成功能。当前的 summary 和 overview 统一生成英文内容,现在根据文档内容自动检测语言并生成对应语言的摘要,提升实用性。

Type of Change

  • New feature (feat)

Testing

  • Unit tests pass (25 tests passed)
  • Manual testing completed

Related Issues

Checklist

  • Code follows project style guidelines
  • Tests added for new functionality
  • Documentation updated (if needed)
  • All tests pass

Changes

  • SemanticProcessor 集成 _detect_language_from_text 自动检测内容语言
  • 更新 5 个 prompt 模板:code_ast_summary.yaml, code_summary.yaml, document_summary.yaml, file_summary.yaml, overview_generation.yaml
  • 通过 Output Language: {{ output_language }} 指令引导 LLM 生成对应语言摘要
  • 支持语言:zh-CN, en, ja, ko, ru, ar

likzn added 2 commits March 29, 2026 23:03
… generation

- Integrate language detection into SemanticProcessor for automatic output language
- Update 5 prompt templates (code_ast_summary, code_summary, document_summary, file_summary, overview_generation)
- Add output_language parameter injection via Output Language: directive
- Fix language_fallback config field documentation
@github-actions
Copy link
Copy Markdown

Failed to generate code suggestions for PR

@likzn
Copy link
Copy Markdown
Author

likzn commented Mar 29, 2026

@qin-ctx Hi

我看这个issue指定给你了,我尝试优化下了这个逻辑,这个PR主要是实现了 Issue #934 - 多语言语义摘要生成功能。有空可以看下

背景

当前上传文件后生成的 summary 和 overview 统一为英文,对其他语言用户不够友好

优化方案

本次优化复用了已有的 _detect_language_from_text 函数,实现了一个更通用的方案:

  1. 自动语言检测 :在 _generate_text_summary 、 _single_generate_overview 、 _batch_generate_overview 方法中,先调用 _detect_language_from_text 检测内容语言
  2. 动态注入 :通过 prompt 模板的 Output Language: {{ output_language }} 指令引导 LLM 生成对应语言
  3. 零配置 :无需用户手动配置 language_fallback,fallback 仅作为空内容时的保底

变更内容

  • 3 个核心方法集成自动语言检测
  • 5 个 prompt 模板添加 output_language 变量: code_ast_summary , code_summary , document_summary , file_summary , overview_generation
  • 25 个单元测试覆盖语言检测 + 端到端流程

测试结果

  • Unit tests: 25 passed
  • 覆盖语言:zh-CN, en, ja, ko, ru, ar

@qin-ctx
Copy link
Copy Markdown
Collaborator

qin-ctx commented Mar 30, 2026

@likzn 哈喽,感谢贡献。可以提供一些摘要结果截图吗,比如配置了语言选项后,摘要等信息和语言配置保持一致

@qin-ctx qin-ctx self-assigned this Mar 30, 2026
@likzn
Copy link
Copy Markdown
Author

likzn commented Mar 30, 2026

@likzn 哈喽,感谢贡献。可以提供一些摘要结果截图吗,比如配置了语言选项后,摘要等信息和语言配置保持一致

晚点我补充下人工测试结果

@MaojiaSheng MaojiaSheng requested a review from qin-ctx March 30, 2026 06:18
@qin-ctx
Copy link
Copy Markdown
Collaborator

qin-ctx commented Mar 30, 2026

fixed #1067

@likzn
Copy link
Copy Markdown
Author

likzn commented Mar 30, 2026

不好意思,看了下没有embedding模型,导致api层调不通,我这里写了个vlm层的识别单元测试结合vlm模型,就是将中文内容给到summay模板可以返回对应中文的摘要,给了对应的截图和测试文件,可以看一下
image
image

测试文件


"""使用真实 LLM 的端到端测试。

跳过 Embedding,直接测试 Summary 生成功能。

运行方式:
uv run pytest tests/storage/test_real_llm_summary.py -v -s

注意:需要配置火山引擎 API Key:
- API Key: 你的火山引擎 API Key
"""

import asyncio

import pytest

from openviking.models.vlm import VLMFactory
from openviking.prompts import render_prompt
from openviking.session.memory.utils.language import _detect_language_from_text

class TestRealLLMSummary:
"""使用真实 LLM 测试 Summary 生成。"""

@pytest.fixture
def vlm_config(self) -> dict:
    """从配置文件读取 VLM 配置。"""
    import json
    from pathlib import Path

    config_path = Path.home() / ".openviking" / "ov.conf"
    if config_path.exists():
        with open(config_path) as f:
            config = json.load(f)
            vlm_cfg = config.get("vlm", {})
            return {
                "model": vlm_cfg.get("model", ""),
                "api_key": vlm_cfg.get("api_key", ""),
                "api_base": vlm_cfg.get("api_base", "https://ark.cn-beijing.volces.com/api/v3"),
                "provider": vlm_cfg.get("provider", "volcengine"),
            }

    pytest.skip("No VLM config found in ~/.openviking/ov.conf")

@pytest.fixture
def vlm_client(self, vlm_config):
    """创建 VLM 客户端。"""
    return VLMFactory.create(vlm_config)

@pytest.fixture
def chinese_content(self) -> str:
    """中文测试内容。"""
    return '''"""中文测试文件 - 用户管理系统"""

class 用户管理:
"""用户管理类"""

def __init__(self):
    self.用户列表 = []

def 添加用户(self, 姓名: str, 年龄: int):
    """添加新用户"""
    用户 = {"姓名": 姓名, "年龄": 年龄}
    self.用户列表.append(用户)
    return 用户

def 删除用户(self, 姓名: str):
    """根据姓名删除用户"""
    self.用户列表 = [u for u in self.用户列表 if u["姓名"] != 姓名]

def 获取所有用户(self):
    """返回所有用户"""
    return self.用户列表

def 欢迎函数():
"""打印欢迎信息"""
print("欢迎使用用户管理系统!")
print("这是一个中文注释的Python代码文件")

if name == "main":
管理器 = 用户管理()
管理器.添加用户("张三", 25)
管理器.添加用户("李四", 30)
欢迎函数()'''

@pytest.fixture
def english_content(self) -> str:
    """英文测试内容。"""
    return '''"""English Test File - User Management System"""

class UserManager:
"""User management class"""

def __init__(self):
    self.users = []

def add_user(self, name: str, age: int):
    """Add new user"""
    user = {"name": name, "age": age}
    self.users.append(user)
    return user

def delete_user(self, name: str):
    """Delete user by name"""
    self.users = [u for u in self.users if u["name"] != name]

def get_all_users(self):
    """Return all users"""
    return self.users

def welcome():
"""Print welcome message"""
print("Welcome to User Management System!")
print("This is a Python code file with English comments")

if name == "main":
manager = UserManager()
manager.add_user("John", 25)
manager.add_user("Jane", 30)
welcome()'''

def _count_chinese_chars(self, text: str) -> int:
    """统计中文字符数量。"""
    return sum(1 for c in text if "\u4e00" <= c <= "\u9fff")

@pytest.mark.asyncio
async def test_chinese_summary_generation(self, chinese_content, vlm_client):
    """端到端测试:中文内容 -> 语言检测 -> 中文 Summary"""
    print("\n" + "=" * 70)
    print("测试:中文内容 -> 中文 Summary")
    print("=" * 70)

    # Step 1: 打印原文
    print("\n【Step 1】原文内容")
    print("-" * 50)
    print(chinese_content)
    print("-" * 50)

    # Step 2: 语言检测
    print("\n【Step 2】语言检测")
    print("-" * 50)
    detected_lang = _detect_language_from_text(chinese_content, fallback_language="en")
    print(f"检测结果: {detected_lang}")
    print("-" * 50)
    assert detected_lang == "zh-CN", f"Expected zh-CN, got {detected_lang}"

    # Step 3: 渲染 Prompt
    print("\n【Step 3】渲染 Prompt")
    print("-" * 50)
    prompt = render_prompt(
        "semantic.code_summary",
        {
            "file_name": "user_manager.py",
            "content": chinese_content,
            "output_language": detected_lang,
        }
    )
    print(f"Prompt 长度: {len(prompt)} 字符")
    print(f"Output Language 指令: Output Language: {detected_lang}")
    print("-" * 50)

    # 打印 Prompt 关键部分
    print("\nPrompt 关键内容:")
    lines = prompt.split("\n")
    for i, line in enumerate(lines[:30]):
        print(f"  {line}")
    if len(lines) > 30:
        print(f"  ... (共 {len(lines)} 行)")
    print("-" * 50)

    # Step 4: 调用 LLM
    print("\n【Step 4】调用火山引擎 LLM")
    print("-" * 50)
    print("正在生成 Summary...")
    summary = await vlm_client.get_completion_async(prompt)
    print("生成完成!")
    print("-" * 50)

    # Step 5: 打印生成的 Summary
    print("\n【Step 5】生成的 Summary")
    print("-" * 50)
    print(summary)
    print("-" * 50)

    # Step 6: 验证
    print("\n【Step 6】验证结果")
    print("-" * 50)
    chinese_chars = self._count_chinese_chars(summary)
    print(f"Summary 中文字符数: {chinese_chars}")
    print(f"语言检测正确: {detected_lang == 'zh-CN'}")
    print(f"Summary 包含足够中文字符 (>= 5): {chinese_chars >= 5}")
    print("-" * 50)

    assert chinese_chars >= 5, (
        f"Expected Chinese summary with >= 5 Chinese chars, got {chinese_chars}"
    )

    print("\n✅ 测试通过!")

@pytest.mark.asyncio
async def test_english_summary_generation(self, english_content, vlm_client):
    """端到端测试:英文内容 -> 语言检测 -> 英文 Summary"""
    import re

    print("\n" + "=" * 70)
    print("测试:英文内容 -> 英文 Summary")
    print("=" * 70)

    # Step 1: 打印原文
    print("\n【Step 1】原文内容")
    print("-" * 50)
    print(english_content)
    print("-" * 50)

    # Step 2: 语言检测
    print("\n【Step 2】语言检测")
    print("-" * 50)
    detected_lang = _detect_language_from_text(english_content, fallback_language="en")
    print(f"检测结果: {detected_lang}")
    print("-" * 50)
    assert detected_lang == "en", f"Expected en, got {detected_lang}"

    # Step 3: 渲染 Prompt
    print("\n【Step 3】渲染 Prompt")
    print("-" * 50)
    prompt = render_prompt(
        "semantic.code_summary",
        {
            "file_name": "user_manager.py",
            "content": english_content,
            "output_language": detected_lang,
        }
    )
    print(f"Prompt 长度: {len(prompt)} 字符")
    print(f"Output Language 指令: Output Language: {detected_lang}")
    print("-" * 50)

    # Step 4: 调用 LLM
    print("\n【Step 4】调用火山引擎 LLM")
    print("-" * 50)
    print("正在生成 Summary...")
    summary = await vlm_client.get_completion_async(prompt)
    print("生成完成!")
    print("-" * 50)

    # Step 5: 打印生成的 Summary
    print("\n【Step 5】生成的 Summary")
    print("-" * 50)
    print(summary)
    print("-" * 50)

    # Step 6: 验证
    print("\n【Step 6】验证结果")
    print("-" * 50)
    english_pattern = re.search(
        r"\b(the|is|are|user|management|class)\b", summary, re.I
    )
    print(f"包含英文常用词: {english_pattern is not None}")
    print(f"语言检测正确: {detected_lang == 'en'}")
    print("-" * 50)

    assert english_pattern is not None, (
        f"Expected English summary with common English words"
    )

    print("\n✅ 测试通过!")

@pytest.mark.asyncio
async def test_multilingual_comparison(self, chinese_content, english_content, vlm_client):
    """端到端测试:中英文对比"""
    import re

    print("\n" + "=" * 70)
    print("测试:中英文 Summary 对比")
    print("=" * 70)

    # 中文测试
    print("\n--- 中文测试 ---")
    lang_ch = _detect_language_from_text(chinese_content, fallback_language="en")
    prompt_ch = render_prompt("semantic.code_summary", {
        "file_name": "test.py",
        "content": chinese_content,
        "output_language": lang_ch,
    })
    summary_ch = await vlm_client.get_completion_async(prompt_ch)
    chinese_chars_ch = self._count_chinese_chars(summary_ch)
    print(f"语言检测: {lang_ch}")
    print(f"Summary 中文字符数: {chinese_chars_ch}")
    print(f"Summary 预览: {summary_ch[:100]}...")

    # 英文测试
    print("\n--- 英文测试 ---")
    lang_en = _detect_language_from_text(english_content, fallback_language="en")
    prompt_en = render_prompt("semantic.code_summary", {
        "file_name": "test.py",
        "content": english_content,
        "output_language": lang_en,
    })
    summary_en = await vlm_client.get_completion_async(prompt_en)
    chinese_chars_en = self._count_chinese_chars(summary_en)
    print(f"语言检测: {lang_en}")
    print(f"Summary 中文字符数: {chinese_chars_en}")
    print(f"Summary 预览: {summary_en[:100]}...")

    # 对比验证
    print("\n--- 验证 ---")
    assert chinese_chars_ch > chinese_chars_en * 2, (
        f"Chinese content should produce more Chinese chars. "
        f"Chinese: {chinese_chars_ch}, English: {chinese_chars_en}"
    )
    print(f"✅ 中文内容产生 {chinese_chars_ch} 个中文字符")
    print(f"✅ 英文内容产生 {chinese_chars_en} 个中文字符")
    print(f"✅ 中文内容产生更多中文字符 (>{chinese_chars_en*2})")

终端测试输出

测试用例 1:中文内容 -> 中文 Summary

============================= test session starts ==============================
tests/storage/test_real_llm_summary.py::TestRealLLMSummary::test_chinese_summary_generation

======================================================================
测试:中文内容 -> 中文 Summary

【Step 1】原文内容

"""中文测试文件 - 用户管理系统"""
class 用户管理:
"""用户管理类"""

def __init__(self):
    self.用户列表 = []

def 添加用户(self, 姓名: str, 年龄: int):
    """添加新用户"""
    用户 = {"姓名": 姓名, "年龄": 年龄}
    self.用户列表.append(用户)
    return 用户

def 删除用户(self, 姓名: str):
    """根据姓名删除用户"""
    self.用户列表 = [u for u in self.用户列表 if u["姓名"] != 姓名]

def 获取所有用户(self):
    """返回所有用户"""
    return self.用户列表

def 欢迎函数():
"""打印欢迎信息"""
print("欢迎使用用户管理系统!")
print("这是一个中文注释的Python代码文件")

if name == "main":
管理器 = 用户管理()
管理器.添加用户("张三", 25)
管理器.添加用户("李四", 30)
欢迎函数()

【Step 2】语言检测

检测结果: zh-CN

【Step 3】渲染 Prompt

Prompt 长度: 1517 字符
Output Language 指令: Output Language: zh-CN

Prompt 关键内容:
Output Language: zh-CN

You are a code analysis expert. Generate a concise yet informative summary for the following code file.

【File Name】
user_manager.py

【File Content】
"""中文测试文件 - 用户管理系统"""
class 用户管理:
"""用户管理类"""

  def __init__(self):
      self.用户列表 = []

  def 添加用户(self, 姓名: str, 年龄: int):
      """添加新用户"""
      用户 = {"姓名": 姓名, "年龄": 年龄}
      self.用户列表.append(用户)
      return 用户

  def 删除用户(self, 姓名: str):
      """根据姓名删除用户"""
      self.用户列表 = [u for u in self.用户列表 if u["姓名"] != 姓名]

  def 获取所有用户(self):
      """返回所有用户"""
      return self.用户列表

def 欢迎函数():
... (共 55 行)

【Step 4】调用火山引擎 LLM

正在生成 Summary...
生成完成!

【Step 5】生成的 Summary

这是基于Python实现的用户管理系统功能文件,核心作用是提供用户数据的基础增删查询能力及系统欢迎提示功能。
文件核心包含「用户管理」类和「欢迎函数」两个组件,「用户管理」类内部用列表存储用户字典结构的用户数据,封装了添加用户、删除用户、获取所有用户三个操作方法,支持传入姓名、年龄参数完成对应用户操作,「欢迎函数」用于打印系统欢迎提示语。
该文件无外部依赖,全部使用Python内置语法实现,采用中文标识符编写。
作为独立的用户管理模块,可直接运行也可被其他业务模块导入调用,适用于小型项目的基础用户信息管理场景。

【Step 6】验证结果

Summary 中文字符数: 219
语言检测正确: True
Summary 包含足够中文字符 (>= 5): True

✅ 测试通过!
PASSED


测试用例 2:英文内容 -> 英文 Summary

tests/storage/test_real_llm_summary.py::TestRealLLMSummary::test_english_summary_generation

======================================================================
测试:英文内容 -> 英文 Summary

【Step 1】原文内容

"""English Test File - User Management System"""
class UserManager:
"""User management class"""

def __init__(self):
    self.users = []

def add_user(self, name: str, age: int):
    """Add new user"""
    user = {"name": name, "age": age}
    self.users.append(user)
    return user

def delete_user(self, name: str):
    """Delete user by name"""
    self.users = [u for u in self.users if u["name"] != name]

def get_all_users(self):
    """Return all users"""
    return self.users

def welcome():
"""Print welcome message"""
print("Welcome to User Management System!")
print("This is a Python code file with English comments")

if name == "main":
manager = UserManager()
manager.add_user("John", 25)
manager.add_user("Jane", 30)
welcome()

【Step 2】语言检测

检测结果: en

【Step 3】渲染 Prompt

Prompt 长度: 1740 字符
Output Language 指令: Output Language: en

【Step 4】调用火山引擎 LLM

正在生成 Summary...
生成完成!

【Step 5】生成的 Summary

This Python code file named user_manager.py serves as a core module for a lightweight user management system, implementing basic user data operation capabilities. It contains the core UserManager class that maintains an internal list to store user records as dictionaries with name and age fields, and provides three key methods: add_user for appending new user entries, delete_user for removing users matching a specified name, and get_all_users for returning the full list of stored users. It also includes a standalone welcome() function that prints system welcome messages to the console. The file has no external dependencies, relying only on native Python built-in data structures and functions, following standard object-oriented design patterns for business logic encapsulation. When executed as a standalone script, it initializes a UserManager instance, adds two test users, and triggers the welcome message. As a foundational business logic module in the project, it can be imported and called by higher-level interface modules to provide user data management support for larger applications.
Relevant keywords: user management, Python, CRUD operations, in-memory storage, object-oriented programming, dictionary data structure, entrypoint script.

【Step 6】验证结果

包含英文常用词: True
语言检测正确: True

✅ 测试通过!
PASSED


测试用例 3:中英文 Summary 对比

tests/storage/test_real_llm_summary.py::TestRealLLMSummary::test_multilingual_comparison

======================================================================
测试:中英文 Summary 对比

--- 中文测试 ---
语言检测: zh-CN
Summary 中文字符数: 261
Summary 预览: 这是一个使用Python编写的用户管理系统测试文件,核心用途是实现基础的用户信息增删查询能力,属于业务逻辑演示类代码。
文件核心包含用户管理类和欢迎函数两个关键组件:用户管理类内部以列表作...

--- 英文测试 ---
语言检测: en
Summary 中文字符数: 0
Summary 预览: This Python code file named test.py is a demo implementation of a basic user management system, prim...

--- 验证 ---
✅ 中文内容产生 261 个中文字符
✅ 英文内容产生 0 个中文字符
✅ 中文内容产生更多中文字符 (>0)
PASSED


测试结果汇总

======================== 3 passed, 5 warnings in 28.58s ========================

验证结论

测试用例 源语言 检测结果 Summary 语言 中文字符数 状态
test_chinese_summary_generation 中文代码 zh-CN 中文 219
test_english_summary_generation 英文代码 en 英文 0
test_multilingual_comparison 对比 zh-CN/en 混合 261/0

功能验证点

  1. 语言检测_detect_language_from_text 能正确识别中英文内容

  2. Prompt 注入Output Language: <lang> 指令正确注入到 Prompt 头部

  3. 多语言生成:LLM 能根据 Output Language 指令生成对应语言的 Summary

  4. 中文保持:中文内容生成的 Summary 保持中文(219-261 个中文字符)

  5. 英文纯净:英文内容生成的 Summary 不含中文字符

结论Output Language 指令能正确引导 LLM 生成对应语言的 Summary,多语言语义摘要生成功能验证通过。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

[Feature]: If you want to summarize and overview, you can configure it to generate Chinese

2 participants