Skip to content

Commit

Permalink
Merge pull request #24 from PRTIMES/feature/add-recommend
Browse files Browse the repository at this point in the history
レコメンド機能の作成(フェーズ4)
  • Loading branch information
kyoya0819 authored Aug 29, 2024
2 parents 71ea8a0 + 210879f commit d457a45
Show file tree
Hide file tree
Showing 17 changed files with 523 additions and 48 deletions.
6 changes: 3 additions & 3 deletions backend/app/Http/Controllers/Api/Auth/SignUpController.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public function register(VerifyRequest $request): true
"validation",
"Validation failed",
[
"code" => ["有効期限切れです。"]
"token" => ["有効期限切れです。"]
]
);

Expand All @@ -92,7 +92,7 @@ public function register(VerifyRequest $request): true
"validation",
"Validation failed",
[
"code" => ["有効期限切れです。"]
"token" => ["有効期限切れです。"]
]
);

Expand All @@ -102,7 +102,7 @@ public function register(VerifyRequest $request): true
"validation",
"Validation failed",
[
"code" => ["ワンタイムパスワードが間違っています"]
"token" => ["ワンタイムパスワードが間違っています。"]
]
);

Expand Down
34 changes: 34 additions & 0 deletions backend/app/Http/Controllers/Api/Company/ListController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace App\Http\Controllers\Api\Company;

use App\Http\Controllers\Controller;
use App\Http\Requests\Api\Company\List\InvokeRequest;
use App\Models\Company;
use App\UseCases\Company\ListFilterByIndustryIds;
use Illuminate\Http\JsonResponse;

class ListController extends Controller
{
/**
* @param InvokeRequest $request
* @return JsonResponse
*/
public function __invoke(InvokeRequest $request): JsonResponse
{
/* @var int[] $industry_ids */
$industry_ids = $request->validated()['industry_ids'];

$companies = ListFilterByIndustryIds::run($industry_ids);

return response()->json(
$companies->map(function ($company) {
/* @var Company $company */
return [
"id" => $company->id,
"name" => $company->name
];
})->toArray()
);
}
}
22 changes: 22 additions & 0 deletions backend/app/Http/Requests/Api/Company/List/InvokeRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace App\Http\Requests\Api\Company\List;

use App\Http\Requests\Api\Request;
use Illuminate\Contracts\Validation\ValidationRule;

class InvokeRequest extends Request
{
/**
* Get the validation rules that apply to the request.
*
* @return array<string, ValidationRule|array|string>
*/
public function rules(): array
{
return [
"industry_ids" => ["required", "array"],
"industry_ids.*" => ["integer", "min:1", "max:16"],
];
}
}
67 changes: 26 additions & 41 deletions backend/app/Jobs/PressReleaseAnalyze.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

use App\Libs\Bedrock;
use App\Libs\OpenAI;
use App\UseCases\Keyword\UpdateOrCreateAction;
use App\Libs\PrTimesApi;
use App\UseCases\Company\CreateOrFirstAction as CompanyCreateOrFirstAction;
use App\UseCases\Keyword\CreateOrFirstAction as KeywordCreateOrFirstAction;
use App\UseCases\PressRelease\CreateAction as PressReleaseCreateAction;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use GuzzleHttp\Client as GuzzleClient;

