pro-craft 0.1.22__tar.gz → 0.1.24__tar.gz

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.

Files changed (28) hide show
  1. {pro_craft-0.1.22 → pro_craft-0.1.24}/PKG-INFO +1 -1
  2. {pro_craft-0.1.22 → pro_craft-0.1.24}/pyproject.toml +1 -1
  3. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/file_manager.py +2 -2
  4. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/prompt_craft/async_.py +228 -25
  5. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/prompt_craft/sync.py +22 -17
  6. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/server/router/prompt.py +1 -0
  7. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft.egg-info/PKG-INFO +1 -1
  8. {pro_craft-0.1.22 → pro_craft-0.1.24}/README.md +0 -0
  9. {pro_craft-0.1.22 → pro_craft-0.1.24}/setup.cfg +0 -0
  10. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/__init__.py +0 -0
  11. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/code_helper/coder.py +0 -0
  12. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/code_helper/designer.py +0 -0
  13. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/database.py +0 -0
  14. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/log.py +0 -0
  15. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/prompt_craft/__init__.py +0 -0
  16. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/prompt_craft/evals.py +0 -0
  17. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/prompt_craft/new.py +0 -0
  18. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/server/mcp/__init__.py +0 -0
  19. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/server/mcp/prompt.py +0 -0
  20. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/server/router/__init__.py +0 -0
  21. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft/utils.py +0 -0
  22. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft.egg-info/SOURCES.txt +0 -0
  23. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft.egg-info/dependency_links.txt +0 -0
  24. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft.egg-info/requires.txt +0 -0
  25. {pro_craft-0.1.22 → pro_craft-0.1.24}/src/pro_craft.egg-info/top_level.txt +0 -0
  26. {pro_craft-0.1.22 → pro_craft-0.1.24}/tests/test22.py +0 -0
  27. {pro_craft-0.1.22 → pro_craft-0.1.24}/tests/test_coder.py +0 -0
  28. {pro_craft-0.1.22 → pro_craft-0.1.24}/tests/test_designer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pro-craft
3
- Version: 0.1.22
3
+ Version: 0.1.24
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pro-craft"
3
- version = "0.1.22"
3
+ version = "0.1.24"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -7,7 +7,7 @@ from pro_craft import Intel
7
7
  from enum import Enum
8
8
  import json
9
9
 
10
- from pro_craft.database import Base, Prompt
10
+ from pro_craft.database import Prompt
11
11
  from sqlalchemy import create_engine, Column, Integer, String
12
12
  from sqlalchemy.orm import sessionmaker, declarative_base
13
13
  from pro_craft.utils import create_session
@@ -30,7 +30,7 @@ class ContentManager():
30
30
  self.qdrant = QdrantManager(host = "localhost")
31
31
  self.neo = None
32
32
 
