olca 0.2.34__py3-none-any.whl → 0.2.36__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
olca/fusewill_cli.py CHANGED
@@ -1,3 +1,4 @@
1
+ from ast import alias
1
2
  import os
2
3
  import sys
3
4
  sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
@@ -12,7 +13,8 @@ from fusewill_utils import (
12
13
  get_trace_by_id,
13
14
  open_trace_in_browser,
14
15
  print_traces,
15
- print_trace
16
+ print_trace,
17
+ list_traces_by_score # Ensure the updated function is imported
16
18
  )
17
19
  import dotenv
18
20
  import json
@@ -30,24 +32,24 @@ def get_single_char_input():
30
32
  return ch
31
33
 
32
34
  def main():
33
- parser = argparse.ArgumentParser(description="Langfuse CLI Wrapper")
35
+ parser = argparse.ArgumentParser(description="FuseWill Langfuse CLI Wrapper")
34
36
  subparsers = parser.add_subparsers(dest="command", help="Available commands")
35
37
 
36
38
  # list_traces command
37
39
  parser_list = subparsers.add_parser('list_traces', help='List traces',aliases=['lt'])
38
- parser_list.add_argument('--limit', type=int, default=100, help='Number of traces to fetch')
40
+ parser_list.add_argument('-L','--limit', type=int, default=100, help='Number of traces to fetch')
39
41
  parser_list.add_argument('--output_dir', type=str, default='../output/traces', help='Directory to save traces')
40
42
  parser_list.add_argument('-C','--comments', action='store_true', help='Show comments from the traces', default=False)
41
43
  parser_list.add_argument('-W','--browse-interact', action='store_true', help='Ask user to open each trace in browser')
42
44
 
43
45
  # create_dataset command
44
- parser_create_dataset = subparsers.add_parser('create_dataset', help='Create a new dataset')
46
+ parser_create_dataset = subparsers.add_parser('create_dataset', help='Create a new dataset',aliases=['cd'])
45
47
  parser_create_dataset.add_argument('name', help='Name of the dataset')
46
- parser_create_dataset.add_argument('--description', default='', help='Description of the dataset')
47
- parser_create_dataset.add_argument('--metadata', type=str, default='{}', help='Metadata in JSON format')
48
+ parser_create_dataset.add_argument('-D','--description', default='', help='Description of the dataset')
49
+ parser_create_dataset.add_argument('-M','--metadata', type=str, default='{}', help='Metadata in JSON format')
48
50
 
49
51
  # create_prompt command
50
- parser_create_prompt = subparsers.add_parser('create_prompt', help='Create a new prompt')
52
+ parser_create_prompt = subparsers.add_parser('create_prompt', help='Create a new prompt',aliases=['cp'])
51
53
  parser_create_prompt.add_argument('name', help='Name of the prompt')
52
54
  parser_create_prompt.add_argument('prompt_text', help='Prompt text')
53
55
  parser_create_prompt.add_argument('--model_name', default='gpt-4o-mini', help='Model name')
@@ -56,7 +58,7 @@ def main():
56
58
  parser_create_prompt.add_argument('--supported_languages', nargs='*', default=[], help='Supported languages')
57
59
 
58
60
  # update_prompt command
59
- parser_update_prompt = subparsers.add_parser('update_prompt', help='Update an existing prompt')
61
+ parser_update_prompt = subparsers.add_parser('update_prompt', help='Update an existing prompt',aliases=['up'])
60
62
  parser_update_prompt.add_argument('name', help='Name of the prompt')
61
63
  parser_update_prompt.add_argument('new_prompt_text', help='New prompt text')
62
64
 
@@ -65,11 +67,11 @@ def main():
65
67
  parser_delete_dataset.add_argument('name', help='Name of the dataset')
66
68
 
67
69
  # get_trace_by_id command
