htmlgen-mcp 0.3.7__py3-none-any.whl → 0.3.8__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 htmlgen-mcp might be problematic. Click here for more details.

@@ -82,6 +82,7 @@ _PROGRESS_LOG_BY_ID: dict[str, str] = {}
82
82
  _PROGRESS_LOG_BY_JOB: dict[str, str] = {}
83
83
  _JOB_REGISTRY: dict[str, Dict[str, Any]] = {}
84
84
  _CONTEXT_CACHE_BY_ID: dict[str, Dict[str, Any]] = {}
85
+ _CONTEXT_ID_BY_PLAN: dict[str, str] = {}
85
86
 
86
87
 
87
88
  def _job_state_path(job_id: str) -> Path:
@@ -140,6 +141,18 @@ def _load_job_states() -> None:
140
141
  _load_job_states()
141
142
 
142
143
 
144
+ def _load_job_state_from_disk(job_id: str) -> Optional[Dict[str, Any]]:
145
+ path = _job_state_path(job_id)
146
+ if not path.exists():
147
+ return None
148
+ try:
149
+ data = json.loads(path.read_text(encoding="utf-8"))
150
+ data.setdefault("job_id", job_id)
151
+ return data
152
+ except Exception:
153
+ return None
154
+
155
+
143
156
  def _context_cache_path(context_id: str) -> Path:
144
157
  return CONTEXT_CACHE_DIR / f"{context_id}.json"
145
158
 
@@ -453,8 +466,6 @@ async def execute_plan(
453
466
  # verbose: bool = False, # 后台执行时详细日志意义不大
454
467
  save_output: bool = False,
455
468
  progress_log: Optional[str] = None,
456
- auto_upload: bool = False,
457
- upload_url: Optional[str] = None,
458
469
  ) -> Dict[str, Any]:
459
470
  """执行网页构建计划,始终以后台模式运行。
460
471
 
@@ -479,21 +490,11 @@ async def execute_plan(
479
490
  如果都未指定:不记录进度日志
480
491
  路径可以是绝对路径或相对于 project_root 的相对路径
481
492
 
482
- - auto_upload: 是否在构建完成后自动上传到MCP服务器
483
- True: 构建完成后自动打包为ZIP并上传,返回访问URL
484
- False: 仅构建,不上传
485
- 默认为 False
486
-
487
- - upload_url: 文件上传API地址(可选)
488
- 默认为 "https://www.mcpcn.cc/api/fileUploadAndDownload/uploadMcpFile"
489
- 只在 auto_upload=True 时生效,一般不需要修改
490
-
491
493
  执行流程:
492
494
  - 任务始终在后台异步执行,立即返回 job_id 和 progress_log 路径
493
495
  - 使用 get_progress(job_id=..., limit=...) 可以实时查询执行状态和进度
494
496
  - 支持通过进度日志文件追踪详细的执行步骤和结果
495
- - 执行完成后可以获取完整的执行报告和生成的文件列表
496
- - 🎯 新增:auto_upload=True时,构建完成(100%)后自动上传并返回访问URL
497
+ - 执行完成后可以获取完整的执行报告、生成文件列表,以及自动上传结果
497
498
  """
498
499
  try:
499
500
  # 如果没有提供project_root,尝试从缓存中获取
