File size: 5,153 Bytes
5b9f9a3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
"""
CodeAgent-MCP — HuggingFace Spaces Demo (Gradio).

Multi-Agent code generation with Planner → Coder → Reviewer loop.
"""

import asyncio
import json
import os
import time

import gradio as gr

from src.core.config import load_settings, load_agents_config
from src.core.llm_client import LLMClient
from src.core.orchestrator import Orchestrator
from src.agents import PlannerAgent, CoderAgent, ReviewerAgent


EXAMPLE_TASKS = [
    "实现一个 LRU Cache,支持 get 和 put 操作,要求 O(1) 时间复杂度",
    "实现一个简单的 Stack 数据结构,支持 push, pop, peek, is_empty 方法",
    "编写一个配置管理器,支持从 YAML/JSON 加载,支持点号路径访问如 config.get('db.host')",
    "实现一个令牌桶限流器 TokenBucketRateLimiter,支持 acquire() 和装饰器用法",
]


async def run_agents(requirement: str, api_key: str, provider: str, progress=gr.Progress()):
    if not api_key.strip():
        return "请输入 API Key", "", ""

    os.environ["OPENAI_API_KEY"] = api_key.strip()

    settings = load_settings()
    agents_config = load_agents_config()

    llm = LLMClient.from_settings(provider, settings)
    planner = PlannerAgent(agents_config["planner"], llm)
    coder = CoderAgent(agents_config["coder"], llm, mcp_manager=None)
    reviewer = ReviewerAgent(agents_config["reviewer"], llm)
    orchestrator = Orchestrator(
        planner=planner, coder=coder, reviewer=reviewer,
        config=settings["orchestrator"],
    )

    progress(0.1, desc="Planner 正在拆解任务...")
    start = time.time()
    result = await orchestrator.run(requirement)
    elapsed = time.time() - start

    code_blocks = []
    log_lines = []

    log_lines.append(f"**任务拆分**: {len(result.plan)} 个子任务")
    for i, task in enumerate(result.plan):
        log_lines.append(f"  T{i+1}: {task['description'][:80]}")
    log_lines.append("")

    for i, r in enumerate(result.results):
        score = r["review"]["score"] if r.get("review") else "N/A"
        status_icon = "✅" if r["status"] == "completed" else "⚠️"
        log_lines.append(
            f"{status_icon} **Task {i+1}**: score={score}/10, "
            f"attempts={r['attempts']}, status={r['status']}"
        )
        if r.get("code"):
            code_blocks.append(r["code"])

    log_lines.append("")
    log_lines.append(f"**总 Token**: {result.total_tokens:,}")
    log_lines.append(f"**耗时**: {elapsed:.1f}s")

    completed = sum(1 for r in result.results if r["status"] == "completed")
    scores = [r["review"]["score"] for r in result.results if r.get("review")]
    avg_score = sum(scores) / len(scores) if scores else 0

    stats = json.dumps({
        "completion_rate": f"{completed}/{len(result.results)}",
        "avg_score": round(avg_score, 1),
        "total_tokens": result.total_tokens,
        "elapsed_seconds": round(elapsed, 1),
    }, indent=2, ensure_ascii=False)

    return "\n\n".join(code_blocks), "\n".join(log_lines), stats


def create_demo():
    with gr.Blocks(title="CodeAgent-MCP", theme=gr.themes.Soft()) as demo:
        gr.Markdown(
            "# 🤖 CodeAgent-MCP\n"
            "**Multi-Agent Code Generation System** — "
            "Planner (任务拆解) → Coder (代码生成) → Reviewer (代码审查) 反馈循环\n\n"
            "基于 MCP 协议的多 Agent 协作代码开发系统。"
        )

        with gr.Row():
            with gr.Column(scale=1):
                api_key = gr.Textbox(
                    label="API Key (DeepSeek / OpenAI)",
                    type="password",
                    placeholder="sk-...",
                )
                provider = gr.Dropdown(
                    choices=["default", "siliconflow", "openai"],
                    value="default",
                    label="LLM Provider",
                )
                requirement = gr.Textbox(
                    label="开发需求",
                    placeholder="请描述你想实现的功能...",
                    lines=3,
                )
                examples = gr.Examples(
                    examples=[[e] for e in EXAMPLE_TASKS],
                    inputs=[requirement],
                )
                run_btn = gr.Button("🚀 开始生成", variant="primary")

            with gr.Column(scale=2):
                code_output = gr.Markdown(label="生成的代码")
                with gr.Row():
                    log_output = gr.Markdown(label="执行日志")
                    stats_output = gr.Code(label="统计数据", language="json")

        run_btn.click(
            fn=run_agents,
            inputs=[requirement, api_key, provider],
            outputs=[code_output, log_output, stats_output],
        )

        gr.Markdown(
            "---\n"
            "**架构**: 自研 300 行编排器,不依赖 LangChain | "
            "**项目系列**: small-llms-tool-use → agenttune → smallrag → CodeAgent-MCP\n\n"
            "[GitHub](https://github.com/XIECHENG6/CodeAgent-MCP)"
        )

    return demo


if __name__ == "__main__":
    demo = create_demo()
    demo.launch()