68
- parser_get_trace = subparsers.add_parser('get_trace_by_id', help='Get a trace by ID')
70
+ parser_get_trace = subparsers.add_parser('get_trace_by_id', help='Get a trace by ID',aliases=['gt'])
69
71
  parser_get_trace.add_argument('trace_id', help='Trace ID')
70
72
 
71
73
  # new_score command
72
- parser_new_score = subparsers.add_parser('new_score', help='Create a new score')
74
+ parser_new_score = subparsers.add_parser('new_score', help='Create a new score',aliases=['ns'])
73
75
  parser_new_score.add_argument('name', help='Score name')
74
76
  parser_new_score.add_argument('data_type', help='Data type of the score')
75
77
  parser_new_score.add_argument('--description', default='', help='Description of the score')
@@ -84,11 +86,11 @@ def main():
84
86
  parser_add_score.add_argument('--comment', default='', help='Comment for the score')
85
87
 
86
88
  # list_traces_by_score command
87
- parser_list_by_score = subparsers.add_parser('list_traces_by_score', help='List traces by score')
89
+ parser_list_by_score = subparsers.add_parser('list_traces_by_score', help='List traces by score', aliases=['ltbs','lbys','lts'])
88
90
  parser_list_by_score.add_argument('score_name', help='Score name')
89
91
  parser_list_by_score.add_argument('--min_value', type=float, help='Minimum score value')
90
92
  parser_list_by_score.add_argument('--max_value', type=float, help='Maximum score value')
91
- parser_list_by_score.add_argument('--limit', type=int, default=100, help='Number of traces to fetch')
93
+ parser_list_by_score.add_argument('-L','--limit', type=int, default=100, help='Number of traces to fetch')
92
94
 
93
95
  args = parser.parse_args()
94
96
 
@@ -115,7 +117,7 @@ def main():
115
117
  elif resp == 'q':
116
118
  print("Quitting.")
117
119
  break
118
- elif args.command == 'create_dataset':
120
+ elif args.command == 'create_dataset' or args.command == 'cd':
119
121
  metadata = json.loads(args.metadata)
120
122
  create_dataset(name=args.name, description=args.description, metadata=metadata)
121
123
  elif args.command == 'create_prompt':
@@ -127,16 +129,16 @@ def main():
127
129
  labels=args.labels,
128
130
  supported_languages=args.supported_languages
129
131
  )
130
- elif args.command == 'update_prompt':
132
+ elif args.command == 'update_prompt' or args.command == 'up':
131
133
  update_prompt(name=args.name, new_prompt_text=args.new_prompt_text)
132
134
  elif args.command == 'delete_dataset':
133
135
  delete_dataset(name=args.name)
134
- elif args.command == 'get_trace_by_id':
136
+ elif args.command == 'get_trace_by_id' or args.command == 'gt' :
135
137
  trace = get_trace_by_id(trace_id=args.trace_id)
136
138
  print(trace)
137
- elif args.command == 'new_score':
139
+ elif args.command == 'new_score' or args.command == 'ns':
138
140
  fu.create_score(name=args.name, data_type=args.data_type, description=args.description)
139
- elif args.command == 'add_score_to_trace':
141
+ elif args.command == 'add_score_to_trace' or args.command == 's2t':
140
142
  if not fu.score_exists(name=args.name):
141
143
  fu.create_score(name=args.name, data_type=args.data_type)
142
144
  fu.add_score_to_a_trace(
@@ -147,7 +149,7 @@ def main():
147
149
  data_type=args.data_type,
148
150
  comment=args.comment
149
151
  )
150
- elif args.command == 'list_traces_by_score':
152
+ elif args.command == 'list_traces_by_score' or args.command == 'ltbs' or args.command == 'lbys' or args.command == 'lts':
151
153
  traces = fu.list_traces_by_score(
152
154
  score_name=args.score_name,
153
155
  min_value=args.min_value,
@@ -155,7 +157,8 @@ def main():
155
157
  limit=args.limit
156
158
  )
157
159
  for trace in traces:
