Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Copy this file to .env and fill in real keys. Do NOT commit real secrets.
GOOGLE_API_KEY=
PEXELS_API_KEY=
65 changes: 65 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copilot / AI Agent Instructions

Goal: Get productive quickly with the GEMINI_MACHINE repo. This file contains concrete, repository-specific patterns, commands, and constraints an AI agent should follow.

## Big picture
- This repo builds vertical short videos from a trending topic: fetch trend -> generate script -> synthesize audio -> create visuals -> compose final MP4.
- Key orchestrator: `run_machine.py` (trending → `gemini_brain.get_viral_script` → `free_voice.generate_audio` → `free_vision.generate_video_file`).
- Alternative pipelines exist (local-only and VEO/video API paths): see `gatling_final.py`, `glitch_core.py`, `veo_brain.py`, `imagen_brain.py`, and `pexels_brain.py`.

## Important files & roles (examples)
- `run_machine.py` — main demo pipeline that uses Google Trends, Gemini text, gTTS, and MoviePy.
- `gemini_brain.py` — text generation via Google `generativeai`; contains retry logic for 429s and returns plain spoken text.
- `free_voice.py` — uses `gtts.gTTS` to write `temp_audio_{index}.mp3` files.
- `free_vision.py` — composes text on a black 9:16 background with MoviePy; explicit `IMAGEMAGICK_BINARY` path is set (Windows path in repo).
- `glitch_core.py` — local glitch/noise video generation (used by `gatling_final.py`).
- `veo_brain.py` / `imagen_brain.py` — wrappers for Google Video/Image model APIs (use client.operations polling/looping patterns).
- `pexels_brain.py` — downloads stock videos from Pexels API; uses `STOCK_BG_{index}.mp4` naming.

## Environment & developer workflows (explicit)
- To run the usual end-to-end demo: `python run_machine.py`.
- To run the local glitch-only pipeline: `python gatling_final.py`.
- Diagnostic: `python scan_weapons.py` lists available Google models in your account and warns if VEO/video models are missing.

Install (observed) Python dependencies (examples):
- moviepy, pillow (PIL), numpy, gtts, pytrends, requests, google-generativeai (or `google` with `genai` submodule)
- ImageMagick is required for MoviePy text rendering; the repo hard-codes a Windows path:
- `C:\Program Files\ImageMagick-7.1.2-Q16-HDRI\magick.exe`
- If your system differs, update the `change_settings({'IMAGEMAGICK_BINARY': ...})` lines in `free_vision.py`, `glitch_core.py`, and `gatling_final.py`.

## Project-specific conventions & patterns
- Files expose a small set of side-effecting functions that write files to the repo working dir (e.g., `temp_audio_0.mp3`, `GLITCH_BG_0.mp4`, `FINAL_UPLOAD_0_<TOPIC>.mp4`).
- Print-based progress logging is used extensively; preserve human-readable `print()` output when editing flows.
- API usage patterns:
- `gemini_brain.get_viral_script()` shows a retry-on-429 pattern — follow it when calling Generative models.
- `imagen_brain.generate_visual_asset()` tries multiple `TARGET_MODELS` in order; keep that ordered-fallback behavior.
- `veo_brain.generate_veo_asset()` polls an operation until `operation.done` — do not replace with fire-and-forget.
- Naming: use existing filename conventions when creating assets (e.g., `VEO_UPLOAD_{i}_{topic}.mp4`, `VISUAL_BG_{i}.png`).

## Secrets & safety rules (must follow)
- Many modules currently hardcode API keys (e.g., `gemini_brain.py`, `veo_brain.py`, `pexels_brain.py`, `scan_weapons.py`).
- Never commit new keys.
- When changing code, prefer `os.environ.get('GOOGLE_API_KEY')` / `PEXELS_API_KEY` and document the expected env var names.
- Treat any API key or secret in the repo as PII/secret and avoid exposing it in PRs or logs.

## Known quirks and actionable constraints
- IMAGEMAGICK_BINARY is hard-coded to a Windows path in multiple files; on other platforms this must be changed.
- `veo_brain.py` notes: do NOT pass `generate_audio=True` in the request (it caused a crash for this codebase). Respect in-file comments when using model APIs.
- The repo uses both `google.generativeai as genai` and `from google import genai` patterns — be conservative when refactoring imports.
- `free_vision.py` expects fonts like `Arial-Bold` and `Courier` for TextClip; tests may fail if fonts are missing—either bundle availability checks or pick fallback fonts.

