Skip to content

Commit

Permalink
TASK: Add very basic module to create and edit assistants
Browse files Browse the repository at this point in the history
  • Loading branch information
mficzel committed Jan 18, 2024
1 parent b1e4fc8 commit f73383e
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 20 deletions.
53 changes: 53 additions & 0 deletions Classes/Controller/AssistantModuleController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);

namespace Sitegeist\Chatterbox\Controller;

use Neos\Flow\Annotations as Flow;
use Neos\Fusion\View\FusionView;
use Neos\Neos\Controller\Module\AbstractModuleController;
use OpenAI\Client;
use OpenAI\Responses\Assistants\AssistantResponse;
use Sitegeist\Chatterbox\Domain\AssistantRecord;

class AssistantModuleController extends AbstractModuleController
{
protected $defaultViewObjectName = FusionView::class;

#[Flow\Inject]
protected Client $client;

public function indexAction():void
{
$assistants = array_map(
fn(AssistantResponse $assistantResponse) => AssistantRecord::fromAssistantResponse($assistantResponse),
$this->client->assistants()->list()->data
);

$this->view->assign('assistants', $assistants);
}

public function editAction(string $assistantId):void
{
$assistantResponse = $this->client->assistants()->retrieve($assistantId);
$this->view->assign('assistant', AssistantRecord::fromAssistantResponse($assistantResponse));
}

public function updateAction(AssistantRecord $assistant):void
{
$this->client->assistants()->modify($assistant->id, ['name' => $assistant->name, 'description' => $assistant->description, 'instructions' => $assistant->instructions]);
$this->addFlashMessage('Assistant ' . $assistant->name . ' was updated');
$this->redirect('index');
}

public function newAction():void
{
}

public function createAction(string $name):void
{
$assistantResponse = $this->client->assistants()->create(['name' => $name, 'model' => 'gpt-4-1106-preview']);
$this->redirect('edit', null, null, ['assistantId' => $assistantResponse->id]);
}

}
15 changes: 3 additions & 12 deletions Classes/DataSources/AssistantIdDataSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,16 @@
use Neos\Flow\Annotations as Flow;
use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\Neos\Service\DataSource\AbstractDataSource;
use OpenAi\Client;
use OpenAI\Responses\Assistants\AssistantResponse;
use Psr\Http\Client\ClientInterface;

class AssistantIdDataSource extends AbstractDataSource
{
protected static $identifier = 'Sitegeist.Chatterbox:AssistantId';

#[Flow\InjectConfiguration(path: 'apis.openAi.token')]
protected string $apiToken = '';

public function __construct(
private readonly ClientInterface $httpClient
private readonly Client $client
) {
}

Expand All @@ -29,14 +27,7 @@ public function __construct(
*/
public function getData(NodeInterface $node = null, array $arguments = [])
{
$client = \OpenAI::factory()
->withApiKey($this->apiToken)
->withOrganization(null)
->withHttpHeader('OpenAI-Beta', 'assistants=v1')
->withHttpClient($this->httpClient)
->make();

$list = $client->assistants()->list(['limit' => 100]);
$list = $this->client->assistants()->list(['limit' => 100]);
return array_map(fn(AssistantResponse $item) => ['value' => $item->id, 'label' => $item->name], $list->data);
}
}
29 changes: 29 additions & 0 deletions Classes/Domain/AssistantRecord.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);

namespace Sitegeist\Chatterbox\Domain;

use OpenAI\Responses\Assistants\AssistantResponse;

class AssistantRecord
{
public function __construct(
public readonly string $id,
public readonly string $model,
public readonly string $name,
public readonly ?string $description,
public readonly ?string $instructions,
) {
}

public static function fromAssistantResponse(AssistantResponse $response): static
{
return new static(
$response->id,
$response->model,
$response->name,
$response->description,
$response->instructions
);
}
}
10 changes: 9 additions & 1 deletion Configuration/Policy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@ privilegeTargets:
'Neos\Flow\Security\Authorization\Privilege\Method\MethodPrivilege':
'Sitegeist.Kaleidoscope:DummyImage':
matcher: 'method(Sitegeist\Chatterbox\Controller\ChatController->(start|messages|postMessage)Action())'

'Neos\Neos\Security\Authorization\Privilege\ModulePrivilege':
'Sitegeist.Chatterbox:ManageAssistants':
matcher: 'management/chatterbox'
roles:
'Neos.Flow:Everybody':
privileges:
-
privilegeTarget: 'Sitegeist.Kaleidoscope:DummyImage'
permission: GRANT

'Neos.Neos:Administrator':
privileges:
-
privilegeTarget: 'Sitegeist.Chatterbox:ManageAssistants'
permission: GRANT
15 changes: 10 additions & 5 deletions Configuration/Settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ Neos:
'Sitegeist.Chatterbox':
position: 'before Neos.Neos'