158
- print(f"Trace ID: {trace.id}, Name: {trace.name}")
160
+ print_trace(trace)
161
+ #print(f"Trace ID: {trace.id}, Name: {trace.name}")
159
162
  else:
160
163
  parser.print_help()
161
164
  exit(1)
olca/fusewill_utils.py CHANGED
@@ -3,6 +3,7 @@ import sys
3
3
  import json
4
4
  import dotenv
5
5
  import webbrowser
6
+ import requests # Add this import
6
7
 
7
8
  # Load .env from the current working directory
8
9
  dotenv.load_dotenv(dotenv_path=os.path.join(os.getcwd(), ".env"))
@@ -53,6 +54,20 @@ def open_trace_in_browser(trace_id):
53
54
  print(f"Opening {full_url}")
54
55
  webbrowser.open(full_url)
55
56
 
57
+ def get_score_by_id(score_id):
58
+ """Retrieve score details by score ID."""
59
+ base_url = os.environ.get("LANGFUSE_HOST")
60
+ public_key = os.environ.get("LANGFUSE_PUBLIC_KEY")
61
+ secret_key = os.environ.get("LANGFUSE_SECRET_KEY")
62
+ url = f"{base_url}/api/public/scores/{score_id}"
63
+ try:
64
+ response = requests.get(url, auth=(public_key, secret_key))
65
+ response.raise_for_status()
66
+ return response.json()
67
+ except Exception as e:
68
+ print(f"Error retrieving score {score_id}: {e}")
69
+ return None
70
+
56
71
  def print_trace(trace, show_comments=False):
57
72
  print(f"<Trace \n\tat=\"{trace.createdAt}\" \n\tid=\"{trace.id}\" \n\tname=\"{trace.name}\" \n\tsession_id=\"{trace.session_id}\" \n\tprojectId=\"{trace.projectId}\" >")
58
73
  print(f"<Input><CDATA[[\n{trace.input}\n]]></Input>")
@@ -61,8 +76,10 @@ def print_trace(trace, show_comments=False):
61
76
  print(f"<Metadata>{trace.metadata}</Metadata>")
62
77
  if trace.scores:
63
78
  print("<Scores>")
64
- for score in trace.scores:
65
- print(f"{score}")
79
+ for score_id in trace.scores:
80
+ score = get_score_by_id(score_id)
81
+ if score:
82
+ print(f"<Score name=\"{score['name']}\" value=\"{score['value']}\" data_type=\"{score['dataType']}\" />")
66
83
  print("</Scores>")
67
84
  if show_comments and hasattr(trace, "comments"):
68
85
  print(f"<Comments>\n{trace.comments}\n</Comments>")
@@ -81,9 +98,10 @@ def list_traces_by_score(score_name, min_value=None, max_value=None, limit=100):
81
98
  traces = langfuse.get_traces(limit=limit)
82
99
  filtered_traces = []
83
100
  for trace in traces.data:
84
- for score in trace.scores:
85
- if score.name == score_name:
86
- if (min_value is None or score.value >= min_value) and (max_value is None or score.value <= max_value):
101
+ for score_id in trace.scores:
102
+ score = get_score_by_id(score_id)
103
+ if score and score.get('name') == score_name:
104
+ if (min_value is None or score.get('value') >= min_value) and (max_value is None or score.get('value') <= max_value):
87
105
  filtered_traces.append(trace)
88
106
  break
89
107
  return filtered_traces
olca/olcacli.py CHANGED
@@ -166,6 +166,8 @@ def _parse_args():
166
166
  parser.add_argument("-y", "--yes", action="store_true", help="Accept the new file olca.yml")
167
167
  return parser.parse_args()
168
168
 
169
+ from olca.tracing import TracingManager
170
+
169
171
  def main():
170
172
  args = _parse_args()
171
173
  olca_config_file = 'olca.yml'
@@ -186,21 +188,14 @@ def main():
186
188
 