class PressReleaseAnalyze implements ShouldQueue
{
Expand All @@ -35,46 +36,22 @@ public function __construct(
*/
public function handle(): void
{
$headers = [
"Authorization" => "Bearer " . config("services.prtimes.token")
];

$guzzle = new GuzzleClient([
"base_uri" => "https://hackathon.stg-prtimes.net/"
]);

$openai = new OpenAI(config("services.openai.token"));

$bedrock = new Bedrock();

$response = $guzzle->get("/api/companies/112/releases/1078", ["headers" => $headers]);

if ($response->getStatusCode() !== 200)
throw new Exception("PR TIMES API Error");

/* @var array{
* body: string,
* company_id: int,
* company_name: string,
* created_at: string,
* lead_paragraph: string,
* like: int,
* main_category_id: int,
* main_category_name: string,
* main_image: string,
* main_image_fastly: string,
* release_id: int,
* release_type: string,
* sub_category_id: string,
* sub_category_name: string,
* subtitle: string,
* title: string,
* url: string
* } $data
*/
$data = json_decode($response->getBody()->getContents(), true);

$body = strip_tags($data["body"]);
$prtimes = new PrTimesApi(config("services.prtimes.token"));

$release_data = $prtimes->release($this->company_id, $this->release_id);
$company_data = $prtimes->company($this->company_id);

CompanyCreateOrFirstAction::run(
company_id: $this->company_id,
name: $company_data["company_name"],
industry_id: $company_data["industry_id"]
);

$body = strip_tags($release_data["body"]);

$summary = $openai->answer(
question: $body,
Expand All @@ -88,9 +65,9 @@ public function handle(): void
$press_release = PressReleaseCreateAction::run(
company_id: $this->company_id,
release_id: $this->release_id,
title: $data["title"],
title: $release_data["title"],
summary: $summary,
release_created_at: $data["created_at"]
release_created_at: $release_data["created_at"]
);

$keywords_string = $bedrock->answer(
Expand All @@ -106,7 +83,7 @@ public function handle(): void

foreach ($keywords as $keyword) {

$keyword = UpdateOrCreateAction::run($keyword);
$keyword = KeywordCreateOrFirstAction::run($keyword);

$press_release->keywords()
->syncWithPivotValues(
Expand All @@ -119,5 +96,13 @@ public function handle(): void
}

// @todo さらに形態素解析をかまして、低い重みでキーワードを登録する。

// ChatGPTのレート制限回避用
sleep(20);
}

public function failed($exception = null)
{
dd($exception);
}
}
160 changes: 160 additions & 0 deletions backend/app/Libs/PrTimesApi.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
<?php

namespace App\Libs;

use Exception;
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Exception\GuzzleException;

class PrTimesApi
{
private GuzzleClient $guzzle;
private array $header;

private array $industries = [
1 => "水産・農林業",
2 => "鉱業",
3 => "建設業",
4 => "製造業",
5 => "電気・ガス業",
6 => "倉庫・運輸関連業",
7 => "情報通信",
8 => "商業(卸売業、小売業)",
9 => "金融・保険業",
10 => "不動産業",
11 => "水産・農林業",
12 => "官公庁・地方自治体",
13 => "飲食店・宿泊業",
14 => "医療・福祉",
15 => "教育・学習支援業",
16 => "財団法人・社団法人・宗教法人"
];

public function __construct(
string $token,
string $endpoint = "https://hackathon.stg-prtimes.net/"
)
{
$this->header = [
"Authorization" => "Bearer " . $token
];

$this->guzzle = new GuzzleClient([
"base_uri" => "https://hackathon.stg-prtimes.net/"
]);
}

/**
* @param int $company_id
* @param int $release_id
* @return array{
* body: string,
* company_id: int,
* company_name: string,
* created_at: string,
* lead_paragraph: string,
* like: int,
* main_category_id: int,
* main_category_name: string,
* main_image: string,
* main_image_fastly: string,
* release_id: int,
* release_type: string,
* sub_category_id: string,
* sub_category_name: string,
* subtitle: string,
* title: string,
* url: string
* }
* @throws GuzzleException
* @throws Exception
*/
public function release(int $company_id, int $release_id): array
{
$response = $this->guzzle->get("/api/companies/$company_id/releases/$release_id", ["headers" => $this->header]);

if ($response->getStatusCode() !== 200)
throw new Exception("PR TIMES API Error");

return json_decode($response->getBody()->getContents(), true);
}

/**
* @param int $per_page
* @param int $page
* @param string $from_date
* @return array<array{
* body: string,
* company_id: int,
* company_name: string,
* created_at: string,
* lead_paragraph: string,
* like: int,
* main_category_id: int,
* main_category_name: string,
* main_image: string,
* main_image_fastly: string,
* release_id: int,
* release_type: string,
* sub_category_id: string,
* sub_category_name: string,
* subtitle: string,
* title: string,
* url: string
* }>
* @throws GuzzleException
* @throws Exception
*/
public function releases(
int $per_page = 10,
int $page = 0,
string $from_date = "2020-01-01"
): array
{
$response = $this->guzzle->get("/api/releases?per_page=$per_page&page=$page&from_date=$from_date", ["headers" => $this->header]);

if ($response->getStatusCode() !== 200)
throw new Exception("PR TIMES API Error");

return json_decode($response->getBody()->getContents(), true);
}

/**
* @param int $company_id
* @return array{
* company_id: int,
* company_name: string,
* president_name: string,
* address: string,
* phone: string,
* description: string,
* industry: string,
* industry_id: int,
* ipo_type: string,
* capital: int,
* foundation_date: string,
* url: string,
* twitter_screen_name: string
* }
* @throws GuzzleException
* @throws Exception
*/
public function company(
int $company_id
): array
{
$response = $this->guzzle->get("/api/companies/$company_id", ["headers" => $this->header]);

if ($response->getStatusCode() !== 200)
throw new Exception("PR TIMES API Error");

$industries = array_flip($this->industries);

$company_data = json_decode($response->getBody()->getContents(), true);
if (!array_key_exists($company_data["industry"], $industries))
$company_data["industry_id"] = 17;
else
$company_data["industry_id"] = $industries[$company_data["industry"]];
return $company_data;
}
}
27 changes: 27 additions & 0 deletions backend/app/Models/Company.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Company extends Model
{
use HasFactory;

protected $fillable = [
"name",
"popularity",
"company_id",
"industry_id"
];

/**
* @return HasMany
*/
public function press_releases(): HasMany
{
return $this->hasMany(PressRelease::class, 'company_id', 'company_id');
}
}
Loading

0 comments on commit d457a45

Please sign in to comment.