### GitHub Actions Deployment Pipeline (YAML) Source: https://context7.com/foxcyber907/ling-docs/llms.txt A GitHub Actions workflow for deploying a VitePress site to GitHub Pages. It automates the build process, including checking out code, setting up Node.js, installing dependencies, building the site with VitePress, and uploading the artifacts for deployment. ```yaml # .github/workflows/deploy.yml name: Deploy VitePress site to Pages on: push: branches: [main] workflow_dispatch: permissions: contents: read pages: write id-token: write concurrency: group: pages cancel-in-progress: false jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Node uses: actions/setup-node@v4 with: node-version: 22 cache: npm - name: Setup Pages uses: actions/configure-pages@v4 - name: Install dependencies run: npm ci - name: Build with VitePress run: npm run docs:build - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: docs/.vitepress/dist deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} needs: build runs-on: ubuntu-latest name: Deploy steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 ``` -------------------------------- ### Configure RAG System with Environment Variables (Bash) Source: https://context7.com/foxcyber907/ling-docs/llms.txt This snippet shows how to configure the RAG system using environment variables in a .env file. It covers enabling the RAG system, specifying paths for chat history and ChromaDB, and setting retrieval parameters like the number of contexts to retrieve and context window sizes. It also includes the command to install necessary Python dependencies. ```bash # .env configuration for RAG system USE_RAG=true # Enable RAG system RAG_HISTORY_PATH=rag_chat_history # History storage path CHROMA_DB_PATH=chroma_db_store # ChromaDB storage path # Retrieval configuration RAG_RETRIEVAL_COUNT=3 # Number of context blocks to retrieve RAG_CANDIDATE_MULTIPLIER=3 # Candidate results multiplier RAG_CONTEXT_M_BEFORE=2 # Forward context window size RAG_CONTEXT_N_AFTER=2 # Backward context window size # Prompt configuration RAG_PROMPT_PREFIX="以下是根据你的问题从历史对话中检索到的相关片段,其中包含了对话发生的大致时间:" RAG_PROMPT_SUFFIX="" # Optional suffix # Install dependencies pip install sentence-transformers chromadb torch ``` -------------------------------- ### VitePress Configuration with TypeScript and Plugins Source: https://context7.com/foxcyber907/ling-docs/llms.txt This configuration sets up a VitePress documentation site using TypeScript. It includes plugins for Mermaid diagrams and Git changelog tracking, along with defining navigation, sidebar structure, and theme settings. ```typescript import { defineConfig } from 'vitepress' import { withMermaid } from 'vitepress-plugin-mermaid' import { GitChangelog, GitChangelogMarkdownSection } from '@nolebase/vitepress-plugin-git-changelog/vite' export default withMermaid( defineConfig({ title: "LingChat Docs", description: "LingChat的官方文档", lang: 'zh-CN', head: [ ['link', { rel: 'icon', href: '/avatars/LingChat.webp' }], ['meta', { name: 'description', content: 'LingChat是一个高自由度的虚拟恋人系统' }] ], vite: { plugins: [ GitChangelog({ repoURL: () => 'https://github.com/foxcyber907/ling-docs', maxGitLogCount: 5000, includeDirs: ['docs'], enableAuthorAvatars: true, enableCommitHashLink: true, }), GitChangelogMarkdownSection({ sections: { disableChangelog: false, disableContributors: false, } }) ] }, markdown: { config: (md) => { // Mermaid configured via withMermaid } }, mermaid: { theme: 'default', themeVariables: { primaryColor: '#ff0000' } }, themeConfig: { editLink: { pattern: 'https://github.com/foxcyber907/ling-docs/edit/main/docs/:path', text: '在 GitHub 编辑此页' }, search: { provider: 'local', }, nav: [ { text: '首页', link: '/' }, { text: '用户手册', link: '/manual/' }, { text: '开发文档', link: '/develop/' }, { text: '常见问题', link: '/faq/' }, { text: '开发团队', link: '/devlist/' }, { text: '官方群聊', items: [ { text: 'QQ安装答疑群', link: 'https://qm.qq.com/q/GTaZGFXqIQ' }, { text: 'Telegram安装答疑群', link: 'https://t.me/aigalgame' } ] }, ], sidebar: { '/manual/': [ { text: '用户手册', items: [ { text: '介绍', link: '/manual/' } ] }, { text: '部署方法(新版)', collapsed: false, items: [ { text: 'Windows部署', link: '/manual/deployment/win' }, { text: 'Android部署', link: '/manual/deployment/android' }, { text: 'Linux部署', link: '/manual/deployment/linux' }, ] }, { text: '额外功能', collapsed: false, items: [ { text: 'RAG 系统', link: '/manual/expand/rag' }, { text: '语音生成', link: '/manual/expand/voice' }, { text: '视觉功能', link: '/manual/expand/vision' }, { text: '桌宠', link: '/manual/expand/ling_pet'} ] }, ], '/develop/': [ { text: '开发文档', items: [ { text: '介绍', link: '/develop/' }, { text: '开发流程', link: '/develop/dev_process' }, { text: '项目结构与实现概述', link: '/develop/project_structure' }, { text: '人物创建指南', link: '/develop/character_guide' }, { text: 'LingChat 后端代码结构', link: '/develop/backend' }, ] } ] }, socialLinks: [ { icon: 'github', link: 'https://github.com/SlimeBoyOwO/LingChat/' } ], lastUpdated: { text: "最后更新", formatOptions: { dateStyle: "short", timeStyle: "short", }, }, } }) ) ``` -------------------------------- ### Initialize AIService - Python Source: https://context7.com/foxcyber907/ling-docs/llms.txt Initializes the AIService with configuration settings, setting up core AI modules like RAG, LLM, TTS, and messaging. It manages asynchronous tasks for message processing and global message handling. Dependencies include core.memory, core.llm_providers, core.TTS, core.messaging, and core.emotion. ```python from core.memory import RAGManager from core.llm_providers import LLMManager from core.TTS import VoiceMaker from core.messaging import MessageGenerator, MessageBroker from core.emotion import EmotionAnalyzer import os import asyncio import logging logger = logging.getLogger(__name__) class AIServiceConfig: def __init__(self, clients: set, user_id: str): self.clients = clients self.user_id = user_id class Translator: def __init__(self, voice_maker): self.voice_maker = voice_maker class MessageProcessor: def __init__(self, voice_maker): self.voice_maker = voice_maker class AILogger: def debug(self, message): logger.debug(message) def error(self, message): logger.error(message) def info(self, message): logger.info(message) class EventsScheduler: def __init__(self, config): self.config = config class ScriptManager: def __init__(self, config): self.config = config message_broker = MessageBroker() class AIService: def __init__(self, settings: dict[str, str]): """ Initialize AI service with all sub-modules Args: settings: Configuration from character settings.txt """ self.memory = [] # Conversation history self.user_id = "1" # Core configuration self.config = AIServiceConfig(clients=set(), user_id=self.user_id) # Initialize sub-modules self.use_rag = os.environ.get("USE_RAG", "False").lower() == "true" self.rag_manager = RAGManager() if self.use_rag else None self.llm_model = LLMManager() self.ai_logger = AILogger() self.voice_maker = VoiceMaker() self.translator = Translator(self.voice_maker) self.message_broker = message_broker self.message_processor = MessageProcessor(self.voice_maker) self.message_generator = MessageGenerator( self.config, self.voice_maker, self.message_processor, self.translator, self.llm_model, self.rag_manager, self.ai_logger ) # Async processing tasks self.client_tasks: Dict[str, asyncio.Task] = {} self.processing_task = asyncio.create_task(self._process_message_loop()) self.global_task = asyncio.create_task(self._process_global_messages()) # Additional features self.events_scheduler = EventsScheduler(self.config) self.scripts_manager = ScriptManager(self.config) # Load character settings self.import_settings(settings) self.reset_memory() async def _process_client_messages(self, client_id: str): """ Process messages from a specific client Producer-consumer pattern implementation """ input_queue_name = f"ai_input_{client_id}" try: async for message in self.message_broker.subscribe(input_queue_name): try: self.is_processing = True user_message = message.get("content", "") if user_message: self.message_generator.memory_init(self.memory) responses = [] async for response in self.message_generator.process_message_stream(user_message): await message_broker.publish(client_id, response.model_dump()) responses.append(response) logger.debug(f"消息处理完成,共生成 {len(responses)} 个响应片段") self.is_processing = False except Exception as e: logger.error(f"处理消息时发生错误: {e}") self.is_processing = False except asyncio.CancelledError: logger.info(f"客户端 {client_id} 的消息处理任务已被取消") except Exception as e: logger.error(f"客户端 {client_id} 的消息处理发生严重错误: {e}") raise async def _process_message_loop(self): # Placeholder for the actual message loop implementation pass async def _process_global_messages(self): # Placeholder for the actual global message processing implementation pass def import_settings(self, settings: dict[str, str]): # Placeholder for settings import pass def reset_memory(self): # Placeholder for memory reset pass ``` -------------------------------- ### LLM Streaming Completion (Python) Source: https://context7.com/foxcyber907/ling-docs/llms.txt Python code for creating streaming completions using the OpenAI library. It initializes an LLMManager with environment variables and defines an asynchronous method to stream content chunks from the LLM response. Requires the 'openai' library. ```python # core/llm_providers/llm_manager.py import openai import os from async_generator import AsyncGenerator from loguru import logger class LLMManager: def __init__(self): self.api_key = os.environ.get("LLM_API_KEY") self.base_url = os.environ.get("LLM_BASE_URL") self.model = os.environ.get("LLM_MODEL") self.client = openai.OpenAI( api_key=self.api_key, base_url=self.base_url ) async def create_stream(self, messages: list[dict]) -> AsyncGenerator: """ Create streaming completion Args: messages: Conversation history in OpenAI format Yields: Content chunks from LLM response stream """ try: response = await self.client.chat.completions.create( model=self.model, messages=messages, stream=True, temperature=0.7, max_tokens=2000 ) async for chunk in response: if chunk.choices[0].delta.content: yield chunk.choices[0].delta.content except Exception as e: logger.error(f"LLM streaming error: {e}") raise ``` -------------------------------- ### LLM and Vision Model Configuration (.env) Source: https://context7.com/foxcyber907/ling-docs/llms.txt Environment variables for configuring Large Language Models (LLM) and Vision models. Includes API keys, base URLs, and model identifiers. Supports various providers like DeepSeek, OpenAI, and compatible endpoints. ```env # .env LLM configuration LLM_API_KEY=your_api_key_here # API key for LLM provider LLM_BASE_URL=https://api.deepseek.com/v1 # API endpoint URL LLM_MODEL=deepseek-chat # Model identifier # Vision model configuration (optional) VD_API_KEY=your_vision_api_key VD_BASE_URL=https://api.openai.com/v1 VD_MODEL=gpt-4-vision-preview # Supported providers: # - DeepSeek # - Silicon Flow # - Rinkoai # - OpenAI # - Any OpenAI-compatible API endpoint ``` -------------------------------- ### Asynchronous Message Broker Source: https://context7.com/foxcyber907/ling-docs/llms.txt Implements an asynchronous message queue using Python's asyncio for decoupled communication. It supports publishing messages to client-specific queues and subscribing to them, enabling a robust publish-subscribe pattern essential for microservices and real-time applications. ```python from typing import Dict, AsyncGenerator import asyncio import time class MessageBroker: def __init__(self): self.queues: Dict[str, asyncio.Queue] = {} async def publish(self, client_id: str, message: dict): """ Publish message to client-specific queue Args: client_id: Unique client identifier message: Message dictionary to send """ if client_id not in self.queues: self.queues[client_id] = asyncio.Queue() await self.queues[client_id].put(message) async def subscribe(self, client_id: str) -> AsyncGenerator[dict, None]: """ Subscribe to client-specific message queue Args: client_id: Unique client identifier Yields: Messages from the queue as they arrive """ if client_id not in self.queues: self.queues[client_id] = asyncio.Queue() while True: yield await self.queues[client_id].get() async def enqueue_ai_message(self, client_id: str, content: str): """ Enqueue message for AI processing """ queue_name = f"ai_input_{client_id}" await self.publish(queue_name, {"content": content, "timestamp": time.time()}) # Global singleton instance message_broker = MessageBroker() ``` -------------------------------- ### RAG System Workflow Implementation (Python) Source: https://context7.com/foxcyber907/ling-docs/llms.txt This Python code defines a RAGManager class responsible for implementing the RAG system's workflow. The `rag_append_sys_message` method vectorizes user queries, searches a ChromaDB for similar conversations, retrieves relevant contexts, and augments the current conversation context with this historical information before returning it for LLM generation. It utilizes environment variables for configuration. ```python # RAG system workflow implementation import os class RAGManager: def __init__(self): self.history_path = os.environ.get("RAG_HISTORY_PATH", "rag_chat_history") self.chroma_db_path = os.environ.get("CHROMA_DB_PATH", "chroma_db_store") self.retrieval_count = int(os.environ.get("RAG_RETRIEVAL_COUNT", "3")) async def rag_append_sys_message(self, context, rag_messages, user_message): """ 1. Vectorize user query using Sentence Transformers 2. Search ChromaDB for semantically similar conversations 3. Retrieve top-k relevant context blocks 4. Augment current context with historical information 5. Return enhanced context for LLM generation """ # Semantic search in vector database relevant_contexts = self.search_similar_contexts(user_message) # Build augmented context rag_prompt = self._build_rag_context(relevant_contexts) context.insert(0, {"role": "system", "content": rag_prompt}) return context def search_similar_contexts(self, query): # Placeholder for actual ChromaDB search implementation print(f"Searching for similar contexts to: {query}") return ["context1", "context2"] def _build_rag_context(self, contexts): # Placeholder for building the RAG prompt return f"Retrieved contexts: {', '.join(contexts)}" ``` -------------------------------- ### Character Configuration Settings Source: https://context7.com/foxcyber907/ling-docs/llms.txt Defines character settings for a game or application, including personality traits, voice models, and display parameters. This configuration is stored in a plain text file. ```text # game_data/characters/{character_name}/settings.txt title = 星空列车-音理 # Character card title info = """ # Multi-line character description 火车,要出发了哦~ 哥哥,准备好一起旅行了吗? """ ai_name = 音理 # AI display name in chat ai_subtitle = 邻家的女孩 # AI subtitle user_name = 旅人 # Player display name user_subtitle = 列车の乘客 # Player subtitle thinking_message = 音理的心脏为你跳动中.... # Thinking indicator text scale = 1.9 # Character sprite scale offset = -3 # Y-axis offset for positioning bubble_top = 15 # Emotion bubble Y position bubble_left = 23 # Emotion bubble X position ``` -------------------------------- ### Process Client Messages - Python Source: https://context7.com/foxcyber907/ling-docs/llms.txt Handles incoming messages from a specific client using a producer-consumer pattern. It subscribes to a dedicated message queue, processes user input, generates responses via the MessageGenerator, and publishes them back. Includes error handling for message processing and task cancellation. ```python async def _process_client_messages(self, client_id: str): """ Process messages from a specific client Producer-consumer pattern implementation """ input_queue_name = f"ai_input_{client_id}" try: async for message in self.message_broker.subscribe(input_queue_name): try: self.is_processing = True user_message = message.get("content", "") if user_message: self.message_generator.memory_init(self.memory) responses = [] async for response in self.message_generator.process_message_stream(user_message): await message_broker.publish(client_id, response.model_dump()) responses.append(response) logger.debug(f"消息处理完成,共生成 {len(responses)} 个响应片段") self.is_processing = False except Exception as e: logger.error(f"处理消息时发生错误: {e}") self.is_processing = False except asyncio.CancelledError: logger.info(f"客户端 {client_id} 的消息处理任务已被取消") except Exception as e: logger.error(f"客户端 {client_id} 的消息处理发生严重错误: {e}") raise ``` -------------------------------- ### FastAPI WebSocket Chat Endpoint Source: https://context7.com/foxcyber907/ling-docs/llms.txt Handles WebSocket connections for real-time chat. It accepts connections, assigns client IDs, and manages message sending and receiving tasks using an asynchronous message broker. It's designed for real-time bidirectional communication between clients and the server. ```python from fastapi import WebSocket, WebSocketDisconnect from core.messaging import message_broker import uuid import asyncio import logging logger = logging.getLogger(__name__) class ChatEndpoint: async def websocket_endpoint(self, websocket: WebSocket): """ Handle WebSocket connections for real-time chat Flow: 1. Accept WebSocket connection 2. Send unique client_id to frontend 3. Start message listener and sender tasks 4. Handle user messages and broadcast AI responses """ await websocket.accept() client_id = str(uuid.uuid4()) # Send client ID to frontend await websocket.send_json({"type": "client_id", "data": client_id}) # Start async tasks send_task = asyncio.create_task(self._send_messages(websocket, client_id)) receive_task = asyncio.create_task(self._receive_messages(websocket, client_id)) await asyncio.gather(send_task, receive_task) async def _handle_user_message(self, client_id: str, user_message: str): """ Enqueue user message for AI processing """ asyncio.create_task( message_broker.enqueue_ai_message(client_id, user_message) ) async def _send_messages(self, websocket: WebSocket, client_id: str): """ Subscribe to message broker and send to client """ try: async for message in message_broker.subscribe(client_id): if message: logger.info(f"向客户端 {client_id} 发送消息: {message}") try: await websocket.send_json(message) except (WebSocketDisconnect, RuntimeError): break except Exception as e: logger.error(f"发送消息失败: {e}") break except Exception as e: logger.error(f"消息订阅异常: {e}") async def _receive_messages(self, websocket: WebSocket, client_id: str): """ Receive messages from client and handle them """ try: while True: data = await websocket.receive_json() if data.get("type") == "user_message": await self._handle_user_message(client_id, data.get("content")) except WebSocketDisconnect: logger.info(f"客户端 {client_id} 断开连接") except Exception as e: logger.info(f"接收消息错误: {e}") ``` -------------------------------- ### Python Message Generation Stream Processing Source: https://context7.com/foxcyber907/ling-docs/llms.txt Processes user messages to generate streaming responses. It handles preprocessing, RAG context injection, LLM generation, sentence segmentation, emotion analysis, and voice synthesis. The method yields `ReplyResponse` objects. ```python import asyncio class MessageGenerator: def __init__(self, config, voice_maker, message_processor, translator, llm_model, rag_manager, ai_logger): self.config = config self.voice_maker = voice_maker self.message_processor = message_processor self.translator = translator self.llm_model = llm_model self.rag_manager = rag_manager self.ai_logger = ai_logger self.memory = [] async def process_message_stream(self, user_message: str, memory=None): """ Process user message and generate streaming responses Flow: 1. Preprocess user message (add timestamps, system prompts) 2. Inject RAG context if enabled 3. Stream LLM generation 4. Segment sentences from stream 5. Analyze emotion for each sentence 6. Synthesize voice audio 7. Yield response chunks to client Args: user_message: User input text memory: Optional conversation history override Yields: ReplyResponse objects with content, emotion, voice """ rag_messages = [] # 1. Setup and preprocessing current_context = self.memory.copy() if not memory else memory.copy() if not memory: processed_user_message = self.message_processor.append_user_message(user_message) self.memory.append({"role": "user", "content": processed_user_message}) current_context = self.memory.copy() # 2. RAG context injection if self.use_rag and self.rag_manager: self.rag_manager.rag_append_sys_message(current_context, rag_messages, processed_user_message) if logger.should_print_context(): self.ai_logger.print_debug_message(current_context, rag_messages, self.memory) # 3. LLM streaming generation sentence_queue = asyncio.Queue() response_queue = asyncio.Queue() # Start producer (LLM stream) and consumer (sentence processor) tasks producer_task = asyncio.create_task( self._stream_producer(current_context, sentence_queue) ) consumer_task = asyncio.create_task( self._sentence_consumer(sentence_queue, response_queue, user_message) ) # 4. Yield responses as they're processed async for response in self._response_publisher(response_queue): yield response await asyncio.gather(producer_task, consumer_task) async def _sentence_consumer(self, sentence_queue, response_queue, user_message): """ Consume sentences from queue, analyze emotion, synthesize voice """ while True: item = await sentence_queue.get() if item is None: # Sentinel for stream end await response_queue.put(None) break sentence, is_final = item # Analyze emotion emotion = self.emotion_analyzer.predict_emotion(sentence) # Translate to Japanese if needed for voice synthesis japanese_text = await self.translator.translate(sentence) # Synthesize voice audio_data = await self.voice_maker.generate_voice(japanese_text, emotion) # Create response response = ReplyResponse( content=sentence, emotion=emotion, audio=audio_data, is_final=is_final ) await response_queue.put(response) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.