kimhyunwoo commited on
Commit
f75669b
·
verified ·
1 Parent(s): 3101b51

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +159 -0
app.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # /app.py
2
+
3
+ import gradio as gr
4
+ import os
5
+ import subprocess
6
+ from langchain_mistralai.chat_models import ChatMistralAI
7
+ from langchain_core.messages import HumanMessage, SystemMessage, AIMessage
8
+ from langchain.agents import AgentExecutor, create_tool_calling_agent
9
+ from langchain_core.prompts import ChatPromptTemplate
10
+ from langchain.tools import tool
11
+
12
+ # --- 1. 환경 설정 및 LLM 초기화 ---
13
+ API_KEY = os.environ.get("MISTRAL_API_KEY", None)
14
+ if API_KEY is None:
15
+ print("FATAL: MISTRAL_API_KEY is not set in Space Secrets.")
16
+ # API 키가 없으면 사용자에게 경고 메시지를 표시하는 UI를 로드
17
+ llm = None
18
+ else:
19
+ llm = ChatMistralAI(model="codestral-latest", temperature=0, api_key=API_KEY, streaming=True)
20
+
21
+ # --- 2. 핵심 도구(Tools) 정의: @tool 데코레이터 사용 ---
22
+ @tool
23
+ def generate_c_code(description: str) -> str:
24
+ """Generates complete, compilable C code based on a natural language description. Use this when the user wants to create new code."""
25
+ code_generation_prompt = f"""You are a world-class C programming expert.
26
+ Generate a single, complete, and compilable C code file based on this request: '{description}'.
27
+ The code must be clean, efficient, and include necessary headers.
28
+ ONLY output the raw C code within a single C code block. No explanations, no extra text."""
29
+ response = llm.invoke([HumanMessage(content=code_generation_prompt)])
30
+ code = response.content
31
+ if "```c" in code:
32
+ code = code.split("```c")[1].split("```")[0].strip()
33
+ return code
34
+
35
+ @tool
36
+ def compile_and_run_c_code(code: str) -> str:
37
+ """Compiles and runs a given C code snippet and returns its output or any errors. Use this to verify or test code."""
38
+ try:
39
+ with open("main.c", "w", encoding='utf-8') as f:
40
+ f.write(code)
41
+
42
+ compile_proc = subprocess.run(
43
+ ["gcc", "main.c", "-o", "main.out", "-lm", "-w"],
44
+ capture_output=True, text=True, timeout=15
45
+ )
46
+ if compile_proc.returncode != 0:
47
+ return f"--- COMPILATION FAILED ---\n{compile_proc.stderr}"
48
+
49
+ run_proc = subprocess.run(
50
+ ["./main.out"],
51
+ capture_output=True, text=True, timeout=15
52
+ )
53
+ if run_proc.returncode != 0:
54
+ return f"--- RUNTIME ERROR ---\n{run_proc.stderr}"
55
+
56
+ output = run_proc.stdout
57
+ if not output.strip():
58
+ return "--- EXECUTION SUCCEEDED ---\n(No output was produced)"
59
+ return f"--- EXECUTION SUCCEEDED ---\n{output}"
60
+
61
+ except subprocess.TimeoutExpired:
62
+ return "--- ERROR ---\nProcess timed out. Check for infinite loops."
63
+ except Exception as e:
64
+ return f"--- SYSTEM ERROR ---\nAn unexpected error occurred: {str(e)}"
65
+
66
+ @tool
67
+ def refactor_or_analyze_c_code(code: str, request: str) -> str:
68
+ """Analyzes, refactors, or explains a given C code based on a user's specific request. Use this for code improvement or understanding."""
69
+ analysis_prompt = f"""You are a senior C code reviewer. Analyze the following C code based on the user's request.
70
+ Provide a clear, concise, and helpful response. If refactoring, provide the complete improved code in a C code block.
71
+
72
+ User's Request: '{request}'
73
+
74
+ C Code to Analyze:
75
+ ```c
76
+ {code}
77
+ ```"""
78
+ response = llm.invoke([HumanMessage(content=analysis_prompt)])
79
+ return response.content
80
+
81
+ # --- 3. LangChain 에이전트 설정 ---
82
+ tools = [generate_c_code, compile_and_run_c_code, refactor_or_analyze_c_code]
83
+
84
+ agent_prompt = ChatPromptTemplate.from_messages(
85
+ [
86
+ ("system", "You are a powerful C-language assistant agent. You can generate, compile, and analyze C code. Think step-by-step and use your tools to fulfill the user's request. If you generate code, you should almost always offer to compile and run it for the user as the next step."),
87
+ ("placeholder", "{chat_history}"),
88
+ ("human", "{input}"),
89
+ ("placeholder", "{agent_scratchpad}"),
90
+ ]
91
+ )
92
+
93
+ if llm:
94
+ agent = create_tool_calling_agent(llm, tools, agent_prompt)
95
+ agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
96
+ else:
97
+ agent_executor = None
98
+
99
+ def agent_chat(user_input, history):
100
+ if agent_executor is None:
101
+ yield "Error: MISTRAL_API_KEY is not configured. Please set it in the Space secrets."
102
+ return
103
+
104
+ chat_history = []
105
+ for human, ai in history:
106
+ chat_history.append(HumanMessage(content=human))
107
+ chat_history.append(AIMessage(content=ai))
108
+
109
+ response_stream = agent_executor.stream({
110
+ "input": user_input,
111
+ "chat_history": chat_history
112
+ })
113
+
114
+ full_response = ""
115
+ for chunk in response_stream:
116
+ if "output" in chunk:
117
+ full_response += chunk["output"]
118
+ yield full_response
119
+
120
+ # --- 4. Gradio UI/UX 디자인 ---
121
+ with gr.Blocks(theme=gr.themes.Monochrome(), css=".gradio-container{max-width: 800px !important; margin: auto;}") as demo:
122
+ gr.Markdown("# 🚀 C-Codestral Agent")
123
+
124
+ chatbot = gr.Chatbot(
125
+ label="C-Agent",
126
+ bubble_full_width=False,
127
+ height=600,
128
+ avatar_images=(None, "https://huggingface.co/datasets/huggingface/brand-assets/resolve/main/hf-logo-with-title.png")
129
+ )
130
+
131
+ with gr.Row():
132
+ txt = gr.Textbox(
133
+ show_label=False,
134
+ placeholder="Enter your request and press enter...",
135
+ container=False,
136
+ scale=7
137
+ )
138
+ submit_btn = gr.Button("Submit", variant="primary", scale=1)
139
+
140
+ txt.submit(agent_chat, [txt, chatbot], chatbot)
141
+ submit_btn.click(agent_chat, [txt, chatbot], chatbot)
142
+ txt.submit(lambda: "", None, txt) # Clear textbox on submit
143
+ submit_btn.click(lambda: "", None, txt) # Clear textbox on submit
144
+
145
+ gr.Examples(
146
+ [
147
+ "Generate a C program to calculate the factorial of a number.",
148
+ "Now, compile and run the code you just created.",
149
+ "Refactor the factorial code to use recursion instead of a loop.",
150
+ ],
151
+ inputs=txt,
152
+ label="Example Prompts"
153
+ )
154
+
155
+ # --- 5. MCP 도구 노출 ---
156
+ gr.load_tools(tools)
157
+
158
+ if __name__ == "__main__":
159
+ demo.queue().launch(debug=True)