Full Code of hankhank10/fakeface for AI

master 527e476377db cached
12 files
16.0 KB
4.3k tokens
20 symbols
1 requests
Download .txt
Repository: hankhank10/fakeface
Branch: master
Commit: 527e476377db
Files: 12
Total size: 16.0 KB

Directory structure:
gitextract__qojwbd0/

├── .gitattributes
├── .gitignore
├── app.py
├── generate_faces.py
├── migrations/
│   ├── README
│   ├── alembic.ini
│   ├── env.py
│   ├── script.py.mako
│   └── versions/
│       └── dcb1be9b8bcc_.py
├── readme.md
├── requirements.txt
└── resize.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto


================================================
FILE: .gitignore
================================================
/.idea/*
/.venv/*

================================================
FILE: app.py
================================================
from flask import Flask, jsonify, request, redirect
from flask_cors import CORS, cross_origin
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.sql import func
from flask_migrate import Migrate
from datetime import datetime

app = Flask(__name__)
cors = CORS(app, resources={r"/*": {"origins": "*"}})
app.config['CORS_HEADERS'] = 'Content-Type'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

db.init_app(app)
migrate = Migrate(app, db)


class ImageRecord(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    gender = db.Column(db.String(10))
    age = db.Column(db.Integer)

    filename = db.Column(db.String(100))
    hosting = db.Column(db.String(100), default="local")

    def image_url(self):
        output = ""
        if self.hosting == "local":
            output = "https://content.fakeface.rest/" + self.filename
        return output

    def thumb_url(self):
        output = ""
        if self.hosting == "local":
            output = "https://thumb.fakeface.rest/thumb_" + self.filename
        return output

    date_added = db.Column(db.DateTime)
    source = db.Column(db.String(100))

    last_served = db.Column(db.DateTime)

    created_at = db.Column(db.DateTime)
    updated_at = db.Column(db.DateTime)
    is_deleted = db.Column(db.DateTime)
    deleted_at = db.Column(db.Boolean)


@app.route('/')
def index():
    return redirect ("https://hankhank10.github.io/fakeface/", code=307)


def get_url(gender = "", minimum_age = 0, maximum_age = 0, thumb=False):
    if gender == '':
        db_output = ImageRecord.query.filter(ImageRecord.age >= minimum_age, ImageRecord.age <= maximum_age).order_by(func.random()).first_or_404()

    if gender != '':
        db_output = ImageRecord.query.filter(ImageRecord.gender == gender, ImageRecord.age >= minimum_age, ImageRecord.age <= maximum_age).order_by(func.random()).first_or_404()

    db_output.last_served = datetime.utcnow()
    db.session.commit()
    if thumb == False: return db_output.image_url()
    if thumb == True: return db_output.thumb_url()


@app.route('/face/json')
def output_json():
    gender = request.args.get('gender', '')
    minimum_age = request.args.get('minimum_age', 0)
    maximum_age = request.args.get('maximum_age', 99)

    if gender == '':
        db_output = ImageRecord.query.filter(ImageRecord.age >= minimum_age, ImageRecord.age <= maximum_age).order_by(func.random()).first_or_404()

    if gender != '':
        db_output = ImageRecord.query.filter(ImageRecord.gender == gender, ImageRecord.age >= minimum_age, ImageRecord.age <= maximum_age).order_by(func.random()).first_or_404()

    dict_output = {
        'gender': db_output.gender,
        'age': db_output.age,
        'filename': db_output.filename,
        'date_added': db_output.date_added,
        'source': db_output.source,
        'image_url': db_output.image_url(),
        'last_served': db_output.last_served
    }

    db_output.last_served = datetime.utcnow()
    db.session.commit()

    return jsonify(dict_output)


@app.route ('/face/view')
@app.route ('/face/view/<x>')
def output_redirect_image(x = 0):
    gender = request.args.get('gender', '')
    minimum_age = request.args.get('minimum_age', 0)
    maximum_age = request.args.get('maximum_age', 99)

    url_to_show = get_url(gender, minimum_age, maximum_age, False)
    return redirect (url_to_show)


@app.route ('/thumb/view')
@app.route ('/thumb/view/<x>')
def output_redirect_thumb(x = 0):
    gender = request.args.get('gender', '')
    minimum_age = request.args.get('minimum_age', 0)
    maximum_age = request.args.get('maximum_age', 99)

    url_to_show = get_url(gender, minimum_age, maximum_age, True)
    return redirect(url_to_show)


@app.route('/stats')
def stats():
    stats_count = ImageRecord.query.count()
    return (str(stats_count) + " faces")


@app.after_request
def set_response_headers(response):
    response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
    response.headers['Pragma'] = 'no-cache'
    response.headers['Expires'] = '0'
    response.headers['Access-Control-Allow-Origin'] = '*'
    return response

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=11000)


================================================
FILE: generate_faces.py
================================================
import requests
import shutil
import cv2
import secrets
from pyagender import PyAgender
import time
from datetime import datetime

from time import sleep

from active_alchemy import ActiveAlchemy

db = ActiveAlchemy('sqlite:///db.sqlite')

# settings
url = "https://thispersondoesnotexist.com/image"
male_threshold = 0.4
female_threshold = 0.6
temp_file = "temp_img.jpg"
times_to_run = 500
seconds_to_sleep = 2


class ImageRecord(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    gender = db.Column(db.String(10))
    age = db.Column(db.Integer)

    filename = db.Column(db.String(100))
    hosting = db.Column(db.String(100), default="local")

    def image_url(self):
        if self.hosting == "local":
            output = "https://fakeface.rest/to_be_uploaded_to_static_host/" + self.filename
        return output

    date_added = db.Column(db.DateTime)
    source = db.Column(db.String(100))

    last_served = db.Column(db.DateTime)

    created_at = db.Column(db.DateTime)
    updated_at = db.Column(db.DateTime)
    is_deleted = db.Column(db.DateTime)
    deleted_at = db.Column(db.Boolean)


def download_face():
    response = requests.get(url, stream=True)
    with open(temp_file, 'wb') as out_file:
        shutil.copyfileobj(response.raw, out_file)
    return


def recoginise_face():
    faces = agender.detect_genders_ages(cv2.imread(temp_file))
    if len(faces) == 1:
        face = faces[0]
        gender_numeric = face['gender']
        age = int(face['age'])

        gender = "unclear"
        if gender_numeric < male_threshold: gender = "male"
        if gender_numeric > male_threshold: gender = "female"
    else:
        #face not detected or multiple faces detected
        gender = "unclear"
        age = 0

    return gender, age


def move_file(gender, age):
    filename = gender + "_" + str(age) + "_" + secrets.token_hex(20) + ".jpg"
    location_to_move_to = "static/classified/" + filename
    shutil.move(temp_file, location_to_move_to)
    return filename


def write_db(gender, age, filename):
    image_record = ImageRecord(
        gender=gender,
        age=age,
        filename=filename,
        date_added=datetime.utcnow(),
        source="thispersondoesnotexist",
        hosting="local",
        last_served=datetime.utcnow()
    )

    db.session.add(image_record)
    db.session.commit()
    return


agender = PyAgender()
starttime = time.time()

for a in range(1, times_to_run):
    download_face()
    gender, age = recoginise_face()
    if gender != "unclear":
        print(str(age) + " year old " + gender)
        filename = move_file(gender, age)
        write_db (gender, age, filename)
    else:
        print("gender unclear, so skipping")
    sleep(seconds_to_sleep)



================================================
FILE: migrations/README
================================================
Generic single-database configuration.

================================================
FILE: migrations/alembic.ini
================================================
# A generic, single database configuration.

[alembic]
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s

# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false


# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S


================================================
FILE: migrations/env.py
================================================
from __future__ import with_statement

import logging
from logging.config import fileConfig

from sqlalchemy import engine_from_config
from sqlalchemy import pool

from alembic import context

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
from flask import current_app
config.set_main_option(
    'sqlalchemy.url',
    str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%'))
target_metadata = current_app.extensions['migrate'].db.metadata

# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.


def run_migrations_offline():
    """Run migrations in 'offline' mode.

    This configures the context with just a URL
    and not an Engine, though an Engine is acceptable
    here as well.  By skipping the Engine creation
    we don't even need a DBAPI to be available.

    Calls to context.execute() here emit the given string to the
    script output.

    """
    url = config.get_main_option("sqlalchemy.url")
    context.configure(
        url=url, target_metadata=target_metadata, literal_binds=True
    )

    with context.begin_transaction():
        context.run_migrations()


def run_migrations_online():
    """Run migrations in 'online' mode.

    In this scenario we need to create an Engine
    and associate a connection with the context.

    """

    # this callback is used to prevent an auto-migration from being generated
    # when there are no changes to the schema
    # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
    def process_revision_directives(context, revision, directives):
        if getattr(config.cmd_opts, 'autogenerate', False):
            script = directives[0]
            if script.upgrade_ops.is_empty():
                directives[:] = []
                logger.info('No changes in schema detected.')

    connectable = engine_from_config(
        config.get_section(config.config_ini_section),
        prefix='sqlalchemy.',
        poolclass=pool.NullPool,
    )

    with connectable.connect() as connection:
        context.configure(
            connection=connection,
            target_metadata=target_metadata,
            process_revision_directives=process_revision_directives,
            **current_app.extensions['migrate'].configure_args
        )

        with context.begin_transaction():
            context.run_migrations()


if context.is_offline_mode():
    run_migrations_offline()
else:
    run_migrations_online()


================================================
FILE: migrations/script.py.mako
================================================
"""${message}

Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}

"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}

# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}


def upgrade():
    ${upgrades if upgrades else "pass"}


def downgrade():
    ${downgrades if downgrades else "pass"}


================================================
FILE: migrations/versions/dcb1be9b8bcc_.py
================================================
"""empty message

Revision ID: dcb1be9b8bcc
Revises: 
Create Date: 2020-08-02 14:59:29.227831

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'dcb1be9b8bcc'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('image_record',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('gender', sa.String(length=10), nullable=True),
    sa.Column('age', sa.Integer(), nullable=True),
    sa.Column('filename', sa.String(length=100), nullable=True),
    sa.Column('hosting', sa.String(length=100), nullable=True),
    sa.Column('date_added', sa.DateTime(), nullable=True),
    sa.Column('source', sa.String(length=100), nullable=True),
    sa.Column('last_served', sa.DateTime(), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=True),
    sa.Column('updated_at', sa.DateTime(), nullable=True),
    sa.Column('is_deleted', sa.DateTime(), nullable=True),
    sa.Column('deleted_at', sa.Boolean(), nullable=True),
    sa.PrimaryKeyConstraint('id')
    )
    # ### end Alembic commands ###


def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table('image_record')
    # ### end Alembic commands ###


================================================
FILE: readme.md
================================================
# This API is deprecated and no longer hosted. You are welcome to make use of the code to host your own version.


This API returns image URLs of fake human faces generated by [thispersondoesnotexist](https://thispersondoesnotexist.com).

![alt text](https://fakeface.rest/thumb/view/7 "Dynamically generated image")

Each image has been pre-analysed by an AI algorithm called [pypy-agender](https://github.com/aristofun/py-agender) to identify gender and age (obviously non-exact).

As such, the user of the API can specify gender, minimum and maximum age for the image to be returned.

Data can be returned via JSON format, a direct redirect to the image or a simple response with the image URL.


# JSON data for a face

### Endpoint
https://fakeface.rest/face/json

### Optional query parameters

* `gender` : accepts "male" or "female"; defaults to both if not provided

* `minimum_age` : integer

* `maximum_age` : integer

### Response
````
{
  age: 45,
  date_added: "Sun, 02 Aug 2020 22:08:56 GMT",
  filename: "female_45_b3e57178eb323fee36df8e8b4690c11ef82f3baa.jpg",
  gender: "female",
  image_url: "https://content.fakeface.rest/female_45_b3e57178eb323fee36df8e8b4690c11ef82f3baa.jpg",
  last_served: "Sun, 02 Aug 2020 22:08:56 GMT",
  source: "thispersondoesnotexist"
}
````

### Example queries:

<https://fakeface.rest/face/json>

<https://fakeface.rest/face/json?gender=male>

<https://fakeface.rest/face/json?gender=female&minimum_age=35>

<https://fakeface.rest/face/json?maximum_age=50&gender=female>

# Redirect to a face

### Endpoint
https://fakeface.rest/face/view

### Query parameters
(same as above for JSON)

### Response

Browser redirects right to image

### Example queries:

<https://fakeface.rest/face/view>

<https://fakeface.rest/face/view?gender=male>

### Inserting into HTML

The above address can be used in the src for an img in HTML to dynamically generate a new face on each load:

![alt text](https://fakeface.rest/face/view?gender=female "Dynamically generated image")

If you want to insert multiple different faces and prevent the browser caching then you can append any number or random string to the end of the endpoint as follows:

<https://fakeface.rest/face/view/55?gender=male>

<https://fakeface.rest/face/view/anythingcangohere_theapidoesntdoanythingwithit?gender=male>


# Redirect to a thumbnail of a face

### Endpoint
https://fakeface.rest/thumb/view

### Query parameters
(same as above for JSON)

### Response

Browser redirects right to thumbnail (350x350 maximum) image.

### Example queries:

<https://fakeface.rest/thumb/view>

<https://fakeface.rest/thumb/view?gender=male>

### Inserting into html:

![alt text](https://fakeface.rest/thumb/view/77 "Dynamically generated image")

![alt text](https://fakeface.rest/thumb/view/66 "Dynamically generated image")


# Licence

All of these images are generated by https://thispersondoesnotexist.com and are provided for usage only as allowed by that project's creators.

# Credits

All the hard work was done by the makers of https://thispersondoesnotexist.com and [pypy-agender](https://github.com/aristofun/py-agender)


================================================
FILE: requirements.txt
================================================
alembic==1.8.1
click==8.1.3
Flask==2.2.2
Flask-Cors==3.0.10
Flask-Migrate==3.1.0
Flask-SQLAlchemy==2.5.1
itsdangerous==2.1.2
Jinja2==3.1.2
Mako==1.2.2
MarkupSafe==2.1.1
six==1.16.0
SQLAlchemy==1.4.40
Werkzeug==2.2.2


================================================
FILE: resize.py
================================================
from PIL import Image
import pathlib

maxsize = (350,350)

for input_img_path in pathlib.Path("input").iterdir():
    output_img_path = str(input_img_path).replace("classified/","thumb/thumb_")
    with Image.open(input_img_path) as im:
        im.thumbnail(maxsize)
        im.save(output_img_path, "JPEG", dpi=(300,300))
        print(f"processing file {input_img_path} done...")
Download .txt
gitextract__qojwbd0/

├── .gitattributes
├── .gitignore
├── app.py
├── generate_faces.py
├── migrations/
│   ├── README
│   ├── alembic.ini
│   ├── env.py
│   ├── script.py.mako
│   └── versions/
│       └── dcb1be9b8bcc_.py
├── readme.md
├── requirements.txt
└── resize.py
Download .txt
SYMBOL INDEX (20 symbols across 4 files)

FILE: app.py
  class ImageRecord (line 20) | class ImageRecord(db.Model):
    method image_url (line 28) | def image_url(self):
    method thumb_url (line 34) | def thumb_url(self):
  function index (line 52) | def index():
  function get_url (line 56) | def get_url(gender = "", minimum_age = 0, maximum_age = 0, thumb=False):
  function output_json (line 70) | def output_json():
  function output_redirect_image (line 99) | def output_redirect_image(x = 0):
  function output_redirect_thumb (line 110) | def output_redirect_thumb(x = 0):
  function stats (line 120) | def stats():
  function set_response_headers (line 126) | def set_response_headers(response):

FILE: generate_faces.py
  class ImageRecord (line 24) | class ImageRecord(db.Model):
    method image_url (line 32) | def image_url(self):
  function download_face (line 48) | def download_face():
  function recoginise_face (line 55) | def recoginise_face():
  function move_file (line 73) | def move_file(gender, age):
  function write_db (line 80) | def write_db(gender, age, filename):

FILE: migrations/env.py
  function run_migrations_offline (line 36) | def run_migrations_offline():
  function run_migrations_online (line 57) | def run_migrations_online():

FILE: migrations/versions/dcb1be9b8bcc_.py
  function upgrade (line 19) | def upgrade():
  function downgrade (line 39) | def downgrade():
Condensed preview — 12 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (18K chars).
[
  {
    "path": ".gitattributes",
    "chars": 66,
    "preview": "# Auto detect text files and perform LF normalization\n* text=auto\n"
  },
  {
    "path": ".gitignore",
    "chars": 17,
    "preview": "/.idea/*\n/.venv/*"
  },
  {
    "path": "app.py",
    "chars": 4285,
    "preview": "from flask import Flask, jsonify, request, redirect\nfrom flask_cors import CORS, cross_origin\nfrom flask_sqlalchemy impo"
  },
  {
    "path": "generate_faces.py",
    "chars": 2751,
    "preview": "import requests\nimport shutil\nimport cv2\nimport secrets\nfrom pyagender import PyAgender\nimport time\nfrom datetime import"
  },
  {
    "path": "migrations/README",
    "chars": 38,
    "preview": "Generic single-database configuration."
  },
  {
    "path": "migrations/alembic.ini",
    "chars": 770,
    "preview": "# A generic, single database configuration.\n\n[alembic]\n# template used to generate migration files\n# file_template = %%("
  },
  {
    "path": "migrations/env.py",
    "chars": 2916,
    "preview": "from __future__ import with_statement\n\nimport logging\nfrom logging.config import fileConfig\n\nfrom sqlalchemy import engi"
  },
  {
    "path": "migrations/script.py.mako",
    "chars": 494,
    "preview": "\"\"\"${message}\n\nRevision ID: ${up_revision}\nRevises: ${down_revision | comma,n}\nCreate Date: ${create_date}\n\n\"\"\"\nfrom ale"
  },
  {
    "path": "migrations/versions/dcb1be9b8bcc_.py",
    "chars": 1333,
    "preview": "\"\"\"empty message\n\nRevision ID: dcb1be9b8bcc\nRevises: \nCreate Date: 2020-08-02 14:59:29.227831\n\n\"\"\"\nfrom alembic import o"
  },
  {
    "path": "readme.md",
    "chars": 3132,
    "preview": "# This API is deprecated and no longer hosted. You are welcome to make use of the code to host your own version.\n\n\nThis "
  },
  {
    "path": "requirements.txt",
    "chars": 216,
    "preview": "alembic==1.8.1\nclick==8.1.3\nFlask==2.2.2\nFlask-Cors==3.0.10\nFlask-Migrate==3.1.0\nFlask-SQLAlchemy==2.5.1\nitsdangerous==2"
  },
  {
    "path": "resize.py",
    "chars": 381,
    "preview": "from PIL import Image\nimport pathlib\n\nmaxsize = (350,350)\n\nfor input_img_path in pathlib.Path(\"input\").iterdir():\n    ou"
  }
]

About this extraction

This page contains the full source code of the hankhank10/fakeface GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 12 files (16.0 KB), approximately 4.3k tokens, and a symbol index with 20 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!