Gulzat commited on
Commit
f6be06c
·
verified ·
1 Parent(s): 1cdc82d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -105
app.py CHANGED
@@ -1,128 +1,83 @@
1
- # app.py ─────────────────────────────────────────────────────────────────────
2
- # 1. Bootstrap: import-or-install helper
3
- import importlib, subprocess, sys, datetime, os
4
- from typing import List, Tuple
5
 
6
- def ensure(pkg: str, version: str | None = None):
7
- """Import a package, or pip-install it if missing, then import again."""
 
 
 
 
8
  try:
9
  return importlib.import_module(pkg)
10
  except ModuleNotFoundError:
11
- target = f"{pkg}=={version}" if version else pkg
12
- print(f"[bootstrap] Installing {target} …", flush=True)
13
  subprocess.check_call([sys.executable, "-m", "pip", "install", target])
14
  return importlib.import_module(pkg)
15
 
16
- # 2. Ensure dependencies
17
- pytz = ensure("pytz")
18
- langchain = ensure("langchain", "0.1.16") # pinned, stable API
19
- langchain_openai = ensure("langchain-openai") # latest OK
20
- from langchain.tools import tool
21
- from langchain_openai import ChatOpenAI
22
- from langchain.agents import Tool, AgentExecutor, create_openai_functions_agent
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
- # 3. Tool: current time in timezone
25
  @tool
26
  def get_current_time_in_timezone(timezone: str) -> str:
27
- """Return the current local time (YYYY-MM-DD HH:MM:SS) in a given timezone."""
28
  try:
29
  tz = pytz.timezone(timezone)
30
  return datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
31
  except Exception as e:
32
  return f"Error: {e}"
 
33
 
34
- # 4. Tool: find overlapping stand-up slot
35
- @tool
36
- def find_overlap_slot(
37
- timezones: List[str],
38
- workday_start: int = 9,
39
- workday_end: int = 18,
40
- slot_minutes: int = 30
41
- ) -> str:
42
- """
43
- Find the next common slot across multiple time-zones.
44
- Args:
45
- timezones: list of IANA tz strings
46
- workday_start / workday_end: local work hours (inclusive start, exclusive end)
47
- slot_minutes: length of slot
48
- """
49
- now_utc = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
50
- intervals: List[Tuple[datetime.datetime, datetime.datetime]] = []
51
-
52
- for tz_name in timezones:
53
- try:
54
- tz = pytz.timezone(tz_name)
55
- except pytz.UnknownTimeZoneError:
56
- return f"Unknown timezone: {tz_name}"
57
-
58
- local_now = now_utc.astimezone(tz)
59
- start_local = local_now.replace(hour=workday_start, minute=0, second=0, microsecond=0)
60
- end_local = local_now.replace(hour=workday_end, minute=0, second=0, microsecond=0)
61
-
62
- # move window to tomorrow if current time past work hours
63
- if local_now >= end_local:
64
- start_local += datetime.timedelta(days=1)
65
- end_local += datetime.timedelta(days=1)
66
- elif local_now > start_local:
67
- start_local = local_now # cannot schedule in the past
68
-
69
- intervals.append((start_local.astimezone(pytz.utc), end_local.astimezone(pytz.utc)))
70
-
71
- slot_start = max(iv[0] for iv in intervals)
72
- slot_end = min(iv[1] for iv in intervals)
73
-
74
- if slot_end - slot_start < datetime.timedelta(minutes=slot_minutes):
75
- return "No overlapping work-hour slot found in the next day."
76
-
77
- chosen_end = slot_start + datetime.timedelta(minutes=slot_minutes)
78
-
79
- lines = [
80
- f"Proposed {slot_minutes}-minute stand-up:",
81
- f"• UTC: {slot_start.strftime('%Y-%m-%d %H:%M')} – {chosen_end.strftime('%H:%M')}"
82
- ]
83
- for tz_name in timezones:
84
- tz = pytz.timezone(tz_name)
85
- local_start = slot_start.astimezone(tz).strftime('%Y-%m-%d %H:%M')
86
- local_end = chosen_end.astimezone(tz).strftime('%H:%M')
87
- lines.append(f"• {tz_name}: {local_start} – {local_end}")
88
-
89
- return "\n".join(lines)
90
-
91
- # 5. Build LangChain tools list
92
- tools = [
93
- Tool.from_function(
94
- func=find_overlap_slot,
95
- name="find_overlap_slot",
96
- description=(
97
- "Find a meeting slot. Args: timezones (List[str]), "
98
- "workday_start, workday_end, slot_minutes."
99
- ),
100
- ),
101
- Tool.from_function(
102
- func=get_current_time_in_timezone,
103
- name="get_current_time_in_timezone",
104
- description="Return current local time for a timezone.",
105
- ),
106
  ]
107
 
