Yauheniya commited on
Commit
5e41fb6
·
1 Parent(s): 45f0f7e

Add full Python AI assistant app

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.png filter=lfs diff=lfs merge=lfs -text
37
+ *.svg filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,684 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ notes/
2
+ ai-assistant/
3
+
4
+ # Created by https://www.toptal.com/developers/gitignore/api/java,visualstudiocode,macos,linux,windows,python,visualstudio
5
+ # Edit at https://www.toptal.com/developers/gitignore?templates=java,visualstudiocode,macos,linux,windows,python,visualstudio
6
+
7
+ ### Java ###
8
+ # Compiled class file
9
+ *.class
10
+
11
+ # Log file
12
+ *.log
13
+
14
+ # BlueJ files
15
+ *.ctxt
16
+
17
+ # Mobile Tools for Java (J2ME)
18
+ .mtj.tmp/
19
+
20
+ # Package Files #
21
+ *.jar
22
+ *.war
23
+ *.nar
24
+ *.ear
25
+ *.zip
26
+ *.tar.gz
27
+ *.rar
28
+
29
+ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
30
+ hs_err_pid*
31
+ replay_pid*
32
+
33
+ ### Linux ###
34
+ *~
35
+
36
+ # temporary files which can be created if a process still has a handle open of a deleted file
37
+ .fuse_hidden*
38
+
39
+ # KDE directory preferences
40
+ .directory
41
+
42
+ # Linux trash folder which might appear on any partition or disk
43
+ .Trash-*
44
+
45
+ # .nfs files are created when an open file is removed but is still being accessed
46
+ .nfs*
47
+
48
+ ### macOS ###
49
+ # General
50
+ .DS_Store
51
+ .AppleDouble
52
+ .LSOverride
53
+
54
+ # Icon must end with two \r
55
+ Icon
56
+
57
+
58
+ # Thumbnails
59
+ ._*
60
+
61
+ # Files that might appear in the root of a volume
62
+ .DocumentRevisions-V100
63
+ .fseventsd
64
+ .Spotlight-V100
65
+ .TemporaryItems
66
+ .Trashes
67
+ .VolumeIcon.icns
68
+ .com.apple.timemachine.donotpresent
69
+
70
+ # Directories potentially created on remote AFP share
71
+ .AppleDB
72
+ .AppleDesktop
73
+ Network Trash Folder
74
+ Temporary Items
75
+ .apdisk
76
+
77
+ ### macOS Patch ###
78
+ # iCloud generated files
79
+ *.icloud
80
+
81
+ ### Python ###
82
+ # Byte-compiled / optimized / DLL files
83
+ __pycache__/
84
+ *.py[cod]
85
+ *$py.class
86
+
87
+ # C extensions
88
+ *.so
89
+
90
+ # Distribution / packaging
91
+ .Python
92
+ build/
93
+ develop-eggs/
94
+ dist/
95
+ downloads/
96
+ eggs/
97
+ .eggs/
98
+ lib/
99
+ lib64/
100
+ parts/
101
+ sdist/
102
+ var/
103
+ wheels/
104
+ share/python-wheels/
105
+ *.egg-info/
106
+ .installed.cfg
107
+ *.egg
108
+ MANIFEST
109
+
110
+ # PyInstaller
111
+ # Usually these files are written by a python script from a template
112
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
113
+ *.manifest
114
+ *.spec
115
+
116
+ # Installer logs
117
+ pip-log.txt
118
+ pip-delete-this-directory.txt
119
+
120
+ # Unit test / coverage reports
121
+ htmlcov/
122
+ .tox/
123
+ .nox/
124
+ .coverage
125
+ .coverage.*
126
+ .cache
127
+ nosetests.xml
128
+ coverage.xml
129
+ *.cover
130
+ *.py,cover
131
+ .hypothesis/
132
+ .pytest_cache/
133
+ cover/
134
+
135
+ # Translations
136
+ *.mo
137
+ *.pot
138
+
139
+ # Django stuff:
140
+ local_settings.py
141
+ db.sqlite3
142
+ db.sqlite3-journal
143
+
144
+ # Flask stuff:
145
+ instance/
146
+ .webassets-cache
147
+
148
+ # Scrapy stuff:
149
+ .scrapy
150
+
151
+ # Sphinx documentation
152
+ docs/_build/
153
+
154
+ # PyBuilder
155
+ .pybuilder/
156
+ target/
157
+
158
+ # Jupyter Notebook
159
+ .ipynb_checkpoints
160
+
161
+ # IPython
162
+ profile_default/
163
+ ipython_config.py
164
+
165
+ # pyenv
166
+ # For a library or package, you might want to ignore these files since the code is
167
+ # intended to run in multiple environments; otherwise, check them in:
168
+ # .python-version
169
+
170
+ # pipenv
171
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
172
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
173
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
174
+ # install all needed dependencies.
175
+ #Pipfile.lock
176
+
177
+ # poetry
178
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
179
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
180
+ # commonly ignored for libraries.
181
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
182
+ #poetry.lock
183
+
184
+ # pdm
185
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
186
+ #pdm.lock
187
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
188
+ # in version control.
189
+ # https://pdm.fming.dev/#use-with-ide
190
+ .pdm.toml
191
+
192
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
193
+ __pypackages__/
194
+
195
+ # Celery stuff
196
+ celerybeat-schedule
197
+ celerybeat.pid
198
+
199
+ # SageMath parsed files
200
+ *.sage.py
201
+
202
+ # Environments
203
+ .env
204
+ .venv
205
+ env/
206
+ venv/
207
+ ENV/
208
+ env.bak/
209
+ venv.bak/
210
+
211
+ # Spyder project settings
212
+ .spyderproject
213
+ .spyproject
214
+
215
+ # Rope project settings
216
+ .ropeproject
217
+
218
+ # mkdocs documentation
219
+ /site
220
+
221
+ # mypy
222
+ .mypy_cache/
223
+ .dmypy.json
224
+ dmypy.json
225
+
226
+ # Pyre type checker
227
+ .pyre/
228
+
229
+ # pytype static type analyzer
230
+ .pytype/
231
+
232
+ # Cython debug symbols
233
+ cython_debug/
234
+
235
+ # PyCharm
236
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
237
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
238
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
239
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
240
+ #.idea/
241
+
242
+ ### Python Patch ###
243
+ # Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
244
+ poetry.toml
245
+
246
+ # ruff
247
+ .ruff_cache/
248
+
249
+ # LSP config files
250
+ pyrightconfig.json
251
+
252
+ ### VisualStudioCode ###
253
+ .vscode/*
254
+ !.vscode/settings.json
255
+ !.vscode/tasks.json
256
+ !.vscode/launch.json
257
+ !.vscode/extensions.json
258
+ !.vscode/*.code-snippets
259
+
260
+ # Local History for Visual Studio Code
261
+ .history/
262
+
263
+ # Built Visual Studio Code Extensions
264
+ *.vsix
265
+
266
+ ### VisualStudioCode Patch ###
267
+ # Ignore all local history of files
268
+ .history
269
+ .ionide
270
+
271
+ ### Windows ###
272
+ # Windows thumbnail cache files
273
+ Thumbs.db
274
+ Thumbs.db:encryptable
275
+ ehthumbs.db
276
+ ehthumbs_vista.db
277
+
278
+ # Dump file
279
+ *.stackdump
280
+
281
+ # Folder config file
282
+ [Dd]esktop.ini
283
+
284
+ # Recycle Bin used on file shares
285
+ $RECYCLE.BIN/
286
+
287
+ # Windows Installer files
288
+ *.cab
289
+ *.msi
290
+ *.msix
291
+ *.msm
292
+ *.msp
293
+
294
+ # Windows shortcuts
295
+ *.lnk
296
+
297
+ ### VisualStudio ###
298
+ ## Ignore Visual Studio temporary files, build results, and
299
+ ## files generated by popular Visual Studio add-ons.
300
+ ##
301
+ ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
302
+
303
+ # User-specific files
304
+ *.rsuser
305
+ *.suo
306
+ *.user
307
+ *.userosscache
308
+ *.sln.docstates
309
+
310
+ # User-specific files (MonoDevelop/Xamarin Studio)
311
+ *.userprefs
312
+
313
+ # Mono auto generated files
314
+ mono_crash.*
315
+
316
+ # Build results
317
+ [Dd]ebug/
318
+ [Dd]ebugPublic/
319
+ [Rr]elease/
320
+ [Rr]eleases/
321
+ x64/
322
+ x86/
323
+ [Ww][Ii][Nn]32/
324
+ [Aa][Rr][Mm]/
325
+ [Aa][Rr][Mm]64/
326
+ bld/
327
+ [Bb]in/
328
+ [Oo]bj/
329
+ [Ll]og/
330
+ [Ll]ogs/
331
+
332
+ # Visual Studio 2015/2017 cache/options directory
333
+ .vs/
334
+ # Uncomment if you have tasks that create the project's static files in wwwroot
335
+ #wwwroot/
336
+
337
+ # Visual Studio 2017 auto generated files
338
+ Generated\ Files/
339
+
340
+ # MSTest test Results
341
+ [Tt]est[Rr]esult*/
342
+ [Bb]uild[Ll]og.*
343
+
344
+ # NUnit
345
+ *.VisualState.xml
346
+ TestResult.xml
347
+ nunit-*.xml
348
+
349
+ # Build Results of an ATL Project
350
+ [Dd]ebugPS/
351
+ [Rr]eleasePS/
352
+ dlldata.c
353
+
354
+ # Benchmark Results
355
+ BenchmarkDotNet.Artifacts/
356
+
357
+ # .NET Core
358
+ project.lock.json
359
+ project.fragment.lock.json
360
+ artifacts/
361
+
362
+ # ASP.NET Scaffolding
363
+ ScaffoldingReadMe.txt
364
+
365
+ # StyleCop
366
+ StyleCopReport.xml
367
+
368
+ # Files built by Visual Studio
369
+ *_i.c
370
+ *_p.c
371
+ *_h.h
372
+ *.ilk
373
+ *.meta
374
+ *.obj
375
+ *.iobj
376
+ *.pch
377
+ *.pdb
378
+ *.ipdb
379
+ *.pgc
380
+ *.pgd
381
+ *.rsp
382
+ *.sbr
383
+ *.tlb
384
+ *.tli
385
+ *.tlh
386
+ *.tmp
387
+ *.tmp_proj
388
+ *_wpftmp.csproj
389
+ *.tlog
390
+ *.vspscc
391
+ *.vssscc
392
+ .builds
393
+ *.pidb
394
+ *.svclog
395
+ *.scc
396
+
397
+ # Chutzpah Test files
398
+ _Chutzpah*
399
+
400
+ # Visual C++ cache files
401
+ ipch/
402
+ *.aps
403
+ *.ncb
404
+ *.opendb
405
+ *.opensdf
406
+ *.sdf
407
+ *.cachefile
408
+ *.VC.db
409
+ *.VC.VC.opendb
410
+
411
+ # Visual Studio profiler
412
+ *.psess
413
+ *.vsp
414
+ *.vspx
415
+ *.sap
416
+
417
+ # Visual Studio Trace Files
418
+ *.e2e
419
+
420
+ # TFS 2012 Local Workspace
421
+ $tf/
422
+
423
+ # Guidance Automation Toolkit
424
+ *.gpState
425
+
426
+ # ReSharper is a .NET coding add-in
427
+ _ReSharper*/
428
+ *.[Rr]e[Ss]harper
429
+ *.DotSettings.user
430
+
431
+ # TeamCity is a build add-in
432
+ _TeamCity*
433
+
434
+ # DotCover is a Code Coverage Tool
435
+ *.dotCover
436
+
437
+ # AxoCover is a Code Coverage Tool
438
+ .axoCover/*
439
+ !.axoCover/settings.json
440
+
441
+ # Coverlet is a free, cross platform Code Coverage Tool
442
+ coverage*.json
443
+ coverage*.xml
444
+ coverage*.info
445
+
446
+ # Visual Studio code coverage results
447
+ *.coverage
448
+ *.coveragexml
449
+
450
+ # NCrunch
451
+ _NCrunch_*
452
+ .*crunch*.local.xml
453
+ nCrunchTemp_*
454
+
455
+ # MightyMoose
456
+ *.mm.*
457
+ AutoTest.Net/
458
+
459
+ # Web workbench (sass)
460
+ .sass-cache/
461
+
462
+ # Installshield output folder
463
+ [Ee]xpress/
464
+
465
+ # DocProject is a documentation generator add-in
466
+ DocProject/buildhelp/
467
+ DocProject/Help/*.HxT
468
+ DocProject/Help/*.HxC
469
+ DocProject/Help/*.hhc
470
+ DocProject/Help/*.hhk
471
+ DocProject/Help/*.hhp
472
+ DocProject/Help/Html2
473
+ DocProject/Help/html
474
+
475
+ # Click-Once directory
476
+ publish/
477
+
478
+ # Publish Web Output
479
+ *.[Pp]ublish.xml
480
+ *.azurePubxml
481
+ # Note: Comment the next line if you want to checkin your web deploy settings,
482
+ # but database connection strings (with potential passwords) will be unencrypted
483
+ *.pubxml
484
+ *.publishproj
485
+
486
+ # Microsoft Azure Web App publish settings. Comment the next line if you want to
487
+ # checkin your Azure Web App publish settings, but sensitive information contained
488
+ # in these scripts will be unencrypted
489
+ PublishScripts/
490
+
491
+ # NuGet Packages
492
+ *.nupkg
493
+ # NuGet Symbol Packages
494
+ *.snupkg
495
+ # The packages folder can be ignored because of Package Restore
496
+ **/[Pp]ackages/*
497
+ # except build/, which is used as an MSBuild target.
498
+ !**/[Pp]ackages/build/
499
+ # Uncomment if necessary however generally it will be regenerated when needed
500
+ #!**/[Pp]ackages/repositories.config
501
+ # NuGet v3's project.json files produces more ignorable files
502
+ *.nuget.props
503
+ *.nuget.targets
504
+
505
+ # Microsoft Azure Build Output
506
+ csx/
507
+ *.build.csdef
508
+
509
+ # Microsoft Azure Emulator
510
+ ecf/
511
+ rcf/
512
+
513
+ # Windows Store app package directories and files
514
+ AppPackages/
515
+ BundleArtifacts/
516
+ Package.StoreAssociation.xml
517
+ _pkginfo.txt
518
+ *.appx
519
+ *.appxbundle
520
+ *.appxupload
521
+
522
+ # Visual Studio cache files
523
+ # files ending in .cache can be ignored
524
+ *.[Cc]ache
525
+ # but keep track of directories ending in .cache
526
+ !?*.[Cc]ache/
527
+
528
+ # Others
529
+ ClientBin/
530
+ ~$*
531
+ *.dbmdl
532
+ *.dbproj.schemaview
533
+ *.jfm
534
+ *.pfx
535
+ *.publishsettings
536
+ orleans.codegen.cs
537
+
538
+ # Including strong name files can present a security risk
539
+ # (https://github.com/github/gitignore/pull/2483#issue-259490424)
540
+ #*.snk
541
+
542
+ # Since there are multiple workflows, uncomment next line to ignore bower_components
543
+ # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
544
+ #bower_components/
545
+
546
+ # RIA/Silverlight projects
547
+ Generated_Code/
548
+
549
+ # Backup & report files from converting an old project file
550
+ # to a newer Visual Studio version. Backup files are not needed,
551
+ # because we have git ;-)
552
+ _UpgradeReport_Files/
553
+ Backup*/
554
+ UpgradeLog*.XML
555
+ UpgradeLog*.htm
556
+ ServiceFabricBackup/
557
+ *.rptproj.bak
558
+
559
+ # SQL Server files
560
+ *.mdf
561
+ *.ldf
562
+ *.ndf
563
+
564
+ # Business Intelligence projects
565
+ *.rdl.data
566
+ *.bim.layout
567
+ *.bim_*.settings
568
+ *.rptproj.rsuser
569
+ *- [Bb]ackup.rdl
570
+ *- [Bb]ackup ([0-9]).rdl
571
+ *- [Bb]ackup ([0-9][0-9]).rdl
572
+
573
+ # Microsoft Fakes
574
+ FakesAssemblies/
575
+
576
+ # GhostDoc plugin setting file
577
+ *.GhostDoc.xml
578
+
579
+ # Node.js Tools for Visual Studio
580
+ .ntvs_analysis.dat
581
+ node_modules/
582
+
583
+ # Visual Studio 6 build log
584
+ *.plg
585
+
586
+ # Visual Studio 6 workspace options file
587
+ *.opt
588
+
589
+ # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
590
+ *.vbw
591
+
592
+ # Visual Studio 6 auto-generated project file (contains which files were open etc.)
593
+ *.vbp
594
+
595
+ # Visual Studio 6 workspace and project file (working project files containing files to include in project)
596
+ *.dsw
597
+ *.dsp
598
+
599
+ # Visual Studio 6 technical files
600
+
601
+ # Visual Studio LightSwitch build output
602
+ **/*.HTMLClient/GeneratedArtifacts
603
+ **/*.DesktopClient/GeneratedArtifacts
604
+ **/*.DesktopClient/ModelManifest.xml
605
+ **/*.Server/GeneratedArtifacts
606
+ **/*.Server/ModelManifest.xml
607
+ _Pvt_Extensions
608
+
609
+ # Paket dependency manager
610
+ .paket/paket.exe
611
+ paket-files/
612
+
613
+ # FAKE - F# Make
614
+ .fake/
615
+
616
+ # CodeRush personal settings
617
+ .cr/personal
618
+
619
+ # Python Tools for Visual Studio (PTVS)
620
+ *.pyc
621
+
622
+ # Cake - Uncomment if you are using it
623
+ # tools/**
624
+ # !tools/packages.config
625
+
626
+ # Tabs Studio
627
+ *.tss
628
+
629
+ # Telerik's JustMock configuration file
630
+ *.jmconfig
631
+
632
+ # BizTalk build output
633
+ *.btp.cs
634
+ *.btm.cs
635
+ *.odx.cs
636
+ *.xsd.cs
637
+
638
+ # OpenCover UI analysis results
639
+ OpenCover/
640
+
641
+ # Azure Stream Analytics local run output
642
+ ASALocalRun/
643
+
644
+ # MSBuild Binary and Structured Log
645
+ *.binlog
646
+
647
+ # NVidia Nsight GPU debugger configuration file
648
+ *.nvuser
649
+
650
+ # MFractors (Xamarin productivity tool) working folder
651
+ .mfractor/
652
+
653
+ # Local History for Visual Studio
654
+ .localhistory/
655
+
656
+ # Visual Studio History (VSHistory) files
657
+ .vshistory/
658
+
659
+ # BeatPulse healthcheck temp database
660
+ healthchecksdb
661
+
662
+ # Backup folder for Package Reference Convert tool in Visual Studio 2017
663
+ MigrationBackup/
664
+
665
+ # Ionide (cross platform F# VS Code tools) working folder
666
+ .ionide/
667
+
668
+ # Fody - auto-generated XML schema
669
+ FodyWeavers.xsd
670
+
671
+ # VS Code files for those working on multiple tools
672
+ *.code-workspace
673
+
674
+ # Local History for Visual Studio Code
675
+
676
+ # Windows Installer files from build outputs
677
+
678
+ # JetBrains Rider
679
+ *.sln.iml
680
+
681
+ ### VisualStudio Patch ###
682
+ # Additional files built by Visual Studio
683
+
684
+ # End of https://www.toptal.com/developers/gitignore/api/java,visualstudiocode,macos,linux,windows,python,visualstudio
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use official Python base image
2
+ FROM python:3.12-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Copy project files
8
+ COPY . /app
9
+
10
+ # Install dependencies
11
+ RUN pip install --no-cache-dir --upgrade pip
12
+ RUN pip install --no-cache-dir -r requirements.txt
13
+
14
+ # Expose the port (Spaces expects 7860 or 5000)
15
+ EXPOSE 7860
16
+
17
+ # Start the FastAPI app with uvicorn
18
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Yauheniya AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,12 +1,86 @@
1
- ---
2
- title: Ai Assistant
3
- emoji: 🐨
4
- colorFrom: green
5
- colorTo: red
6
- sdk: docker
7
- pinned: false
8
- license: mit
9
- short_description: A web-based AI assistant built with FastAPI and Hugging Face
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python AI Assistant
2
+
3
+ This is a web-based AI assistant built with FastAPI and Hugging Face Inference API. The app allows users to interact with multiple AI models, either by chatting with text models or generating images with image models.
4
+
5
+ <div style="text-align:center;">
6
+ <img src="./Screenshot.png" style="width:100%; max-width:1200px;">
7
+ <p><em>Fig. 1: Screenshot of the Python AI Assistant interface.</em></p>
8
+ </div>
9
+
10
+ ## Features
11
+
12
+ - Chat with various text-based AI models.
13
+ - Generate images using a text prompt.
14
+ - Dynamic model selection from a dropdown menu.
15
+ - Inline chat interface showing user questions and AI responses.
16
+ - Supports both text and image output.
17
+ - Base64-encoded images are displayed directly in the chat window.
18
+
19
+ ## Available Models
20
+
21
+ - **DeepSeek-V3-0324**: Text-based AI model for general-purpose conversation and responses.
22
+
23
+ - **Llama-3.2-3B-Instruct**: Instruction-tuned text model suitable for chat and instruction tasks.
24
+
25
+ - **GLM-4.5-Air**: Multilingual text model optimized for instruction following and efficiency.
26
+
27
+ - **FLUX.1-dev**: Generates images based on text prompts.
28
+
29
+ ## Structure
30
+
31
+ ```text
32
+ python-ai-assistant/
33
+ ├── main.py # FastAPI app entry point with routes and endpoints
34
+ ├── models/ # Contains model definitions
35
+ │ ├── __init__.py # Marks 'models' as a Python package
36
+ │ └── request_models.py # Defines available AI models and their metadata
37
+ ├── services/ # Contains service logic
38
+ │ ├── __init__.py # Marks 'services' as a Python package
39
+ │ └── ai_assistant.py # Core logic for interacting with Hugging Face models
40
+ ├── static/ # Frontend assets
41
+ │ ├── css/
42
+ │ │ └── styles.css # All CSS styles for the chat interface
43
+ │ ├── images/
44
+ │ │ └── models/ # Icons for each AI model in the dropdown
45
+ │ └── index.html # Main frontend page for the chat interface
46
+ ├── README.md # Project documentation, usage, and models list
47
+ └── requirements.txt # Python dependencies for the project
48
+ ```
49
+
50
+
51
+ ## Installation
52
+
53
+ 1. Clone the repository:
54
+ ```bash
55
+ git clone <repository-url>
56
+ cd python-ai-assistant
57
+ ```
58
+
59
+ 2. Create a virtual environment and install dependencies:
60
+ ```bash
61
+ uv venv --python 3.12
62
+ source .venv/bin/activate
63
+ uv pip install -r requirements.txt
64
+ ```
65
+
66
+ 3. Create a .env file with your Hugging Face API token:
67
+ ```text
68
+ HUGGINGFACE_API_TOKEN=your_token_here
69
+ ```
70
+
71
+ 4. Start the app:
72
+ ```bash
73
+ uvicorn main:app --reload
74
+ ```
75
+
76
+ 5. Open your browser at http://127.0.0.1:8000.
77
+
78
+ ## Usage
79
+ - Select a model from the dropdown menu at the top.
80
+ - Type your question or prompt in the input box.
81
+ - Click the send button or press Enter to submit.
82
+ - Text responses appear directly in the chat. Image responses are displayed in-line and can be saved.
83
+
84
+ ## Notes
85
+ The app differentiates between text models and image models for proper rendering.
86
+ Only models available via Hugging Face Inference API are supported.
Screenshot.png ADDED

Git LFS Details

  • SHA256: bfadfe48e8f57ed563b170affb312195a0f79cee59c7f8fdf06cc66af80588a7
  • Pointer size: 132 Bytes
  • Size of remote file: 1.33 MB
main.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from fastapi.responses import HTMLResponse, PlainTextResponse
3
+ from fastapi.staticfiles import StaticFiles
4
+ from models.request_models import AskRequest
5
+ #from services.openai_assistant import OpenAIAssistantService
6
+ from services.ai_assistant import HuggingFaceAssistantService
7
+ from fastapi.responses import JSONResponse
8
+
9
+ app = FastAPI()
10
+
11
+ # Mount static files (UI assets from Java project)
12
+ app.mount("/static", StaticFiles(directory="static"), name="static")
13
+
14
+ # Service instance
15
+ assistant_service = HuggingFaceAssistantService()
16
+
17
+
18
+ @app.post("/ask")
19
+ async def ask(request: AskRequest):
20
+ result = await assistant_service.ask(request.question, request.model)
21
+ return JSONResponse(content=result)
22
+
23
+ @app.get("/", response_class=HTMLResponse)
24
+ async def serve_index():
25
+ with open("static/index.html") as f:
26
+ return f.read()
models/__init__.py ADDED
File without changes
models/request_models.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+
3
+ class AskRequest(BaseModel):
4
+ question: str
5
+ model: str | None = None
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ python-dotenv
4
+ openai
5
+ huggingface_hub
6
+ huggingface_hub[cli]
7
+ Pillow==11.3.0
services/__init__.py ADDED
File without changes
services/ai_assistant.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # services/ai_assistant.py
2
+ import io
3
+ import base64
4
+ import os
5
+ import asyncio
6
+ from dotenv import load_dotenv
7
+ from huggingface_hub import InferenceClient
8
+
9
+ load_dotenv()
10
+
11
+ class HuggingFaceAssistantService:
12
+ def __init__(self):
13
+ token = os.getenv("HUGGINGFACE_API_TOKEN")
14
+ if not token:
15
+ raise RuntimeError("HUGGINGFACE_API_TOKEN not set")
16
+ self.client = InferenceClient(api_key=token)
17
+
18
+ async def ask(self, question: str, model: str | None):
19
+ model_repo = model or "meta-llama/Llama-3.2-3B-Instruct"
20
+
21
+ if model_repo.startswith("black-forest-labs/"):
22
+ # Generate image in a thread
23
+ image = await asyncio.to_thread(
24
+ self.client.text_to_image,
25
+ prompt=question,
26
+ model=model_repo
27
+ )
28
+ # Convert to base64
29
+ buf = io.BytesIO()
30
+ image.save(buf, format="PNG")
31
+ img_b64 = base64.b64encode(buf.getvalue()).decode("utf-8")
32
+ return {"type": "image", "content": img_b64}
33
+
34
+ else:
35
+ completion = await asyncio.to_thread(
36
+ self.client.chat.completions.create,
37
+ model=model_repo,
38
+ messages=[{"role": "user", "content": question}]
39
+ )
40
+ return {"type": "text", "content": completion.choices[0].message.content}
static/css/styles.css ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root {
2
+ --max-w: 800px;
3
+ --bg: #ffffff;
4
+ --panel: #f7f7f7;
5
+ --muted: #767676;
6
+ --accent: #000;
7
+ --rounded: 12px;
8
+ }
9
+ html,body { height:100%; margin:0; font-family: Inter, Arial, sans-serif; background:var(--bg); color:#111; }
10
+ .outer { display:flex; align-items:center; justify-content:center; min-height:100vh; padding:24px; box-sizing:border-box; }
11
+ .container {
12
+ width:100%; max-width:var(--max-w);
13
+ display:flex; flex-direction:column;
14
+ gap:16px;
15
+ }
16
+
17
+ /* header */
18
+ .top-bar { display:flex; align-items:center; gap:12px; }
19
+ .model-select {
20
+ position:relative;
21
+ display:inline-flex;
22
+ align-items:center;
23
+ gap:10px;
24
+ padding:10px 14px;
25
+ border-radius:10px;
26
+ background:#f2f2f2;
27
+ border:1px solid #e6e6e6;
28
+ cursor:pointer;
29
+ min-width:220px;
30
+ box-shadow:0 0 0 0 rgba(0,0,0,0);
31
+ }
32
+ .model-select .selected {
33
+ display:flex; align-items:center; gap:10px;
34
+ }
35
+ .model-select .meta {
36
+ display:flex;
37
+ flex-direction:column;
38
+ }
39
+ .model-select img { width:32px; height:32px; border-radius:6px; object-fit:cover; }
40
+ .model-select .name { font-weight:600; font-size:14px; }
41
+ .model-select .note { font-size:12px; color:var(--muted); margin-left:6px; font-weight:500; }
42
+
43
+ /* dropdown list */
44
+ .dropdown {
45
+ position:absolute;
46
+ top:calc(100% + 8px);
47
+ left:0;
48
+ right:auto;
49
+ background:white;
50
+ border-radius:10px;
51
+ box-shadow:0 6px 18px rgba(0,0,0,0.08);
52
+ border:1px solid #eee;
53
+ overflow:hidden;
54
+ z-index:30;
55
+ max-height:360px;
56
+ overflow-y: auto;
57
+ width:250px;
58
+ }
59
+ .dropdown .item {
60
+ display:flex; align-items:center; gap:10px;
61
+ padding:10px 12px; cursor:pointer;
62
+ }
63
+ .dropdown .item:hover { background:#fafafa; }
64
+ .dropdown .item .meta { display:flex; flex-direction:column; }
65
+ .dropdown .item .title { font-weight:600; font-size:13px; }
66
+ .dropdown .item .sub { font-size:12px; color:var(--muted); }
67
+
68
+ /* chat area */
69
+ .chat-box {
70
+ background:var(--panel);
71
+ padding:20px;
72
+ border-radius:var(--rounded);
73
+ min-height:720px;
74
+ max-height:56vh;
75
+ overflow:auto;
76
+ display:flex;
77
+ flex-direction:column;
78
+ gap:12px;
79
+ }
80
+ .message { max-width:72%; padding:12px 14px; border-radius:12px; }
81
+ .user { margin-left:auto; background:white; border:1px solid #f1d8f8; }
82
+ .assistant { margin-right:auto; background:white; border:1px solid #ececec; }
83
+
84
+ /* input area */
85
+ .input-row {
86
+ display:flex; gap:10px; align-items:center;
87
+ }
88
+ .input {
89
+ flex: 1;
90
+ background: white;
91
+ border-radius: 24px;
92
+ border: 1px solid #ddd;
93
+ padding: 12px 24px;
94
+ box-sizing: border-box; /* VERY IMPORTANT */
95
+ min-height: 48px;
96
+ max-height: 200px; /* limit expansion */
97
+ overflow-y: auto; /* show scroll after max-height */
98
+ resize: none;
99
+ outline: none;
100
+ font-size: 18px;
101
+ line-height: 1.5; /* slightly bigger line spacing */
102
+ }
103
+
104
+
105
+ .send-btn {
106
+ width:44px; height:44px; border-radius:50%;
107
+ background:var(--accent); color:white; display:inline-flex;
108
+ align-items:center; justify-content:center; border:none; cursor:pointer;
109
+ box-shadow: 0 2px 6px rgba(0,0,0,0.12);
110
+ }
111
+ .note-footer {
112
+ text-align:center; color:var(--muted); font-size:13px; margin-top:6px;
113
+ }
114
+
115
+ /* small helpers */
116
+ .small { font-size:12px; color:var(--muted); }
static/images/models/DeepSeek.svg ADDED

Git LFS Details

  • SHA256: b51855814ddd603974f82223b63446165b7ca4b486112bdc6a73de709e5e8284
  • Pointer size: 129 Bytes
  • Size of remote file: 2.15 kB
static/images/models/Meta.svg ADDED

Git LFS Details

  • SHA256: b83a9e3acd26e2d172f42e50fc3d2de33b3e4f291860f56070154a5814c4cd6a
  • Pointer size: 129 Bytes
  • Size of remote file: 2.73 kB
static/images/models/Screenshot 2025-09-22 at 20.30.50.png ADDED

Git LFS Details

  • SHA256: bfadfe48e8f57ed563b170affb312195a0f79cee59c7f8fdf06cc66af80588a7
  • Pointer size: 132 Bytes
  • Size of remote file: 1.33 MB
static/images/models/bfl.svg ADDED

Git LFS Details

  • SHA256: c08f545c77c40f2447fb91d75f78db81dc2aeebb7291bb51ad2a982276219dc7
  • Pointer size: 128 Bytes
  • Size of remote file: 387 Bytes
static/images/models/zai.svg ADDED

Git LFS Details

  • SHA256: e748cb5108ce37b116d7a5ba97d37e0ae97eadf6849b0de11afb248e244a01e1
  • Pointer size: 128 Bytes
  • Size of remote file: 319 Bytes
static/index.html ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>AI Assistant</title>
6
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
7
+ <link rel="stylesheet" href="/static/css/styles.css">
8
+ </head>
9
+ <body>
10
+ <div class="outer">
11
+ <div class="container">
12
+
13
+ <!-- top bar: model dropdown left -->
14
+ <div class="top-bar">
15
+ <div id="modelSelector" class="model-select" tabindex="0" aria-haspopup="listbox">
16
+ <div class="selected">
17
+ <img id="selectedIcon" src="./static/images/models/DeepSeek.svg" alt="model"/>
18
+ <div class="meta">
19
+ <div class="name" id="selectedName">DeepSeek V3</div>
20
+ <div class="note small" id="selectedNote" ></div>
21
+ </div>
22
+ </div>
23
+ </div>
24
+ </div>
25
+
26
+ <!-- chat -->
27
+ <div id="chatBox" class="chat-box"></div>
28
+
29
+ <!-- input -->
30
+ <div class="input-row">
31
+ <textarea id="inputText" class="input" rows="1" placeholder="Ask anything"></textarea>
32
+ <button id="sendBtn" class="send-btn" title="Send">➤</button>
33
+ </div>
34
+
35
+ <div class="note-footer">A minimal AI assistant to generate text and images.</div>
36
+ </div>
37
+ </div>
38
+
39
+ <!-- dropdown template (hidden until used) -->
40
+ <div id="dropdownTemplate" style="display:none">
41
+ <div class="dropdown" id="modelDropdown" role="listbox" aria-label="Models"></div>
42
+ </div>
43
+
44
+ <script>
45
+ const models = [
46
+ {
47
+ id: "deepseek-ai/DeepSeek-V3-0324",
48
+ display: "DeepSeek-V3-0324",
49
+ icon: "DeepSeek.svg",
50
+ note: "Text model"
51
+ },
52
+ {
53
+ id: "meta-llama/Llama-3.2-3B-Instruct",
54
+ display: "Llama-3.2-3B-Instruct",
55
+ icon: "Meta.svg",
56
+ note: "Text model"
57
+ },
58
+ {
59
+ id: "zai-org/GLM-4.5-Air",
60
+ display: "GLM-4.5-Air",
61
+ icon: "Zai.svg",
62
+ note: "Text model"
63
+ },
64
+ {
65
+ id: "black-forest-labs/FLUX.1-dev",
66
+ display: "FLUX.1-dev",
67
+ icon: "bfl.svg",
68
+ note: "Image model"
69
+ },
70
+ ];
71
+
72
+
73
+ // build dropdown
74
+ const modelSelector = document.getElementById('modelSelector');
75
+ const dropdown = document.createElement('div');
76
+ dropdown.className = 'dropdown';
77
+ dropdown.style.display = 'none';
78
+ document.body.appendChild(dropdown);
79
+
80
+ function buildList() {
81
+ dropdown.innerHTML = '';
82
+ models.forEach(m => {
83
+ const item = document.createElement('div');
84
+ item.className = 'item';
85
+ item.tabIndex = 0;
86
+
87
+ item.innerHTML = `
88
+ <img src="./static/images/models/${m.icon}" alt="${m.display}"
89
+ style="width:36px;height:36px;border-radius:6px;object-fit:cover;margin-right:8px;">
90
+ <div class="meta">
91
+ <div class="title">${m.display}</div>
92
+ <div class="sub">${m.note || ''}</div>
93
+ </div>
94
+ `;
95
+
96
+ item.addEventListener('click', () => {
97
+ selectModel(m);
98
+ hideDropdown();
99
+ document.getElementById('inputText').focus();
100
+ });
101
+
102
+ dropdown.appendChild(item);
103
+ });
104
+ }
105
+
106
+ function showDropdown() {
107
+ buildList();
108
+ const rect = modelSelector.getBoundingClientRect();
109
+ dropdown.style.left = rect.left + 'px';
110
+ dropdown.style.top = (rect.bottom + 8) + 'px';
111
+ dropdown.style.display = 'block';
112
+ }
113
+ function hideDropdown() { dropdown.style.display = 'none'; }
114
+
115
+ // selection
116
+ let currentModel = models[0];
117
+ function selectModel(m) {
118
+ currentModel = m;
119
+ document.getElementById('selectedIcon').src = './static/images/models/' + m.icon;
120
+ document.getElementById('selectedName').innerText = m.display;
121
+ if (m.id.startsWith("black-forest-labs/")) {
122
+ document.getElementById('selectedNote').innerText = "■ " + (m.note || "");
123
+ } else {
124
+ document.getElementById('selectedNote').innerText = "文 " + (m.note || "");
125
+ }
126
+ }
127
+
128
+ modelSelector.addEventListener('click', () => {
129
+ if (dropdown.style.display === 'block') hideDropdown(); else showDropdown();
130
+ });
131
+
132
+ document.addEventListener('click', (e) => {
133
+ if (!modelSelector.contains(e.target) && !dropdown.contains(e.target)) hideDropdown();
134
+ });
135
+
136
+ // init
137
+ selectModel(currentModel);
138
+
139
+ // chat logic: send question + model to /ask
140
+ const sendBtn = document.getElementById('sendBtn');
141
+ const inputText = document.getElementById('inputText');
142
+ const chatBox = document.getElementById('chatBox');
143
+
144
+ function autoResizeTextarea() {
145
+ this.style.height = 'auto'; // reset height
146
+ this.style.height = Math.min(this.scrollHeight, 200) + 'px'; // respect max-height
147
+ }
148
+ inputText.addEventListener('input', autoResizeTextarea);
149
+
150
+ async function sendQuestion() {
151
+ const question = inputText.value.trim();
152
+ if (!question) return;
153
+
154
+ // show user bubble
155
+ const um = document.createElement('div');
156
+ um.className = 'message user';
157
+ um.innerText = question;
158
+ chatBox.appendChild(um);
159
+ inputText.value = '';
160
+ chatBox.scrollTop = chatBox.scrollHeight;
161
+
162
+ try {
163
+ const res = await fetch('/ask', {
164
+ method: 'POST',
165
+ headers: { 'Content-Type': 'application/json' },
166
+ body: JSON.stringify({ question, model: currentModel.id })
167
+ });
168
+
169
+ const data = await res.json(); // parse JSON from backend
170
+ const am = document.createElement('div');
171
+ am.className = 'message assistant';
172
+
173
+ if (data.type === "text") {
174
+ am.innerText = data.content;
175
+ } else if (data.type === "image") {
176
+ const img = document.createElement('img');
177
+ img.src = "data:image/png;base64," + data.content;
178
+ img.style.maxWidth = "100%";
179
+ img.style.borderRadius = "8px";
180
+
181
+ // 👇 Add download link
182
+ const link = document.createElement('a');
183
+ link.href = img.src;
184
+ link.download = "Image.png"; // default filename instead of "Unknown"
185
+ link.innerText = "💾";
186
+ link.style.display = "block";
187
+ link.style.marginTop = "4px";
188
+
189
+ am.appendChild(img);
190
+ am.appendChild(link); // add link below the image
191
+ } else {
192
+ am.innerText = "⚠️ Unknown response type";
193
+ }
194
+
195
+ chatBox.appendChild(am);
196
+ chatBox.scrollTop = chatBox.scrollHeight;
197
+ } catch (err) {
198
+ const am = document.createElement('div');
199
+ am.className = 'message assistant';
200
+ am.innerText = 'Error: ' + (err.message || err);
201
+ chatBox.appendChild(am);
202
+ chatBox.scrollTop = chatBox.scrollHeight;
203
+ }
204
+ }
205
+
206
+ sendBtn.addEventListener('click', sendQuestion);
207
+ inputText.addEventListener('keydown', (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendQuestion(); } });
208
+ </script>
209
+ </body>
210
+ </html>