187
189
  config = load_config(olca_config_file)
188
190
 
189
- # Check for tracing flag in config and CLI
190
- tracing_enabled = config.get('tracing', False) or args.tracing or os.getenv("LANGCHAIN_TRACING_V2") == "true"
191
- if tracing_enabled:
192
- os.environ["LANGCHAIN_TRACING_V2"] = "true"
193
- if not os.getenv("LANGCHAIN_API_KEY"):
194
- print("Error: LANGCHAIN_API_KEY environment variable is required for tracing. Please set it up at : https://smith.langchain.com/settings")
195
- exit(1)
196
- # Initialize LangSmith client
197
- import langsmith
198
- LANGSMITH_API_KEY = os.getenv("LANGSMITH_API_KEY")
199
- LANGCHAIN_API_KEY = os.getenv("LANGCHAIN_API_KEY")
200
- if not LANGSMITH_API_KEY and not LANGCHAIN_API_KEY:
201
- print("Error: LANGSMITH_API_KEY or LANGCHAIN_API_KEY environment variable is not set.")
202
- exit(1)
203
- client = langsmith.Client(api_key=LANGSMITH_API_KEY or LANGCHAIN_API_KEY)
191
+ # Initialize tracing
192
+ tracing_manager = TracingManager(config)
193
+ callbacks = tracing_manager.get_callbacks()
194
+
195
+ # Remove old tracing setup
196
+ tracing_enabled = config.get('tracing', False) or args.tracing
197
+ if tracing_enabled and not callbacks:
198
+ print("Warning: Tracing enabled but no handlers configured")
204
199
 
205
200
  try:
206
201
 
@@ -286,7 +281,10 @@ def main():
286
281
 
287
282
 
288
283
  try:
289
- print_stream(graph.stream(inputs, stream_mode="values"))
284
+ graph_config = {"callbacks": callbacks} if callbacks else {}
285
+ if recursion_limit:
286
+ graph_config["recursion_limit"] = recursion_limit
287
+ print_stream(graph.stream(inputs, config=graph_config))
290
288
  except GraphRecursionError as e:
291
289
  #print(f"Error: {e}")
292
290
  print("Recursion limit reached. Please increase the 'recursion_limit' in the olca_config.yaml file.")
@@ -317,7 +315,8 @@ def initialize_config_file():
317
315
  "recursion_limit": int(input("recursion_limit [12]: ") or default_recursion_limit),
318
316
  "temperature": float(input("temperature [0]: ") or default_temperature),
319
317
  "human": input("human [true]: ").lower() in ["true", "yes", "y", "1", ""] or use_default_human_input,
320
- "tracing": input("tracing [true]: ").lower() in ["true", "yes", "y", "1", ""] or use_default_tracing
318
+ "tracing": input("tracing [true]: ").lower() in ["true", "yes", "y", "1", ""] or use_default_tracing,
319
+ "tracing_providers": ["langsmith", "langfuse"]
321
320
  }
322
321
 
323
322
  user_system_instructions = input(f"system_instructions [{default_system_instructions}]: ")
