This commit is contained in:
Dan Chadwick
2024-04-09 01:47:04 +00:00
parent 3bcbe3b783
commit 3cfd95ee81
219 changed files with 47894 additions and 3767 deletions

View File

@@ -0,0 +1,211 @@
<?php
namespace Drupal\ufc\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\StreamWrapper\StreamWrapperManager;
use Drupal\Core\Render\Renderer;
use Drupal\node\NodeInterface;
use Drupal\node\Entity\Node;
use Drupal\media\Entity\Media;
use Drupal\file\Entity\File;
use Drupal\Core\Cache\CacheableResponse;
use Symfony\Component\DependencyInjection\ContainerInterface;
// use Symfony\Component\HttpFoundation\Response;
// use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpFoundation\Request;
class DcjsRouteController extends ControllerBase {
/**
* The entity type manager service.
*
* @var Drupal\Core\Entity\EntityTypeManager
* The entity type manager service.
*/
protected $entityTypeManager;
/**
* The renderer service.
*
* @var \Drupal\Core\Render\Renderer
* The renderer service.
*/
protected $renderer;
/**
* The Stream Wrapper Manager service.
*
* @var \Drupal\Core\StreamWrapper\StreamWrapperManager
* Stream wrapper manager service.
*/
protected $streamWrapperManager;
/**
* Public constructor.
*
* @var \Drupal\Core\Entity\EntityTypeManager $entityTypeManager
* The entity type manager service.
*
* @var \Drupal\Core\Render\Renderer $renderer
* The renderer service.
*
* @var \Drupal\Core\StreamWrapper\StreamWrapperManager $streamWrapperManager
* The stream wrapper manager service.
*
*/
public function __construct(
EntityTypeManager $entityTypeManager,
Renderer $renderer,
StreamWrapperManager $streamWrapperManager
) {
$this->entityTypeManager = $entityTypeManager;
$this->renderer = $renderer;
$this->streamWrapperManager = $streamWrapperManager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
// Instantiates this form class.
return new static(
// Load the service required to construct this class.
$container->get('entity_type.manager'),
$container->get('renderer'),
$container->get('stream_wrapper_manager'),
);
}
/**
* Not working right now.
*/
private function validateDcjsUserAgent(Request $request): bool {
$user_agent = $request->headers->get('user-agent');
if ($user_agent !== "DCJS Fetcher") {
return TRUE;
}
return TRUE;
}
/**
* Get all fighters to serve via DCJS.
*
* @return array<string,string>
*/
public function allFightersForDcjs(): CacheableResponse {
$query = $this->entityTypeManager->getStorage('node')->getQuery();
$query->accessCheck(TRUE);
$query->condition('type', 'fighter')->sort('title', 'ASC');
$query->range(0, 200);
$nids = $query->execute();
$all_fighters = Node::loadMultiple($nids);
$fighter_data = [];
foreach ($all_fighters as $fighter) {
$photo_mid = $fighter->field_player_photo->target_id;
$fighter_id = $fighter->id();
$link_to_content = "/node/$fighter_id";
$fighter_name = $fighter->title->value;
$photo_uri = $this->retrievePhotoUri($photo_mid);
$fighter_data[] = [
'link' => $link_to_content,
'name' => $fighter_name,
'picUrl' => $photo_uri,
];
}
$build = [
'#theme' => 'fighters_dcjs_list',
'#fighters' => $fighter_data,
];
return new CacheableResponse($this->renderer->renderPlain($build));
}
/**
* Retrieves an individual fighter.
*/
public function fighterForDcjs(NodeInterface $fighter_node): CacheableResponse {
$personal_fields = [
'age',
'division',
'height',
'weight',
'reach',
'leg_reach',
];
$stats_fields = [
'knockouts',
'striking_accuracy',
'strikes_per_minute',
'sig_strike_defense',
'absorbed_per_min',
'standing_strikes',
'clinch_strikes',
'ground_strikes',
'grappling_accuracy',
'strikes_to_head',
'strikes_to_body',
'strikes_to_leg',
'knockdown_ratio',
'takedowns_per_15',
'takedown_defense',
'average_fight_time',
'first_round_finishes',
];
$fighter_build = [
'#theme' => 'fighter_for_dcjs',
'#node' => $fighter_node,
'#personal_info' => $this->getFieldValuesFromNode($fighter_node, $personal_fields),
'#stats' => $this->getFieldValuesFromNode($fighter_node, $stats_fields),
];
$rendered = $this->renderer->renderPlain($fighter_build);
return new CacheableResponse($rendered);
}
/**
* Extracts target field values from a node.
*
* @param NodeInterface $node
* The node.
*
* @param array[] $retrieve
* The fields to retrieve
*
* @return array[]
*/
private function getFieldValuesFromNode(NodeInterface $node, array $retrieve): array {
$return_data = [];
foreach ($retrieve as $field_name) {
$field_name_with_prefix = "field_$field_name";
if ($field_name == 'division') {
$div_id = $node->get($field_name_with_prefix)->target_id;
$term = $this->entityTypeManager->getStorage('taxonomy_term')->load($div_id);
$return_data['division'] = $term->getName();
}
else {
$return_data[$field_name] = $node->{$field_name_with_prefix}->value;
}
}
return $return_data;
}
/**
* Retrieve URI for a player photo.
*/
private function retrievePhotoUri(int $media_id): string {
$player_fid = Media::load($media_id)->field_media_image->target_id;
$file = File::load($player_fid);
if ($wrapper = $this->streamWrapperManager->getViaUri($file->getFileUri())) {
return $wrapper->getExternalUrl();
}
}
}

