merleau 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
merleau/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """Merleau - Video analysis using Google's Gemini API."""
2
+
3
+ __version__ = "0.2.0"
merleau/cli.py ADDED
@@ -0,0 +1,117 @@
1
+ """Command-line interface for Merleau video analysis."""
2
+
3
+ import argparse
4
+ import os
5
+ import sys
6
+ import time
7
+
8
+ from dotenv import load_dotenv
9
+ from google import genai
10
+
11
+
12
+ def wait_for_processing(client, file):
13
+ """Wait for file to finish processing."""
14
+ while file.state.name == "PROCESSING":
15
+ print(".", end="", flush=True)
16
+ time.sleep(2)
17
+ file = client.files.get(name=file.name)
18
+ print()
19
+ return file
20
+
21
+
22
+ def print_usage(usage):
23
+ """Print token usage and cost estimation."""
24
+ print("\n--- Usage Information ---")
25
+ print(f"Prompt tokens: {usage.prompt_token_count}")
26
+ print(f"Response tokens: {usage.candidates_token_count}")
27
+ print(f"Total tokens: {usage.total_token_count}")
28
+
29
+ # Gemini 2.5 Flash pricing (as of 2025):
30
+ # Input: $0.15 per 1M tokens (text/image), $0.075 per 1M tokens for video
31
+ # Output: $0.60 per 1M tokens, $3.50 for thinking tokens
32
+ input_cost = (usage.prompt_token_count / 1_000_000) * 0.15
33
+ output_cost = (usage.candidates_token_count / 1_000_000) * 0.60
34
+ total_cost = input_cost + output_cost
35
+ print(f"\nEstimated cost:")
36
+ print(f" Input: ${input_cost:.6f}")
37
+ print(f" Output: ${output_cost:.6f}")
38
+ print(f" Total: ${total_cost:.6f}")
39
+
40
+
41
+ def analyze(video_path, prompt, model, show_cost):
42
+ """Analyze a video file using Gemini."""
43
+ load_dotenv()
44
+
45
+ api_key = os.getenv("GEMINI_API_KEY")
46
+ if not api_key:
47
+ print("Error: GEMINI_API_KEY not found in environment or .env file", file=sys.stderr)
48
+ sys.exit(1)
49
+
50
+ if not os.path.exists(video_path):
51
+ print(f"Error: Video file not found: {video_path}", file=sys.stderr)
52
+ sys.exit(1)
53
+
54
+ client = genai.Client(api_key=api_key)
55
+
56
+ # Upload video
57
+ print(f"Uploading video: {video_path}")
58
+ myfile = client.files.upload(file=video_path)
59
+ print(f"Upload complete. File URI: {myfile.uri}")
60
+
61
+ # Wait for processing
62
+ print("Waiting for file to be processed...", end="")
63
+ myfile = wait_for_processing(client, myfile)
64
+
65
+ if myfile.state.name == "FAILED":
66
+ print(f"Error: File processing failed", file=sys.stderr)
67
+ sys.exit(1)
68
+
69
+ print(f"File state: {myfile.state.name}")
70
+
71
+ # Generate analysis
72
+ print(f"\nAnalyzing video with {model}...")
73
+ response = client.models.generate_content(
74
+ model=model,
75
+ contents=[myfile, prompt]
76
+ )
77
+
78
+ print("\n--- Video Analysis ---")
79
+ print(response.text)
80
+
81
+ # Show usage if requested
82
+ if show_cost and hasattr(response, 'usage_metadata'):
83
+ print_usage(response.usage_metadata)
84
+
85
+
86
+ def main():
87
+ """Main entry point for the CLI."""
88
+ parser = argparse.ArgumentParser(
89
+ prog="ponty",
90
+ description="Analyze videos using Google's Gemini API"
91
+ )
92
+ parser.add_argument(
93
+ "video",
94
+ help="Path to the video file to analyze"
95
+ )
96
+ parser.add_argument(
97
+ "-p", "--prompt",
98
+ default="Explain what happens in this video",
99
+ help="Prompt for the analysis (default: 'Explain what happens in this video')"
100
+ )
101
+ parser.add_argument(
102
+ "-m", "--model",
103
+ default="gemini-2.5-flash",
104
+ help="Gemini model to use (default: gemini-2.5-flash)"
105
+ )
106
+ parser.add_argument(
107
+ "--no-cost",
108
+ action="store_true",
109
+ help="Hide usage and cost information"
110
+ )
111
+
112
+ args = parser.parse_args()
113
+ analyze(args.video, args.prompt, args.model, show_cost=not args.no_cost)
114
+
115
+
116
+ if __name__ == "__main__":
117
+ main()
@@ -1,7 +1,7 @@
1
- Metadata-Version: 2.4
2
- Name: merleau
3
- Version: 0.1.0
4
- Summary: Video analysis using Google's Gemini 2.5 Flash API
5
- Requires-Python: >=3.10
6
- Requires-Dist: google-genai
7
- Requires-Dist: python-dotenv
1
+ Metadata-Version: 2.4
2
+ Name: merleau
3
+ Version: 0.2.0
4
+ Summary: Video analysis using Google's Gemini 2.5 Flash API
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: google-genai
7
+ Requires-Dist: python-dotenv
@@ -0,0 +1,6 @@
1
+ merleau/__init__.py,sha256=y5-8LWAim3ziWojAKzkwChDCV3rFkVzPmJ3m6Lkojgo,81
2
+ merleau/cli.py,sha256=XQz6ncqj4Zl_jLAmiRhhYXdn7kFNM76ReuG0gTvF9KY,3471
3
+ merleau-0.2.0.dist-info/METADATA,sha256=-71rumv5Gjq75t9fwzKSUBl_W-cPm1rLMsUrKlhRimE,192
4
+ merleau-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
5
+ merleau-0.2.0.dist-info/entry_points.txt,sha256=pMCcADIqyZbK-lQ5d2iLKIWqNeeY3pAQDHI1IBmtdEQ,43
6
+ merleau-0.2.0.dist-info/RECORD,,
@@ -1,5 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.10.2)
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
-
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ ponty = merleau.cli:main
@@ -1,4 +0,0 @@
1
- merleau-0.1.0.dist-info/METADATA,sha256=CE2o3opn5MUqcOf47bVQ_QhN4xxIYPzjQ95eigmRSKQ,199
2
- merleau-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
3
- merleau-0.1.0.dist-info/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
4
- merleau-0.1.0.dist-info/RECORD,,
@@ -1 +0,0 @@
1
-