gptdiff 0.1.8__py3-none-any.whl → 0.1.9__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
gptdiff/gptdiff.py CHANGED
@@ -67,6 +67,25 @@ def create_think_toolbox():
67
67
  )
68
68
  return toolbox
69
69
 
70
+ def color_code_diff(diff_text: str) -> str:
71
+ """
72
+ Color code lines in a diff. Lines beginning with '-' in red, and
73
+ lines beginning with '+' in green.
74
+ """
75
+ red = "\033[31m"
76
+ green = "\033[32m"
77
+ reset = "\033[0m"
78
+
79
+ colorized_lines = []
80
+ for line in diff_text.split('\n'):
81
+ if line.startswith('-'):
82
+ colorized_lines.append(f"{red}{line}{reset}")
83
+ elif line.startswith('+'):
84
+ colorized_lines.append(f"{green}{line}{reset}")
85
+ else:
86
+ colorized_lines.append(line)
87
+
88
+ return '\n'.join(colorized_lines)
70
89
 
71
90
  def load_gitignore_patterns(gitignore_path):
72
91
  with open(gitignore_path, 'r') as f:
@@ -308,8 +327,16 @@ def smartapply(diff_text, files, model=None, api_key=None, base_url=None):
308
327
  updated = call_llm_for_apply_with_think_tool_available(path, original, patch, model, api_key=api_key, base_url=base_url)
309
328
  files[path] = updated.strip()
310
329
 
330
+ threads = []
331
+
311
332
  for path, patch in parsed_diffs:
312
- process_file(path, patch)
333
+ thread = threading.Thread(target=process_file, args=(path, patch))
334
+ thread.start()
335
+ threads.append(thread)
336
+
337
+ # Wait for all threads to complete
338
+ for thread in threads:
339
+ thread.join()
313
340
 
314
341
  return files
315
342
 
@@ -339,6 +366,7 @@ def parse_arguments():
339
366
  parser.add_argument('--temperature', type=float, default=0.7, help='Temperature parameter for model creativity (0.0 to 2.0)')
340
367
  parser.add_argument('--max_tokens', type=int, default=30000, help='Temperature parameter for model creativity (0.0 to 2.0)')
341
368
  parser.add_argument('--model', type=str, default=None, help='Model to use for the API call.')
369
+ parser.add_argument('--applymodel', type=str, default=None, help='Model to use for applying the diff. Defaults to the value of --model if not specified.')
342
370
 
343
371
  parser.add_argument('--nowarn', action='store_true', help='Disable large token warning')
344
372
 
@@ -404,11 +432,11 @@ def parse_diff_per_file(diff_text):
404
432
 
405
433
  return diffs
406
434
 
407
- def call_llm_for_apply_with_think_tool_available(file_path, original_content, file_diff, model, api_key=None, base_url=None):
435
+ def call_llm_for_apply_with_think_tool_available(file_path, original_content, file_diff, model, api_key=None, base_url=None, extra_prompt=None, max_tokens=30000):
408
436
  parser = FlatXMLParser("think")
409
437
  formatter = FlatXMLPromptFormatter(tag="think")
410
438
  toolbox = create_think_toolbox()
411
- full_response = call_llm_for_apply(file_path, original_content, file_diff, model, api_key=None, base_url=None)
439
+ full_response = call_llm_for_apply(file_path, original_content, file_diff, model, api_key=api_key, base_url=base_url, extra_prompt=extra_prompt, max_tokens=max_tokens)
412
440
  notool_response = ""
413
441
  events = parser.parse(full_response)
414
442
  is_in_tool = False
