peterpeter8585 commited on
Commit
dcf4ed6
Β·
verified Β·
1 Parent(s): 557b800

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +202 -3
app.py CHANGED
@@ -18,6 +18,204 @@ from langchain.callbacks.base import BaseCallbackHandler
18
  from langchain.tools import YouTubeSearchTool as YTS
19
  # 2. μ»€μŠ€ν…€ 콜백 ν•Έλ“€λŸ¬
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  from langchain_community.retrievers import WikipediaRetriever
23
  from langchain.tools.retriever import create_retriever_tool
@@ -26,6 +224,7 @@ wiki=Tool(func=retriever.get_relevant_documents,name="WIKI SEARCH",description="
26
  # ──────────────────────────────
27
  # βœ… GitHub Models LLM
28
  # ──────────────────────────────
 
29
  class GitHubModelLLM(LLM):
30
  model: str = "openai/gpt-4.1"
31
  endpoint: str = "https://models.github.ai/inference"
@@ -49,7 +248,7 @@ class GitHubModelLLM(LLM):
49
  if resp.status_code != 200:
50
  raise ValueError(f"API 였λ₯˜: {resp.status_code} - {resp.text}")
51
  return resp.json()["choices"][0]["message"]["content"]
52
-
53
  # ──────────────────────────────
54
  # βœ… LLM μ„€μ •
55
  # ──────────────────────────────
@@ -57,7 +256,7 @@ token = os.getenv("GITHUB_TOKEN") or os.getenv("token")
57
  if not token:
58
  print("⚠️ GitHub Token이 ν•„μš”ν•©λ‹ˆλ‹€. 예: setx GITHUB_TOKEN your_token")
59
 
60
- llm = GitHubModelLLM(model="openai/gpt-4.1", token=token)
61
 
62
  # ──────────────────────────────
63
  # βœ… LangChain κΈ°λ³Έ 도ꡬ 뢈러였기
@@ -113,7 +312,7 @@ tools.extend(FMT(root_dir=str(os.getcwd())).get_tools())
113
  # βœ… Agent μ΄ˆκΈ°ν™”
114
  # ─────────────────��────────────
115
  mem=MEM()
116
- agent=initialize_agent(toos,llm,agent=AgentType.OPENAI_MULTI_FUNCTIONS,verbose=True,memory=mem)
117
  #agent = create_structured_chat_agent(llm, tools, prompt)
118
  #agent= AgentExecutor(agent=agent, tools=tools,memory=mem)
119
 
 
18
  from langchain.tools import YouTubeSearchTool as YTS
19
  # 2. μ»€μŠ€ν…€ 콜백 ν•Έλ“€λŸ¬
20
 
21
+ # github_model_llm.py
22
+ """
23
+ GitHub Models API 기반 LLM 래퍼 (LangChain LLM ν˜Έν™˜)
24
+ - OpenAI-style chat completions ν˜Έν™˜
25
+ - function calling (OPENAI_MULTI_FUNCTIONS) 지원: functions, function_call 전달 κ°€λŠ₯
26
+ - system prompt (system_prompt) 지원
27
+ - μ˜΅μ…˜: temperature, max_tokens, top_p λ“± 전달
28
+ - raw response λ°˜ν™˜ λ©”μ„œλ“œ 포함
29
+ """
30
+
31
+ from typing import Optional, List, Dict, Any
32
+ import os
33
+ import time
34
+ import json
35
+ import requests
36
+ from requests.adapters import HTTPAdapter, Retry
37
+ from langchain.llms.base import LLM
38
+
39
+
40
+ class GitHubModelLLM(LLM):
41
+ model: str
42
+ endpoint: str
43
+ token: Optional[str]
44
+ system_prompt: Optional[str]
45
+
46
+ def __init__(
47
+ self,
48
+ model: str = "openai/gpt-4.1",
49
+ token: Optional[str] = os.environ["token"],
50
+ endpoint: str = "https://models.github.ai/inference",
51
+ system_prompt: Optional[str] = "λ„ˆλŠ” PIXAL(Primary Interactive X-ternal Assistant with multi Language)이야.λ„ˆμ˜ κ°œλ°œμžλŠ” μ •μ„±μœ€ μ΄λΌλŠ” 6ν•™λ…„ 파이썬 ν”„λ‘œκ·Έλž˜λ¨Έμ•Ό.",
52
+ request_timeout: float = 30.0,
53
+ max_retries: int = 2,
54
+ backoff_factor: float = 0.3,
55
+ **kwargs,
56
+ ):
57
+ """
58
+ Args:
59
+ model: λͺ¨λΈ 이름 (예: "openai/gpt-4.1")
60
+ token: GitHub Models API 토큰 (Bearer). ν™˜κ²½λ³€μˆ˜ GITHUB_TOKEN / token μ‚¬μš© κ°€λŠ₯ as fallback.
61
+ endpoint: API endpoint (κΈ°λ³Έ: https://models.github.ai/inference)
62
+ system_prompt: (선택) system role λ©”μ‹œμ§€λ‘œ 항상 μ•žμ— λΆ™μž„
63
+ request_timeout: μš”μ²­ νƒ€μž„μ•„μ›ƒ (초)
64
+ max_retries: λ„€νŠΈμ›Œν¬ μž¬μ‹œλ„ 횟수
65
+ backoff_factor: μž¬μ‹œλ„ μ§€μˆ˜ 보정
66
+ kwargs: LangChain LLM λΆ€λͺ¨μ— 전달할 μΆ”κ°€ 인자
67
+ """
68
+ super().__init__(**kwargs)
69
+ self.model = model
70
+ self.endpoint = endpoint.rstrip("/")
71
+ self.token = token or os.getenv("GITHUB_TOKEN") or os.getenv("token")
72
+ self.system_prompt = system_prompt
73
+ self.request_timeout = request_timeout
74
+
75
+ # requests μ„Έμ…˜ + μž¬μ‹œλ„ μ„€μ •
76
+ self.session = requests.Session()
77
+ retries = Retry(total=max_retries, backoff_factor=backoff_factor,
78
+ status_forcelist=[429, 500, 502, 503, 504],
79
+ allowed_methods=["POST", "GET"])
80
+ self.session.mount("https://", HTTPAdapter(max_retries=retries))
81
+ self.session.headers.update({
82
+ "Content-Type": "application/json"
83
+ })
84
+ if self.token:
85
+ self.session.headers.update({"Authorization": f"Bearer {self.token}"})
86
+
87
+ @property
88
+ def _llm_type(self) -> str:
89
+ return "github_models_api"
90
+
91
+ # ---------- 편의 internal helper ----------
92
+ def _build_messages(self, prompt: str, extra_messages: Optional[List[Dict[str, Any]]] = None) -> List[Dict[str, Any]]:
93
+ """
94
+ messages λ°°μ—΄ 생성: system (optional) + extra_messages (if any) + user prompt
95
+ extra_messages: 이미 role keys둜 κ΅¬μ„±λœ λ©”μ‹œμ§€ 리슀트 (예: conversation history)
96
+ """
97
+ msgs: List[Dict[str, Any]] = []
98
+ if self.system_prompt:
99
+ msgs.append({"role": "system", "content": self.system_prompt})
100
+ if extra_messages:
101
+ # ensure format: list of {"role":..,"content":..}
102
+ msgs.extend(extra_messages)
103
+ msgs.append({"role": "user", "content": prompt})
104
+ return msgs
105
+
106
+ def _post_chat(self, body: Dict[str, Any]) -> Dict[str, Any]:
107
+ url = f"{self.endpoint}/chat/completions"
108
+ # ensure Authorization present
109
+ if "Authorization" not in self.session.headers and not self.token:
110
+ raise ValueError("GitHub Models token not set. Provide token param or set GITHUB_TOKEN env var.")
111
+
112
+ resp = self.session.post(url, json=body, timeout=self.request_timeout)
113
+ try:
114
+ resp.raise_for_status()
115
+ except requests.HTTPError as e:
116
+ # try to surface JSON error if present
117
+ content = resp.text
118
+ try:
119
+ j = resp.json()
120
+ content = json.dumps(j, ensure_ascii=False, indent=2)
121
+ except Exception:
122
+ pass
123
+ raise RuntimeError(f"GitHub Models API error: {e} - {content}")
124
+ return resp.json()
125
+
126
+ # ---------- LangChain LLM interface ----------
127
+ def _call(self, prompt: str, stop: Optional[List[str]] = None, **kwargs) -> str:
128
+ """
129
+ LangChain LLM `_call` κ΅¬ν˜„ (동기).
130
+ Supports kwargs:
131
+ - functions: list[dict] (function schemas)
132
+ - function_call: "auto" | {"name": "..."} | etc.
133
+ - messages: list[dict] (if you want to pass full conversation instead of prompt)
134
+ - temperature, top_p, max_tokens, n, stream, etc.
135
+ Returns:
136
+ assistant content (string). If function_call is returned by model, returns the 'content' if present,
137
+ otherwise returns function_call object as JSON string (so caller can parse).
138
+ """
139
+ # support passing full messages via kwargs['messages']
140
+ messages = None
141
+ extra_messages = None
142
+ if "messages" in kwargs and isinstance(kwargs["messages"], list):
143
+ messages = kwargs.pop("messages")
144
+ else:
145
+ # optionally allow 'history' or 'extra_messages'
146
+ extra_messages = kwargs.pop("extra_messages", None)
147
+
148
+ if messages is None:
149
+ messages = self._build_messages(prompt, extra_messages=extra_messages)
150
+
151
+ body: Dict[str, Any] = {
152
+ "model": self.model,
153
+ "messages": messages,
154
+ }
155
+
156
+ # pass optional top-level params (temperature, max_tokens, etc.) from kwargs
157
+ for opt in ["temperature", "top_p", "max_tokens", "n", "stream", "presence_penalty", "frequency_penalty"]:
158
+ if opt in kwargs:
159
+ body[opt] = kwargs.pop(opt)
160
+
161
+ # pass function-calling related keys verbatim if provided
162
+ if "functions" in kwargs:
163
+ body["functions"] = kwargs.pop("functions")
164
+ if "function_call" in kwargs:
165
+ body["function_call"] = kwargs.pop("function_call")
166
+
167
+ # include stop if present
168
+ if stop:
169
+ body["stop"] = stop
170
+
171
+ # send request
172
+ raw = self._post_chat(body)
173
+
174
+ # save raw for caller if needed
175
+ self._last_raw = raw
176
+
177
+ # parse assistant message
178
+ choices = raw.get("choices") or []
179
+ if not choices:
180
+ return ""
181
+
182
+ message_obj = choices[0].get("message", {})
183
+
184
+ # if assistant returned a function_call, include that info
185
+ if "function_call" in message_obj:
186
+ # return function_call as JSON string so agent/tool orchestrator can parse it
187
+ # but if content also exists, prefer content
188
+ func = message_obj["function_call"]
189
+ # sometimes content may be absent; return structured JSON string
190
+ return json.dumps({"function_call": func}, ensure_ascii=False)
191
+
192
+ # otherwise return assistant content
193
+ return message_obj.get("content", "") or ""
194
+
195
+ # optional: expose raw response getter
196
+ def last_raw_response(self) -> Optional[Dict[str, Any]]:
197
+ return getattr(self, "_last_raw", None)
198
+
199
+ # optional: provide a convenience chat method to get full message object
200
+ def chat_completions(self, prompt: str, messages: Optional[List[Dict[str, Any]]] = None, **kwargs) -> Dict[str, Any]:
201
+ """
202
+ Directly call chat completions and return full parsed JSON response.
203
+ - If `messages` provided, it's used as the full messages array (system/user/assistant roles as needed)
204
+ - else uses prompt + system_prompt to construct messages.
205
+ """
206
+ if messages is None:
207
+ messages = self._build_messages(prompt)
208
+ body: Dict[str, Any] = {"model": self.model, "messages": messages}
209
+ for opt in ["temperature", "top_p", "max_tokens", "n", "stream"]:
210
+ if opt in kwargs:
211
+ body[opt] = kwargs.pop(opt)
212
+ if "functions" in kwargs:
213
+ body["functions"] = kwargs.pop("functions")
214
+ if "function_call" in kwargs:
215
+ body["function_call"] = kwargs.pop("function_call")
216
+ raw = self._post_chat(body)
217
+ self._last_raw = raw
218
+ return raw
219
 
220
  from langchain_community.retrievers import WikipediaRetriever
221
  from langchain.tools.retriever import create_retriever_tool
 
224
  # ──────────────────────────────
225
  # βœ… GitHub Models LLM
226
  # ──────────────────────────────
227
+ '''
228
  class GitHubModelLLM(LLM):
229
  model: str = "openai/gpt-4.1"
230
  endpoint: str = "https://models.github.ai/inference"
 
248
  if resp.status_code != 200:
249
  raise ValueError(f"API 였λ₯˜: {resp.status_code} - {resp.text}")
250
  return resp.json()["choices"][0]["message"]["content"]
251
+ '''
252
  # ──────────────────────────────
253
  # βœ… LLM μ„€μ •
254
  # ──────────────────────────────
 
256
  if not token:
257
  print("⚠️ GitHub Token이 ν•„μš”ν•©λ‹ˆλ‹€. 예: setx GITHUB_TOKEN your_token")
258
 
259
+ llm = GitHubModelLLM()
260
 
261
  # ──────────────────────────────
262
  # βœ… LangChain κΈ°λ³Έ 도ꡬ 뢈러였기
 
312
  # βœ… Agent μ΄ˆκΈ°ν™”
313
  # ─────────────────��────────────
314
  mem=MEM()
315
+ agent=initialize_agent(tools,llm,agent=AgentType.OPENAI_MULTI_FUNCTIONS,verbose=True,memory=mem)
316
  #agent = create_structured_chat_agent(llm, tools, prompt)
317
  #agent= AgentExecutor(agent=agent, tools=tools,memory=mem)
318