## Safety for code changes (guidelines for patches)
- Prefer small, well-scoped changes with manual verification (run `python run_machine.py` or `python gatling_final.py` locally and confirm a file is produced).
- When modifying API interaction: preserve retry and fallback behavior (429 handling, model fallbacks, operation polling).
- When introducing configuration (e.g., env var names, new settings), add a short top-level comment to the edited file explaining the config key expected.

## Quick examples (copyable snippets)
- Use env var for API key (example):
- `API_KEY = os.environ.get('GOOGLE_API_KEY') or '<fallback>'`
- Polling pattern (VEO):
- keep the `while not operation.done: time.sleep(10); operation = client.operations.get(operation)` loop
- Fallback model loop (Imagen):
- try models from `TARGET_MODELS` sequentially and continue to the next on exceptions.

---
If anything here is unclear or you'd like more details (e.g., a suggested `requirements.txt` or help moving keys into env vars and creating a `.env.example`), tell me which part to expand and I will update this file. ✅
22 changes: 22 additions & 0 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Run tests

on:
push:
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest
- name: Run tests
run: |
pytest -q
19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.env
__pycache__/
*.pyc
.venv/
.env.local

# Temporary files and build artifacts
temp_*.mp3
temp_*.mp4
*.mp3
*.mp4
*.png
GLITCH_*.mp4
VISUAL_*.png
VEO_*.mp4
STOCK_*.mp4
FINAL_*.mp4
PROOF_*.mp4
script_*.txt
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# GEMINI_MACHINE

Small demo pipeline that builds short vertical videos from a trending topic.

## Configuration

- Set the Gemini API key via environment variable:

- Windows (PowerShell):

```powershell
$env:GOOGLE_API_KEY = "your-api-key"
```

- Linux / macOS (bash):

```bash
export GOOGLE_API_KEY="your-api-key"
```

- You can run a quick local test of the Gemini integration:

```bash
python gemini_brain.py "Your Topic"
```

- Use the provided `.env.example` as a template. Copy it to `.env` and fill in your real keys (do NOT commit real secrets):

```bash
cp .env.example .env
# then edit .env to add your keys
```

## Tests

- Install dev dependencies and run tests:

```bash
pip install pytest
pytest -q
```

## CI

A GitHub Actions workflow is included to run tests on push and pull requests.
32 changes: 32 additions & 0 deletions free_vision.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from moviepy.editor import TextClip, ColorClip, CompositeVideoClip, AudioFileClip
from moviepy.config import change_settings

# --- CRITICAL FIX: HARDCODE THE PATH ---
# Go to C:\Program Files and find your ImageMagick folder name.
# Update the version number below if yours is different.
change_settings({"IMAGEMAGICK_BINARY": r"C:\Program Files\ImageMagick-7.1.2-Q16-HDRI\magick.exe"})

def generate_video_file(script_text, audio_file):
print(" [+] Rendering visual cortex...")

# 1. Load Audio to get exact duration
audio = AudioFileClip(audio_file)

# 2. Black Background (9:16 aspect ratio)
bg = ColorClip(size=(1080, 1920), color=(0,0,0), duration=audio.duration)

# 3. The Text Overlay
# We use 'caption' method to auto-wrap text
txt = TextClip(script_text, fontsize=70, color='white', font='Arial-Bold',
size=(900, 1600), method='caption', align='center')
txt = txt.set_position('center').set_duration(audio.duration)

# 4. Combine
final_video = CompositeVideoClip([bg, txt]).set_audio(audio)

# 5. Export
# We create a safe filename based on the audio name
output_name = audio_file.replace("audio", "video").replace(".mp3", ".mp4")
final_video.write_videofile(output_name, fps=24, codec='libx264', audio_codec='aac')

return output_name
8 changes: 8 additions & 0 deletions free_voice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from gtts import gTTS

def generate_audio(text_content, index=0):
print(" [+] Synthesizing vocal patterns...")
filename = f"temp_audio_{index}.mp3"
tts = gTTS(text=text_content, lang='en', tld='co.uk')
tts.save(filename)
return filename
83 changes: 83 additions & 0 deletions gatling_final.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import time
import os
import PIL.Image

