-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfeed.xml
843 lines (600 loc) · 90.1 KB
/
feed.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Pepabo Tech Portal</title>
<id>https://tech.pepabo.com/</id>
<link href="https://tech.pepabo.com/"/>
<link href="https://tech.pepabo.com/feed.xml" rel="self"/>
<updated>2025-01-30T15:00:00+00:00</updated>
<author>
<name>GMO Pepabo, Inc.</name>
</author>
<entry>
<title>BuriKaigiにtesuwo、donokun、ugo、doskoiが登壇します!</title>
<link rel="alternate" href="https://tech.pepabo.com/2025/01/31/burikaigi2025-entry/"/>
<id>https://tech.pepabo.com/2025/01/31/burikaigi2025-entry/</id>
<published>2025-01-30T15:00:00+00:00</published>
<updated>2025-02-03T00:06:09+00:00</updated>
<author>
<name>ugo</name>
</author>
<content type="html"><p>2025年2月1日(土)に開催される<a href="https://burikaigi.dev/">Burikaigi2025</a>にGMOペパボからは<a href="https://x.com/tetsuwo0717">@てつを。</a>、<a href="https://x.com/furudono2">@どのくん</a>、<a href="https://x.com/yukyu30">@ugo</a>、<a href="https://twitter.com/doskoi64">@どすこい</a>が登壇します!
去年のBurikaigiに、参加したパートナーがとても良かったと言っていたので、プロポーザルを提出しました!
どのメンバーも30分のセッションが初めてなので緊張していますが、精一杯準備するので、ぜひ足を運んでみてください!</p>
<h3 id="てつを-あなたの配信ワイワイたりていますか配信を盛り上げるaiwaiwai-aiを作った話">@てつを。 あなたの配信ワイワイたりていますか?? 配信を盛り上げるAI「waiwai-ai」を作った話</h3>
<p>新規配信者の課題である「コメントの少なさ」に対し、配信の盛り上げ役となるAI「waiwai-ai」を開発しました。本トークでは、waiwai-aiが視聴者のコメントを生成・投稿する仕組みを支える技術スタックについて解説します。具体的には、Pythonライブラリを用いた音声認識と仮想オーディオデバイスによるリアルタイム文字起こしから、その文字をDifyを活用して視聴者のようなコメントを生成するAI、そしてそのコメントを見える形で出力するために工夫した点を紹介します!!</p>
<h3 id="donokun-cliツール開発をprotocol-buffers-スキーマで駆動する">@donokun CLIツール開発をProtocol Buffers スキーマで駆動する</h3>
<p><a href="https://htdp.org/">How to Design Programs</a>を引用して、ぼくが思う上手で楽しいプログラミングとは何かを主張します。</p>
<p>次にWeb APIの開発にもこの手法は適用できると考え、スキーマ駆動開発でどのようにその考え方を適用できるかを紹介します。そのためにProtocol Buffersを用いる例を説明します。</p>
<p>さらにCLI開発にもこの方法を広げるために作成したツールを紹介します。</p>
<h3 id="ugo-3dモデル作成販売を行うwebアプリケーションの裏側">@ugo 3Dモデル作成、販売を行うWebアプリケーションの裏側</h3>
<p>SUZURIにて画像から3Dモデルを作成する「<a href="https://lp.suzuri.jp/3d-t-shirt">3Dグッズ作成機能</a>」が公開されました。
この機能は画像をアップロードすることで、3Dモデルの生成、販売をシームレスに行うことができる機能です。
本発表では3Dモデルの生成手法と、生成された3Dモデルをデジタルコンテンツとしての出品するための方法を、実例を交えて機能の裏側を解説します!</p>
<h3 id="どすこい-データサイエンスをするつもりがkpi数値算出がなーんできてないぜ新卒1年目が配属1ヶ月で挑んだサブスクサービスのkpi数値算出タスク">@どすこい データサイエンスをするつもりが、KPI数値算出がなーんできてないぜ!新卒1年目が配属1ヶ月で挑んだサブスクサービスのKPI数値算出タスク</h3>
<p>研修が終わって事業部に配属されてから今までで挑んだタスクの中で、最も大変だったタスクの話です!
サブスクサービスのKPI数値は、新規契約数、更新契約数、解約数、有効契約数、などがあります。
これらの算出は、ECサービスの売上高と違い、契約のイベントを追跡して状態を管理する必要があります。
また、契約のイベントと状態の種類は多岐にわたるため、テストケースも多くなりますし、テストケースが十分であることを担保するのも難しいです。
これらに対して、どのように対処したのかをお話しします。</p>
</content>
</entry>
<entry>
<title>2つの決裁書承認システムとSlackを連携させて効率化した話</title>
<link rel="alternate" href="https://tech.pepabo.com/2025/01/29/cn-xpoint/"/>
<id>https://tech.pepabo.com/2025/01/29/cn-xpoint/</id>
<published>2025-01-28T15:00:00+00:00</published>
<updated>2025-02-03T00:06:09+00:00</updated>
<author>
<name>よしだ</name>
</author>
<content type="html"><p>こんにちは!
GMO ペパボのグループ会社である GMO クリエイターズネットワークの<a href="https://twitter.com/theyoshida3">よしだ</a>です。</p>
<p>今回は、社内で使われている 2 つの決裁書承認システムと Slack を連携させて効率化した話をします。</p>
<h1 id="以前の状態">以前の状態</h1>
<p>フリーナンスでは、ユーザー様が登録した請求書の審査など、サービス運営業務に利用する管理画面が存在します。
サービス運営業務の中でも、管理画面へのアカウント追加といった上長の承認を必要とするものがあり、管理画面上で承認を行います。</p>
<p>また、サービス運営以外の決裁は X-point<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>という承認システムを導入していました。</p>
<h2 id="問題点">問題点</h2>
<p>以前の状態では下記の問題点がありました。</p>
<p><strong>アカウントの二重管理</strong></p>
<p>承認を扱うシステムが 2 つ存在することにより、それぞれのシステムにログインして承認する必要があります。</p>
<p><strong>承認者の二重管理</strong></p>
<p>承認を扱うシステムが 2 つ存在することにより、承認フローもそれぞれ管理する必要があります。
承認者の異動の際には、それぞれのシステムで反映する必要があります。</p>
<p><strong>承認作業時間</strong></p>
<p>また、管理画面では一件ずつの決裁書作成や決裁書承認しかできず、承認件数が増えてくると承認に時間がかかっていました。</p>
<h1 id="現在の状態">現在の状態</h1>
<p>現在の状態をフロー図にまとめました。
<img src="/blog/2025/01/29/cn_xpoint/images/mermaid.png" alt="現在のフロー" /></p>
<p>申請者は決裁書を提出する人です。
以後は、フローの流れを説明していきます。</p>
<h2 id="決裁書作成--決裁書提出">決裁書作成 ~ 決裁書提出</h2>
<p>フリーナンス管理画面から、 X-point の API を実行し、承認を取りたい内容の決裁書を下書き書類として作成します。</p>
<p>下書き書類作成後は、新しいタブで X-point の決裁書編集画面を開き、申請者は内容の確認と提出を行います。</p>
<h2 id="承認依頼-webhook--承認依頼の送信">承認依頼 Webhook ~ 承認依頼の送信</h2>
<p>決裁書提出時に X-point からフリーナンスへ承認依頼が送信されます。フリーナンスは、現在の X-point の承認フローから承認者を判断し、承認者毎の専用 Slack チャンネルに承認依頼を送信します。</p>
<h2 id="承認操作--承認実施">承認操作 ~ 承認実施</h2>
<p>承認依頼で送信された Slack は下記となります。
<img src="/blog/2025/01/29/cn_xpoint/images/slack.png" alt="承認依頼" /></p>
<p>「承認」ボタンを押下することで、フリーナンス側の承認操作が実行されます。
承認操作では、承認をした Slack ユーザーから X-point ユーザーを判断し、 X-point の承認 API を実行します。</p>
<p>「却下」ボタン却下の場合、決議書は却下として、フリーナンスから X-point へ API を実行します。</p>
<h2 id="承認完了-webhook">承認完了 Webhook</h2>
<p>承認操作が実行された際は、Webhook のステータスで承認フローが完了しているか判断できます。
承認フローが完了している場合、後続の処理を実施します。
承認フローがまだ残っている場合には、次の承認者の専用 Slack チャンネルへ承認依頼を送信します。</p>
<h1 id="改善された点">改善された点</h1>
<p>以前の状態で挙げてた問題点は、2 つの決裁書承認システムと Slack を連携することで改善されました。</p>
<p><strong>アカウントの二重管理</strong></p>
<p>決裁書承認は X-point の責務とすることで、承認者は X-point だけ確認すればよくなりました。</p>
<p><strong>承認者の二重管理</strong></p>
<p>承認フローも X-point の責務とすることで、承認者の異動の際には、X-point のみ反映すればよくなりました。</p>
<p><strong>承認作業時間</strong></p>
<p>Slack 上での一覧表示から決裁書承認ができ、承認件数が増えた場合にも時間がかかりにくくなりました。</p>
<h1 id="考慮した点">考慮した点</h1>
<p>連携の仲介役をフリーナンスの管理ユーザーに担わせました。</p>
<ul>
<li>X-point API を利用するために、フリーナンスの管理ユーザーと X-point ユーザーの紐づけ(X-point トークン保持)</li>
<li>Slack から承認操作をするために、フリーナンスの管理ユーザーと Slack ユーザーの紐づけ(Slack ユーザー ID 保持)</li>
</ul>
<p>Slack から X-point 上の決裁書を操作する際に、フリーナンスを経由することで「Slack ユーザー ID → フリーナンス管理ユーザー ID → X-point トークン」と X-point へのアクセスが可能になります。</p>
<h1 id="最後に">最後に</h1>
<p>承認フローを X-point の責務にすることで、承認者の変更に強いと述べました。
では、承認フローの階層が増えた場合、どうなるのでしょうか。</p>
<p>次回は、決裁書承認フローの階層が増えた話をします。</p>
<h2 id="gmo-クリエイターズネットワークではプロダクト開発職種の採用をおこなっています">GMO クリエイターズネットワークでは、プロダクト開発職種の採用をおこなっています!</h2>
<p>フリーナンスでは今、プロダクト開発組織を立ち上げていこうとしている最中です。</p>
<p>ソフトウェアエンジニアとして面白い部分は、フロントエンド〜バックエンド〜インフラを横断的に触る開発スタイルで開発している点です。
Go のコードを書いたり、Terraform を書いたりしながら開発を進めていることが多いです。</p>
<p>現在は Go や React を中心としたシステムへのリアーキテクチャを検討しています。
バックエンドアーキテクチャの設計やフレームワークの選定、検証とやれることは非常に多いです。</p>
<p>そんな技術課題の解消やユーザに価値を提供出来る仕組みづくりを私達と一緒に進めていってくださる方々を募集中です!以下の職種を積極採用しています!</p>
<ul>
<li><a href="https://open.talentio.com/r/1/c/gmo-cn/pages/78518">ソフトウェアエンジニア(バックエンド)</a></li>
</ul>
<p>また、<a href="https://open.talentio.com/r/1/c/gmo-cn/pages/78856">カジュアル面談</a>も大歓迎ですのでお気軽に申し込んでいただけると嬉しいです!</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>https://www.atled.jp/xpoint_cloud/ <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
</li>
</ol>
</div>
</content>
</entry>
<entry>
<title>視聴者と同様に配信をコメントで盛り上げるwaiwai-aiを作った話</title>
<link rel="alternate" href="https://tech.pepabo.com/2025/01/17/waiwai-ai/"/>
<id>https://tech.pepabo.com/2025/01/17/waiwai-ai/</id>
<published>2025-01-16T15:00:00+00:00</published>
<updated>2025-02-03T00:06:09+00:00</updated>
<author>
<name>どすこい</name>
</author>
<content type="html"><ol id="markdown-toc">
<li><a href="#はじめに" id="markdown-toc-はじめに">はじめに</a></li>
<li><a href="#技術選定" id="markdown-toc-技術選定">技術選定</a></li>
<li><a href="#任意の音声映像から文字起こしをする技術-てつを" id="markdown-toc-任意の音声映像から文字起こしをする技術-てつを">任意の音声/映像から文字起こしをする技術 @てつを。</a> <ol>
<li><a href="#音声入力部分" id="markdown-toc-音声入力部分">音声入力部分</a></li>
<li><a href="#映像入力部分" id="markdown-toc-映像入力部分">映像入力部分</a></li>
</ol>
</li>
<li><a href="#わいわいをaiで生成する部分-どすこい" id="markdown-toc-わいわいをaiで生成する部分-どすこい">わいわいをAIで生成する部分 @どすこい</a> <ol>
<li><a href="#生成aiアプリ開発基盤について" id="markdown-toc-生成aiアプリ開発基盤について">生成AIアプリ開発基盤について</a></li>
<li><a href="#入力部分とのインターフェースについて" id="markdown-toc-入力部分とのインターフェースについて">入力部分とのインターフェースについて</a></li>
<li><a href="#コメント生成部分のllmアプリケーションについて" id="markdown-toc-コメント生成部分のllmアプリケーションについて">コメント生成部分のLLMアプリケーションについて</a></li>
<li><a href="#コメント生成部分のハイパーパラメータのチューニングについて" id="markdown-toc-コメント生成部分のハイパーパラメータのチューニングについて">コメント生成部分のハイパーパラメータのチューニングについて</a></li>
</ol>
</li>
<li><a href="#生成した内容の出力部分-はるおつ" id="markdown-toc-生成した内容の出力部分-はるおつ">生成した内容の出力部分 @はるおつ</a> <ol>
<li><a href="#実装の手順" id="markdown-toc-実装の手順">実装の手順</a></li>
<li><a href="#コンソールへの出力" id="markdown-toc-コンソールへの出力">コンソールへの出力</a></li>
<li><a href="#slackの特定のチャンネルにそのまま出力する" id="markdown-toc-slackの特定のチャンネルにそのまま出力する">Slackの特定のチャンネルにそのまま出力する</a></li>
<li><a href="#slackの特定のメッセージに対してスレッドで出力する" id="markdown-toc-slackの特定のメッセージに対してスレッドで出力する">Slackの特定のメッセージに対してスレッドで出力する</a></li>
</ol>
</li>
<li><a href="#結果" id="markdown-toc-結果">結果</a></li>
<li><a href="#感想" id="markdown-toc-感想">感想</a> <ol>
<li><a href="#どすこい" id="markdown-toc-どすこい">どすこい</a></li>
<li><a href="#はるおつ" id="markdown-toc-はるおつ">はるおつ</a></li>
<li><a href="#てつを" id="markdown-toc-てつを">てつを</a></li>
</ol>
</li>
</ol>
<h2 id="はじめに">はじめに</h2>
<p>こんにちは。2024年度新卒エンジニアの<a href="https://x.com/hrt_ykym">はるおつ</a>、<a href="https://x.com/tetsuwo0717">てつを</a>、<a href="https://x.com/doskoi64">どすこい</a>です。普段の事業部の開発から離れて、事業部や職種を跨いでチームを組んで、2日間かけてプロダクトを作るイベントである、<a href="https://hr.pepabo.com/report/2023/04/06/8730">お産合宿</a>(こちらは2023年のものです)で開発したプロダクトについてブログを書きます!</p>
<p>今回のテーマは"配信"で、昨今伸びている配信業界にアプローチしたプロダクトを各々開発しました。</p>
<p>上記テーマのもとで私たちが開発したプロダクトを<strong>waiwai-ai</strong>と名付けました。視聴者と同様にコメント投稿することで配信を盛り上げるAI botです。新規の配信者は視聴者が少なく、配信が寂しくなってしまうという課題があります。waiwai-aiが配信を盛り上げることで、新規配信者でも配信を楽しめるようにすることが目的です。</p>
<h2 id="技術選定">技術選定</h2>
<p>本アプリケーションは以下のような技術を用いて実現しました。</p>
<p><strong>入力部分</strong></p>
<ul>
<li>pyaudio</li>
<li>speech_recognition</li>
<li>VB-Cable</li>
<li>OBS の仮想カメラ機能</li>
</ul>
<p><strong>わいわいをAIで生成する部分</strong></p>
<ul>
<li>Dify</li>
<li>LLMマルチエージェントモデル</li>
<li>ハイパーパラメータのチューニング</li>
</ul>
<p><strong>生成した内容の出力部分</strong></p>
<ul>
<li>Slack API</li>
<li>正規表現 (Python)</li>
</ul>
<p><img src="/blog/2025/01/17/waiwai-ai/images/waiwai-ai-image.png" alt="waiwai-aiのアーキテクチャ図" /></p>
<p>以降ではそれぞれが担当した、各コンポーネントの詳細を説明します。</p>
<h2 id="任意の音声映像から文字起こしをする技術-てつを">任意の音声/映像から文字起こしをする技術 @てつを。</h2>
<p>こんにちは!入力部分を担当した<a href="https://x.com/tetsuwo0717">てつを</a>です!!</p>
<p>はじめに、私が担当した <strong>waiwai-ai</strong> の「入力部分」の実装について、音声入力と映像キャプチャ機能を中心に解説します。特に、リアルタイムの音声からテキストの生成、そして映像のキャプチャ方法に至るまでのライブラリの選定理由と工夫点について触れていきます。</p>
<p>配信中は雑音やBGM、効果音などさまざまな音声が混在する環境であり、精度の高い文字起こしを実現するために<strong>pyaudio</strong>、<strong>speech_recognition</strong>、そして仮想オーディオデバイスとしての <strong>VB-Cable</strong> を組み合わせ、マルチデバイス対応とノイズの多い環境でも安定した文字起こしを目指しました。
これによってOBSからの音声をリアルタイムで取得し、音声データを統合的に扱うことができます。また配信者自体は話していなくても、流れている音楽やゲーム音に対してもコメントを返してくれるようになります。
また、今回採用したwaiwai-aiのLLMは動画を入力することができなかったためOBSのモニターを画像としてキャプチャすることでLLMに読み込ませました。画像をLLMに入力することでLLMはより的確なコメントを返してくれます。キャプチャをするためのライブラリには <strong>cv2</strong> を採用しました。</p>
<h3 id="音声入力部分">音声入力部分</h3>
<p>音声入力部分の目的は、配信者の音声やゲーム音をリアルタイムで取り込み、それをテキスト化することです。以下のツール、ライブラリを用いて実装し、以下の順で処理していきます。</p>
<h4 id="音声の取得">音声の取得</h4>
<p>配信者が使用するマイクやOBSからの音声出力を取得します。これは <a href="https://pypi.org/project/PyAudio/">pyaudio</a> を使用して任意のマイクデバイスを選択し、音声を録音することで実現します。</p>
<h4 id="obsとの連携">OBSとの連携</h4>
<p>OBSの音声出力(配信者の声、ゲーム音、BGM)を仮想オーディオデバイスとしてPythonに取り込むために <a href="https://vb-audio.com/Cable/">VB-Cable</a> を使用します。</p>
<ul>
<li>使用ツール: VB-Cable(仮想オーディオケーブル)</li>
</ul>
<h4 id="音声の文字起こし">音声の文字起こし</h4>
<p>取り込んだ音声を <a href="https://pypi.org/project/SpeechRecognition/">speech_recognition</a> を使ってリアルタイムで文字起こしします。Google Speech Recognition APIを活用し、日本語に対応しています。
以下はspeech_recognitionを使用した文字起こしのコード例です。</p>
<div class="highlight"><pre class="highlight python"><code><span class="c1"># 音声ファイルを文字起こしする関数
</span><span class="k">def</span> <span class="nf">transcribe_audio</span><span class="p">(</span><span class="n">file_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="n">recognizer</span> <span class="o">=</span> <span class="n">sr</span><span class="p">.</span><span class="n">Recognizer</span><span class="p">()</span>
<span class="k">with</span> <span class="n">sr</span><span class="p">.</span><span class="n">AudioFile</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span> <span class="k">as</span> <span class="n">source</span><span class="p">:</span>
<span class="n">audio</span> <span class="o">=</span> <span class="n">recognizer</span><span class="p">.</span><span class="n">record</span><span class="p">(</span><span class="n">source</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">recognizer</span><span class="p">.</span><span class="n">recognize_google</span><span class="p">(</span><span class="n">audio</span><span class="p">,</span> <span class="n">language</span><span class="o">=</span><span class="s">"ja-JP"</span><span class="p">)</span>
<span class="k">return</span> <span class="n">text</span>
<span class="k">except</span> <span class="n">sr</span><span class="p">.</span><span class="n">UnknownValueError</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">AudioError</span><span class="p">(</span><span class="s">"Google Speech Recognition could not understand audio"</span><span class="p">)</span>
<span class="k">except</span> <span class="n">sr</span><span class="p">.</span><span class="n">RequestError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">AudioError</span><span class="p">(</span><span class="s">"Could not request results from Google Speech Recognition service"</span><span class="p">)</span>
</code></pre></div>
<p>音声入力部分の処理は「音声/映像の取得 → 文字起こし → わいわいをAIで生成する部分へ渡す」のループを30秒単位で繰り返しています。</p>
<h3 id="映像入力部分">映像入力部分</h3>
<p>映像入力部分の目的は、配信映像をキャプチャしてフレーム単位で保存することです。これにより実況中の特定のシーンを自動的に記録できます。</p>
<h4 id="obsとの連携-1">OBSとの連携</h4>
<p>OBSの映像を仮想カメラ機能を使ってPythonに入力します。この仮想カメラ機能により、配信者が意図した画面レイアウトをそのまま処理可能です。</p>
<h4 id="フレームのキャプチャと保存">フレームのキャプチャと保存</h4>
<p><a href="https://pypi.org/project/opencv-python/">cv2</a> を使用してフレームをキャプチャし、任意のタイミングで画像として保存します。30秒間隔でのキャプチャを設定しています。</p>
<div class="highlight"><pre class="highlight python"><code><span class="kn">import</span> <span class="nn">cv2</span>
<span class="n">cap</span> <span class="o">=</span> <span class="n">cv2</span><span class="p">.</span><span class="n">VideoCapture</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="c1"># フレームをキャプチャ
</span><span class="n">ret</span><span class="p">,</span> <span class="n">frame</span> <span class="o">=</span> <span class="n">cap</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
<span class="k">if</span> <span class="n">ret</span><span class="p">:</span>
<span class="c1"># スクリーンショットを保存
</span> <span class="n">cv2</span><span class="p">.</span><span class="n">imwrite</span><span class="p">(</span><span class="s">'screenshot.png'</span><span class="p">,</span> <span class="n">frame</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="s">"フレームの取得に失敗しました"</span><span class="p">)</span>
<span class="n">cap</span><span class="p">.</span><span class="n">release</span><span class="p">()</span>
</code></pre></div>
<h2 id="わいわいをaiで生成する部分-どすこい">わいわいをAIで生成する部分 @どすこい</h2>
<p>こんにちは!AIが好き好き人間の<a href="https://x.com/doskoi64">どすこい</a>です!私はわいわいを生成する部分を担当しました。ここでいう”わいわい”とは、配信を盛り上げるコメントのことです。わいわい生成部は、入力部分で受け取った配信の情報を、LLM(大規模言語モデル)アプリケーションの入力として用いて”わいわい”を生成させ、出力部に渡すことが責務となっています。</p>
<p>ここでは、そのLLMアプリケーションの構成について説明します。</p>
<h3 id="生成aiアプリ開発基盤について">生成AIアプリ開発基盤について</h3>
<p>配信を盛り上げる”わいわい”を生み出すために、LLMを用いることにしました。そこで、当時少しずつ盛り上がり始めていたDifyを用いてLLMアプリを開発することにしました。<a href="https://dify.ai/jp">Dify</a>はオープンソースのLLMアプリ開発プラットフォームで、LLMの設定や処理、ハイパーパラメータ設定をGUI上で簡単に操作することができます。</p>
<p>今回の話とは別に、DifyとSlackbotの連携についてはこのブログでまとめて書いたので、ぜひみてください。
https://zenn.dev/ctk64/articles/f7e6cf44bf4be7</p>
<h3 id="入力部分とのインターフェースについて">入力部分とのインターフェースについて</h3>
<p>入力部分から受け取るデータは、<strong>配信者の発言内容を抽出したテキストデータ</strong>を、用いることにしました。具体的には、配信者の発言やそれに関連する情報をテキスト形式で受け取ることを想定しています。この仕様を早い段階で定義したことで、わいわい生成部ではダミーデータを用いた開発が可能となり、チームメンバーが独立かつ並列して作業を進められる体制が構築できました。</p>
<p>また、このテキストデータはノイズ処理などをせずにそのまま用いることにしました。この判断の理由として、以下の点が挙げられます:</p>
<ol>
<li>入力部分で取得されるテキストデータの精度が実証済みで十分高いこと。</li>
<li>使用するLLMアプリケーションが、ある程度のノイズを処理できる性能を有していること。</li>
</ol>
<p>このため、入力部分から受け取ったテキストデータをそのままLLMに渡して処理する設計としました。</p>
<p>なお、将来的に以下の状況が生じた場合には、入力部分とわいわい生成部分の間にデータの前処理を行う仕組みが必要になると考えられます:</p>
<ul>
<li>入力部分から送られるデータにノイズが多く含まれる場合。</li>
<li>使用するLLMアプリケーションがノイズに対して脆弱な場合。</li>
</ul>
<p>出力部分とのインターフェースに関しては、別途「出力部分の仕様」で詳述します。</p>
<h3 id="コメント生成部分のllmアプリケーションについて">コメント生成部分のLLMアプリケーションについて</h3>
<p>LLMのユーモアに関する研究はいくつかあり、その中で手軽で効果の高そうな手法を応用することにしました。それは、異なる人格のLLMをいくつか用意して、ランダムなLLMにユーモアを生成させるものです。</p>
<p>今回の開発では、3種類の異なるキャラクターを持つLLMを用意しました。それぞれ、
①視聴者を積極的に褒めてくれるLLM
②状況を整理して褒めるLLM
③自分のことを面白いと思っている少し自信過剰なLLM
という特徴を持たせています。</p>
<p>また、複数のLLMモデルを用いたマルチエージェントモデルを用いることで、単一のLLMを使うよりも人間に近いコメントを出せるように工夫しました。</p>
<h3 id="コメント生成部分のハイパーパラメータのチューニングについて">コメント生成部分のハイパーパラメータのチューニングについて</h3>
<p>さらに、LLMのハイパーパラメータを調整して、発言にランダムさを加え、配信ごとに異なるリアクションを楽しめるようにしました。これにより、視聴者が配信に参加するたびに新しい体験ができるようになっています。
LLMのハイパーパラメータは以下のような値です。詳しくは<a href="https://platform.openai.com/docs/api-reference/completions/create">OpenAIのドキュメント</a>も参考にみてください!</p>
<ul>
<li>
<p>Temperature<br />
応答のランダム性やクリエイティビティを制御する。</p>
</li>
<li>
<p>Top P<br />
上位P%の確率のトークンを選択する。</p>
</li>
<li>
<p>Presence Penalty<br />
応答内で既に使用されたトークンの再利用を抑制する。</p>
</li>
<li>
<p>Frequency Penalty<br />
応答内で同じトークンが繰り返される頻度を抑える。</p>
</li>
<li>
<p>Max Tokens<br />
応答に含められるトークン(単語や記号など)の最大数を指定する。</p>
</li>
<li>
<p>Seed<br />
ランダム性の再現性を確保するためのシード値。実験のために主に利用する。</p>
</li>
</ul>
<p>Difyでは、LLMのプロンプティングやハイパーパラメータを変えて試行錯誤する実験が非常にやりやすかったです。ChatGPTのAPIを用いた場合と比較すると、Difyでは下記の画像のように、プロンプトやハイパーパラメータのチューニングの検証が非常にやりやすく、短時間で多くの検証を行うことができました。</p>
<p><img src="/blog/2025/01/17/waiwai-ai/images/dify-tuning.png" alt="Difyのチューニング" /></p>
<h2 id="生成した内容の出力部分-はるおつ">生成した内容の出力部分 @はるおつ</h2>
<p>こんにちは。waiwai-aiの生成した内容の出力部分を担当したはるおつです。</p>
<p>今回は、AIコメントで配信を盛り上げる「waiwai-ai」の開発において、出力部分をどのように実装し、Slack APIとの繋ぎ込み、そして今後の拡張についてどのように取り組んだかをご紹介します。</p>
<h3 id="実装の手順">実装の手順</h3>
<p>waiwai-aiの生成した内容の出力部分を実装するにあたり、以下の3つのステップに分けて開発を行いました。</p>
<ol>
<li>基本的な動作確認とデバッグを容易に行える環境を整えるため、コンソールへの出力を実装する。</li>
<li>Slack APIの仕様を把握し、実際のユーザー環境での動作を確認するために、特定のチャンネルに出力する。</li>
<li>ユーザーとの自然なインタラクションを実現するため、スレッドのリンクを指定して返信できる機能を実装する。</li>
</ol>
<p>このように、段階的にタスクを分解することで、開発の進捗を管理しつつ、それぞれのステップで直面する課題を明確にしながら作業を進めました。</p>
<p>それでは、実際の開発について述べていきたいと思います。</p>
<h3 id="コンソールへの出力">コンソールへの出力</h3>
<p>まず最初に、waiwai-aiの基本となる<strong>コンソールへの出力</strong>と、<strong>AIから出力されたコメントの受け渡し形式</strong>を検討しました。特に、チーム開発における連携のしやすさと、将来の拡張性を考慮した設計を心がけました。</p>
<h4 id="実装内容">実装内容</h4>
<p>以下のようなシンプルなクラスを作成し、<code>answers</code> リストに含まれるコメントをコンソールに出力するメソッドを実装しました。</p>
<div class="highlight"><pre class="highlight python"><code><span class="k">class</span> <span class="nc">Outputs</span><span class="p">:</span>
<span class="n">answers</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">answers</span><span class="p">):</span>
<span class="bp">self</span><span class="p">.</span><span class="n">answers</span> <span class="o">=</span> <span class="n">answers</span>
<span class="k">def</span> <span class="nf">outputConsole</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">for</span> <span class="n">answer</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">.</span><span class="n">answers</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="n">answer</span><span class="p">)</span>
</code></pre></div>
<h4 id="データ形式の設計と選択">データ形式の設計と選択</h4>
<p>コメントの受け渡しには様々な方法がありますが、わいわいをAIで生成するチームと密に連携し、以下のような配列(リスト)形式での渡し方を採用しました。</p>
<div class="highlight"><pre class="highlight python"><code><span class="n">answers</span> <span class="o">=</span> <span class="p">[</span>
<span class="s">"ピザと寿司と肉が好きなところ、もう最高ですね! #食べ物仲間"</span><span class="p">,</span>
<span class="s">"自己紹介してくれて嬉しいです!音声合成技術、すごく興味深いですね😊"</span><span class="p">,</span>
<span class="s">"草"</span>
<span class="p">]</span>
</code></pre></div><p>この配列を用いて、各コメントを順にコンソールへ出力するようにしました。この形式を選んだ理由は主に以下の3点です。</p>
<ol>
<li>複数行コメントや順序付きの発言を扱いやすい</li>
<li>チーム間でのデータ受け渡しがシンプル</li>
<li>SlackやYouTubeなど、異なる出力先への拡張が容易</li>
</ol>
<h3 id="slackの特定のチャンネルにそのまま出力する">Slackの特定のチャンネルにそのまま出力する</h3>
<p>次に、<strong>Slackの特定のチャンネルに直接出力する機能</strong>を実装しました。これは、実際のユーザー環境でコメントがどのように表示されるかを確認するための重要なプロセスです。</p>
<h4 id="実装内容-1">実装内容</h4>
<p><code>Outputs</code> クラスに <code>outputSlack</code> メソッドを追加し、Slack APIを利用して指定したチャンネルにメッセージを投稿できるようにしました。</p>
<div class="highlight"><pre class="highlight python"><code><span class="k">def</span> <span class="nf">outputSlack</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">from</span> <span class="nn">dotenv</span> <span class="kn">import</span> <span class="n">load_dotenv</span>
<span class="n">load_dotenv</span><span class="p">()</span>
<span class="n">TOKEN</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">"SLACK_OAUTH_TOKEN_FOR_TEST"</span><span class="p">)</span>
<span class="n">CHANNEL</span> <span class="o">=</span> <span class="s">'HOGEHOGE'</span> <span class="c1"># チャンネルIDを指定
</span>
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s">"Authorization"</span><span class="p">:</span> <span class="sa">f</span><span class="s">"Bearer </span><span class="si">{</span><span class="n">TOKEN</span><span class="si">}</span><span class="s">"</span><span class="p">}</span>
<span class="k">for</span> <span class="n">answer</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">.</span><span class="n">answers</span><span class="p">:</span>
<span class="n">url</span> <span class="o">=</span> <span class="s">"https://slack.com/api/chat.postMessage"</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">'channel'</span><span class="p">:</span> <span class="n">CHANNEL</span><span class="p">,</span>
<span class="s">'text'</span><span class="p">:</span> <span class="n">answer</span>
<span class="p">}</span>
<span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">data</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"chat.postMessage response:"</span><span class="p">,</span> <span class="n">r</span><span class="p">.</span><span class="n">json</span><span class="p">())</span>
</code></pre></div>
<h4 id="slack-apiの設定">Slack APIの設定</h4>
<p>Slack APIを利用するために、以下のOAuthスコープを設定しました。(2024/5/30時点の設定)</p>
<p><strong>Bot Token Scopes:</strong></p>
<ul>
<li><strong>channels</strong>
<ul>
<li>@waiwai-aiが追加されたパブリックチャンネル内のメッセージやその他のコンテンツを閲覧するための権限です。スレッドの存在確認やメッセージの取得のために設定しました。</li>
</ul>
</li>
<li><strong>chat</strong>
<ul>
<li>@waiwai-aiとしてチャンネルにメッセージを送信するための権限です。</li>
</ul>
</li>
<li><strong>chat.customize</strong>
<ul>
<li>@waiwai-aiとして、カスタマイズされたユーザー名やアバターでメッセージを送信するための権限です。waiwai-aiの見た目を変えることを想定して、設定しました。</li>
</ul>
</li>
</ul>
<p><strong>User Token Scopes:</strong></p>
<ul>
<li><strong>chat</strong>
<ul>
<li>ユーザーに代わってメッセージを送信するための権限です。現在はbotとして表示されますが、今後ユーザーの代わりになってユーザー権限でメッセージを送信する際に使用します。</li>
</ul>
</li>
</ul>
<h4 id="実際にslackに出力した様子">実際にSlackに出力した様子</h4>
<p>実際にSlackに出力した様子は以下の通りです。配列で区切ったテスト用に作成したコメントが、そのままSlackに出力されていることがわかります。
<img src="/blog/2025/01/17/waiwai-ai/images/output1.png" alt="実際にSlackに出力した様子" /></p>
<h3 id="slackの特定のメッセージに対してスレッドで出力する">Slackの特定のメッセージに対してスレッドで出力する</h3>
<p>Slackのスレッドをリンクで指定できるように機能を拡張しました。</p>
<p>これにより、ユーザーはスレッドのURLを直接指定するだけで、そのスレッドに対してAIコメントを投稿できるようになりました。</p>
<h4 id="実装の背景と工夫点">実装の背景と工夫点</h4>
<p>これまでの実装では、SlackのチャンネルIDとメッセージのタイムスタンプ(<code>thread_ts</code>)を個別に指定する必要がありました。しかし、ユーザーがこれらの情報を手動で取得して指定するのは手間がかかり、UXの観点から改善の余地がありました。</p>
<p>そこで着目したのが、SlackのスレッドURLに含まれる情報です。実は、SlackのスレッドURLの末尾には、そのスレッドのタイムスタンプが含まれており、この点を活用することでユーザーの利便性を向上させることができました。</p>
<h4 id="urlから情報を抽出する方法">URLから情報を抽出する方法</h4>
<p>SlackのスレッドURLは以下のような形式になっています。</p>
<div class="highlight"><pre class="highlight plaintext"><code>https://&lt;workspace&gt;.slack.com/archives/&lt;channel_id&gt;/p&lt;timestamp&gt;
</code></pre></div>
<p>ここで、</p>
<ul>
<li><code>&lt;workspace&gt;</code> はワークスペースの名前</li>
<li><code>&lt;channel_id&gt;</code> はチャンネルのID</li>
<li><code>&lt;timestamp&gt;</code> はスレッドのタイムスタンプ(小数点が省略された形式)</li>
</ul>
<p><strong>例:</strong></p>
<p>タイムスタンプが <code>1622547803.000200</code> の場合、URLの末尾は <code>p1622547803000200</code> となります。</p>
<p>このURLから以下の情報を抽出します。</p>
<ol>
<li><strong>チャンネルID</strong>: <code>&lt;channel_id&gt;</code></li>
<li><strong>タイムスタンプ</strong>: <code>&lt;timestamp&gt;</code> を小数点を挿入して元の形式に戻す</li>
</ol>
<h4 id="実装内容-2">実装内容</h4>
<h4 id="正規表現による情報抽出">正規表現による情報抽出</h4>
<p>URLからチャンネルIDとタイムスタンプを抽出するために、正規表現を使用しました。</p>
<div class="highlight"><pre class="highlight python"><code><span class="k">def</span> <span class="nf">extract_slack_info</span><span class="p">(</span><span class="n">url</span><span class="p">):</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="c1"># 正規表現パターンを定義
</span> <span class="n">pattern</span> <span class="o">=</span> <span class="sa">r</span><span class="s">'https://[^/]+/archives/([A-Z0-9]+)/p(\d{16})'</span>
<span class="n">match</span> <span class="o">=</span> <span class="n">re</span><span class="p">.</span><span class="n">match</span><span class="p">(</span><span class="n">pattern</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">match</span><span class="p">:</span>
<span class="k">raise</span> <span class="nb">ValueError</span><span class="p">(</span><span class="s">"URLの形式が正しくありません。"</span><span class="p">)</span>
<span class="n">channel</span> <span class="o">=</span> <span class="n">match</span><span class="p">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">raw_ts</span> <span class="o">=</span> <span class="n">match</span><span class="p">.</span><span class="n">group</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="c1"># タイムスタンプの形式を修正(小数点を挿入)
</span> <span class="n">thread_ts</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="n">raw_ts</span><span class="p">[</span><span class="si">:</span><span class="mi">10</span><span class="p">]</span><span class="si">}</span><span class="s">.</span><span class="si">{</span><span class="n">raw_ts</span><span class="p">[</span><span class="mi">10</span><span class="si">:</span><span class="p">]</span><span class="si">}</span><span class="s">"</span>
<span class="k">return</span> <span class="n">channel</span><span class="p">,</span> <span class="n">thread_ts</span>
</code></pre></div>
<p><strong>工夫点:</strong></p>
<ul>
<li><strong>正規表現パターンの設計</strong>: ワークスペース名やドメイン部分を一般化し、どのSlackワークスペースでも対応できるようにしました。</li>
<li><strong>タイムスタンプの復元</strong>: URL中のタイムスタンプは小数点が除かれているため、適切な位置に小数点を挿入して元の形式に戻す必要があります。
<ul>
<li>具体的には、16桁の数字のうち、最初の10桁が秒、残りの6桁がマイクロ秒を表しているため、<code>raw_ts[:10] + '.' + raw_ts[10:]</code> の形で復元します。</li>
</ul>
</li>
</ul>
<h4 id="outputslack-メソッドの修正"><code>outputSlack</code> メソッドの修正</h4>
<p>抽出したチャンネルIDとタイムスタンプを用いて、指定したスレッドにメッセージを投稿します。</p>
<div class="highlight"><pre class="highlight python"><code><span class="k">def</span> <span class="nf">outputSlack</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">url</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="n">channel</span><span class="p">,</span> <span class="n">thread_ts</span> <span class="o">=</span> <span class="n">extract_slack_info</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="n">TOKEN</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">getenv</span><span class="p">(</span><span class="s">"SLACK_OAUTH_TOKEN"</span><span class="p">)</span>
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s">"Authorization"</span><span class="p">:</span> <span class="sa">f</span><span class="s">"Bearer </span><span class="si">{</span><span class="n">TOKEN</span><span class="si">}</span><span class="s">"</span><span class="p">}</span>
<span class="k">for</span> <span class="n">answer</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">.</span><span class="n">answers</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">"channel"</span><span class="p">:</span> <span class="n">channel</span><span class="p">,</span>
<span class="s">"text"</span><span class="p">:</span> <span class="n">answer</span><span class="p">,</span>
<span class="s">"thread_ts"</span><span class="p">:</span> <span class="n">thread_ts</span>
<span class="p">}</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="s">"https://slack.com/api/chat.postMessage"</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">data</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Response:"</span><span class="p">,</span> <span class="n">response</span><span class="p">.</span><span class="n">json</span><span class="p">())</span>
</code></pre></div>
<h4 id="使用例">使用例</h4>
<div class="highlight"><pre class="highlight python"><code><span class="n">answers</span> <span class="o">=</span> <span class="p">[</span><span class="s">"素晴らしいアイデアですね!"</span><span class="p">,</span> <span class="s">"その点については賛成です!"</span><span class="p">]</span>
<span class="n">h</span> <span class="o">=</span> <span class="n">Outputs</span><span class="p">(</span><span class="n">answers</span><span class="p">)</span>
<span class="n">h</span><span class="p">.</span><span class="n">outputSlack</span><span class="p">(</span><span class="s">'https://yourworkspace.slack.com/archives/C01ABCDEF/p1622547803000200'</span><span class="p">)</span>
</code></pre></div>
<p>このように、スレッドのURLを引数として渡すだけで、該当するスレッドに対してメッセージを投稿できるようになりました。</p>
<h4 id="まとめ">まとめ</h4>
<p>以上が、waiwai-aiが生成した内容の出力部分を実装する際の各ステップとその背景、具体的な実装内容になります。段階的に機能を拡張することで、開発効率を高めつつ、ユーザー体験の向上を図ることができました。</p>
<h2 id="結果">結果</h2>
<p>waiwai-aiを導入した結果、Slackのやり取りは大いに盛り上がりを見せました!画像にあるように、AIが生成したコメントが、視聴者のリアクションを引き出し、自然な会話の流れを作り出しています。例えば「なるほどw」や「AIっぽいwww」といったリアクションが飛び交い、AIがまるで本当の参加者のように受け入れられている様子が伺えます。</p>
<p>「人間もコメントしないとって気持ちになってくるな」という声が示すように、AIが視聴者のコミュニケーションを自然に促し、会話に活気を与えていることが大きな成果です。結果的に、わいわいAIは新規配信者でも視聴者とのやり取りが弾む楽しい配信空間を作り出すことができました。</p>
<p><img src="/blog/2025/01/17/waiwai-ai/images/output2.png" alt="Slackのやり取りがwaiwai-aiのおかげで大いに盛り上がっている図" /></p>
<h2 id="感想">感想</h2>
<h3 id="どすこい">どすこい</h3>
<p>自分たちがおもしろいと思えるプロダクトを開発できたこと、チームでわいわいかつ本気で開発できたこと、先輩エンジニアのすごさを目の当たりに体験できたことがとても勉強になりました!来年がすでに楽しみです!</p>
<h3 id="はるおつ">はるおつ</h3>
<p>それぞれが、それぞれの得意を活かして開発できたことがとても良い体験でした。チーム開発ならではの速度感や意見のぶつけ合いを研修の一環で経験できたことは大きな糧となりました。現時点で来年は何をつくろうかな。こんなのが面白いかな。のようなことを考えていて、次のお産合宿がとても楽しみです。</p>
<h3 id="てつを">てつを</h3>
<p>誰かと一緒にゲームがしたい、コメントを盛り上げてほしい。普段ゲームをしながら考えていたことを形にしました。やっぱりチーム開発、かつ0からプロダクトを作るのは本当に楽しいなと改めて感じ、各々の強みを活かして最高のものができました。業務でも、お産合宿のような熱量とこの楽しさを常に持って取り組みたいなと思いました!</p>
</content>
</entry>
<entry>
<title>東京Ruby会議12にbuty4649、yumu、kenchanが登壇します!</title>
<link rel="alternate" href="https://tech.pepabo.com/2025/01/16/tokyorubykaigi-entry/"/>
<id>https://tech.pepabo.com/2025/01/16/tokyorubykaigi-entry/</id>
<published>2025-01-15T15:00:00+00:00</published>
<updated>2025-02-03T00:06:09+00:00</updated>
<author>
<name>yumu</name>
</author>
<content type="html"><p>2025年1月18日(土)に開催される<a href="https://regional.rubykaigi.org/tokyo12/">東京Ruby会議12</a>にGMOペパボからは<a href="https://x.com/buty4649">@buty4649</a>、<a href="https://x.com/myumura3">@yumu</a>、<a href="https://x.com/kenchan">@kenchan</a>が登壇します!</p>
<h3 id="buty4649-mrubyでワンバイナリーなテキストフィルタツールを作った">@buty4649 mrubyでワンバイナリーなテキストフィルタツールを作った</h3>
<p>mrubyを用いたワンバイナリーアプリケーションの実装手法に焦点を当て、テキスト処理ツールの開発を例に、シンプルなアプリケーションの作成方法について解説します。一般的なRubyアプリケーションはスクリプト言語としての性質からRubyの実行環境が必要ですが、mrubyを活用することで単体で実行できるバイナリ形式のツールを実現できます。</p>
<p>今回の発表では、実際に私がOSSとして公開しているテキストフィルタツールを題材に、mrubyによるビルドプロセス、ワンバイナリー化における設計上の工夫や実装手法、クロスプラットフォーム対応や配布手順の最適化について紹介します。</p>
<h3 id="yumu-rubyawsで作る動画変換システム">@yumu Ruby×AWSで作る動画変換システム</h3>
<p>動画変換システムというと、既存のSaaSを使うか、低レイヤーな実装に踏み込むかの二択と思われがちです。しかし、RubyのエコシステムとAWSの各種サービスを活用することで、より手軽に独自の動画変換システムを構築できます。</p>
<p>今回のセッションでは、ハンドメイドECサービス「minne」における動画変換システムの実装方法をご紹介します。</p>
<p>動画変換の核となるFFmpegをRubyから扱う方法、変換処理を担うShoryuken workerの実装、そして実運用に耐えうる設計の作り方まで、具体的なコードを交えながら解説します。開発環境はDockerで簡単に構築でき、ローカルでの開発から本番展開まで、スムーズに進められる構成をお見せします。</p>
<h3 id="kenchan-regionalrb-and-the-tokyo-metropolis">@kenchan Regional.rb and the Tokyo Metropolis</h3>
<p><a href="https://shibuyarb.connpass.com/">Shibuya.rb</a>を代表して、「Regional.rb and the Tokyo Metropolis」のセッションに登壇します。東京における地域Rubyコミュニティの活動と展望についてお話しします。</p>
</content>
</entry>
<entry>
<title>RubyWorld Conference 2024 参加レポート</title>
<link rel="alternate" href="https://tech.pepabo.com/2024/12/26/rwc-2024/"/>
<id>https://tech.pepabo.com/2024/12/26/rwc-2024/</id>
<published>2024-12-25T15:00:00+00:00</published>
<updated>2025-02-03T00:06:09+00:00</updated>
<author>
<name>yumu</name>
</author>
<content type="html"><p>こんにちは!GMOペパボでエンジニアをしている<a href="https://x.com/myumura3">@yumu</a>です。</p>
<p>2024年12月5日〜6日の2日間、島根県立産業交流会館「くにびきメッセ」にて<a href="https://2024.rubyworld-conf.org/ja/">RubyWorld Conference 2024</a>が開催されました。今年で16回目の開催となる本カンファレンスは、プログラミング言語「Ruby」の国内最大のビジネスカンファレンスです。私は普段からRubyを用いた開発に携わっていますが、このカンファレンスへの参加は今回が初めてでした。</p>
<p>本記事では、印象に残ったセッションの内容や、スポンサーブースの様子についてお伝えします。</p>
<ol id="markdown-toc">
<li><a href="#全体の印象" id="markdown-toc-全体の印象">全体の印象</a></li>
<li><a href="#印象に残ったセッション紹介" id="markdown-toc-印象に残ったセッション紹介">印象に残ったセッション紹介</a> <ol>
<li><a href="#クリエイティブコーディングとruby学習" id="markdown-toc-クリエイティブコーディングとruby学習">クリエイティブコーディングとRuby学習</a></li>
<li><a href="#rubyプログラミングスクールからの採用と育成" id="markdown-toc-rubyプログラミングスクールからの採用と育成">Rubyプログラミングスクールからの採用と育成</a></li>
<li><a href="#スパイクアクセス対策としてのpitchfork導入" id="markdown-toc-スパイクアクセス対策としてのpitchfork導入">スパイクアクセス対策としてのpitchfork導入</a></li>
<li><a href="#長年運用されているサービスの主要データ移行をサービス停止せず安全にリリースしました" id="markdown-toc-長年運用されているサービスの主要データ移行をサービス停止せず安全にリリースしました">長年運用されているサービスの主要データ移行をサービス停止せず安全にリリースしました</a></li>
</ol>
</li>
<li><a href="#スポンサーブース探訪" id="markdown-toc-スポンサーブース探訪">スポンサーブース探訪</a></li>
<li><a href="#おわりに" id="markdown-toc-おわりに">おわりに</a></li>
</ol>
<h2 id="全体の印象">全体の印象</h2>
<p>RubyWorld Conferenceで印象的だったのは、技術的な話題だけでなく、ビジネスの視点からもRubyの可能性を探るセッションが多かったことです。RubyKaigiやKaigi on Railsでは技術の話が中心なのですが、今回はRubyを活用した事業展開、エンジニア採用、人材育成などのテーマも多く取り上げられていました。</p>
<p>セッションの内容は幅広く、技術面では大規模サービスの運用ノウハウやパフォーマンスチューニングの実例など、明日から使えそうな知見が多く共有されました。一方で、エンジニアの採用・育成の話や、島根の企業のRuby活用事例、プログラミング教育の取り組みなど、技術以外の話題も充実していました。</p>
<p>松江市での開催というのも面白いポイントでした。東京のカンファレンスとは一味違う、地方ならではのテック企業の展開や、地域でのRubyコミュニティの盛り上がりを知ることができて新鮮でした。会場の雰囲気もとても良くて、休憩時間やレセプションでは登壇者の方々や他の参加者と気軽に話ができました。</p>
<p><img src="/blog/2024/12/26/rwc-2024/images/reception.png" alt="レセプションのお刺身" /></p>
<h2 id="印象に残ったセッション紹介">印象に残ったセッション紹介</h2>
<h3 id="クリエイティブコーディングとruby学習">クリエイティブコーディングとRuby学習</h3>
<p>株式会社スマートバンクの小芝美由紀さんによる<a href="https://speakerdeck.com/chobishiba/creative-coding-and-learning-ruby">クリエイティブコーディングとRuby学習</a>のセッションでは、実際にRubyWorld ConferenceのロゴをRubyとp5.jsで作成したデモを交えながら、プログラミング学習の新しいアプローチが紹介されました。</p>
<p>このセッションにおけるクリエイティブコーディングとは、コードでビジュアルアート作品を作ることを指します。この手法の面白いところは、プログラミングの基礎を視覚的に理解できる点です。例えば変数や繰り返し処理の結果が直接目に見える形で表示されるため、それらの概念を体験的に学べるとのことでした。さらに「楽しみながら学べる」「手軽に試せる」という特徴は、プログラミング初学者の意欲を高めるのに効果的だそうです。</p>
<p>また、実践の場として、ワークショップ形式での学習を提案されていました。ワークショップとは、従来の教師主導の学習とは異なり、参加者が主体となって学び合い、ファシリテーターがサポートする学習の形式です。これまでも複数の技術イベントでクリエイティブコーディングのワークショップを開催されていて、2025年1月に開催される<a href="https://regional.rubykaigi.org/tokyo12/">東京Ruby会議</a>の前夜祭でもワークショップを開催されるそうで、プログラミング入門の新しい形として注目されています。</p>
<p>クリエイティブコーディングは、プログラミングを仕事のスキルとしてだけでなく、創造的な趣味として楽しむ可能性を見せてくれました。普段はビジネスロジックを書くことが多いRubyですが、もっと自由に遊べる言語としての一面も感じられて新鮮でした。</p>
<h3 id="rubyプログラミングスクールからの採用と育成">Rubyプログラミングスクールからの採用と育成</h3>
<p>株式会社永和システムマネジメントの伊藤浩一さんは<a href="https://speakerdeck.com/koic/carving-the-way-to-ruby-engineering">Rubyプログラミングスクールからの採用と育成</a>について話してくださいました。</p>
<p>同社は社員の約3割がプログラミングスクール出身者で、元警察官だった人や獣医師、教師など、かなり多彩なバックグラウンドを持つメンバーが活躍しているそうです。ペパボでもプログラミングスクール出身のエンジニアが多く在籍しているので、とても親近感を覚えました。</p>
<p>採用においては、組織文化(コミュニティ)とのマッチングを重視しており、「信頼できる人が信頼できると言っている人は信頼できる」というシンプルな考え方を大切にしているそうです。つまり、コミュニティ内での信頼関係が重視されるということで、私も技術力だけでなく、コミュニティから信頼される人になっていきたいと感じました。</p>
<p>また、エンジニアの育成については、エンジニアの成長の主役はあくまでもエンジニア本人であるため、会社はその成長を支える環境づくりに注力しているとおっしゃっていました。例えば、日報や1on1を通じてその人に必要な技術を見極めサポートしたり、資格取得の支援で体系的な知識習得を後押ししたり。さらに、複数のメンバーと1on1の機会を設けたり、様々な社内勉強会を開催したりと、エンジニアの成長をしっかりと支える仕組みが用意されているのが印象的でした。</p>
<h3 id="スパイクアクセス対策としてのpitchfork導入">スパイクアクセス対策としてのpitchfork導入</h3>
<p>STORES株式会社のシムサンヨンさんによる、<a href="https://speakerdeck.com/riseshia/introducing-pitchfork-as-a-countermeasure-for-traffic-spikes">スパイクアクセス対策としてのpitchfork導入</a>のセッションも面白かったです。ECサイトでよくある「○時から販売開始!」というケースで、開始時刻に大量のアクセスが集中してレイテンシが悪化する問題にどう対処したのか、具体的な解決策を説明していただきました。</p>
<p>特に興味深かったのは、問題の原因分析でした。unicornのワーカープロセスの挙動を調べてみると、リクエストが一部のワーカーに偏っていることが判明。これはunicornの仕様によるもので、処理を終えたワーカーが待ち列の先頭に入るため、同じワーカーが続けて仕事を受け取る仕組みになっていたとのことです。そのため、スパイクアクセスに備えて多くのワーカーを用意していたにもかかわらず、実際には一部のワーカーしか「温まって」おらず、アクセス集中時に十分な処理能力を発揮できるようになるまで時間がかかっていたということでした。</p>
<p>対策として採用したのが、Shopify製のunicornフォークである「pitchfork」です。pitchforkの特徴的な機能の一つが「refork」で、一定数のリクエストを処理した「暖まった」ワーカーをテンプレートとして、全ワーカーを再生成する機能です。これにより、全てのワーカーを効率的な状態に保てるようになったそうです。</p>
<p>導入の結果、2023年と2024年の同規模の販売時のパフォーマンスを比較すると、レイテンシの改善が見られたそうです。特にRubyの処理時間が大きく改善されており、低コストで導入できる効果的な対策として注目を集めていました。ただし、コネクションの継承やバックグラウンドで動くスレッドの扱いなど、fork safetyの確認は必要とのことです。</p>
<h3 id="長年運用されているサービスの主要データ移行をサービス停止せず安全にリリースしました">長年運用されているサービスの主要データ移行をサービス停止せず安全にリリースしました</h3>
<p>STORES株式会社の山下隼人さんによる<a href="https://speakerdeck.com/phayacell/chang-nian-yun-yong-sareteirusahisunozhu-yao-tetayi-xing-wosahisuting-zhi-sesuan-quan-niririsusimasita">長年運用されているサービスの主要データ移行をサービス停止せず安全にリリースしました</a>のセッションでは、5,000万件を超える注文データのデータ構造を移行するプロジェクトについて紹介されました。</p>
<p>注文データは日々データ量が増え続け、頻繁な書き込みと読み込みが発生し、過去データも継続的に参照される重要なものです。長年の運用で積み重なった改修により、当初は最適だったデータ構造が現状に適さなくなってきていました。このセッションでは、24時間稼働のサービスを止めることなく、どのように新しいデータ構造へと移行したのかが紹介されました。</p>
<p>移行は次のような手順で進められました。まず新しいデータ構造に対して二重書き込みを行い、その後書き込み先を変更するというアプローチを取りました。具体的には、最初は古いデータ構造で注文データを作成し新しい構造に変換する形から始め、次のステップで新しいデータ構造での作成→古い構造への変換という流れに切り替えました。</p>
<p>特に興味深かったのは、以下の2つのポイントです。</p>
<ul>
<li>カナリアリリースをロードバランサーではなくアプリケーションレベルで実装。これにより、注文の一連の処理を一貫してカナリアかベースラインのどちらかで処理できるようにした</li>
<li>テストコードのカバレッジが不足する中、「動いているコード」を正として新旧で生成されたデータを比較することで品質を担保</li>
</ul>
<p>実際の移行では、パフォーマンス低下や想定外のエッジケースなどいくつかの問題に直面したものの、これらの工夫により大きな問題なく移行を完了できたそうです。長期運用サービスではどこでも直面しうる「データ構造の移行」という課題に対する、実践的なアプローチが示されたセッションでした。</p>
<h2 id="スポンサーブース探訪">スポンサーブース探訪</h2>
<p>スポンサーブースには、東京で開催される技術カンファレンスでは見かけることの少ない地元松江の企業が多くスポンサーとして参加しており、地域におけるRubyコミュニティの広がりを実感できました。</p>
<p>スポンサーブースで特に面白かったのは、株式会社ネットワーク応⽤通信研究所さんが展示していたファミコンゲームのデモです。スポンサーセッションの<a href="https://2024.rubyworld-conf.org/ja/program/day1/#ruby-sponsor-session-day1">ファミコン meets Ruby</a>で紹介されていたゲームを実際にプレイできるというもので、私も挑戦してみました。通常のRubyよりもメモリ使用量を大幅に抑えたmruby/cを使うことで、ファミコンゲームのプログラミングが可能になるという点が印象に残りました。</p>
<p>一般社団法人Rubyビジネス推進協議会さんの、IoTの展示も印象的でした。SenStick4という超小型センサーボードにmruby/cを搭載したキットを使ったデモで、加速度、温度、湿度、気圧、照度など8種類のセンサーからデータを収集し、Bluetooth経由で通信。そのデータに応じてブラウザ上の部屋のカーテンが開いたり扇風機が動いたりするデモは、とても面白かったです。普段はWebアプリケーション開発でしかRubyを触っていない私にとって、Rubyの活用の幅広さを実感できる良い機会でした。</p>
<p><img src="/blog/2024/12/26/rwc-2024/images/sponsor.png" alt="スポンサーブースの様子" /></p>
<h2 id="おわりに">おわりに</h2>
<p>RubyWorld Conference 2024に参加して、技術的な学びはもちろん、Rubyコミュニティの活気を直接感じられてとても良かったです。まつもとさんが語ってくれたRubyの未来像や、明日から使えそうな技術的なノウハウの数々は、自分の開発者としての視野を大きく広げてくれました。</p>
<p>特に印象的だったのは、Rubyの活用の幅広さです。Webアプリケーション開発はもちろん、ファミコンのゲーム開発や小型IoTデバイスのプログラミングなど、普段の仕事ではなかなか目にすることのない使い方を知ることができて、新鮮な驚きがありました。</p>
<p>松江でRubyが確実に根付いているのを目の当たりにできたのも面白かったです。地元企業が積極的に参加し、次々と新しい取り組みにチャレンジしている様子を見て、Rubyの持つ可能性の大きさを改めて感じました。</p>
<p>次は自分も登壇者として参加したいなと思っています。今回のカンファレンスでたくさんの刺激と学びをもらったので、これを日々の開発に活かしながら、来年は自分の経験も皆さんと共有できたらいいなと思います!</p>
</content>
</entry>
<entry>
<title>PHP Conference 2024に参加しました</title>
<link rel="alternate" href="https://tech.pepabo.com/2024/12/24/phpcon2024/"/>
<id>https://tech.pepabo.com/2024/12/24/phpcon2024/</id>
<published>2024-12-23T15:00:00+00:00</published>
<updated>2025-02-03T00:06:09+00:00</updated>
<author>
<name>pyama</name>
</author>
<content type="html"><hr />
<p>こんにちは、カンファレンスの二次会のプロこと、pyama86です。年の瀬、いかがお過ごしでしょうか?この度、大田区産業プラザPiOにて開催されたPHP Conference 2024に参加したので、その内容をご紹介します。</p>
<h2 id="gmoペパボとphp">GMOペパボとPHP</h2>
<p>まず最初にGMOペパボとPHPの関わりについて紹介します。GMOペパボは国内のWEBサービス黎明期にホスティング事業から始まった会社であり、その後ECサービスなどを展開してきた歴史があります。故に、GMOペパボの比較的古いサービスはPHPで実装されているものが多いです。近年はRubyやGoで実装されているサービスが増えていますが、PHPで動いているリポジトリは今でも多く存在し、日々活発に開発されています。</p>
<h2 id="セッション紹介">セッション紹介</h2>
<p>ここからは私が聞いたセッションについて紹介します。</p>
<h3 id="beyond-orm"><strong>Beyond ORM</strong></h3>
<script defer="" class="speakerdeck-embed" data-id="54762efbeec94c74b1b76cdd6757f964" data-ratio="1.414516129032258" src="//speakerdeck.com/assets/embed.js"></script>
<p><a href="https://x.com/77web">@77web</a>さんのセッションでは、ORMがどのようなもので、どういった用途で使われるのか、またどういった場合に問題があるかについて紹介されました。その後、それらをいかに乗り越えていくかという方法が解説され、PHPでよく利用されるEloquentやDoctrineの違いにも触れられていました。初学者にも分かりやすい内容で、またPHPカンファレンス名古屋も開催されるとのことで楽しみです。</p>
<h3 id="終了の危機にあった15年続くwebサービスを全力で存続させるtwilogtogetter統合の舞台裏"><strong>終了の危機にあった15年続くWebサービスを全力で存続させる〜Twilog・Togetter統合の舞台裏〜</strong></h3>
<script defer="" class="speakerdeck-embed" data-id="39993f787e024fb0b981266c42f2e881" data-ratio="1.7772511848341233" src="//speakerdeck.com/assets/embed.js"></script>
<p>エンジニアならば誰もが目にしたことがあるツールであるTwilogとTogetter。吉田俊明さんと青山民人さんによるセッションでは、統合の舞台裏が紹介されました。移行の途中で渋い構成があったり、歴史を感じさせる内容でしたが、最終的にはベターな構成に落ち着いたという印象でした。クラウドサービスで大きなデータをローコストで運用するためのご苦労が伺えましたが、今後の伸び代にも期待しています。</p>
<h3 id="技術を楽しむphpで実装するtlssslプロトコル"><strong>技術を楽しむ:PHPで実装するTLS/SSLプロトコル</strong></h3>
<p><a href="https://docs.google.com/presentation/d/10pbead0QnnRzIIr-YvoMeGpFTRnrteV-erQrE4UKPIk/edit#slide=id.p">資料はGoogleスライドです</a></p>
<p><a href="https://x.com/cakephper">@cakephper</a>さんの作ってみたシリーズ。今回はTLS/SSLのレイヤーに加えてTCPレイヤーまで実装されており、ますます進化した内容でした。Wiresharkの紹介は、ネットワークエンジニア以外にはあまり馴染みがないかもしれませんが、非常に参考になりました。次回はNICドライバの実装に期待したいですね!</p>
<h3 id="ある日突然あなたが管理しているサーバーにddosが来たらどうなるでしょう知ってるようで何も知らなかったddos攻撃と対策"><strong>ある日突然あなたが管理しているサーバーにDDoSが来たらどうなるでしょう?知ってるようで何も知らなかったDDoS攻撃と対策</strong></h3>
<script defer="" class="speakerdeck-embed" data-id="95a877e06d3e4e5aa208a874ed962f05" data-ratio="1.7777777777777777" src="//speakerdeck.com/assets/embed.js"></script>
<p>最近はツナギメエフエムの中の人という認知になりつつある<a href="https://x.com/akase244">@akase244</a>さんによるセッションでした。DDoSの概要や最近の傾向についての解説に続き、それらに対する対策が体系的に紹介されました。時折心の声が漏れる場面があり、熟年のトーク技術も感じました。我々の事業でもDDoS対策は必須で、HTTP/3の普及に伴いUDP通信の増加が見込まれる中で、ブラッシュアップが必要だと感じました。</p>
<h3 id="情報漏洩させないための設計"><strong>情報漏洩させないための設計</strong></h3>
<script defer="" class="speakerdeck-embed" data-id="657625eeb44945c3be6fd207a32f3382" data-ratio="1.7772511848341233" src="//speakerdeck.com/assets/embed.js"></script>
<p>CQRS+ESカンファレンスでご一緒した<a href="https://x.com/kubotak_public">@kubotak_public</a>さんのセッションです。情報漏洩を防ぐためにいかに安全に実装するかが、コード例を交えながら紹介されました。特にDDD(ドメイン駆動設計)のナレッジを活用し、抽象と具象、型を駆使した設計はとても勉強になりました。境界づけられたコンテキストを守るツールの紹介もあり、実践的な内容でした。</p>
<h2 id="懇親会">懇親会</h2>
<p>当日懇親会も盛大に行われました。初めてお会いする方や、お友達のお友達など、多くの方と様々な話ができました。他社の優秀なエンジニアの取り組みや考え方を知ることで、自社だけでは得られない知見やノウハウを得られるのがコミュニティの良いところだと改めて感じました。</p>
<p>懇親会中には業務委託で入っていただいている<a href="https://x.com/uzulla">@uzulla</a>さんと業界や自社のことについて話したり、来年も多く開催されるPHPカンファレンスの主催の方々とカンファレンスの運営や、トーク応募の話などをしたりしていました。</p>
<h2 id="最後に">最後に</h2>
<p>あらためて、GMOペパボひいてはGMOインターネットグループではPHPのプロダクトが多くあり、今回PHP Conference 2024においてもGMOインターネットグループがスペシャルスポンサーを務めさせていただきました。</p>
<p><img src="/blog/2024/12/24/phpcon2024/images/gmo_booth.jpg" alt="GMOのブース" /></p>
<p>僕自身は普段は登壇での参加が多いのですが、リスナーとして参加するだけでも何かしらの刺激をもらえたり、情報を得られることも多いので、今後も積極的にコミュニティとの関わりを続けていきたいと思います。 またGMOペパボとしてはこれからもPHPを利用し、新しい価値をどんどん届けていきたいと考えています。ぜひ一緒に働きましょう!</p>
</content>
</entry>
</feed>