olca/tracing.py ADDED
@@ -0,0 +1,38 @@
1
+ import os
2
+ from langfuse.callback import CallbackHandler as LangfuseCallbackHandler
3
+
4
+ class TracingManager:
5
+ def __init__(self, config):
6
+ self.config = config
7
+ self.handlers = []
8
+ self.initialize_tracing()
9
+
10
+ def initialize_tracing(self):
11
+ tracing_enabled = self.config.get('tracing', False)
12
+ providers = self.config.get('tracing_providers', ['langsmith'])
13
+
14
+ if not tracing_enabled:
15
+ return
16
+
17
+ if 'langsmith' in providers:
18
+ self._setup_langsmith()
19
+
20
+ if 'langfuse' in providers:
21
+ handler = self._setup_langfuse()
22
+ if handler:
23
+ self.handlers.append(handler)
24
+
25
+ def _setup_langsmith(self):
26
+ api_key = os.getenv("LANGCHAIN_API_KEY") or os.getenv("LANGSMITH_API_KEY")
27
+ if api_key:
28
+ os.environ["LANGCHAIN_TRACING_V2"] = "true"
29
+
30
+ def _setup_langfuse(self):
31
+ if not (os.getenv("LANGFUSE_PUBLIC_KEY") and os.getenv("LANGFUSE_SECRET_KEY")):
32
+ print("Warning: LANGFUSE_PUBLIC_KEY/LANGFUSE_SECRET_KEY not set for Langfuse tracing")
33
+ return None
34
+
35
+ return LangfuseCallbackHandler()
36
+
37
+ def get_callbacks(self):
38
+ return self.handlers if self.handlers else None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: olca
3
- Version: 0.2.34
3
+ Version: 0.2.36
4
4
  Summary: A Python package for experimental usage of Langchain and Human-in-the-Loop
5
5
  Home-page: https://github.com/jgwill/olca
6
6
  Author: Jean GUillaume ISabelle
@@ -0,0 +1,11 @@
1
+ olca/__init__.py,sha256=3QyLLAys_KiiDIe-cfO_7QyY7di_qCaCS-sVziW2BOw,23
2
+ olca/fusewill_cli.py,sha256=Gf8CaYs7Uo4NH8QfgRNYalpmSUo047p9rzdkvIABHi8,7872
3
+ olca/fusewill_utils.py,sha256=IOIElqWCIsNzePlS1FZa5_35vySYLwbMUGW6UhNefIc,6065
4
+ olca/olcacli.py,sha256=MBWanmGn1vWiy0S2lhe_dJc7u-B14n3ywA7lEP4qttM,14578
5
+ olca/tracing.py,sha256=A6K9K_mhCPS1_NncFv2-7hbeMkqfKT3XgUCERusbIYE,1248
6
+ olca-0.2.36.dist-info/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
7
+ olca-0.2.36.dist-info/METADATA,sha256=ovFeWWj5Xn2It7PqskYfvDNCSW0MjjO9bTKhb3y8DyY,25311
8
+ olca-0.2.36.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
9
+ olca-0.2.36.dist-info/entry_points.txt,sha256=AhP5FMv6vnOq9C76V_vxRVIO50smnZXG4RIY47oD2_U,103
10
+ olca-0.2.36.dist-info/top_level.txt,sha256=bGDtAReS-xlS0F6MM-DyD0IQUqjNdWmgemnM3vNtrpI,5
11
+ olca-0.2.36.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- olca/__init__.py,sha256=3QyLLAys_KiiDIe-cfO_7QyY7di_qCaCS-sVziW2BOw,23
2
- olca/fusewill_cli.py,sha256=-hq-uCQfx9Tkb8TTTJNgQS7hgigS9XDaNBL9CKAouMU,7415
3
- olca/fusewill_utils.py,sha256=qh_ZGx9hV18wrdPM6ofXNFqyP51TeuoUeeTWfWIG1y8,5251
4
- olca/olcacli.py,sha256=s-dqJRE6xqQLG_qSwp8prahRV3vZNueEaK7OXgmU9wc,14885
5
- olca-0.2.34.dist-info/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
6
- olca-0.2.34.dist-info/METADATA,sha256=a453tzxvh71r4zn0ikUB-J9q-Btp2D3y3LRfDIGlCCU,25311
7
- olca-0.2.34.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
8
- olca-0.2.34.dist-info/entry_points.txt,sha256=AhP5FMv6vnOq9C76V_vxRVIO50smnZXG4RIY47oD2_U,103
9
- olca-0.2.34.dist-info/top_level.txt,sha256=bGDtAReS-xlS0F6MM-DyD0IQUqjNdWmgemnM3vNtrpI,5
10
- olca-0.2.34.dist-info/RECORD,,
File without changes
File without changes