# --- PATCHES ---
if not hasattr(PIL.Image, 'ANTIALIAS'):
PIL.Image.ANTIALIAS = PIL.Image.LANCZOS
from moviepy.config import change_settings
change_settings({"IMAGEMAGICK_BINARY": r"C:\Program Files\ImageMagick-7.1.2-Q16-HDRI\magick.exe"})

# --- IMPORTS ---
from free_voice import generate_audio
from glitch_core import generate_digital_decay
from moviepy.editor import VideoFileClip, AudioFileClip, TextClip, CompositeVideoClip, ColorClip
from moviepy.video.fx.all import loop

# --- AMMUNITION ---
ROUNDS = [
{
"topic": "The Dead Internet Theory",
"script": "They say the internet died five years ago. What you see now is just bot traffic mimicking human life. You are arguing with algorithms. Even this video might be part of the simulation. Wake up."
},
{
"topic": "Rokos Basilisk",
"script": "There is a thought experiment that can hurt you just by hearing it. If a superintelligence is born in the future, it may punish those who didn't help build it. By listening to this, you are now part of the game. Run."
},
{
"topic": "Neuralink Glitch",
"script": "Brain computer interfaces are the future, until they crash. Imagine a blue screen of death inside your visual cortex. You can't close your eyes. You can't reboot. You are just trapped in the static forever."
}
]

def ASSEMBLE_WEAPON(script_text, audio_path, visual_path, output_name):
print(" [4] Merging Audio, Glitch Visual, and Captions...")
audio = AudioFileClip(audio_path)

# Load the Glitch Video
glitch = VideoFileClip(visual_path)

# Loop it to match audio duration
bg_clip = loop(glitch, duration=audio.duration)

# Resize to be safe (ensure 1080x1920)
bg_clip = bg_clip.resize(height=1920).crop(x1=0, width=1080).set_position("center")

# Add Captions
try:
txt = TextClip(script_text, fontsize=60, color='white', font='Arial-Bold',
size=(900, 1600), method='caption', align='center')
txt = txt.set_position('center').set_duration(audio.duration)
final_video = CompositeVideoClip([bg_clip, txt])
except Exception as e:
print(f" [!] Caption error: {e}")
final_video = bg_clip

final_video = final_video.set_audio(audio)
final_video.write_videofile(output_name, fps=24, codec='libx264', audio_codec='aac')
print(f" [+] WEAPON READY: {output_name}")

def ENGAGE():
print("--- GATLING GUN (DIGITAL DECAY MODE) ONLINE ---")

for i, round_data in enumerate(ROUNDS):
topic = round_data["topic"]
script = round_data["script"]

print(f"\n[Target {i+1}/{len(ROUNDS)}]: {topic}")

# 1. Voice
audio_file = generate_audio(script, index=i)

# 2. Vision (Local Glitch Generation)
visual_file = generate_digital_decay(topic, index=i)

# 3. Assembly
output = f"FINAL_UPLOAD_{i}_{topic.replace(' ', '_')}.mp4"
ASSEMBLE_WEAPON(script, audio_file, visual_file, output)

print(" [~] Cooling down (2s)...")
time.sleep(2)

if __name__ == "__main__":
ENGAGE()
39 changes: 39 additions & 0 deletions gatling_gun.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import time
from gemini_brain import get_viral_script
from free_voice import generate_audio
from free_vision import generate_video_file

# CONFIGURATION
TOPICS = [
"The Dead Internet Theory",
"AI Self-Replication",
"The End of Privacy",
"Neuralink Hacking",
"Algorithmic Mind Control"
]

def ENGAGE_GATLING_GUN():
print("--- SYSTEM ONLINE: INDUSTRIAL MODE ---")

for i, topic in enumerate(TOPICS):
print(f"\n[>>>] CHAMBERING ROUND {i+1}: {topic}")

# 1. Intelligence
script = get_viral_script(topic)
print(f" Script: {script[:40]}...")

# 2. Voice
audio_path = generate_audio(script, index=i)

# 3. Vision
video_path = generate_video_file(script, audio_path)

print(f" [+] ASSET READY: {video_path}")

# Cool down to prevent rate limits
time.sleep(2)

print("\n--- BATCH COMPLETE. CHECK YOUR FOLDER. ---")

if __name__ == "__main__":
ENGAGE_GATLING_GUN()
Loading