View File

@@ -0,0 +1,220 @@
<?php
namespace Drupal\ufc\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\node\NodeInterface;
use Drupal\node\Entity\Node;
use Drupal\media\Entity\Media;
use Drupal\file\Entity\File;
use Drupal\Core\Cache\CacheableJsonResponse;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpFoundation\Request;
class FightTrainingController extends ControllerBase {
/*
* Fields holding fighter data.
*/
protected $fields = [
'age',
'height',
'reach',
'leg_reach',
'knockouts',
'striking_accuracy',
'strikes_per_minute',
'sig_strike_defense',
'absorbed_per_min',
'standing_strikes',
'clinch_strikes',
'ground_strikes',
'grappling_accuracy',
'strikes_to_head',
'strikes_to_body',
'strikes_to_leg',
'knockdown_ratio',
'takedowns_per_15',
'takedown_defense',
'average_fight_time',
'first_round_finishes',
];
/**
* The entity type manager service.
*
* @var Drupal\Core\Entity\EntityTypeManager
* The entity type manager service.
*/
protected $entityTypeManager;
/**
* Public constructor.
*
* @var \Drupal\Core\Entity\EntityTypeManager $entityTypeManager
* The entity type manager service.
*
*/
public function __construct(
EntityTypeManager $entityTypeManager
) {
$this->entityTypeManager = $entityTypeManager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
// Instantiates this form class.
return new static(
// Load the service required to construct this class.
$container->get('entity_type.manager'),
);
}
/**
* Generates all fighting data for training NN.
*/
public function generateTrainingData(): CacheableJsonResponse {
// Go get all fights.
$all_fights = $this->entityTypeManager->getStorage('node')->loadByProperties(['type' => 'fight']);
$training_data = [];
foreach ($all_fights as $fight) {
$train_array = [
'input' => [],
'output' => [],
];
// Ensure we have a winner.
if (!$fight->field_result->target_id) {
continue;
}
// Extract fighters.
$fighter_one_id = $fight->field_fighter_one->target_id;
$fighter_two_id = $fight->field_fighter_two->target_id;
if (!$fighter_one_id || !$fighter_two_id) {
continue;
}
$fighter_one_data = $this->getFighterData($fighter_one_id);
$fighter_two_data = $this->getFighterData($fighter_two_id, FALSE);
if (empty($fighter_one_data) || empty($fighter_two_data)) {
continue;
}
$train_array['input'] = array_merge($fighter_one_data, $fighter_two_data);
if ($fight->field_result->target_id == $fighter_one_id) {
$train_array['output'] = [
'fighter_one' => 1,
'fighter_two' => 0,
];
$training_data[] = $train_array;
}
else if ($fight->field_result->target_id == $fighter_two_id) {
$train_array['output'] = [
'fighter_one' => 0,
'fighter_two' => 1,
];
$training_data[] = $train_array;
}
else {
continue;
}
}
return new CacheableJsonResponse($training_data);
}
/**
* Retrieves data about a specific fight for predictions.
*/
public function getFightData(NodeInterface $fight): CacheableJsonResponse {
$fighter_1_id = $fight->field_fighter_one->target_id;
$fighter_2_id = $fight->field_fighter_two->target_id;
$fight_data = array_merge(
$this->getFighterData($fighter_1_id),
$this->getFighterData($fighter_2_id, FALSE),
);
return new CacheableJsonResponse($fight_data);
}
/**
* Gets the fighter data.
*
* @return array<string,mixed>
*/
private function getFighterData(int $id, bool $is_f1 = TRUE): array {
if ($is_f1) {
$prefix = 'fighter_one_';
}
else {
$prefix = 'fighter_two_';
}
$extracted_values = $this->extractValuesFromFields($id, $this->fields, $prefix);
return $this->normalizeData($extracted_values);
}
/**
* Extracts a value from a given field (cannot be ent reference)
*/
private function extractValuesFromFields(int $id, array $field_names, string $prefix): mixed {
$fighter = Node::load($id);
$values = [];
foreach ($field_names as $field) {
$value_key = $prefix . $field;
$field_machine_name = 'field_' . $field;
$values[$value_key] = $fighter->{$field_machine_name}->value ?? 0;
}
return $values;
}
/**
* Normalize the field value.
*
* This needs to be between 0-1
*/
private function normalizeData(array $data): array {
$min = min(array_values($data));
$max = max(array_values($data));
$normalized = [];
foreach ($data as $key => $value) {
$norm_val = 0;
if ($max - $min == 0) {
$normalized[$key] = $norm_val;
}
else {
$norm_val = ($value - $min) / ($max - $min);
$normalized[$key] = $norm_val;
}
}
return $normalized;
}
/**
* Gets the trained neural network.
*/
public function getNeuralNetwork(): CacheableJsonResponse {
$build = [];
$cur_network = \Drupal::state()->get('neuralNetwork') ?? FALSE;
if (!$cur_network) {
$build['ERROR'] = "There is no spoon.";
}
else {
$build['data'] = base64_decode($cur_network);
}
return new CacheableJsonResponse($build);
}
}