@@ -424,7 +452,7 @@ def call_llm_for_apply_with_think_tool_available(file_path, original_content, fi
424
452
 
425
453
  return notool_response
426
454
 
427
- def call_llm_for_apply(file_path, original_content, file_diff, model, api_key=None, base_url=None):
455
+ def call_llm_for_apply(file_path, original_content, file_diff, model, api_key=None, base_url=None, extra_prompt=None, max_tokens=30000):
428
456
  """AI-powered diff application with conflict resolution.
429
457
 
430
458
  Internal workhorse for smartapply that handles individual file patches.
@@ -474,6 +502,8 @@ Diff to apply:
474
502
  {file_diff}
475
503
  </diff>"""
476
504
 
505
+ if extra_prompt:
506
+ user_prompt += f"\n\n{extra_prompt}"
477
507
  if model == "gemini-2.0-flash-thinking-exp-01-21":
478
508
  user_prompt = system_prompt+"\n"+user_prompt
479
509
  messages = [
@@ -490,7 +520,7 @@ Diff to apply:
490
520
  response = client.chat.completions.create(model=model,
491
521
  messages=messages,
492
522
  temperature=0.0,
493
- max_tokens=30000)
523
+ max_tokens=max_tokens)
494
524
  full_response = response.choices[0].message.content
495
525
 
496
526
  elapsed = time.time() - start_time
@@ -590,12 +620,21 @@ def main():
590
620
  if confirmation != 'y':
591
621
  print("Request canceled")
592
622
  sys.exit(0)
593
- full_text, diff_text, prompt_tokens, completion_tokens, total_tokens, cost = call_llm_for_diff(system_prompt, user_prompt, files_content, args.model,
623
+ try:
624
+ full_text, diff_text, prompt_tokens, completion_tokens, total_tokens, cost = call_llm_for_diff(system_prompt, user_prompt, files_content, args.model,
594
625
  temperature=args.temperature,
595
626
  api_key=os.getenv('GPTDIFF_LLM_API_KEY'),
596
627
  base_url=os.getenv('GPTDIFF_LLM_BASE_URL', "https://nano-gpt.com/api/v1/"),
597
628
  max_tokens=args.max_tokens
598
629
  )
630
+ except Exception as e:
631
+ full_text = f"{e}"
632
+ diff_text = ""
633
+ prompt_tokens = 0
634
+ completion_tokens = 0
635
+ total_tokens = 0
636
+ cost = 0
637
+ print(f"Error in LLM response {e}")
599
638
 
600
639
  if(diff_text.strip() == ""):
601
640
  print(f"\033[1;33mThere was no data in this diff. The LLM may have returned something invalid.\033[0m")
@@ -608,7 +647,7 @@ def main():
608
647
  elif args.apply:
609
648
  print("\nAttempting apply with the following diff:")
610
649
  print("\n<diff>")
611
- print(diff_text)
650
+ print(color_code_diff(diff_text))
612
651
  print("\n</diff>")
613
652
  print("Saved to patch.diff")
614
653
  if apply_diff(project_dir, diff_text):
@@ -651,8 +690,11 @@ def main():
651
690
  print("SMARTAPPLY")
652
691
  print(file_diff)
653
692
  print("-" * 40)
693
+ if args.applymodel is None:
694
+ args.applymodel = args.model
695
+
654
696
  try:
655
- updated_content = call_llm_for_apply_with_think_tool_available(file_path, original_content, file_diff, args.model)
697
+ updated_content = call_llm_for_apply_with_think_tool_available(file_path, original_content, file_diff, args.applymodel, extra_prompt=f"This changeset is from the following instructions:\n{user_prompt}", max_tokens=args.max_tokens)
656
698
 
657
699
  if updated_content.strip() == "":
658
700
  print("Cowardly refusing to write empty file to", file_path, "merge failed")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: gptdiff
3
- Version: 0.1.8
3
+ Version: 0.1.9
4
4
  Summary: A tool to generate and apply git diffs using LLMs
5
5
  Author: 255labs
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -0,0 +1,8 @@
1
+ gptdiff/__init__.py,sha256=yGjgwv7tNvH1ZLPsQyoo1CxpTOl1iCAwwDBp-_17ksQ,89
2
+ gptdiff/gptdiff.py,sha256=k4-iqho7h6NV0hxfpiSVpT3wyG3liBr8Ut_5V5-hjyk,27595
3
+ gptdiff-0.1.9.dist-info/LICENSE.txt,sha256=zCJk7yUYpMjFvlipi1dKtaljF8WdZ2NASndBYYbU8BY,1228
4
+ gptdiff-0.1.9.dist-info/METADATA,sha256=jG17S0CxskLxN2HyTXKYOH1Az7i5iafyqe4PcbCj9Ok,7317
5
+ gptdiff-0.1.9.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
6
+ gptdiff-0.1.9.dist-info/entry_points.txt,sha256=0yvXYEVAZFI-p32kQ4-h3qKVWS0a86jsM9FAwF89t9w,49
7
+ gptdiff-0.1.9.dist-info/top_level.txt,sha256=XNkQkQGINaDndEwRxg8qToOrJ9coyfAb-EHrSUXzdCE,8
8
+ gptdiff-0.1.9.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- gptdiff/__init__.py,sha256=yGjgwv7tNvH1ZLPsQyoo1CxpTOl1iCAwwDBp-_17ksQ,89
2
- gptdiff/gptdiff.py,sha256=kzLeNc5M3saCdqBOoE-OjkyHztGbQr39XPiVcFJ_pyY,25958
3
- gptdiff-0.1.8.dist-info/LICENSE.txt,sha256=zCJk7yUYpMjFvlipi1dKtaljF8WdZ2NASndBYYbU8BY,1228
4
- gptdiff-0.1.8.dist-info/METADATA,sha256=ErNMAtAqN7HDzarpVJi0IVA5i1pryUQwkjVjus9kjkM,7317
5
- gptdiff-0.1.8.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
6
- gptdiff-0.1.8.dist-info/entry_points.txt,sha256=0yvXYEVAZFI-p32kQ4-h3qKVWS0a86jsM9FAwF89t9w,49
7
- gptdiff-0.1.8.dist-info/top_level.txt,sha256=XNkQkQGINaDndEwRxg8qToOrJ9coyfAb-EHrSUXzdCE,8
8
- gptdiff-0.1.8.dist-info/RECORD,,