108
- # 6. Create the agent
109
- openai_api_key = os.getenv("OPENAI_API_KEY") or "sk-..." # replace or set as HF secret
110
- llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0, api_key=openai_api_key)
 
 
111
  agent = create_openai_functions_agent(llm, tools)
112
  agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=False)
 
113
 
114
- # 7. Minimal Gradio interface
115
- import gradio as gr
116
-
117
- def chat_agent(user_input, history):
118
- """Wrapper to make the agent compatible with Gradio ChatInterface."""
119
- result = agent_executor.invoke({"input": user_input})
120
- return result["output"]
121
 
122
- with gr.Blocks() as demo:
123
- gr.Markdown("# 🕒 Time-zone Helper Agent")
124
- gr.ChatInterface(chat_agent)
125
-
126
- # 8. Launch if running locally; HF Spaces ignores this in production
127
  if __name__ == "__main__":
128
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
 
 
 
 
 
 
 
 
 
 
1
+ # ───────────────────────────── app.py ─────────────────────────────────────
2
+ # NOTE: just push this one file to your HF Space repo. The bootstrap section
3
+ # installs the needed packages inside the container at first launch.
 
4
 
5
+ # ╭──────────────────────── 0. Bootstrap helper ─────────────────────────────╮
6
+ import importlib, subprocess, sys, os, datetime
7
+ from typing import List
8
+
9
+ def ensure(pkg: str, ver: str | None = None):
10
+ """Import a package or pip-install it into the current env, then import."""
11
  try:
12
  return importlib.import_module(pkg)
13
  except ModuleNotFoundError:
14
+ target = f"{pkg}=={ver}" if ver else pkg
15
+ print(f"[bootstrap] installing {target} …", flush=True)
16
  subprocess.check_call([sys.executable, "-m", "pip", "install", target])
17
  return importlib.import_module(pkg)
18
 
19
+ # minimal deps: pytz + *monolithic* langchain (0.1.x) + openai
20
+ pytz = ensure("pytz")
21
+ langchain = ensure("langchain", "0.1.16") # stable, includes tool decorator
22
+ openai_pkg = ensure("openai") # backend used by ChatOpenAI
23
+
24
+ # ╰───────────────────────────────────────────────────────────────────────────╯
25
+
26
+
27
+ # ╭──────────────────────── 1. Imports after install ────────────────────────╮
28
+ from langchain.tools import tool, Tool
29
+ from langchain.chat_models import ChatOpenAI
30
+ from langchain.agents import create_openai_functions_agent, AgentExecutor
31
+ # ╰───────────────────────────────────────────────────────────────────────────╯
32
+
33
+
34
+ # ╭──────────────────────── 2. Tool definitions ─────────────────────────────╮
35
+ @tool
36
+ def my_custom_tool(arg1: str, arg2: int) -> str:
37
+ """A placeholder tool you can extend later.
38
+ Args:
39
+ arg1: any string
40
+ arg2: any integer
41
+ """
42
+ return f"Received arg1='{arg1}', arg2={arg2}. Build your magic here!"
43
 
 
44
  @tool
45
  def get_current_time_in_timezone(timezone: str) -> str:
46
+ """Return the current local time in the given IANA timezone."""
47
  try:
48
  tz = pytz.timezone(timezone)
49
  return datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
50
  except Exception as e:
51
  return f"Error: {e}"
52
+ # ╰───────────────────────────────────────────────────────────────────────────╯
53
 
54
+
55
+ # ╭──────────────────────── 3. Build agent once ─────────────────────────────╮
56
+ tools: List[Tool] = [
57
+ Tool.from_function(my_custom_tool, name="my_custom_tool"),
58
+ Tool.from_function(get_current_time_in_timezone, name="get_current_time_in_timezone"),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  ]
60
 
61
+ llm = ChatOpenAI( # uses env var OPENAI_API_KEY
62
+ model = "gpt-3.5-turbo",
63
+ temperature = 0,
64
+ )
65
+
66
  agent = create_openai_functions_agent(llm, tools)
67
  agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=False)
68
+ # ╰───────────────────────────────────────────────────────────────────────────╯
69
 
 
 
 
 
 
 
 
70
 
71
+ # ╭──────────────────────── 4. CLI test loop (optional) ─────────────────────╮
 
 
 
 
72
  if __name__ == "__main__":
73
+ if not os.getenv("OPENAI_API_KEY"):
74
+ print("⚠️ Please set OPENAI_API_KEY as an env-var (HF Space → Secrets).")
75
+ print("🔮 Agent ready. Type a question or 'q' to quit.")
76
+ while True:
77
+ user = input("🗣 ")
78
+ if user.lower().strip() in {"q", "quit", "exit"}:
79
+ break
80
+ result = agent_executor.invoke({"input": user})
81
+ print("🤖", result["output"])
82
+ # ╰───────────────────────────────────────────────────────────────────────────╯
83
+