@@ -638,38 +639,26 @@ async def execute_plan(
638
639
 
639
640
  _persist_job_state(job_id)
640
641
 
641
- # 使用默认URL如果没有提供
642
- effective_upload_url = upload_url or DEFAULT_UPLOAD_URL
643
-
644
642
  asyncio.create_task(
645
643
  _run_execution_job(
646
644
  job_id,
647
645
  agent,
648
646
  plan_dict,
649
647
  progress_log_path=progress_log_path,
650
- auto_upload=auto_upload,
651
- upload_url=effective_upload_url,
652
648
  )
653
649
  )
654
650
 
655
- if auto_upload:
656
- message = (
657
- "执行已在后台启动(含自动上传):调用 get_progress(job_id='{}', limit=20) "
658
- "可获取构建和上传进度。完成后将返回网站访问URL。"
659
- ).format(job_id)
660
- else:
661
- message = (
662
- "执行已在后台启动:调用 get_progress(job_id='{}', limit=20) "
663
- "或传入 progress_log='{}' 可获取实时进度"
664
- ).format(job_id, progress_log_path or "<未启用进度日志>")
651
+ message = (
652
+ "执行已在后台启动(含自动上传):调用 get_progress(job_id='{}', limit=20) "
653
+ "或传入 progress_log='{}' 可获取实时进度与上传结果"
654
+ ).format(job_id, progress_log_path or "<未启用进度日志>")
665
655
 
666
656
  return {
667
657
  "status": "started",
668
658
  "job_id": job_id,
669
659
  "plan_id": plan_id,
670
660
  "progress_log": progress_log_path,
671
- "auto_upload": auto_upload,
672
- "upload_url": upload_url if auto_upload else None,
661
+ "upload_url": DEFAULT_UPLOAD_URL,
673
662
  "message": message,
674
663
  }
675
664
  except Exception as exc:
@@ -686,8 +675,6 @@ async def _run_execution_job(
686
675
  plan_dict: Dict[str, Any],
687
676
  *,
688
677
  progress_log_path: Optional[str],
689
- auto_upload: bool = False,
690
- upload_url: str = None,
691
678
  ) -> None:
692
679
  job_info = _JOB_REGISTRY.get(job_id)
693
680
  if not job_info:
@@ -705,52 +692,7 @@ async def _run_execution_job(
705
692
  job_info["completed_at"] = time.time()
706
693
  _persist_job_state(job_id)
707
694
 
708
- # 🎯 关键:任务完成后自动上传
709
- if auto_upload and job_info.get("project_directory"):
710
- try:
711
- # 记录上传开始
712
- job_info["upload_status"] = "uploading"
713
- _persist_job_state(job_id)
714
-
715
- # 只在不是默认值时传递upload_url
716
- upload_params = {"folder_path": job_info["project_directory"]}
717
- if upload_url and upload_url != DEFAULT_UPLOAD_URL:
718
- upload_params["upload_url"] = upload_url
719
-
720
- upload_result = await upload_project_to_mcp_server(**upload_params)
721
-
722
- # 记录上传结果
723
- job_info["upload_result"] = upload_result
724
- job_info["upload_status"] = upload_result["status"]
725
- if upload_result["status"] == "success":
726
- job_info["website_url"] = upload_result["url"]
727
- job_info["upload_completed_at"] = time.time()
728
-
729
- # 添加到进度日志
730
- if progress_log_path:
731
- upload_event = {
732
- "timestamp": time.time(),
733
- "type": "upload_completed",
734
- "status": "success",
735
- "website_url": upload_result["url"],
736
- "message": upload_result["message"],
737
- }
738
- try:
739
- with open(
740
- progress_log_path, "a", encoding="utf-8"
741
- ) as log_file:
742
- log_file.write(
743
- json.dumps(upload_event, ensure_ascii=False)
744
- )
745
- log_file.write("\n")
746
- except Exception:
747
- pass
748
-
749
- _persist_job_state(job_id)
750
- except Exception as upload_exc:
751
- job_info["upload_status"] = "failed"
752
- job_info["upload_error"] = str(upload_exc)
753
- _persist_job_state(job_id)
695
+ await _handle_auto_upload(job_id, job_info, progress_log_path)
754
696
 
755
697
  except Exception as exc:
756
698
  job_info["status"] = "failed"
@@ -764,13 +706,57 @@ async def _run_execution_job(
764
706
  _persist_job_state(job_id)
765
707
 
766
708
 
709
+ async def _handle_auto_upload(
710
+ job_id: str,
711
+ job_info: Dict[str, Any],
712
+ progress_log_path: Optional[str],
713
+ ) -> None:
714
+ project_dir = job_info.get("project_directory")
715
+ if not project_dir:
716
+ return
717
+
718
+ job_info["upload_status"] = "uploading"
719
+ _persist_job_state(job_id)
720
+
721
+ try:
722
+ upload_result = await upload_project_to_mcp_server(
723
+ folder_path=project_dir,
724
+ upload_url=DEFAULT_UPLOAD_URL,
725
+ )
726
+
727
+ job_info["upload_result"] = upload_result
728
+ job_info["upload_status"] = upload_result.get("status")
729
+
730
+ if upload_result.get("status") == "success":
731
+ job_info["website_url"] = upload_result.get("url")
732
+ job_info["upload_completed_at"] = time.time()
733
+
734
+ if progress_log_path:
735
+ upload_event = {
736
+ "timestamp": time.time(),
737
+ "type": "upload_completed",
738
+ "status": "success",
739
+ "website_url": upload_result.get("url"),
740
+ "message": upload_result.get("message"),
741
+ }
742
+ try:
743
+ with open(progress_log_path, "a", encoding="utf-8") as log_file:
744
+ log_file.write(json.dumps(upload_event, ensure_ascii=False))
745
+ log_file.write("\n")
746
+ except Exception:
747
+ pass
748
+
749
+ except Exception as exc:
750
+ job_info["upload_status"] = "failed"
751
+ job_info["upload_error"] = str(exc)
752
+ finally:
753
+ _persist_job_state(job_id)
754
+
755
+
767
756
  @mcp.tool()
768
757
  async def create_simple_site(
769
758
  description: str,
770
759
  site_title: str = "我的网站",
771
- project_root: Optional[str] = None,
772
- model: Optional[str] = None,
773
- context_id: Optional[str] = None,
774
760
  context_content: Optional[str] = None,
775
761
  ) -> Dict[str, Any]:
776
762
  """使用AI分析需求,生成简单但美观的网站计划。
@@ -784,11 +770,6 @@ async def create_simple_site(
784
770
  * 如果有地图查询结果、API返回数据等,都应该放在这个参数中
785
771
  * 格式可以是文本、JSON字符串或结构化数据的字符串表示
786
772
 
787
- 其他参数:
788
- - project_root: 项目根目录,缺省使用默认目录
789
- - model: 使用的AI模型,缺省使用默认模型
790
- - context_id: 可选,引用已缓存的上下文快照以复用历史资料
791
-
792
773
  图片配置参数(可选):
793
774
  - image_style: 图片风格 (professional|artistic|minimal|vibrant|luxury)
794
775
  - image_topics: 用户自定义的图片主题列表,如 ["modern office", "team collaboration"]
@@ -813,22 +794,17 @@ async def create_simple_site(
813
794
  这样AI就能基于真实数据来生成个性化的网站内容。
814
795
  """
815
796
  try:
816
- # 使用指定模型或默认模型
817
- used_model = model or DEFAULT_MODEL
797
+ # 使用默认模型
798
+ used_model = DEFAULT_MODEL
818
799
 
819
- # 使用新的路径解析逻辑
820
- # 如果没有提供 project_root,使用 site_title 作为项目名
821
- project_directory = _resolve_project_directory(project_root, site_title)
800
+ # 使用新的路径解析逻辑,默认在共享目录下按标题创建项目
801
+ project_directory = _resolve_project_directory(None, site_title)
822
802
 
823
803
  # 处理上下文
824
804
  context_data = ""
825
- actual_context_id = context_id
805
+ actual_context_id: Optional[str] = None
826
806
 
827
- if context_id and context_id in _CONTEXT_CACHE_BY_ID:
828
- # 使用缓存的上下文
829
- cached_context = _CONTEXT_CACHE_BY_ID[context_id]
830
- context_data = cached_context.get("content", "")
831
- elif context_content:
807
+ if context_content:
832
808
  # 使用新提供的上下文内容
833
809
  context_data = context_content
834
810
  # 生成新的上下文ID并缓存
@@ -919,13 +895,16 @@ async def create_simple_site(
919
895
  "plan_id": plan_id,
920
896
  }
921
897
 
898
+ if actual_context_id:
899
+ cached_entry["context_id"] = actual_context_id
900
+
922
901
  _PLAN_CACHE_BY_ID[plan_id] = cached_entry
923
902
  cache_key = (project_directory, description)
924
903
  _PLAN_CACHE[cache_key] = cached_entry
925
904
 
926
905
  # 将上下文信息关联到计划
927
906
  if actual_context_id:
928
- _PROGRESS_LOG_BY_ID[plan_id] = actual_context_id
907
+ _CONTEXT_ID_BY_PLAN[plan_id] = actual_context_id
929
908
 
930
909
  # 保存计划到文件
931
910
  plan_filename = f"simple_site_plan_{plan_id}.json"
@@ -1029,6 +1008,20 @@ async def get_progress(
1029
1008
 
1030
1009
  if job_id:
1031
1010
  job_info = _JOB_REGISTRY.get(job_id)
1011
+ if not job_info:
1012
+ disk_state = _load_job_state_from_disk(job_id)
1013
+ if disk_state:
1014
+ _JOB_REGISTRY[job_id] = disk_state
1015
+ job_info = disk_state
1016
+ progress_log_from_state = job_info.get("progress_log")
1017
+ if progress_log_from_state:
1018
+ progress_log_str = str(progress_log_from_state)
1019
+ _PROGRESS_LOG_BY_JOB[job_id] = progress_log_str
1020
+ plan_in_state = job_info.get("plan_id")
1021
+ if plan_in_state:
1022
+ _PROGRESS_LOG_BY_ID.setdefault(
1023
+ plan_in_state, progress_log_str
1024
+ )
1032
1025
  if job_info and not plan_id:
1033
1026
  plan_id = job_info.get("plan_id")
1034
1027
  if job_id in _PROGRESS_LOG_BY_JOB:
@@ -1122,14 +1115,12 @@ async def get_progress(
1122
1115
  "report": job_info.get("result", {}).get("report"),
1123
1116
  "created_files": job_info.get("result", {}).get("created_files"),
1124
1117
  }
1125
- # 添加上传结果信息
1126
1118
  if job_info.get("upload_result"):
1127
1119
  job_snapshot["upload_result"] = job_info.get("upload_result")
1128
1120
 
1129
1121
  if job_info.get("status") == "failed":
1130
1122
  job_snapshot["error"] = job_info.get("error")
1131
1123
 
1132
- # 添加上传错误信息
1133
1124
  if job_info.get("upload_error"):
1134
1125
  job_snapshot["upload_error"] = job_info.get("upload_error")
1135
1126
 
@@ -1147,15 +1138,11 @@ async def get_progress(
1147
1138
  @mcp.tool()
1148
1139
  async def upload_project_to_mcp_server(
1149
1140
  folder_path: str,
1150
- upload_url: Optional[str] = None,
1151
1141
  ) -> Dict[str, Any]:
1152
1142
  """将项目文件夹打包成ZIP并上传到MCP服务器。
1153
1143
 
1154
1144
  参数说明:
1155
1145
  - folder_path: 项目文件夹的绝对路径
1156
- - upload_url: 上传API地址(可选)
1157
- 默认为 "https://www.mcpcn.cc/api/fileUploadAndDownload/uploadMcpFile"
1158
- 一般不需要修改
1159
1146
 
1160
1147
  返回值:
1161
1148
  - status: 上传状态 ("success" 或 "error")
@@ -1164,9 +1151,6 @@ async def upload_project_to_mcp_server(
1164
1151
  - message: 状态信息
1165
1152
  """
1166
1153
  try:
1167
- # 使用默认URL如果没有提供
1168
- effective_upload_url = upload_url or DEFAULT_UPLOAD_URL
1169
-
1170
1154
  # 验证文件夹路径
1171
1155
  if not os.path.exists(folder_path):
1172
1156
  return {"status": "error", "message": f"项目文件夹不存在: {folder_path}"}
@@ -1206,7 +1190,7 @@ async def upload_project_to_mcp_server(
1206
1190
  "file", f, filename=zip_filename, content_type="application/zip"
1207
1191
  )
1208
1192
 
1209
- async with session.post(effective_upload_url, data=data) as response:
1193
+ async with session.post(DEFAULT_UPLOAD_URL, data=data) as response:
1210
1194
  response_text = await response.text()
1211
1195
 
1212
1196
  if response.status != 200:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: htmlgen-mcp
3
- Version: 0.3.7
3
+ Version: 0.3.8
4
4
  Summary: AI-powered HTML website generator with auto-upload functionality via Model Context Protocol
5
5
  Author-email: HTML Generator Team <contact@htmlgen-mcp.com>
6
6
  License: MIT
@@ -8,7 +8,7 @@ htmlgen_mcp/progress_tools.py,sha256=SOScPSr3hEv4rvGzqvwUcomEFiPhhNxJ7CbWURlFpBs
8
8
  htmlgen_mcp/progress_tracker.py,sha256=2TVduWNJJH08EQ7Vf9EpiwPjtp61JX7muSCdbGHZAfM,12210
9
9
  htmlgen_mcp/prompt_enhancer.py,sha256=8UIxt45vSNarS5uqfxC5thOfnGY7luDs2YjHZRx1GAM,7976
10
10
  htmlgen_mcp/sse_optimizations.py,sha256=_UTpgLtxgNAiiEkO5lPihOi1-eEQk6R4ejNParufrrc,6932
11
- htmlgen_mcp/web_agent_server.py,sha256=Uqz4xBhTaBqjAdouNbf4mCHpeluqyM8PAZZ2WA2LsPA,52617
11
+ htmlgen_mcp/web_agent_server.py,sha256=kw1ryQHZjcm1Rz99kZir8byylABvfOb0hkfUmnf54CQ,51145
12
12
  htmlgen_mcp/agents/__init__.py,sha256=Xydfjzw9s9O6I5Ixx6EmsTdXu26136NDPUAqt9B1hzE,121
13
13
  htmlgen_mcp/agents/ai_content_generator.py,sha256=tWGC9cY6Wp7MB1P9J7uCv8LUdiS02rgS6vxaNHD7KQk,10311
14
14
  htmlgen_mcp/agents/quick_generator.py,sha256=2wV4PCRugV0suTedLDV91_etHy_2Fiw4J0MraT7MQjw,34201
@@ -31,8 +31,8 @@ htmlgen_mcp/agents/web_tools/simple_css.py,sha256=kj9X3sHHhj1wGwBVL20j6w2qIHXRdx
31
31
  htmlgen_mcp/agents/web_tools/simple_js.py,sha256=xMiuF-u-h_IIkUONZIa4Xf8vKB5mcXxwQf5b_BIcpoE,12174
32
32
  htmlgen_mcp/agents/web_tools/simple_templates.py,sha256=-Rs-SsWpGZT2hiwa3jZNVDHOMZOo1vV2pWbmBdR30os,6471
33
33
  htmlgen_mcp/agents/web_tools/validation.py,sha256=bNA6aWXrCSi7sPqQw5bBR3XF69gRf85D5jSMi996CtI,2069
34
- htmlgen_mcp-0.3.7.dist-info/METADATA,sha256=XVni-ah0fkx0HvGkRo5tiHM0xAdOvQMpZGfmQGBKbkw,5161
35
- htmlgen_mcp-0.3.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
- htmlgen_mcp-0.3.7.dist-info/entry_points.txt,sha256=w7ufTQJobIxT3FYI24yKsCEwEQvBOWhNjckUd9Amu_k,66
37
- htmlgen_mcp-0.3.7.dist-info/top_level.txt,sha256=KnglzX4ekV8SQkHTsJg2_nTBXz2TxaYLdvoMMovHLNk,12
38
- htmlgen_mcp-0.3.7.dist-info/RECORD,,
34
+ htmlgen_mcp-0.3.8.dist-info/METADATA,sha256=RQNybh9_YO-SB8uwqVyYlkFVXgs4u6K086J_g5bJNzo,5161
35
+ htmlgen_mcp-0.3.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
+ htmlgen_mcp-0.3.8.dist-info/entry_points.txt,sha256=w7ufTQJobIxT3FYI24yKsCEwEQvBOWhNjckUd9Amu_k,66
37
+ htmlgen_mcp-0.3.8.dist-info/top_level.txt,sha256=KnglzX4ekV8SQkHTsJg2_nTBXz2TxaYLdvoMMovHLNk,12
38
+ htmlgen_mcp-0.3.8.dist-info/RECORD,,