from __future__ import annotations import logging import os import requests try: from openai import OpenAI except ImportError: # pragma: no cover - depends on deployment environment OpenAI = None import time from typing import List try: import numpy as np except ImportError: # pragma: no cover - depends on deployment environment np = None from code_parser import FUNCTION_CALL_GRAPH, CALLED_BY_GRAPH, FILE_DEPENDENCIES from config import QWEN_API_KEY, QWEN_API_URL, QWEN_CHAT_MODEL, QWEN_EMBEDDING_MODEL MAX_CODE_LENGTH = 800 logger = logging.getLogger(__name__) def _get_qwen_api_key() -> str: api_key = ( os.getenv("DASHSCOPE_API_KEY") or os.getenv("DASH_SCOPE_API_KEY") or os.getenv("QWEN_API_KEY") or QWEN_API_KEY ) if not api_key: raise RuntimeError( "Qwen/DashScope API key is not configured. Set DASHSCOPE_API_KEY, " "DASH_SCOPE_API_KEY, or QWEN_API_KEY." ) return api_key def _chat_completions_url() -> str: return QWEN_API_URL.rstrip("/") + "/chat/completions" def generate_code_summary(func_name, comment, logic, code_snippet, file_path): called_functions = FUNCTION_CALL_GRAPH.get(func_name, []) caller_functions = CALLED_BY_GRAPH.get(func_name, []) included_headers = FILE_DEPENDENCIES.get(file_path, []) prompt = f""" 你是一名资深的航天软件工程师,请总结以下C++函数的核心功能,**必须严格包含以下6点**: 1. 函数流程与逻辑: {logic} 2. 函数目的: → 结合航天术语总结,必须根据上述“函数流程与逻辑”推导生成,不得依赖假设! 3. 输入参数(名称、类型、作用,用括号列出) 4. 返回值(类型和含义) 5. 与其他函数的关联关系: - 被调用的函数: {', '.join(called_functions) or '无'} - 调用此函数的函数: {', '.join(caller_functions) or '无'} 6. 与跨文件关联的函数(头文件): {', '.join(included_headers) or '无'} --- 函数名: {func_name} 注释: {comment or '无'} 代码片段(截断至{MAX_CODE_LENGTH}字符): {code_snippet[:MAX_CODE_LENGTH]} 输出格式: "功能: [按上述6点组织的连贯段落,不要编号]" """ headers = {"Authorization": f"Bearer {_get_qwen_api_key()}", "Content-Type": "application/json"} payload = { "model": QWEN_CHAT_MODEL, "messages": [{"role": "user", "content": prompt}], "temperature": 0.1 } response = requests.post( _chat_completions_url(), headers=headers, json=payload ) response.raise_for_status() summary = response.json()['choices'][0]['message']['content'].strip() return summary.replace("功能: ", "") def generate_code_logic(func_name, comment, code_snippet, file_path): prompt = f""" 你是一名资深的航天软件工程师,请分析以下C++函数,并生成其markdown格式的**核心流程逻辑总结**。 **函数名**: {func_name} **所在文件**: {file_path} **前置注释**: {comment or '无'} **函数代码片段**:{code_snippet}请严格按照以下步骤执行: 1. **步骤分解**:逐行或按代码块分析函数体,用简洁的步骤描述其执行流程。例如:“1. 检查输入参数x是否有效。2. 调用内部函数compute()进行计算。3. 对结果进行格式化处理。4. 返回格式化后的字符串。” 2. **逻辑归纳**:基于上述步骤,用1-3句话概括这个函数的核心功能与逻辑主线。 **输出格式**:只需输出纯粹的、不带Markdown标题的流程逻辑描述文本。 """ headers = { "Authorization": f"Bearer {_get_qwen_api_key()}", "Content-Type": "application/json" } payload = { "model": QWEN_CHAT_MODEL, "messages": [{"role": "user", "content": prompt}], "temperature": 0.1 } response = requests.post( _chat_completions_url(), headers=headers, json=payload ) response.raise_for_status() result = response.json() logic = result['choices'][0]['message']['content'].strip() return logic def get_qwen_embedding(text: str) -> np.ndarray: try: if OpenAI is None: raise RuntimeError("openai package is not installed.") client = OpenAI( api_key=_get_qwen_api_key(), base_url=QWEN_API_URL ) response = client.embeddings.create( model=QWEN_EMBEDDING_MODEL, input=text ) embedding = response.data[0].embedding if np is not None: return np.array(embedding, dtype='float32') return [float(value) for value in embedding] except Exception as e: logger.error(f"获取嵌入失败: {e}") raise RuntimeError(f"Failed to get embedding: {e}") from e def call_qwen_max(prompt: str, max_tokens: int = 1500, temperature: float = 0.1) -> str: """ 调用 Qwen-Max 进行推理 Args: prompt: 输入的提示文本 max_tokens: 最大输出token数 temperature: 温度参数,控制随机性 Returns: 模型生成的文本 """ try: # 使用 OpenAI 兼容格式调用通义千问 if OpenAI is None: raise RuntimeError("openai package is not installed.") client = OpenAI( api_key=_get_qwen_api_key(), base_url=QWEN_API_URL ) response = client.chat.completions.create( model=QWEN_CHAT_MODEL, messages=[ {"role": "user", "content": prompt} ], max_tokens=max_tokens, temperature=temperature ) return response.choices[0].message.content.strip() except Exception as e: logger.error(f"调用Qwen-Max失败: {e}") return f"API调用失败: {str(e)}"