33
-
33
+
34
34
  @intel.intellect_2(IntellectType.inference,
35
35
  prompt_id = "db_help_001",
36
36
  demand="""
@@ -16,13 +16,24 @@ from datetime import datetime
16
16
  from pro_craft.utils import extract_
17
17
  import asyncio
18
18
  import re
19
-
19
+ from pydantic import BaseModel, ValidationError, field_validator
20
20
  from sqlalchemy import select, desc
21
21
  from json.decoder import JSONDecodeError
22
+ from pro_craft.database import SyncMetadata
23
+ from datetime import datetime, timedelta
24
+ from datetime import datetime, timedelta
25
+ from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
26
+ from sqlalchemy import select, and_ # 引入 select 和 and_
27
+ from sqlalchemy.orm import class_mapper # 用于检查对象是否是持久化的
28
+
22
29
 
23
30
  class IntellectRemoveFormatError(Exception):
24
31
  pass
25
32
 
33
+ class IntellectRemoveError(Exception):
34
+ pass
35
+
36
+ BATCH_SIZE = 100
26
37
 
27
38
  def slog(s, target: str = "target",logger = None):
28
39
  COLOR_GREEN = "\033[92m"
@@ -59,6 +70,64 @@ def fix_broken_json_string(broken_json_str):
59
70
  return fixed_json_str
60
71
 
61
72
 
73
+ # def get_last_sync_time(target_session) -> datetime:
74
+ # """从目标数据库获取上次同步时间"""
75
+ # metadata_entry = target_session.query(SyncMetadata).filter_by(table_name="sync_metadata").first()
76
+ # if metadata_entry:
77
+ # return metadata_entry.last_sync_time
78
+ # return datetime(1970, 1, 1) # 默认一个很早的时间
79
+
80
+ # def update_last_sync_time(target_session, new_sync_time: datetime):
81
+ # """更新目标数据库的上次同步时间"""
82
+ # metadata_entry = target_session.query(SyncMetadata).filter_by(table_name="sync_metadata").first()
83
+ # if metadata_entry:
84
+ # metadata_entry.last_sync_time = new_sync_time
85
+ # else:
86
+ # # 如果不存在,则创建
87
+ # new_metadata = SyncMetadata(table_name="sync_metadata", last_sync_time=new_sync_time)
88
+ # target_session.add(new_metadata)
89
+ # target_session.commit()
90
+ # print(f"Updated last sync time to: {new_sync_time}")
91
+
92
+
93
+ async def get_last_sync_time(target_session: AsyncSession) -> datetime:
94
+ """从目标数据库获取上次同步时间"""
95
+ # 修正点:使用 select() 和 execute()
96
+ result = await target_session.execute(
97
+ select(SyncMetadata).filter_by(table_name="sync_metadata")
98
+ )
99
+ metadata_entry = result.scalar_one_or_none() # 获取单个对象或 None
100
+
101
+ if metadata_entry:
102
+ return metadata_entry.last_sync_time
103
+ return datetime(1970, 1, 1) # 默认一个很早的时间
104
+
105
+
106
+ # from your_module import SyncMetadata # 假设 SyncMetadata 已导入
107
+ # from sqlalchemy import select # 确保引入 select
108
+
109
+ async def update_last_sync_time(target_session: AsyncSession, new_sync_time: datetime):
110
+ """更新目标数据库的上次同步时间"""
111
+ # 修正点:使用 select() 和 execute()
112
+ result = await target_session.execute(
113
+ select(SyncMetadata).filter_by(table_name="sync_metadata")
114
+ )
115
+ metadata_entry = result.scalar_one_or_none()
116
+
117
+ if metadata_entry:
118
+ metadata_entry.last_sync_time = new_sync_time
119
+ else:
120
+ # 如果不存在,则创建
121
+ new_metadata = SyncMetadata(table_name="sync_metadata", last_sync_time=new_sync_time)
122
+ target_session.add(new_metadata)
123
+
124
+ # 异步提交事务
125
+ await target_session.commit() # TODO
126
+ print(f"Updated last sync time to: {new_sync_time}")
127
+
128
+
129
+
130
+
62
131
  class IntellectType(Enum):
63
132
  train = "train"
64
133
  inference = "inference"
@@ -143,6 +212,101 @@ class AsyncIntel():
143
212
 
144
213
  return specific_prompt
145
214
 
215
+ async def sync_prompt_data_to_database(self,database_url:str):
216
+ target_engine = create_async_engine(database_url, echo=False)
217
+ async with target_engine.begin() as conn:
218
+ await conn.run_sync(PromptBase.metadata.create_all)
219
+
220
+ async with create_async_session(self.engine) as source_session:
221
+ async with create_async_session(target_engine) as target_session:
222
+
223
+ last_sync_time = await get_last_sync_time(target_session)
224
+ print(f"Starting sync for sync_metadata from: {last_sync_time}")
225
+
226
+
227
+ processed_count = 0
228
+ #2 next_sync_watermark = last_sync_time
229
+ current_batch_max_updated_at = last_sync_time
230
+
231
+ while True:
232
+ source_results = await source_session.execute(
233
+ select(Prompt)
234
+ .filter(Prompt.timestamp > last_sync_time)
235
+ .order_by(Prompt.timestamp.asc(), Prompt.id.asc())
236
+ .limit(BATCH_SIZE)
237
+ )
238
+ records_to_sync = source_results.scalars().all()
239
+ if not records_to_sync:
240
+ break # 没有更多记录了
241
+
242
+ #2 max_timestamp_in_batch = datetime(1970, 1, 1) # 初始化为最早时间
243
+
244
+ # 准备要插入或更新到目标数据库的数据
245
+ for record in records_to_sync:
246
+ # 查找目标数据库中是否存在该ID的记录
247
+ # 这里的 `User` 模型会对应到 target_db.users
248
+ target_prompt_result = await target_session.execute(
249
+ select(Prompt).filter_by(id=record.id) # 假设 prompt_id 是唯一标识符
250
+ )
251
+ target_prompt = target_prompt_result.scalar_one_or_none()
252
+
253
+ if target_prompt:
254
+ # 如果存在,则更新
255
+ target_prompt.prompt_id = record.prompt_id
256
+ target_prompt.version = record.version
257
+ target_prompt.timestamp = record.timestamp
258
+ target_prompt.prompt = record.prompt
259
+ target_prompt.use_case = record.use_case
260
+ target_prompt.action_type = record.action_type
261
+ target_prompt.demand = record.demand
262
+ target_prompt.score = record.score
263
+ target_prompt.is_deleted = record.is_deleted
264
+ else:
265
+ # 如果不存在,则添加新记录
266
+ # 注意:这里需要创建一个新的User实例,而不是直接添加源数据库的record对象
267
+ new_prompt = Prompt(
268
+ prompt_id=record.prompt_id,
269
+ version=record.version,
270
+ timestamp=record.timestamp,
271
+ prompt = record.prompt,
272
+ use_case = record.use_case,
273
+ action_type = record.action_type,
274
+ demand = record.demand,
275
+ score = record.score,
276
+ is_deleted = record.is_deleted
277
+ )
278
+ target_session.add(new_prompt)
279
+
280
+ # 记录当前批次最大的 updated_at
281
+ #2
282
+ # if record.timestamp > max_timestamp_in_batch:
283
+ # max_timestamp_in_batch = record.timestamp
284
+ if record.timestamp > current_batch_max_updated_at:
285
+ current_batch_max_updated_at = record.timestamp
286
+
287
+
288
+ await target_session.commit()
289
+ processed_count += len(records_to_sync)
290
+ print(f"Processed {len(records_to_sync)} records. Total processed: {processed_count}")
291
+
292
+ #2 next_sync_watermark = max_timestamp_in_batch + timedelta(microseconds=1)
293
+ last_sync_time = current_batch_max_updated_at + timedelta(microseconds=1)
294
+
295
+
296
+ if len(records_to_sync) < BATCH_SIZE: # 如果查询到的记录数小于批次大小,说明已经处理完所有符合条件的记录
297
+ break
298
+
299
+ if processed_count > 0:
300
+ # 最终更新last_sync_time到数据库,确保记录的是所有已处理记录中最新的一个
301
+ await update_last_sync_time(target_session, current_batch_max_updated_at + timedelta(microseconds=1))
302
+
303
+ #2 await update_last_sync_time(target_session, next_sync_watermark)
304
+
305
+ await target_session.commit() # 确保最终的 metadata 更新也被提交
306
+ else:
307
+ print("No new records to sync.")
308
+
309
+
146
310
  async def get_prompts_from_sql(self,
147
311
  prompt_id: str,
148
312
  version = None,
@@ -241,7 +405,7 @@ class AsyncIntel():
241
405
  chat_history = s_prompt or system_result
242
406
  await self.save_prompt_increment_version(prompt_id,
243
407
  new_prompt = chat_history,
244
- use_case = " summary ",
408
+ use_case = "",
245
409
  score = 60,
246
410
  session = session)
247
411
 
@@ -292,7 +456,7 @@ class AsyncIntel():
292
456
  new_prompt = prompt_
293
457
  await self.save_prompt_increment_version(prompt_id = prompt_id,
294
458
  new_prompt = new_prompt,
295
- use_case = " finetune ",
459
+ use_case = "",
296
460
  score = 60,
297
461
  session = session)
298
462
 
@@ -310,8 +474,8 @@ class AsyncIntel():
310
474
  async with create_async_session(self.engine) as session:
311
475
 
312
476
  latest_prompt = await self.get_prompts_from_sql(prompt_id=prompt_id,session=session)
313
-
314
- await self.save_prompt_increment_version(prompt_id=latest_prompt.prompt_id,
477
+ if latest_prompt:
478
+ await self.save_prompt_increment_version(prompt_id=latest_prompt.prompt_id,
315
479
  new_prompt = latest_prompt.prompt,
316
480
  use_case = latest_prompt.use_case,
317
481
  action_type=action_type,
@@ -319,8 +483,21 @@ class AsyncIntel():
319
483
  score=latest_prompt.score,
320
484
  session=session
321
485
  )
486
+ return "success"
487
+ else:
488
+ await self.save_prompt_increment_version(prompt_id=prompt_id,
489
+ new_prompt = demand,
490
+ use_case = "init",
491
+ action_type="inference",
492
+ demand=demand,
493
+ score=60,
494
+ session=session
495
+ )
496
+ return "init"
497
+
498
+
499
+
322
500
 
323
- return "success"
324
501
 
325
502
 
326
503
 
@@ -330,6 +507,7 @@ class AsyncIntel():
330
507
  prompt_id: str,
331
508
  version: str = None,
332
509
  inference_save_case = True,
510
+ change_case = False,
333
511
  ):
334
512
  if isinstance(input_data,dict):
335
513
  input_ = json.dumps(input_data,ensure_ascii=False)
@@ -339,23 +517,13 @@ class AsyncIntel():
339
517
  # 查数据库, 获取最新提示词对象
340
518
  async with create_async_session(self.engine) as session:
341
519
  result_obj = await self.get_prompts_from_sql(prompt_id=prompt_id,session=session)
342
-
343
-
344
520
  if result_obj is None:
345
- await self.save_prompt_increment_version(
346
- prompt_id = prompt_id,
347
- new_prompt = "做一些处理",
348
- use_case = input_,
349
- score = 60,
350
- session = session
351
- )
352
- ai_result = "初始化完成"
353
- return ai_result
521
+ raise IntellectRemoveError("不存在的prompt_id")
354
522
 
355
523
  prompt = result_obj.prompt
356
524
  if result_obj.action_type == "inference":
357
525
  # 直接推理即可
358
- ai_result = await self.llm.aproduct(prompt + output_format + "\n-----input----\n" + input_)
526
+ ai_result = await self.llm.aproduct(prompt + output_format + "\nuser:" + input_)
359
527
  if inference_save_case:
360
528
  await self.save_use_case_by_sql(prompt_id,
361
529
  use_case = input_,
@@ -391,10 +559,35 @@ class AsyncIntel():
391
559
  # score = 60,
392
560
  # session = session)
393
561
 
394
- if input_ == before_input:
395
- new_prompt = prompt + "\nuser:" + demand
396
- else:
397
- new_prompt = prompt + "\nuser:" + input_
562
+
563
+ # version 2
564
+
565
+ # if input_ == before_input:
566
+ # new_prompt = prompt + "\nuser:" + demand
567
+ # else:
568
+ # new_prompt = prompt + "\nuser:" + input_
569
+
570
+ # ai_result = await self.llm.aproduct(new_prompt + output_format)
571
+
572
+ # save_new_prompt = new_prompt + "\nassistant:\n" + ai_result
573
+
574
+
575
+ # await self.save_prompt_increment_version(
576
+ # prompt_id,
577
+ # new_prompt=save_new_prompt,
578
+ # use_case = input_,
579
+ # action_type = "inference",
580
+ # score = 60,
581
+ # session = session)
582
+
583
+ if before_input == "" or change_case is True:
584
+ result_obj.use_case = input_
585
+ await session.commit()
586
+ # 查询上一条, 将before_input 更新位input_
587
+ prompt += input_
588
+
589
+ # 使用更新后的数据进行后续步骤
590
+ new_prompt = prompt + "\nuser:" + demand
398
591
 
399
592
  ai_result = await self.llm.aproduct(new_prompt + output_format)
400
593
 
@@ -405,6 +598,7 @@ class AsyncIntel():
405
598
  prompt_id,
406
599
  new_prompt=save_new_prompt,
407
600
  use_case = input_,
601
+ action_type = "inference",
408
602
  score = 60,
409
603
  session = session)
410
604
 
@@ -414,7 +608,7 @@ class AsyncIntel():
414
608
  prompt = prompt,
415
609
  session = session
416
610
  )
417
- ai_result = await self.llm.aproduct(prompt + output_format + "\n-----input----\n" + input_)
611
+ ai_result = await self.llm.aproduct(prompt + output_format + "\nuser:" + input_)
418
612
 
419
613
  elif result_obj.action_type == "finetune":
420
614
  demand = result_obj.demand
@@ -424,12 +618,12 @@ class AsyncIntel():
424
618
  demand = demand,
425
619
  session = session
426
620
  )
427
- ai_result = await self.llm.aproduct(prompt + output_format + "\n-----input----\n" + input_)
621
+ ai_result = await self.llm.aproduct(prompt + output_format + "\nuser:" + input_)
428
622
  elif result_obj.action_type == "patch":
429
623
  demand = result_obj.demand
430
624
  assert demand
431
625
  chat_history = prompt + demand
432
- ai_result = await self.llm.aproduct(chat_history + output_format + "\n-----input----\n" + input_)
626
+ ai_result = await self.llm.aproduct(chat_history + output_format + "\nuser:" + input_)
433
627
  self.save_prompt_increment_version(prompt_id,
434
628
  chat_history,
435
629
  use_case = input_,
@@ -615,6 +809,13 @@ class AsyncIntel():
615
809
 
616
810
  except JSONDecodeError as e:
617
811
  raise IntellectRemoveFormatError(f"prompt_id: {prompt_id} 在生成后做json解析时报错") from e
812
+
813
+ except ValidationError as e:
814
+ err_info = e.errors()[0]
815
+ raise IntellectRemoveFormatError(f"{err_info["type"]}: 属性:{err_info['loc']}, 发生了如下错误: {err_info['msg']}, 格式校验失败, 当前输入为: {err_info['input']} 请检查") from e
816
+
817
+ except Exception as e:
818
+ raise Exception(f"Error {prompt_id} : {e}") from e
618
819
 
619
820
  return ai_result
620
821
 
@@ -630,6 +831,8 @@ class AsyncIntel():
630
831
  async with create_async_session(self.engine) as session:
631
832
  prompt_result = await self.get_prompts_from_sql(prompt_id=prompt_id,
632
833
  session=session)
834
+ if prompt_result is None:
835
+ raise IntellectRemoveError("不存在的prompt_id")
633
836
  if prompt_result.action_type != "inference":
634
837
  input_datas = input_datas[:1]
635
838
  tasks = []
@@ -22,6 +22,8 @@ BATCH_SIZE = 1000
22
22
  class IntellectRemoveFormatError(Exception):
23
23
  pass
24
24
 
25
+ class IntellectRemoveError(Exception):
26
+ pass
25
27
 
26
28
  def slog(s, target: str = "target",logger = None):
27
29
  COLOR_GREEN = "\033[92m"
@@ -354,17 +356,28 @@ class Intel():
354
356
  # 查看是否已经存在
355
357
  with create_session(self.engine) as session:
356
358
  latest_prompt = self.get_prompts_from_sql(prompt_id=prompt_id,session=session)
357
-
358
- self.save_prompt_increment_version(prompt_id=latest_prompt.prompt_id,
359
- new_prompt = latest_prompt.prompt,
360
- use_case = latest_prompt.use_case,
361
- action_type=action_type,
359
+
360
+ if latest_prompt:
361
+ self.save_prompt_increment_version(prompt_id=latest_prompt.prompt_id,
362
+ new_prompt = latest_prompt.prompt,
363
+ use_case = latest_prompt.use_case,
364
+ action_type=action_type,
365
+ demand=demand,
366
+ score=latest_prompt.score,
367
+ session=session
368
+ )
369
+
370
+ return "success"
371
+ else:
372
+ self.save_prompt_increment_version(prompt_id=prompt_id,
373
+ new_prompt = demand,
374
+ use_case = "init",
375
+ action_type="inference",
362
376
  demand=demand,
363
- score=latest_prompt.score,
377
+ score=60,
364
378
  session=session
365
379
  )
366
-
367
- return "success"
380
+ return "init"
368
381
 
369
382
  def intellect_remove(self,
370
383
  input_data: dict | str,
@@ -393,15 +406,7 @@ class Intel():
393
406
  result_obj = self.get_prompts_from_sql(prompt_id=prompt_id,session=session)
394
407
 
395
408
  if result_obj is None:
396
- self.save_prompt_increment_version(
397
- prompt_id = prompt_id,
398
- new_prompt = "做一些处理",
399
- use_case = input_,
400
- score = 60,
401
- session = session
402
- )
403
- ai_result = "初始化完成"
404
- return ai_result
409
+ raise IntellectRemoveError("不存在的prompt_id")
405
410
  prompt = result_obj.prompt
406
411
  if result_obj.action_type == "inference":
407
412
  # 直接推理即可
@@ -8,6 +8,7 @@ def create_router(database_url: str,
8
8
  slave_database_url: str,
9
9
  model_name: str):
10
10
  """
11
+ # TODO 整理改为异步
11
12
  创建一个包含 ProCraft 路由的 FastAPI APIRouter 实例。
12
13
 
13
14
  Args:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pro-craft
3
- Version: 0.1.22
3
+ Version: 0.1.24
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
File without changes
File without changes
File without changes