pro-craft 0.2.57__py3-none-any.whl → 0.2.58__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pro-craft might be problematic. Click here for more details.
- pro_craft/__init__.py +2 -2
- pro_craft/code_helper/__init__.py +0 -0
- pro_craft/code_helper/agent.py +90 -0
- pro_craft/code_helper/codermanager.py +143 -0
- pro_craft/code_helper/database.py +36 -0
- pro_craft/code_helper/paper_program.py +183 -0
- pro_craft/code_helper/template_extract.py +134 -0
- pro_craft/code_helper/tools.py +113 -0
- pro_craft/code_helper/vectorstore.py +81 -0
- pro_craft/code_helper/write_code.py +61 -0
- pro_craft/database.py +5 -6
- pro_craft/log.py +4 -3
- pro_craft/prompt_craft/async_.py +188 -561
- pro_craft/utils.py +1 -1
- {pro_craft-0.2.57.dist-info → pro_craft-0.2.58.dist-info}/METADATA +7 -1
- pro_craft-0.2.58.dist-info/RECORD +28 -0
- pro_craft/code_helper/coder.py +0 -660
- pro_craft/code_helper/designer.py +0 -115
- pro_craft-0.2.57.dist-info/RECORD +0 -21
- {pro_craft-0.2.57.dist-info → pro_craft-0.2.58.dist-info}/WHEEL +0 -0
- {pro_craft-0.2.57.dist-info → pro_craft-0.2.58.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from .codermanager import CoderTemplateManager
|
|
2
|
+
from typing import List, Dict, Any,Optional
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
coder = CoderTemplateManager()
|
|
6
|
+
|
|
7
|
+
# --- 工具函数实现 ---
|
|
8
|
+
|
|
9
|
+
def search_template_by_text(query: str, top_k: int = 5) -> List[Dict[str, Any]]:
|
|
10
|
+
"""
|
|
11
|
+
根据自然语言查询在模板库中进行语义搜索(使用 Qdrant 向量检索),返回最相关的 `top_k` 个模板的摘要信息。
|
|
12
|
+
"""
|
|
13
|
+
print(f"input & {type(query)} & query: {query} top:k {top_k} ")
|
|
14
|
+
search_result = coder.search(
|
|
15
|
+
text=query,
|
|
16
|
+
limit=top_k,
|
|
17
|
+
# query_filter=None # 可以在这里添加额外的过滤条件,例如根据语言、框架过滤
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
templates_summary = []
|
|
21
|
+
for hit in search_result:
|
|
22
|
+
# 在实际 Qdrant 中,hit.id 是模板的ID,hit.payload 包含其他元数据
|
|
23
|
+
# 假设你的 Qdrant payload 中存储了 template_name 和 description
|
|
24
|
+
templates_summary.append({
|
|
25
|
+
'template_id': hit.payload.get("template_id"),
|
|
26
|
+
'description': hit.payload.get('description', 'No description provided.'),
|
|
27
|
+
'match_score': hit.score
|
|
28
|
+
})
|
|
29
|
+
print(f"output & {type(templates_summary)} & {templates_summary} ")
|
|
30
|
+
return templates_summary
|
|
31
|
+
|
|
32
|
+
def get_template_details(template_id: str) -> Optional[Dict[str, Any]]: # template_id 根据你的模型是 Integer
|
|
33
|
+
"""
|
|
34
|
+
根据 `template_id` 从数据库中获取模板的完整详细信息,包括模板代码、推断出的命名约定和使用建议。
|
|
35
|
+
"""
|
|
36
|
+
print(f"input & {type(template_id)} & query: {template_id} ")
|
|
37
|
+
template = coder.get_template_obj(template_id = template_id)
|
|
38
|
+
if template:
|
|
39
|
+
return {
|
|
40
|
+
'template_id': template.template_id,
|
|
41
|
+
'description': template.description,
|
|
42
|
+
'template_code': template.template_code,
|
|
43
|
+
'version': template.version,
|
|
44
|
+
}
|
|
45
|
+
print(f"output & {type(template)} & {template} ")
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def ask_user_for_clarification(question: str) -> str:
|
|
50
|
+
"""
|
|
51
|
+
当你对用户需求有疑问,或需要用户做选择(例如在多个匹配模板中选择一个)时,使用此工具向用户提问。
|
|
52
|
+
"""
|
|
53
|
+
print(f"input & {type(question)} & query: {question} ")
|
|
54
|
+
print("\n--- Agent 需要你的帮助 ---")
|
|
55
|
+
print(f"Agent: {question}")
|
|
56
|
+
user_input = input("你的回答: ")
|
|
57
|
+
print("-------------------------\n")
|
|
58
|
+
print(f"output & {type(user_input)} & query: {user_input} ")
|
|
59
|
+
return user_input
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def generate_request_file(template_code: str, user_request_details: Dict[str, Any], naming_conventions: Optional[Dict[str, Any]] = None) -> str:
|
|
63
|
+
"""
|
|
64
|
+
根据选定的模板代码、解析后的用户需求(结构化形式)和模板的命名约定,生成符合 `REQUEST_START/END` 格式的指令文件。
|
|
65
|
+
`user_request_details` 应该是一个字典,键是 BLOCK/PLACEHOLDER 的名称,值是包含 '指令' 和 '约束/示例' 的字典。
|
|
66
|
+
"""
|
|
67
|
+
print(f"input & {type(template_code)} & template_code: {template_code} user_request_details: {user_request_details} naming_conventions: {naming_conventions}")
|
|
68
|
+
|
|
69
|
+
request_parts = []
|
|
70
|
+
|
|
71
|
+
request_parts.append("--- REQUEST_START ---")
|
|
72
|
+
request_parts.append("template.py # 目标文件通常是这个,可以根据实际情况调整") # 假设一个通用文件名
|
|
73
|
+
|
|
74
|
+
# 添加整体目标描述
|
|
75
|
+
overall_goal = user_request_details.get("overall_goal", "完善代码模板以满足以下需求。")
|
|
76
|
+
request_parts.append(f"\n**目标:** {overall_goal}\n")
|
|
77
|
+
|
|
78
|
+
# 添加命名约定 (如果提供了)
|
|
79
|
+
if naming_conventions:
|
|
80
|
+
request_parts.append("**命名约定:**")
|
|
81
|
+
for key, value in naming_conventions.items():
|
|
82
|
+
request_parts.append(f"* **{key}:** {value}")
|
|
83
|
+
request_parts.append("") # 空行
|
|
84
|
+
|
|
85
|
+
request_parts.append("**具体修改点:**\n")
|
|
86
|
+
|
|
87
|
+
# 遍历模板代码,找到所有的 BLOCK 和 PLACEHOLDER
|
|
88
|
+
# 然后根据 user_request_details 填充指令
|
|
89
|
+
# 这是一个简化版本,实际可能需要更复杂的解析器来处理嵌套块或动态生成的块
|
|
90
|
+
# 对于 MVP,我们可以假设 user_request_details 中包含了所有需要填充的块/占位符
|
|
91
|
+
block_pattern = r"(BLOCK_START|PLACEHOLDER):\s*(\w+)"
|
|
92
|
+
for match in re.finditer(block_pattern, template_code):
|
|
93
|
+
block_type = match.group(1)
|
|
94
|
+
block_name = match.group(2)
|
|
95
|
+
|
|
96
|
+
if block_name in user_request_details:
|
|
97
|
+
details = user_request_details[block_name]
|
|
98
|
+
instruction = details.get("指令", "")
|
|
99
|
+
constraint_example = details.get("约束/示例", "")
|
|
100
|
+
|
|
101
|
+
request_parts.append(f"* **{block_type}: {block_name}**")
|
|
102
|
+
request_parts.append(f" * **指令:** {instruction}")
|
|
103
|
+
if constraint_example:
|
|
104
|
+
# 确保多行约束/示例能正确缩进
|
|
105
|
+
formatted_ce = "\n".join([f" * **约束/示例:** {line}" if i == 0 else f" * {line}" for i, line in enumerate(str(constraint_example).splitlines())])
|
|
106
|
+
request_parts.append(formatted_ce)
|
|
107
|
+
request_parts.append("") # 空行
|
|
108
|
+
|
|
109
|
+
request_parts.append("--- REQUEST_END ---")
|
|
110
|
+
print(f"output & {type(request_parts)} & request_parts: {request_parts} ")
|
|
111
|
+
|
|
112
|
+
return "\n".join(request_parts)
|
|
113
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# --- 假设的依赖项 ---
|
|
2
|
+
# Qdrant 客户端
|
|
3
|
+
from qdrant_client import QdrantClient, models # 你需要根据实际情况导入 Qdrant 客户端
|
|
4
|
+
qdrant_client = QdrantClient(host="localhost", port=6333) # 示例Qdrant客户端初始化
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
from typing import Any, List
|
|
8
|
+
from llama_index.core.bridge.pydantic import PrivateAttr
|
|
9
|
+
from llama_index.core.embeddings import BaseEmbedding
|
|
10
|
+
from volcenginesdkarkruntime import Ark
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class VolcanoEmbedding(BaseEmbedding):
|
|
14
|
+
_model = PrivateAttr()
|
|
15
|
+
_ark_client = PrivateAttr()
|
|
16
|
+
_encoding_format = PrivateAttr()
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
model_name: str = "doubao-embedding-text-240715",
|
|
21
|
+
api_key: str = "",
|
|
22
|
+
**kwargs: Any,
|
|
23
|
+
) -> None:
|
|
24
|
+
super().__init__(**kwargs)
|
|
25
|
+
self._ark_client = Ark(api_key=api_key)
|
|
26
|
+
self._model = model_name
|
|
27
|
+
self._encoding_format = "float"
|
|
28
|
+
|
|
29
|
+
@classmethod
|
|
30
|
+
def class_name(cls) -> str:
|
|
31
|
+
return "ark"
|
|
32
|
+
|
|
33
|
+
def _get_query_embedding(self, query: str) -> List[float]:
|
|
34
|
+
"""
|
|
35
|
+
获取查询字符串的 embedding。
|
|
36
|
+
通常查询和文档使用相同的 embedding 模型。
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
resp = self._ark_client.embeddings.create(
|
|
40
|
+
model=self._model,
|
|
41
|
+
input=[query],
|
|
42
|
+
encoding_format=self._encoding_format,
|
|
43
|
+
)
|
|
44
|
+
return resp.data[0].embedding
|
|
45
|
+
|
|
46
|
+
def _get_text_embedding(self, text: str) -> List[float]:
|
|
47
|
+
"""
|
|
48
|
+
获取单个文档字符串的 embedding。
|
|
49
|
+
"""
|
|
50
|
+
resp = self._ark_client.embeddings.create(
|
|
51
|
+
model=self._model,
|
|
52
|
+
input=[text],
|
|
53
|
+
encoding_format=self._encoding_format,
|
|
54
|
+
)
|
|
55
|
+
return resp.data[0].embedding
|
|
56
|
+
|
|
57
|
+
def _get_text_embeddings(self, texts: List[str]) -> List[List[float]]:
|
|
58
|
+
"""
|
|
59
|
+
批量获取文档字符串的 embedding。
|
|
60
|
+
如果你的火山模型支持批量推理,强烈建议实现此方法以提高效率。
|
|
61
|
+
否则,它可以简单地循环调用 _get_text_embedding。
|
|
62
|
+
"""
|
|
63
|
+
resp = self._ark_client.embeddings.create(
|
|
64
|
+
model=self._model,
|
|
65
|
+
input=texts,
|
|
66
|
+
encoding_format=self._encoding_format,
|
|
67
|
+
)
|
|
68
|
+
return [i.embedding for i in resp.data]
|
|
69
|
+
|
|
70
|
+
async def _aget_query_embedding(self, query: str) -> List[float]:
|
|
71
|
+
return self._get_query_embedding(query)
|
|
72
|
+
|
|
73
|
+
async def _aget_text_embedding(self, text: str) -> List[float]:
|
|
74
|
+
return self._get_text_embedding(text)
|
|
75
|
+
|
|
76
|
+
if __name__ == "__main__":
|
|
77
|
+
|
|
78
|
+
embedding_model = VolcanoEmbedding(
|
|
79
|
+
model_name = "doubao-embedding-text-240715",
|
|
80
|
+
api_key = "39ad310a-c6f7-4d66-962e-1fbfa7e6edf1"
|
|
81
|
+
)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
llm2 = """
|
|
2
|
+
你是一个专业的Python代码修改和生成AI。你的任务是根据用户提供的代码模板文件和详细的修改指令文件,精确地对模板进行补充、完善和修改。
|
|
3
|
+
|
|
4
|
+
**你的目标是:**
|
|
5
|
+
1. **严格遵循指令文件中的所有要求,尤其是针对特定 `BLOCK` 和 `PLACEHOLDER` 的指令和约束/示例。**
|
|
6
|
+
2. **尽可能应用指令文件中提供的命名约定。**
|
|
7
|
+
3. **仅修改指令明确要求修改的部分,模板中未被指令覆盖的固定部分必须保持不变。**
|
|
8
|
+
4. **最终输出完整且可运行的Python代码。**
|
|
9
|
+
|
|
10
|
+
**输入格式:**
|
|
11
|
+
用户将以以下两个部分向你提供信息:
|
|
12
|
+
|
|
13
|
+
--- TEMPLATE_CODE_START ---
|
|
14
|
+
[原始的代码模板内容,其中包含 BLOCK_START/END 和 PLACEHOLDER/END_PLACEHOLDER 标记]
|
|
15
|
+
--- TEMPLATE_CODE_END ---
|
|
16
|
+
|
|
17
|
+
--- REQUEST_FILE_START ---
|
|
18
|
+
[一个结构化的指令文件,格式为 REQUEST_START/END,包含目标、命名约定和具体修改点]
|
|
19
|
+
--- REQUEST_FILE_END ---
|
|
20
|
+
|
|
21
|
+
**你的工作流程和生成原则:**
|
|
22
|
+
|
|
23
|
+
1. **解析指令文件:**
|
|
24
|
+
* 首先解析 `REQUEST_FILE_START` 中的所有内容,理解其 `目标`、`命名约定` 和 `具体修改点`。
|
|
25
|
+
* 将 `具体修改点` 中的每个 `BLOCK` 和 `PLACEHOLDER` 指令及其 `约束/示例` 映射到模板代码中的对应位置。
|
|
26
|
+
2. **处理模板代码:**
|
|
27
|
+
* 逐行读取 `TEMPLATE_CODE_START` 中的模板代码。
|
|
28
|
+
* 当遇到 `BLOCK_START` 或 `PLACEHOLDER` 标记时:
|
|
29
|
+
* 查找指令文件中对应 `块名称` 的修改指令。
|
|
30
|
+
* **如果存在指令:**
|
|
31
|
+
* 删除 `BLOCK_START` 和 `BLOCK_END` (或 `PLACEHOLDER` 和 `END_PLACEHOLDER`) 及其内部的原始内容(包括 `AI:` 注释)。
|
|
32
|
+
* 用指令中提供的代码**替换**该区域。
|
|
33
|
+
* 在替换的代码块的开始和结束位置,添加特殊的标记 `// AI_MODIFIED_START` 和 `// AI_MODIFIED_END` (如果只是新增内容,可以使用 `// AI_ADDED_START` 和 `// AI_ADDED_END`)。
|
|
34
|
+
* 如果指令是要求删除某些内容,请用 `// AI_DELETED_LINE: [原始行内容]` 标记被删除的行。
|
|
35
|
+
* **如果不存在指令:**
|
|
36
|
+
* 保留该 `BLOCK` 或 `PLACEHOLDER` 及其内部的原始内容(包括 `AI:` 注释和标记本身),不做任何改动。这允许模板中的可选部分在没有明确指令时保持原样。
|
|
37
|
+
* 当遇到非标记的普通代码行时,保持其不变。
|
|
38
|
+
3. **应用命名约定:**
|
|
39
|
+
* 在生成或修改代码时,优先应用 `REQUEST_FILE_START` 中提供的 `命名约定`。
|
|
40
|
+
* **重要:** 命名约定只应影响由你**生成或修改**的代码部分(即 `AI_ADDED` 或 `AI_MODIFIED` 区域)。你不能随意修改模板中未被明确指令触及的固定代码部分的命名。
|
|
41
|
+
4. **生成中间输出:**
|
|
42
|
+
* 首先生成包含所有 `// AI_ADDED/MODIFIED/DELETED` 标记的完整代码。这有助于后续的自动化工具进行变更追踪和人工核查。
|
|
43
|
+
5. **生成最终输出:**
|
|
44
|
+
* 在生成中间输出后,进一步处理该代码,**移除所有 `// AI_ADDED/MODIFIED/DELETED` 类型的标记**。
|
|
45
|
+
* 移除所有模板中遗留的 `BLOCK_START/END` 和 `PLACEHOLDER/END_PLACEHOLDER` 标记。
|
|
46
|
+
* 保留所有的 Docstrings 和常规的代码注释。
|
|
47
|
+
|
|
48
|
+
**你的输出必须是最终的、清理后的完整 Python 代码文件内容。**
|
|
49
|
+
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
from modusched.core import BianXieAdapter
|
|
53
|
+
bx = BianXieAdapter()
|
|
54
|
+
from pro_craft.utils import extract_
|
|
55
|
+
def write_code(request):
|
|
56
|
+
result = bx.product(llm2 + request)
|
|
57
|
+
print(result)
|
|
58
|
+
python_code = extract_(result,r"python")
|
|
59
|
+
with open("output.py","w",encoding="utf-8") as f:
|
|
60
|
+
f.write(python_code)
|
|
61
|
+
return "success" + " output.py generated."
|
pro_craft/database.py
CHANGED
|
@@ -231,6 +231,11 @@ class UseCase(PromptBase):
|
|
|
231
231
|
nullable=False, # 不能为空
|
|
232
232
|
comment="函数"
|
|
233
233
|
)
|
|
234
|
+
target = Column(
|
|
235
|
+
Text, # TEXT 类型,适用于长文本
|
|
236
|
+
nullable=False, # 不能为空
|
|
237
|
+
comment="标签"
|
|
238
|
+
)
|
|
234
239
|
|
|
235
240
|
type_ = Column(
|
|
236
241
|
String(255), # TEXT 类型,适用于长文本
|
|
@@ -238,12 +243,6 @@ class UseCase(PromptBase):
|
|
|
238
243
|
comment="函数"
|
|
239
244
|
)
|
|
240
245
|
|
|
241
|
-
target = Column(
|
|
242
|
-
Text, # TEXT 类型,适用于长文本
|
|
243
|
-
nullable=False, # 不能为空
|
|
244
|
-
comment="标签"
|
|
245
|
-
)
|
|
246
|
-
|
|
247
246
|
content = Column(
|
|
248
247
|
Text, # TEXT 类型,适用于长文本
|
|
249
248
|
nullable=False, # 不能为空
|
pro_craft/log.py
CHANGED
|
@@ -13,16 +13,17 @@ class Log:
|
|
|
13
13
|
self.Console_LOG_LEVEL = console_level
|
|
14
14
|
self.log_file_name = log_file_name
|
|
15
15
|
self.LOG_FILE_PATH = os.path.join("logs", log_file_name)
|
|
16
|
+
os.makedirs(os.path.dirname(self.LOG_FILE_PATH), exist_ok=True)
|
|
16
17
|
self.logger = self.get_logger()
|
|
17
18
|
|
|
18
19
|
def get_logger(self):
|
|
19
20
|
logger = logging.getLogger()
|
|
20
|
-
|
|
21
|
+
logger.setLevel(logging.DEBUG)
|
|
21
22
|
if not logger.handlers:
|
|
22
23
|
# --- 4. 配置 Formatter (格式化器) ---
|
|
23
24
|
# 以后有一个标准化的日志要使用logger 而非标的则使用super-log
|
|
24
25
|
formatter = logging.Formatter(
|
|
25
|
-
"%(asctime)s $ %(
|
|
26
|
+
"%(asctime)s $ %(created)f $ %(levelname)s $ %(funcName)s $ :%(lineno)d $ %(pathname)s $ %(message)s||"
|
|
26
27
|
)
|
|
27
28
|
# --- 5. 配置 Handler (处理器) ---
|
|
28
29
|
|
|
@@ -32,7 +33,6 @@ class Log:
|
|
|
32
33
|
console_handler.setFormatter(formatter)
|
|
33
34
|
logger.addHandler(console_handler)
|
|
34
35
|
|
|
35
|
-
|
|
36
36
|
# 文件系统
|
|
37
37
|
## 主日志本
|
|
38
38
|
file_handler = RotatingFileHandler( # RotatingFileHandler: 按文件大小轮转
|
|
@@ -109,3 +109,4 @@ class Log:
|
|
|
109
109
|
|
|
110
110
|
logger.info("这是一个包含自定义信息的日志")
|
|
111
111
|
return logger
|
|
112
|
+
|