Sitegeist:
Chatterbox:
apis:
openAi:
token: ''
Neos:
modules:
management:
submodules:
chatterbox:
label: 'Chatterbox Assistants'
description: 'Manage Assitants'
icon: 'icon-robot'
controller: 'Sitegeist\Chatterbox\Controller\AssistantModuleController'
privilegeTarget: 'Sitegeist.Chatterbox:ManageAssistants'
101 changes: 101 additions & 0 deletions Resources/Private/Fusion/Root.fusion
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
include: resource://Neos.Fusion/Private/Fusion/Root.fusion
include: resource://Neos.Fusion.Form/Private/Fusion/Root.fusion
include: **/*.fusion

Sitegeist.Chatterbox.AssistantModuleController.index = Sitegeist.Chatterbox:Assistant.List
Sitegeist.Chatterbox.AssistantModuleController.edit = Sitegeist.Chatterbox:Assistant.Edit
Sitegeist.Chatterbox.AssistantModuleController.new = Sitegeist.Chatterbox:Assistant.New

prototype(Sitegeist.Chatterbox:Assistant.List) < prototype(Neos.Fusion:Component) {
renderer = afx`
<legend>Available assistants</legend>
<table class="neos-table">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th></th>
</tr>
</thead>
<tbody>
<Neos.Fusion:Loop items={assistants} itemName="assistant">
<tr>
<td>{assistant.name}</td>
<td>{assistant.description}</td>
<td class="neos-priority1 neos-aCenter">
<Neos.Fusion:Link.Action href.action="edit" href.arguments.assistantId={assistant.id}>
<i class="fas fa-pencil-alt icon-white"></i>
</Neos.Fusion:Link.Action>
</td>
</tr>
</Neos.Fusion:Loop>
</tbody>
</table>

<div class="neos-footer">
<Neos.Fusion:Link.Action href.action="new" class="neos-button" >Create new assistant</Neos.Fusion:Link.Action>
</div>

`
}

prototype(Sitegeist.Chatterbox:Assistant.New) < prototype(Neos.Fusion:Component) {
renderer = afx`
<legend>Create new assistant</legend>
<Neos.Fusion.Form:Form
form.target.action="create"
>
<div class="neos-control-group">
<label class="neos-control-label" >Name</label>
<div class="neos-controls neos-controls-row">
<Neos.Fusion.Form:Input field.name="name" />
</div>
</div>
<div class="neos-footer">
<Neos.Fusion:Link.Action href.action="index" class="neos-button" >Back</Neos.Fusion:Link.Action>
<Neos.Fusion.Form:Button attributes.class="neos-button neos-button-primary">Create</Neos.Fusion.Form:Button>
</div>
</Neos.Fusion.Form:Form>
`
}


prototype(Sitegeist.Chatterbox:Assistant.Edit) < prototype(Neos.Fusion:Component) {
renderer = afx`
<legend>Edit assistant {assistant.name}</legend>
<Neos.Fusion.Form:Form
form.target.action="update"
form.data.assistant={assistant}
>
<Neos.Fusion.Form:Hidden field.name="assistant[id]" />
<Neos.Fusion.Form:Hidden field.name="assistant[model]" />

<div class="neos-control-group">
<label class="neos-control-label" >Name</label>
<div class="neos-controls neos-controls-row">
<Neos.Fusion.Form:Input attributes.class="neos-span12" field.name="assistant[name]" />
</div>
</div>

<div class="neos-control-group">
<label class="neos-control-label" >Description</label>
<div class="neos-controls neos-controls-row">
<Neos.Fusion.Form:Textarea attributes.rows="5" attributes.class="neos-span12" field.name="assistant[description]" />
</div>
</div>

<div class="neos-control-group">
<label class="neos-control-label" >Instructions</label>
<div class="neos-controls neos-controls-row">
<Neos.Fusion.Form:Textarea attributes.rows="20" attributes.class="neos-span12" field.name="assistant[instructions]" />
</div>
</div>

<div class="neos-footer">
<Neos.Fusion:Link.Action href.action="index" class="neos-button" >Back</Neos.Fusion:Link.Action>
<Neos.Fusion.Form:Button attributes.class="neos-button neos-button-primary">Save</Neos.Fusion.Form:Button>
</div>

</Neos.Fusion.Form:Form>
`
}
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
"license": "GPL-3.0-or-later",
"require": {
"neos/neos": "*",
"openai-php/client": "^0.8",
"symfony/http-client": "^6.4"
"sitegeist/flow-openaiclientfactory": "*"
},
"require-dev": {
"phpstan/phpstan": "~1.10.50",
Expand Down

0 comments on commit f73383e

Please sign in to comment.